[llvm] [JumpThreading][Local] Redirect other phi values from BB to Succ except commom preds (PR #166390)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 4 09:00:36 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Kunqiu Chen (Camsyn)
<details>
<summary>Changes</summary>
Previously, #<!-- -->67275 redirected phi values from BB to Succ, but bailed out when there were >1 common predecessors between BB and Succ.
This PR redirects other incoming blocks in phi from BB to Succ, except the common predecessors of BB and Succ, **relaxing** the intermediate phis (some optimizations, like JumpThreading, can benefit from this).
E.g.,
before:
```LLVM
define i8 @<!-- -->phis_of_switch(i8 noundef %arg, i1 %cond) {
start:
switch i8 %arg, label %unreachable [
i8 0, label %case0
i8 1, label %case1
i8 2, label %case2
i8 3, label %end
]
unreachable: ; preds = %start
unreachable
case1: ; preds = %start
br label %case0
case2: ; preds = %start
br i1 %cond, label %case0, label %end
case0: ; preds = %case2, %case1, %start
; %case2 and %start are common predecessors, but we can redirect %case1 to %end
%phi1 = phi i8 [ 1, %start ], [ 2, %case1 ], [ 3, %case2 ]
br label %end
end: ; preds = %case0, %case2, %start
%phi2 = phi i8 [ %phi1, %case0 ], [ 3, %start ], [ 4, %case2 ]
ret i8 %phi2
}
```
after:
```LLVM
define i8 @<!-- -->phis_of_switch(i8 noundef %arg, i1 %cond) {
start:
switch i8 %arg, label %unreachable [
i8 0, label %case0
i8 1, label %case1
i8 2, label %case2
i8 3, label %end
]
unreachable: ; preds = %start
unreachable
case1: ; preds = %start
br label %end
case2: ; preds = %start
br i1 %cond, label %case0, label %end
case0: ; preds = %case2, %start
%phi1 = phi i8 [ 1, %start ], [ 3, %case2 ]
br label %end
end: ; preds = %case1, %case0, %case2, %start
%phi2 = phi i8 [ 3, %start ], [ 4, %case2 ], [ 2, %case1 ], [ %phi1, %case0 ]
ret i8 %phi2
}
```
---
Alive2 Proof: & Impact to JumpThreading: https://alive2.llvm.org/ce/z/qvQvY_
Fix the regression found in https://github.com/dtcxzyw/llvm-opt-benchmark/pull/3007#discussion_r2486806895
Negligible CompTime Impact: https://github.com/dtcxzyw/llvm-opt-benchmark/pull/3022
IR diff:
---
Full diff: https://github.com/llvm/llvm-project/pull/166390.diff
4 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/JumpThreading.cpp (+2-2)
- (modified) llvm/lib/Transforms/Utils/Local.cpp (+56-39)
- (added) llvm/test/Transforms/JumpThreading/common-preds.ll (+65)
- (added) llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll (+170)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index c7d71eb5633ec..683fc40154a1c 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -2397,8 +2397,8 @@ void JumpThreadingPass::threadEdge(BasicBlock *BB,
// And finally, do it!
LLVM_DEBUG(dbgs() << " Threading edge from '" << PredBB->getName()
- << "' to '" << SuccBB->getName()
- << ", across block:\n " << *BB << "\n");
+ << "' to '" << SuccBB->getName() << "', across block:\n "
+ << *BB << "\n");
LVI->threadEdge(PredBB, BB, SuccBB);
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 46f29030ddb05..daf1005cd0a82 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -1001,13 +1001,14 @@ static void replaceUndefValuesInPhi(PHINode *PN,
}
}
-// Only when they shares a single common predecessor, return true.
+// Only when there exists other incoming blocks besides the common predecessors
+// of BB and Succ, return true.
// Only handles cases when BB can't be merged while its predecessors can be
// redirected.
static bool
CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ,
const SmallPtrSetImpl<BasicBlock *> &BBPreds,
- BasicBlock *&CommonPred) {
+ SmallPtrSetImpl<BasicBlock *> &CommonPreds) {
// There must be phis in BB, otherwise BB will be merged into Succ directly
if (BB->phis().empty() || Succ->phis().empty())
@@ -1022,17 +1023,14 @@ CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ,
}))
return false;
- // Get the single common predecessor of both BB and Succ. Return false
- // when there are more than one common predecessors.
- for (BasicBlock *SuccPred : predecessors(Succ)) {
- if (BBPreds.count(SuccPred)) {
- if (CommonPred)
- return false;
- CommonPred = SuccPred;
- }
- }
-
- return true;
+ // Get the common predecessors of BB and Succ.
+ CommonPreds.insert_range(
+ make_filter_range(predecessors(Succ), [&BBPreds](BasicBlock *SuccPred) {
+ return BBPreds.count(SuccPred);
+ }));
+ // If all the preds of BB are also common preds of Succ, we can't redirect
+ // them to Succ.
+ return CommonPreds.size() < BBPreds.size();
}
/// Check whether removing \p BB will make the phis in its \p Succ have too
@@ -1069,11 +1067,10 @@ static bool introduceTooManyPhiEntries(BasicBlock *BB, BasicBlock *Succ) {
/// \param BB The block with the value flowing into the phi.
/// \param BBPreds The predecessors of BB.
/// \param PN The phi that we are updating.
-/// \param CommonPred The common predecessor of BB and PN's BasicBlock
-static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
- const PredBlockVector &BBPreds,
- PHINode *PN,
- BasicBlock *CommonPred) {
+/// \param CommonPreds The common predecessors of BB and PN's BasicBlock
+static void redirectValuesFromPredecessorsToPhi(
+ BasicBlock *BB, const PredBlockVector &BBPreds, PHINode *PN,
+ const SmallPtrSetImpl<BasicBlock *> &CommonPreds) {
Value *OldVal = PN->removeIncomingValue(BB, false);
assert(OldVal && "No entry in PHI for Pred BB!");
@@ -1102,7 +1099,7 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
// simplifying the corresponding conditional branch).
BasicBlock *PredBB = OldValPN->getIncomingBlock(i);
- if (PredBB == CommonPred)
+ if (CommonPreds.contains(PredBB))
continue;
Value *PredVal = OldValPN->getIncomingValue(i);
@@ -1113,14 +1110,20 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
// newly retargeted branch.
PN->addIncoming(Selected, PredBB);
}
- if (CommonPred)
- PN->addIncoming(OldValPN->getIncomingValueForBlock(CommonPred), BB);
+ if (CommonPreds.size() == 1) {
+ // Single common predecessor, fold the phi node into Succ.
+ PN->addIncoming(OldValPN->getIncomingValueForBlock(*CommonPreds.begin()),
+ BB);
+ } else if (CommonPreds.size() >= 2) {
+ // >1 common predecessors, reserve the phi in BB.
+ PN->addIncoming(OldVal, BB);
+ }
} else {
for (BasicBlock *PredBB : BBPreds) {
// Update existing incoming values in PN for this
// predecessor of BB.
- if (PredBB == CommonPred)
+ if (CommonPreds.contains(PredBB))
continue;
Value *Selected =
@@ -1130,7 +1133,7 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
// newly retargeted branch.
PN->addIncoming(Selected, PredBB);
}
- if (CommonPred)
+ if (!CommonPreds.empty())
PN->addIncoming(OldVal, BB);
}
@@ -1149,15 +1152,15 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
SmallPtrSet<BasicBlock *, 16> BBPreds(llvm::from_range, predecessors(BB));
- // The single common predecessor of BB and Succ when BB cannot be killed
- BasicBlock *CommonPred = nullptr;
+ // The common predecessors of BB and Succ when BB cannot be killed
+ SmallPtrSet<BasicBlock *, 4> CommonPreds;
bool BBKillable = CanPropagatePredecessorsForPHIs(BB, Succ, BBPreds);
// Even if we can not fold BB into Succ, we may be able to redirect the
// predecessors of BB to Succ.
bool BBPhisMergeable = BBKillable || CanRedirectPredsOfEmptyBBToSucc(
- BB, Succ, BBPreds, CommonPred);
+ BB, Succ, BBPreds, CommonPreds);
if ((!BBKillable && !BBPhisMergeable) || introduceTooManyPhiEntries(BB, Succ))
return false;
@@ -1192,10 +1195,13 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
}
}
- if (BBPhisMergeable && CommonPred)
- LLVM_DEBUG(dbgs() << "Found Common Predecessor between: " << BB->getName()
- << " and " << Succ->getName() << " : "
- << CommonPred->getName() << "\n");
+ if (BBPhisMergeable && !CommonPreds.empty()) {
+ LLVM_DEBUG(dbgs() << "Found Common Predecessors between " << BB->getName()
+ << " and " << Succ->getName() << " :");
+ for (BasicBlock *Pred : CommonPreds)
+ LLVM_DEBUG(dbgs() << " " << Pred->getName());
+ LLVM_DEBUG(dbgs() << "\n");
+ }
// 'BB' and 'BB->Pred' are loop latches, bail out to presrve inner loop
// metadata.
@@ -1296,7 +1302,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
for (auto *PredOfBB : predecessors(BB))
// When BB cannot be killed, do not remove the edge between BB and
// CommonPred.
- if (SeenPreds.insert(PredOfBB).second && PredOfBB != CommonPred)
+ if (SeenPreds.insert(PredOfBB).second && !CommonPreds.contains(PredOfBB))
Updates.push_back({DominatorTree::Delete, PredOfBB, BB});
if (BBKillable)
@@ -1312,7 +1318,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
// Loop over all of the PHI nodes in the successor of BB.
for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I) {
PHINode *PN = cast<PHINode>(I);
- redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN, CommonPred);
+ redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN, CommonPreds);
}
}
@@ -1323,11 +1329,22 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
BB->getTerminator()->eraseFromParent();
Succ->splice(Succ->getFirstNonPHIIt(), BB);
} else {
- while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
- // We explicitly check for such uses for merging phis.
- assert(PN->use_empty() && "There shouldn't be any uses here!");
- PN->eraseFromParent();
- }
+ // If we have >1 common preds, we should retain the phis in BB; Otherwise,
+ // remove any PHI nodes in BB.
+ bool RetainPhi = CommonPreds.size() >= 2;
+ if (RetainPhi)
+ for (PHINode &PN : BB->phis())
+ PN.removeIncomingValueIf([&CommonPreds, &PN](unsigned idx) {
+ // If the incoming block is not a common predecessor, remove it from
+ // the phi.
+ return !CommonPreds.contains(PN.getIncomingBlock(idx));
+ });
+ else
+ while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
+ // We explicitly check for such uses for merging phis.
+ assert(PN->use_empty() && "There shouldn't be any uses here!");
+ PN->eraseFromParent();
+ }
}
// If the unconditional branch we replaced contains non-debug llvm.loop
@@ -1356,9 +1373,9 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
"applying corresponding DTU updates.");
} else if (BBPhisMergeable) {
// Everything except CommonPred that jumped to BB now goes to Succ.
- BB->replaceUsesWithIf(Succ, [BBPreds, CommonPred](Use &U) -> bool {
+ BB->replaceUsesWithIf(Succ, [BBPreds, CommonPreds](Use &U) -> bool {
if (Instruction *UseInst = dyn_cast<Instruction>(U.getUser()))
- return UseInst->getParent() != CommonPred &&
+ return !CommonPreds.contains(UseInst->getParent()) &&
BBPreds.contains(UseInst->getParent());
return false;
});
diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll
new file mode 100644
index 0000000000000..28a6c079993e6
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/common-preds.ll
@@ -0,0 +1,65 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=jump-threading < %s | FileCheck %s
+
+; Jump threading would generate an intermediate BB `foo.thread` uncond to `succ`,
+; with preds case0, case1, and case2.
+; Theoretically, path case1/case0 -> foo.thread -> succ -> exit can be folded into case1/case0 -> exit.
+
+define i64 @bar(i64 %0, i1 %1, i64 %num) {
+; CHECK-LABEL: @bar(
+; CHECK-NEXT: switch i64 [[TMP0:%.*]], label [[EXIT2:%.*]] [
+; CHECK-NEXT: i64 0, label [[CASE0:%.*]]
+; CHECK-NEXT: i64 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i64 2, label [[CASE2:%.*]]
+; CHECK-NEXT: ]
+; CHECK: case0:
+; CHECK-NEXT: br i1 [[TMP1:%.*]], label [[SUCC:%.*]], label [[FOO_THREAD:%.*]]
+; CHECK: case1:
+; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]]
+; CHECK: case2:
+; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]]
+; CHECK: succ:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0
+; CHECK-NEXT: br i1 [[COND2]], label [[FOO_THREAD]], label [[EXIT2]]
+; CHECK: exit:
+; CHECK-NEXT: [[PHI25:%.*]] = phi i64 [ [[PHI2]], [[SUCC]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ]
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: ret i64 [[PHI25]]
+; CHECK: exit2:
+; CHECK-NEXT: ret i64 0
+;
+ switch i64 %0, label %foo [
+ i64 0, label %case0
+ i64 1, label %case1
+ i64 2, label %case2
+ ]
+
+case0: ; preds = %2
+ br i1 %1, label %succ, label %foo
+
+case1: ; preds = %2
+ br i1 %1, label %succ, label %foo
+
+case2:
+ br i1 %1, label %exit2, label %foo
+
+foo: ; preds = %case1, %case0, %2
+ %phi1 = phi i64 [ 0, %case0 ], [ 0, %case1 ], [ 1, %case2 ], [ 10, %2 ]
+ %cond1 = icmp ult i64 %phi1, 2
+ br i1 %cond1, label %succ, label %exit2
+
+succ: ; preds = %foo, %case1, %case0
+ %phi2 = phi i64 [ %phi1, %foo ], [ %num, %case1 ], [ %num, %case0 ]
+ %cond2 = icmp eq i64 %phi2, 0
+ br i1 %cond2, label %exit, label %exit2
+
+exit:
+ call void @foo()
+ ret i64 %phi2
+
+exit2:
+ ret i64 0
+}
+
+declare void @foo()
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll
new file mode 100644
index 0000000000000..1ccef71cb173b
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+; Test a bunch of cases where the other phi values (i.e., comes from non-common predecessors)
+; should be merged into phi of the successor if there are >1 common predecessors.
+
+declare void @use(i8)
+
+define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) {
+; CHECK-LABEL: define i8 @phis_of_switch(
+; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[START:.*]]:
+; CHECK-NEXT: switch i8 [[ARG]], label %[[UNREACHABLE:.*]] [
+; CHECK-NEXT: i8 0, label %[[CASE0:.*]]
+; CHECK-NEXT: i8 1, label %[[CASE1:.*]]
+; CHECK-NEXT: i8 2, label %[[CASE2:.*]]
+; CHECK-NEXT: i8 3, label %[[END:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[UNREACHABLE]]:
+; CHECK-NEXT: unreachable
+; CHECK: [[CASE1]]:
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[CASE2]]:
+; CHECK-NEXT: br i1 [[COND]], label %[[CASE0]], label %[[END]]
+; CHECK: [[CASE0]]:
+; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ]
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ]
+; CHECK-NEXT: ret i8 [[PHI2]]
+;
+start:
+ switch i8 %arg, label %unreachable [
+ i8 0, label %case0
+ i8 1, label %case1
+ i8 2, label %case2
+ i8 3, label %end
+ ]
+
+unreachable: ; preds = %start
+ unreachable
+
+case1: ; preds = %start
+ br label %case0
+
+case2: ; preds = %start
+ br i1 %cond, label %case0, label %end
+
+case0: ; preds = %case2, %case1, %start
+ ; %case2 and %start are common predecessors, but we can redirect %case1 to %end
+ %phi1 = phi i8 [ 1, %start ], [ 2, %case1 ], [ 3, %case2 ]
+ br label %end
+
+end: ; preds = %case0, %case2, %start
+ %phi2 = phi i8 [ %phi1, %case0 ], [ 3, %start ], [ 4, %case2 ]
+ ret i8 %phi2
+}
+
+define i8 @phis_of_if(i8 noundef %arg, i1 %cond) {
+; CHECK-LABEL: define i8 @phis_of_if(
+; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[START:.*]]:
+; CHECK-NEXT: br i1 [[COND]], label %[[BRANCH:.*]], label %[[END:.*]]
+; CHECK: [[BRANCH]]:
+; CHECK-NEXT: [[COND0:%.*]] = icmp sgt i8 [[ARG]], 0
+; CHECK-NEXT: call void @use(i8 1)
+; CHECK-NEXT: br i1 [[COND0]], label %[[CASE0:.*]], label %[[CASE1:.*]]
+; CHECK: [[CASE0]]:
+; CHECK-NEXT: call void @use(i8 1)
+; CHECK-NEXT: [[COND1:%.*]] = icmp eq i8 [[ARG]], 1
+; CHECK-NEXT: br i1 [[COND1]], label %[[SINK:.*]], label %[[END]]
+; CHECK: [[CASE1]]:
+; CHECK-NEXT: call void @use(i8 1)
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i8 [[ARG]], -1
+; CHECK-NEXT: br i1 [[COND2]], label %[[SINK]], label %[[END]]
+; CHECK: [[SINK]]:
+; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[CASE0]] ], [ 2, %[[CASE1]] ]
+; CHECK-NEXT: br label %[[END]]
+; CHECK: [[END]]:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ 0, %[[START]] ], [ [[PHI1]], %[[SINK]] ]
+; CHECK-NEXT: ret i8 [[PHI2]]
+;
+start:
+ br i1 %cond, label %branch, label %sink
+
+branch: ; preds = %start
+ %cond0 = icmp sgt i8 %arg, 0
+ call void @use(i8 1)
+ br i1 %cond0, label %case0, label %case1
+
+case0: ; preds = %branch
+ call void @use(i8 1)
+ %cond1 = icmp eq i8 %arg, 1
+ br i1 %cond1, label %sink, label %end
+
+case1: ; preds = %branch
+ call void @use(i8 1)
+ %cond2 = icmp eq i8 %arg, -1
+ br i1 %cond2, label %sink, label %end
+
+sink: ; preds = %case1, %case0, %start
+ ; %case0 and %case1 are common predecessors, but we can redirect %start to %end
+ %phi1 = phi i8 [ 0, %start ], [ 1, %case0 ], [ 2, %case1 ]
+ br label %end
+
+end: ; preds = %sink, %case1, %case0
+ %phi2 = phi i8 [ 3, %case0 ], [ 4, %case1 ], [ %phi1, %sink ]
+ ret i8 %phi2
+}
+
+define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) {
+; CHECK-LABEL: define i64 @from_jump_threading(
+; CHECK-SAME: i64 [[TMP0:%.*]], i1 [[TMP1:%.*]], i64 [[NUM:%.*]]) {
+; CHECK-NEXT: switch i64 [[TMP0]], label %[[COMMON_RET:.*]] [
+; CHECK-NEXT: i64 0, label %[[CASE0:.*]]
+; CHECK-NEXT: i64 1, label %[[CASE1:.*]]
+; CHECK-NEXT: i64 2, label %[[CASE2:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[CASE0]]:
+; CHECK-NEXT: br i1 [[TMP1]], label %[[SUCC:.*]], label %[[FOO_THREAD:.*]]
+; CHECK: [[CASE1]]:
+; CHECK-NEXT: br i1 [[TMP1]], label %[[SUCC]], label %[[FOO_THREAD]]
+; CHECK: [[CASE2]]:
+; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[SUCC]]
+; CHECK: [[FOO_THREAD]]:
+; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ]
+; CHECK-NEXT: br label %[[SUCC]]
+; CHECK: [[SUCC]]:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM]], %[[CASE1]] ], [ [[NUM]], %[[CASE0]] ], [ 1, %[[CASE2]] ], [ [[PHI1_PH]], %[[FOO_THREAD]] ]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0
+; CHECK-NEXT: br i1 [[COND2]], label %[[EXIT:.*]], label %[[COMMON_RET]]
+; CHECK: [[COMMON_RET]]:
+; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i64 [ [[PHI2]], %[[EXIT]] ], [ 0, %[[SUCC]] ], [ 0, %[[CASE2]] ], [ 0, [[TMP2:%.*]] ]
+; CHECK-NEXT: ret i64 [[COMMON_RET_OP]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: call void @use(i8 0)
+; CHECK-NEXT: br label %[[COMMON_RET]]
+;
+ switch i64 %0, label %exit2 [
+ i64 0, label %case0
+ i64 1, label %case1
+ i64 2, label %case2
+ ]
+
+case0: ; preds = %2
+ br i1 %1, label %succ, label %foo.thread
+
+case1: ; preds = %2
+ br i1 %1, label %succ, label %foo.thread
+
+case2: ; preds = %2
+ br i1 %1, label %exit2, label %foo.thread
+
+foo.thread: ; preds = %case2, %case1, %case0
+ ; %case0 and %case1 are common predecessors, but we can redirect %case2 to %succ
+ %phi1.ph = phi i64 [ 1, %case2 ], [ 0, %case1 ], [ 0, %case0 ]
+ br label %succ
+
+succ: ; preds = %foo.thread, %case1, %case0
+ %phi2 = phi i64 [ %num, %case1 ], [ %num, %case0 ], [ %phi1.ph, %foo.thread ]
+ %cond2 = icmp eq i64 %phi2, 0
+ br i1 %cond2, label %exit, label %exit2
+
+exit: ; preds = %succ
+ call void @use(i8 0)
+ ret i64 %phi2
+
+exit2: ; preds = %succ, %case2, %2
+ ret i64 0
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/166390
More information about the llvm-commits
mailing list