Skip to content

Commit 42ca7cc

Browse files
committed
[SimplifyCFG] 'merge compatible invokes': support normal destination w/ uses
If the original invokes had uses, the uses must have been in PHI's, but that immediately results in the incoming values being incompatible. But we'll replace uses of the original invokes with the use of the merged invoke, so as long as the incoming values become compatible after that, we can merge.
1 parent 9986d60 commit 42ca7cc

File tree

2 files changed

+33
-35
lines changed

2 files changed

+33
-35
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

+20-13
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,28 @@ class SimplifyCFGOpt {
296296
/// Return true if all the PHI nodes in the basic block \p BB
297297
/// receive compatible (identical) incoming values when coming from
298298
/// all of the predecessor blocks that are specified in \p IncomingBlocks.
299-
static bool IncomingValuesAreCompatible(BasicBlock *BB,
300-
ArrayRef<BasicBlock *> IncomingBlocks) {
299+
///
300+
/// Note that if the values aren't exactly identical, but \p EquivalenceSet
301+
/// is provided, and *both* of the values are present in the set,
302+
/// then they are considered equal.
303+
static bool IncomingValuesAreCompatible(
304+
BasicBlock *BB, ArrayRef<BasicBlock *> IncomingBlocks,
305+
SmallPtrSetImpl<Value *> *EquivalenceSet = nullptr) {
301306
assert(IncomingBlocks.size() == 2 &&
302307
"Only for a pair of incoming blocks at the time!");
303308

304309
// FIXME: it is okay if one of the incoming values is an `undef` value,
305310
// iff the other incoming value is guaranteed to be a non-poison value.
306311
// FIXME: it is okay if one of the incoming values is a `poison` value.
307-
return all_of(BB->phis(), [IncomingBlocks](PHINode &PN) {
308-
return PN.getIncomingValueForBlock(IncomingBlocks[0]) ==
309-
PN.getIncomingValueForBlock(IncomingBlocks[1]);
312+
return all_of(BB->phis(), [IncomingBlocks, EquivalenceSet](PHINode &PN) {
313+
Value *IV0 = PN.getIncomingValueForBlock(IncomingBlocks[0]);
314+
Value *IV1 = PN.getIncomingValueForBlock(IncomingBlocks[1]);
315+
if (IV0 == IV1)
316+
return true;
317+
if (EquivalenceSet && EquivalenceSet->contains(IV0) &&
318+
EquivalenceSet->contains(IV1))
319+
return true;
320+
return false;
310321
});
311322
}
312323

@@ -2309,13 +2320,10 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef<InvokeInst *> Invokes) {
23092320

23102321
// In the normal destination, the incoming values for these two `invoke`s
23112322
// must be compatible.
2323+
SmallPtrSet<Value *, 16> EquivalenceSet(Invokes.begin(), Invokes.end());
23122324
if (!IncomingValuesAreCompatible(
2313-
NormalBB, {Invokes[0]->getParent(), Invokes[1]->getParent()}))
2314-
return false;
2315-
2316-
// For now, simply don't deal with `invoke`s that have uses.
2317-
auto Unused = [](InvokeInst *II) { return II->use_empty(); };
2318-
if (!all_of(Invokes, Unused))
2325+
NormalBB, {Invokes[0]->getParent(), Invokes[1]->getParent()},
2326+
&EquivalenceSet))
23192327
return false;
23202328
}
23212329

@@ -2470,8 +2478,7 @@ static void MergeCompatibleInvokesImpl(ArrayRef<InvokeInst *> Invokes,
24702478
for (BasicBlock *OrigSuccBB : successors(II->getParent()))
24712479
OrigSuccBB->removePredecessor(II->getParent());
24722480
BranchInst::Create(MergedInvoke->getParent(), II->getParent());
2473-
// Since the normal destination was unreachable, there are no live uses.
2474-
II->replaceAllUsesWith(UndefValue::get(II->getType()));
2481+
II->replaceAllUsesWith(MergedInvoke);
24752482
II->eraseFromParent();
24762483
++NumInvokesMerged;
24772484
}

llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll

+13-22
Original file line numberDiff line numberDiff line change
@@ -1688,13 +1688,9 @@ define void @t28_invoke_ret_value_is_used_in_phi_node() personality i8* bitcast
16881688
; CHECK-LABEL: @t28_invoke_ret_value_is_used_in_phi_node(
16891689
; CHECK-NEXT: entry:
16901690
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
1691-
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
1692-
; CHECK: if.then0:
1693-
; CHECK-NEXT: [[V0:%.*]] = invoke i32 @returning_maybe_throw()
1694-
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
1691+
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]]
16951692
; CHECK: invoke.cont:
1696-
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[V0]], [[IF_THEN0]] ], [ [[V1:%.*]], [[IF_THEN1:%.*]] ]
1697-
; CHECK-NEXT: call void @consume(i32 [[PHI]])
1693+
; CHECK-NEXT: call void @consume(i32 [[TMP0:%.*]])
16981694
; CHECK-NEXT: call void @sideeffect()
16991695
; CHECK-NEXT: unreachable
17001696
; CHECK: lpad:
@@ -1704,10 +1700,10 @@ define void @t28_invoke_ret_value_is_used_in_phi_node() personality i8* bitcast
17041700
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
17051701
; CHECK: if.else:
17061702
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
1707-
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1]], label [[IF_END:%.*]]
1708-
; CHECK: if.then1:
1709-
; CHECK-NEXT: [[V1]] = invoke i32 @returning_maybe_throw()
1710-
; CHECK-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD]]
1703+
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
1704+
; CHECK: if.then1.invoke:
1705+
; CHECK-NEXT: [[TMP0]] = invoke i32 @returning_maybe_throw()
1706+
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
17111707
; CHECK: if.end:
17121708
; CHECK-NEXT: call void @sideeffect()
17131709
; CHECK-NEXT: ret void
@@ -1933,15 +1929,10 @@ define void @t32_invoke_ret_value_is_used_in_phi_node_other_phi_is_fine() person
19331929
; CHECK-LABEL: @t32_invoke_ret_value_is_used_in_phi_node_other_phi_is_fine(
19341930
; CHECK-NEXT: entry:
19351931
; CHECK-NEXT: [[C0:%.*]] = call i1 @cond()
1936-
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
1937-
; CHECK: if.then0:
1938-
; CHECK-NEXT: [[V0:%.*]] = invoke i32 @returning_maybe_throw()
1939-
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
1932+
; CHECK-NEXT: br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]]
19401933
; CHECK: invoke.cont:
1941-
; CHECK-NEXT: [[PHI0:%.*]] = phi i32 [ [[V0]], [[IF_THEN0]] ], [ [[V1:%.*]], [[IF_THEN1:%.*]] ]
1942-
; CHECK-NEXT: [[PHI1:%.*]] = phi i32 [ 0, [[IF_THEN0]] ], [ 0, [[IF_THEN1]] ]
1943-
; CHECK-NEXT: call void @consume(i32 [[PHI0]])
1944-
; CHECK-NEXT: call void @consume(i32 [[PHI1]])
1934+
; CHECK-NEXT: call void @consume(i32 [[TMP0:%.*]])
1935+
; CHECK-NEXT: call void @consume(i32 0)
19451936
; CHECK-NEXT: call void @sideeffect()
19461937
; CHECK-NEXT: unreachable
19471938
; CHECK: lpad:
@@ -1951,10 +1942,10 @@ define void @t32_invoke_ret_value_is_used_in_phi_node_other_phi_is_fine() person
19511942
; CHECK-NEXT: resume { i8*, i32 } [[EH]]
19521943
; CHECK: if.else:
19531944
; CHECK-NEXT: [[C1:%.*]] = call i1 @cond()
1954-
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1]], label [[IF_END:%.*]]
1955-
; CHECK: if.then1:
1956-
; CHECK-NEXT: [[V1]] = invoke i32 @returning_maybe_throw()
1957-
; CHECK-NEXT: to label [[INVOKE_CONT]] unwind label [[LPAD]]
1945+
; CHECK-NEXT: br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
1946+
; CHECK: if.then1.invoke:
1947+
; CHECK-NEXT: [[TMP0]] = invoke i32 @returning_maybe_throw()
1948+
; CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
19581949
; CHECK: if.end:
19591950
; CHECK-NEXT: call void @sideeffect()
19601951
; CHECK-NEXT: ret void

0 commit comments

Comments
 (0)