[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:
Roman Lebedev 2022-02-08 21:17:23 +03:00
parent 414b47645d
commit c8ba2b67a0
No known key found for this signature in database
GPG Key ID: 083C3EBB4A1689E0
2 changed files with 63 additions and 59 deletions

View File

@ -2284,16 +2284,25 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef<InvokeInst *> 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<InvokeInst *> 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<InvokeInst *> 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);
}

View File

@ -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()