forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
414b47645d
commit
c8ba2b67a0
|
@ -2284,16 +2284,25 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef<InvokeInst *> Invokes) {
|
||||||
if (any_of(Invokes, IsIllegalToMerge))
|
if (any_of(Invokes, IsIllegalToMerge))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// All callees must be identical.
|
// Either both `invoke`s must be direct,
|
||||||
// FIXME: support indirect callees?
|
// or both `invoke`s must be indirect.
|
||||||
Value *Callee = nullptr;
|
auto IsIndirectCall = [](InvokeInst *II) { return II->isIndirectCall(); };
|
||||||
for (InvokeInst *II : Invokes) {
|
bool HaveIndirectCalls = any_of(Invokes, IsIndirectCall);
|
||||||
Value *CurrCallee = II->getCalledOperand();
|
bool AllCallsAreIndirect = all_of(Invokes, IsIndirectCall);
|
||||||
assert(CurrCallee && "There is always a called operand.");
|
if (HaveIndirectCalls) {
|
||||||
if (!Callee)
|
if (!AllCallsAreIndirect)
|
||||||
Callee = CurrCallee;
|
|
||||||
else if (Callee != CurrCallee)
|
|
||||||
return false;
|
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,
|
// Either both `invoke`s must not have a normal destination,
|
||||||
|
@ -2436,8 +2445,17 @@ static void MergeCompatibleInvokesImpl(ArrayRef<InvokeInst *> Invokes,
|
||||||
{DominatorTree::Delete, II->getParent(), SuccOfPredBB});
|
{DominatorTree::Delete, II->getParent(), SuccOfPredBB});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Form the merged data operands for the merged invoke.
|
bool IsIndirectCall = Invokes[0]->isIndirectCall();
|
||||||
for (Use &U : MergedInvoke->data_ops()) {
|
|
||||||
|
// 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.
|
// Don't create trivial PHI's with all-identical incoming values.
|
||||||
bool NeedPHI = any_of(Invokes, [&U](InvokeInst *II) {
|
bool NeedPHI = any_of(Invokes, [&U](InvokeInst *II) {
|
||||||
return II->getOperand(U.getOperandNo()) != U.get();
|
return II->getOperand(U.getOperandNo()) != U.get();
|
||||||
|
@ -2448,10 +2466,8 @@ static void MergeCompatibleInvokesImpl(ArrayRef<InvokeInst *> Invokes,
|
||||||
// Form a PHI out of all the data ops under this index.
|
// Form a PHI out of all the data ops under this index.
|
||||||
PHINode *PN = PHINode::Create(
|
PHINode *PN = PHINode::Create(
|
||||||
U->getType(), /*NumReservedValues=*/Invokes.size(), "", MergedInvoke);
|
U->getType(), /*NumReservedValues=*/Invokes.size(), "", MergedInvoke);
|
||||||
for (InvokeInst *II : Invokes) {
|
for (InvokeInst *II : Invokes)
|
||||||
Use *IVU = II->data_operands_begin() + MergedInvoke->getDataOperandNo(&U);
|
PN->addIncoming(II->getOperand(U.getOperandNo()), II->getParent());
|
||||||
PN->addIncoming(IVU->get(), II->getParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
U.set(PN);
|
U.set(PN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2166,12 +2166,7 @@ define void @t36_different_indirect_callees(void()* %callee0, void()* %callee1)
|
||||||
; CHECK-LABEL: @t36_different_indirect_callees(
|
; CHECK-LABEL: @t36_different_indirect_callees(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
|
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], 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: lpad:
|
; CHECK: lpad:
|
||||||
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
||||||
; CHECK-NEXT: cleanup
|
; CHECK-NEXT: cleanup
|
||||||
|
@ -2179,11 +2174,12 @@ define void @t36_different_indirect_callees(void()* %callee0, void()* %callee1)
|
||||||
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
|
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
|
||||||
; CHECK: if.else:
|
; CHECK: if.else:
|
||||||
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
|
||||||
; CHECK: if.then1:
|
; CHECK: if.then1.invoke:
|
||||||
; CHECK-NEXT: invoke void [[CALLEE1:%.*]]()
|
; CHECK-NEXT: [[TMP0:%.*]] = phi void ()* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY:%.*]] ]
|
||||||
; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
|
; CHECK-NEXT: invoke void [[TMP0]]()
|
||||||
; CHECK: invoke.cont2:
|
; CHECK-NEXT: to label [[IF_THEN1_CONT:%.*]] unwind label [[LPAD:%.*]]
|
||||||
|
; CHECK: if.then1.cont:
|
||||||
; CHECK-NEXT: unreachable
|
; CHECK-NEXT: unreachable
|
||||||
; CHECK: if.end:
|
; CHECK: if.end:
|
||||||
; CHECK-NEXT: call void @sideeffect()
|
; 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-LABEL: @t38_different_arguments_and_operand_bundes_are_fine(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
|
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], 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: lpad:
|
; CHECK: lpad:
|
||||||
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
||||||
; CHECK-NEXT: cleanup
|
; 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-NEXT: resume { i8*, i32 } [[EH]]
|
||||||
; CHECK: if.else:
|
; CHECK: if.else:
|
||||||
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
|
||||||
; CHECK: if.then1:
|
; CHECK: if.then1.invoke:
|
||||||
; CHECK-NEXT: invoke void [[CALLEE1:%.*]](i32 42)
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 42, [[IF_ELSE]] ], [ 0, [[ENTRY:%.*]] ]
|
||||||
; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
|
; CHECK-NEXT: [[TMP1:%.*]] = phi void (i32)* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY]] ]
|
||||||
; CHECK: invoke.cont2:
|
; 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-NEXT: unreachable
|
||||||
; CHECK: if.end:
|
; CHECK: if.end:
|
||||||
; CHECK-NEXT: call void @sideeffect()
|
; 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-LABEL: @t39_different_arguments_and_operand_bundes_are_fine(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
|
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], 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: lpad:
|
; CHECK: lpad:
|
||||||
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
||||||
; CHECK-NEXT: cleanup
|
; 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-NEXT: resume { i8*, i32 } [[EH]]
|
||||||
; CHECK: if.else:
|
; CHECK: if.else:
|
||||||
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
|
||||||
; CHECK: if.then1:
|
; CHECK: if.then1.invoke:
|
||||||
; CHECK-NEXT: invoke void [[CALLEE1:%.*]]() [ "abc"(i32 0) ]
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[IF_ELSE]] ], [ 42, [[ENTRY:%.*]] ]
|
||||||
; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
|
; CHECK-NEXT: [[TMP1:%.*]] = phi void ()* [ [[CALLEE1:%.*]], [[IF_ELSE]] ], [ [[CALLEE0:%.*]], [[ENTRY]] ]
|
||||||
; CHECK: invoke.cont2:
|
; 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-NEXT: unreachable
|
||||||
; CHECK: if.end:
|
; CHECK: if.end:
|
||||||
; CHECK-NEXT: call void @sideeffect()
|
; 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-LABEL: @t40_different_arguments_and_operand_bundes_are_fine(
|
||||||
; CHECK-NEXT: entry:
|
; CHECK-NEXT: entry:
|
||||||
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
|
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], 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: lpad:
|
; CHECK: lpad:
|
||||||
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
; CHECK-NEXT: [[EH:%.*]] = landingpad { i8*, i32 }
|
||||||
; CHECK-NEXT: cleanup
|
; 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-NEXT: resume { i8*, i32 } [[EH]]
|
||||||
; CHECK: if.else:
|
; CHECK: if.else:
|
||||||
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
|
||||||
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
|
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
|
||||||
; CHECK: if.then1:
|
; CHECK: if.then1.invoke:
|
||||||
; CHECK-NEXT: invoke void [[CALLEE1:%.*]](i32 42) [ "abc"(i32 0) ]
|
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 42, [[IF_ELSE]] ], [ 0, [[ENTRY:%.*]] ]
|
||||||
; CHECK-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
|
; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 0, [[IF_ELSE]] ], [ 42, [[ENTRY]] ]
|
||||||
; CHECK: invoke.cont2:
|
; 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-NEXT: unreachable
|
||||||
; CHECK: if.end:
|
; CHECK: if.end:
|
||||||
; CHECK-NEXT: call void @sideeffect()
|
; CHECK-NEXT: call void @sideeffect()
|
||||||
|
|
Loading…
Reference in New Issue