From c8ba2b67a0adebd15dcda70766d4ebaa0ec03720 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 8 Feb 2022 21:17:23 +0300 Subject: [PATCH] [SimplifyCFG] 'merge compatible invokes': fully support indirect invokes As long as *all* the invokes in the set are indirect, we can merge them, but don't merge direct invokes into the set, even though it would be legal to do. --- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 46 ++++++++----- .../X86/merge-compatible-invokes-of-landingpad.ll | 76 +++++++++------------- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 2f67573..5c6a7b7 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -2284,16 +2284,25 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef Invokes) { if (any_of(Invokes, IsIllegalToMerge)) return false; - // All callees must be identical. - // FIXME: support indirect callees? - Value *Callee = nullptr; - for (InvokeInst *II : Invokes) { - Value *CurrCallee = II->getCalledOperand(); - assert(CurrCallee && "There is always a called operand."); - if (!Callee) - Callee = CurrCallee; - else if (Callee != CurrCallee) + // Either both `invoke`s must be direct, + // or both `invoke`s must be indirect. + auto IsIndirectCall = [](InvokeInst *II) { return II->isIndirectCall(); }; + bool HaveIndirectCalls = any_of(Invokes, IsIndirectCall); + bool AllCallsAreIndirect = all_of(Invokes, IsIndirectCall); + if (HaveIndirectCalls) { + if (!AllCallsAreIndirect) return false; + } else { + // All callees must be identical. + Value *Callee = nullptr; + for (InvokeInst *II : Invokes) { + Value *CurrCallee = II->getCalledOperand(); + assert(CurrCallee && "There is always a called operand."); + if (!Callee) + Callee = CurrCallee; + else if (Callee != CurrCallee) + return false; + } } // Either both `invoke`s must not have a normal destination, @@ -2436,8 +2445,17 @@ static void MergeCompatibleInvokesImpl(ArrayRef Invokes, {DominatorTree::Delete, II->getParent(), SuccOfPredBB}); } - // Form the merged data operands for the merged invoke. - for (Use &U : MergedInvoke->data_ops()) { + bool IsIndirectCall = Invokes[0]->isIndirectCall(); + + // Form the merged operands for the merged invoke. + for (Use &U : MergedInvoke->operands()) { + // Only PHI together the indirect callees and data operands. + if (MergedInvoke->isCallee(&U)) { + if (!IsIndirectCall) + continue; + } else if (!MergedInvoke->isDataOperand(&U)) + continue; + // Don't create trivial PHI's with all-identical incoming values. bool NeedPHI = any_of(Invokes, [&U](InvokeInst *II) { return II->getOperand(U.getOperandNo()) != U.get(); @@ -2448,10 +2466,8 @@ static void MergeCompatibleInvokesImpl(ArrayRef Invokes, // Form a PHI out of all the data ops under this index. PHINode *PN = PHINode::Create( U->getType(), /*NumReservedValues=*/Invokes.size(), "", MergedInvoke); - for (InvokeInst *II : Invokes) { - Use *IVU = II->data_operands_begin() + MergedInvoke->getDataOperandNo(&U); - PN->addIncoming(IVU->get(), II->getParent()); - } + for (InvokeInst *II : Invokes) + PN->addIncoming(II->getOperand(U.getOperandNo()), II->getParent()); U.set(PN); } diff --git a/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll b/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll index fb44442..20ecd03 100644 --- a/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll +++ b/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll @@ -2166,12 +2166,7 @@ define void @t36_different_indirect_callees(void()* %callee0, void()* %callee1) ; CHECK-LABEL: @t36_different_indirect_callees( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C0:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]] -; CHECK: if.then0: -; CHECK-NEXT: invoke void [[CALLEE0:%.*]]() -; CHECK-NEXT: to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]] -; CHECK: invoke.cont0: -; CHECK-NEXT: unreachable +; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]] ; CHECK: lpad: ; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 } ; CHECK-NEXT: cleanup @@ -2179,11 +2174,12 @@ define void @t36_different_indirect_callees(void()* %callee0, void()* %callee1) ; CHECK-NEXT: resume { i8*, i32 } [[EH]] ; CHECK: if.else: ; CHECK-NEXT: [[C1:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] -; CHECK: if.then1: -; CHECK-NEXT: invoke void [[CALLEE1:%.*]]() -; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] -; CHECK: invoke.cont2: +; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]] +; CHECK: if.then1.invoke: +; CHECK-NEXT: [[TMP0:%.*]] = phi void ()* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY:%.*]] ] +; CHECK-NEXT: invoke void [[TMP0]]() +; CHECK-NEXT: to label [[IF_THEN1_CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: if.then1.cont: ; CHECK-NEXT: unreachable ; CHECK: if.end: ; CHECK-NEXT: call void @sideeffect() @@ -2295,12 +2291,7 @@ define void @t38_different_arguments_and_operand_bundes_are_fine(void(i32)* %cal ; CHECK-LABEL: @t38_different_arguments_and_operand_bundes_are_fine( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C0:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]] -; CHECK: if.then0: -; CHECK-NEXT: invoke void [[CALLEE0:%.*]](i32 0) -; CHECK-NEXT: to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]] -; CHECK: invoke.cont0: -; CHECK-NEXT: unreachable +; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]] ; CHECK: lpad: ; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 } ; CHECK-NEXT: cleanup @@ -2308,11 +2299,13 @@ define void @t38_different_arguments_and_operand_bundes_are_fine(void(i32)* %cal ; CHECK-NEXT: resume { i8*, i32 } [[EH]] ; CHECK: if.else: ; CHECK-NEXT: [[C1:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] -; CHECK: if.then1: -; CHECK-NEXT: invoke void [[CALLEE1:%.*]](i32 42) -; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] -; CHECK: invoke.cont2: +; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]] +; CHECK: if.then1.invoke: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 42, [[IF_ELSE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[TMP1:%.*]] = phi void (i32)* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY]] ] +; CHECK-NEXT: invoke void [[TMP1]](i32 [[TMP0]]) +; CHECK-NEXT: to label [[IF_THEN1_CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: if.then1.cont: ; CHECK-NEXT: unreachable ; CHECK: if.end: ; CHECK-NEXT: call void @sideeffect() @@ -2353,12 +2346,7 @@ define void @t39_different_arguments_and_operand_bundes_are_fine(void()* %callee ; CHECK-LABEL: @t39_different_arguments_and_operand_bundes_are_fine( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C0:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]] -; CHECK: if.then0: -; CHECK-NEXT: invoke void [[CALLEE0:%.*]]() [ "abc"(i32 42) ] -; CHECK-NEXT: to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]] -; CHECK: invoke.cont0: -; CHECK-NEXT: unreachable +; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]] ; CHECK: lpad: ; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 } ; CHECK-NEXT: cleanup @@ -2366,11 +2354,13 @@ define void @t39_different_arguments_and_operand_bundes_are_fine(void()* %callee ; CHECK-NEXT: resume { i8*, i32 } [[EH]] ; CHECK: if.else: ; CHECK-NEXT: [[C1:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] -; CHECK: if.then1: -; CHECK-NEXT: invoke void [[CALLEE1:%.*]]() [ "abc"(i32 0) ] -; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] -; CHECK: invoke.cont2: +; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]] +; CHECK: if.then1.invoke: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[IF_ELSE]] ], [ 42, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[TMP1:%.*]] = phi void ()* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY]] ] +; CHECK-NEXT: invoke void [[TMP1]]() [ "abc"(i32 [[TMP0]]) ] +; CHECK-NEXT: to label [[IF_THEN1_CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: if.then1.cont: ; CHECK-NEXT: unreachable ; CHECK: if.end: ; CHECK-NEXT: call void @sideeffect() @@ -2411,12 +2401,7 @@ define void @t40_different_arguments_and_operand_bundes_are_fine(void(i32)* %cal ; CHECK-LABEL: @t40_different_arguments_and_operand_bundes_are_fine( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C0:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]] -; CHECK: if.then0: -; CHECK-NEXT: invoke void [[CALLEE0:%.*]](i32 0) [ "abc"(i32 42) ] -; CHECK-NEXT: to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]] -; CHECK: invoke.cont0: -; CHECK-NEXT: unreachable +; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]] ; CHECK: lpad: ; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 } ; CHECK-NEXT: cleanup @@ -2424,11 +2409,14 @@ define void @t40_different_arguments_and_operand_bundes_are_fine(void(i32)* %cal ; CHECK-NEXT: resume { i8*, i32 } [[EH]] ; CHECK: if.else: ; CHECK-NEXT: [[C1:%.*]] = call i1 @cond() -; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]] -; CHECK: if.then1: -; CHECK-NEXT: invoke void [[CALLEE1:%.*]](i32 42) [ "abc"(i32 0) ] -; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]] -; CHECK: invoke.cont2: +; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]] +; CHECK: if.then1.invoke: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 42, [[IF_ELSE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 0, [[IF_ELSE]] ], [ 42, [[ENTRY]] ] +; CHECK-NEXT: [[TMP2:%.*]] = phi void (i32)* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY]] ] +; CHECK-NEXT: invoke void [[TMP2]](i32 [[TMP0]]) [ "abc"(i32 [[TMP1]]) ] +; CHECK-NEXT: to label [[IF_THEN1_CONT:%.*]] unwind label [[LPAD:%.*]] +; CHECK: if.then1.cont: ; CHECK-NEXT: unreachable ; CHECK: if.end: ; CHECK-NEXT: call void @sideeffect() -- 2.7.4