From 149ff264994f1764cb3dc76576d6e501cff45373 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Tue, 4 Nov 2025 23:28:27 +0800 Subject: [PATCH 01/11] Add tests before commit --- .../Transforms/JumpThreading/common-preds.ll | 67 +++++++ .../SimplifyCFG/merge-phi-values.ll | 170 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 llvm/test/Transforms/JumpThreading/common-preds.ll create mode 100644 llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll new file mode 100644 index 0000000000000..dd3925ae87cd5 --- /dev/null +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -0,0 +1,67 @@ +; 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 [[FOO_THREAD]] +; CHECK: foo.thread: +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] +; CHECK-NEXT: br label [[SUCC]] +; CHECK: succ: +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] +; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2]] +; CHECK: exit: +; CHECK-NEXT: call void @foo() +; CHECK-NEXT: ret i64 [[PHI2]] +; 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..1c5e2bb030ba8 --- /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 %[[CASE0]] +; CHECK: [[CASE2]]: +; CHECK-NEXT: br i1 [[COND]], label %[[CASE0]], label %[[END]] +; CHECK: [[CASE0]]: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: br label %[[END]] +; CHECK: [[END]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] +; 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 %[[SINK:.*]] +; 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 [ 0, %[[START]] ], [ 1, %[[CASE0]] ], [ 2, %[[CASE1]] ] +; CHECK-NEXT: br label %[[END]] +; CHECK: [[END]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ [[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 %[[FOO_THREAD]] +; CHECK: [[FOO_THREAD]]: +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; CHECK-NEXT: br label %[[SUCC]] +; CHECK: [[SUCC]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM]], %[[CASE1]] ], [ [[NUM]], %[[CASE0]] ], [ [[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 +} From 91e69c2e4648ec9ff1b7d6215784912c0b744584 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Tue, 4 Nov 2025 22:44:57 +0800 Subject: [PATCH 02/11] [JumpThread][Local] Redirect phi values between BB and Succ with >1 common preds --- llvm/lib/Transforms/Scalar/JumpThreading.cpp | 2 +- llvm/lib/Transforms/Utils/Local.cpp | 95 ++++++++++++-------- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp index c7d71eb5633ec..d2fa42275fd52 100644 --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -2398,7 +2398,7 @@ 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"); + << "', 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..283fb4684ca88 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 &BBPreds, - BasicBlock *&CommonPred) { + SmallPtrSetImpl &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 &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 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 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(I); ++I) { PHINode *PN = cast(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(&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(&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(U.getUser())) - return UseInst->getParent() != CommonPred && + return !CommonPreds.contains(UseInst->getParent()) && BBPreds.contains(UseInst->getParent()); return false; }); From 3649a41f1fdb52fbd5c65caf172534689dc72a36 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Tue, 4 Nov 2025 23:31:02 +0800 Subject: [PATCH 03/11] Regenerate the tests after commit --- .../Transforms/JumpThreading/common-preds.ll | 12 +++++------ .../SimplifyCFG/merge-phi-values.ll | 20 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll index dd3925ae87cd5..28a6c079993e6 100644 --- a/llvm/test/Transforms/JumpThreading/common-preds.ll +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -17,17 +17,15 @@ define i64 @bar(i64 %0, i1 %1, i64 %num) { ; CHECK: case1: ; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]] ; CHECK: case2: -; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[FOO_THREAD]] -; CHECK: foo.thread: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] -; CHECK-NEXT: br label [[SUCC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2]] +; 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 [[PHI2]] +; CHECK-NEXT: ret i64 [[PHI25]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll index 1c5e2bb030ba8..1ccef71cb173b 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll @@ -19,14 +19,14 @@ define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[CASE1]]: -; CHECK-NEXT: br label %[[CASE0]] +; 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]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ] ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -60,7 +60,7 @@ 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 %[[SINK:.*]] +; 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) @@ -68,16 +68,16 @@ define i8 @phis_of_if(i8 noundef %arg, i1 %cond) { ; 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-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 [ 0, %[[START]] ], [ 1, %[[CASE0]] ], [ 2, %[[CASE1]] ] +; 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]] ], [ [[PHI1]], %[[SINK]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ 0, %[[START]] ], [ [[PHI1]], %[[SINK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -121,12 +121,12 @@ define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) { ; CHECK: [[CASE1]]: ; CHECK-NEXT: br i1 [[TMP1]], label %[[SUCC]], label %[[FOO_THREAD]] ; CHECK: [[CASE2]]: -; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[FOO_THREAD]] +; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[SUCC]] ; CHECK: [[FOO_THREAD]]: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; 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]] ], [ [[PHI1_PH]], %[[FOO_THREAD]] ] +; 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]]: From 1fb0bfe47eb0b1e40c63f83a70bed47bd94d4f57 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Tue, 4 Nov 2025 23:56:47 +0800 Subject: [PATCH 04/11] Make formatter happy --- llvm/lib/Transforms/Scalar/JumpThreading.cpp | 4 ++-- llvm/lib/Transforms/Utils/Local.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp index d2fa42275fd52..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 283fb4684ca88..daf1005cd0a82 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1112,9 +1112,9 @@ static void redirectValuesFromPredecessorsToPhi( } 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) { + PN->addIncoming(OldValPN->getIncomingValueForBlock(*CommonPreds.begin()), + BB); + } else if (CommonPreds.size() >= 2) { // >1 common predecessors, reserve the phi in BB. PN->addIncoming(OldVal, BB); } From 53396de57b238c9d2db0925da22f841c534596bc Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 01:00:33 +0800 Subject: [PATCH 05/11] Address review comment --- llvm/lib/Transforms/Utils/Local.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index daf1005cd0a82..ab33c21690551 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1373,7 +1373,7 @@ 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, CommonPreds](Use &U) -> bool { + BB->replaceUsesWithIf(Succ, [&BBPreds, &CommonPreds](Use &U) -> bool { if (Instruction *UseInst = dyn_cast(U.getUser())) return !CommonPreds.contains(UseInst->getParent()) && BBPreds.contains(UseInst->getParent()); From 9d3b70971fd52841abeff3f925ffbbda9811a1b8 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 15:40:53 +0800 Subject: [PATCH 06/11] Add some new tests --- .../Transforms/JumpThreading/common-preds.ll | 66 ++++++++++- .../SimplifyCFG/merge-phi-values.ll | 105 ++++++++++++++++-- 2 files changed, 156 insertions(+), 15 deletions(-) diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll index 28a6c079993e6..507f8137efcba 100644 --- a/llvm/test/Transforms/JumpThreading/common-preds.ll +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -17,15 +17,17 @@ define i64 @bar(i64 %0, i1 %1, i64 %num) { ; CHECK: case1: ; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]] ; CHECK: case2: -; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]] +; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[FOO_THREAD]] +; CHECK: foo.thread: +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] +; CHECK-NEXT: br label [[SUCC]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[FOO_THREAD]], label [[EXIT2]] +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], 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-NEXT: ret i64 [[PHI2]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; @@ -62,4 +64,58 @@ exit2: ret i64 0 } +define i64 @multicase(i64 %0, i1 %1, i64 %num) { +; CHECK-LABEL: @multicase( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i64 [[TMP0:%.*]], label [[DEFAULT:%.*]] [ +; CHECK-NEXT: i64 0, label [[FOO:%.*]] +; CHECK-NEXT: i64 1, label [[FOO]] +; CHECK-NEXT: i64 2, label [[SUCC:%.*]] +; CHECK-NEXT: i64 3, label [[SUCC]] +; CHECK-NEXT: ] +; CHECK: default: +; CHECK-NEXT: br label [[FOO]] +; CHECK: foo: +; CHECK-NEXT: [[PHI1:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 0, [[ENTRY]] ], [ 1, [[DEFAULT]] ] +; CHECK-NEXT: br label [[SUCC]] +; CHECK: succ: +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY]] ], [ [[NUM]], [[ENTRY]] ], [ [[PHI1]], [[FOO]] ] +; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2:%.*]] +; CHECK: exit: +; CHECK-NEXT: call void @foo() +; CHECK-NEXT: ret i64 [[PHI2]] +; CHECK: exit2: +; CHECK-NEXT: ret i64 0 +; +entry: + switch i64 %0, label %default [ + i64 0, label %foo + i64 1, label %foo + i64 2, label %succ + i64 3, label %succ + ] + +default: ; preds = %entry + br label %foo + +foo: ; preds = %default, %entry, %entry + %phi1 = phi i64 [ 0, %entry ], [ 0, %entry ], [ 1, %default ] + %cond1 = icmp ult i64 %phi1, 2 + br i1 %cond1, label %succ, label %exit2 + +succ: ; preds = %foo, %entry, %entry + %phi2 = phi i64 [ %num, %entry ], [ %num, %entry ], [ %phi1, %foo ] + %cond2 = icmp eq i64 %phi2, 0 + br i1 %cond2, label %exit, label %exit2 + +exit: ; preds = %succ + call void @foo() + ret i64 %phi2 + +exit2: ; preds = %succ, %foo + 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 index 1ccef71cb173b..bce04f2d2f2dc 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll @@ -19,14 +19,14 @@ define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[CASE1]]: -; CHECK-NEXT: br label %[[END]] +; CHECK-NEXT: br label %[[CASE0]] ; CHECK: [[CASE2]]: ; CHECK-NEXT: br i1 [[COND]], label %[[CASE0]], label %[[END]] ; CHECK: [[CASE0]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -60,7 +60,7 @@ 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-NEXT: br i1 [[COND]], label %[[BRANCH:.*]], label %[[SINK:.*]] ; CHECK: [[BRANCH]]: ; CHECK-NEXT: [[COND0:%.*]] = icmp sgt i8 [[ARG]], 0 ; CHECK-NEXT: call void @use(i8 1) @@ -68,16 +68,16 @@ define i8 @phis_of_if(i8 noundef %arg, i1 %cond) { ; 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-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: [[PHI1:%.*]] = phi i8 [ 0, %[[START]] ], [ 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: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ [[PHI1]], %[[SINK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -121,12 +121,12 @@ define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) { ; 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-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[FOO_THREAD]] ; CHECK: [[FOO_THREAD]]: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 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: [[PHI2:%.*]] = phi i64 [ [[NUM]], %[[CASE1]] ], [ [[NUM]], %[[CASE0]] ], [ [[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]]: @@ -168,3 +168,88 @@ exit: ; preds = %succ exit2: ; preds = %succ, %case2, %2 ret i64 0 } + +define i8 @multicase_dest(i8 noundef %arg) { +; CHECK-LABEL: define i8 @multicase_dest( +; CHECK-SAME: i8 noundef [[ARG:%.*]]) { +; CHECK-NEXT: [[START:.*]]: +; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ +; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] +; CHECK-NEXT: i8 1, label %[[BLOCK]] +; CHECK-NEXT: i8 2, label %[[SUCC:.*]] +; CHECK-NEXT: i8 3, label %[[SUCC]] +; CHECK-NEXT: ] +; CHECK: [[DEFAULT]]: +; CHECK-NEXT: br label %[[BLOCK]] +; CHECK: [[BLOCK]]: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ] +; CHECK-NEXT: br label %[[SUCC]] +; CHECK: [[SUCC]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] +; CHECK-NEXT: ret i8 [[PHI2]] +; +start: + switch i8 %arg, label %default [ + i8 0, label %block + i8 1, label %block + i8 2, label %succ + i8 3, label %succ + ] + +default: ; preds = %start + br label %block + +block: ; preds = %default, %start, %start + %phi1 = phi i8 [ 1, %start ], [ 1, %start ], [ 3, %default ] + br label %succ + +succ: ; preds = %block, %start, %start + %phi2 = phi i8 [ %phi1, %block ], [ 3, %start ], [ 3, %start ] + ret i8 %phi2 +} + +define i8 @multicase_dest2(i8 noundef %arg, i1 %cond) { +; CHECK-LABEL: define i8 @multicase_dest2( +; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: [[START:.*]]: +; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ +; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] +; CHECK-NEXT: i8 1, label %[[BLOCK]] +; CHECK-NEXT: i8 2, label %[[SUCC:.*]] +; CHECK-NEXT: i8 3, label %[[SUCC]] +; CHECK-NEXT: i8 4, label %[[CASE:.*]] +; CHECK-NEXT: ] +; CHECK: [[DEFAULT]]: +; CHECK-NEXT: br label %[[BLOCK]] +; CHECK: [[CASE]]: +; CHECK-NEXT: br i1 [[COND]], label %[[BLOCK]], label %[[SUCC]] +; CHECK: [[BLOCK]]: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: br label %[[SUCC]] +; CHECK: [[SUCC]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: ret i8 [[PHI2]] +; +start: + switch i8 %arg, label %default [ + i8 0, label %block + i8 1, label %block + i8 2, label %succ + i8 3, label %succ + i8 4, label %case + ] + +default: ; preds = %start + br label %block + +case: ; preds = %start + br i1 %cond, label %block, label %succ + +block: ; preds = %case, %default, %start, %start + %phi1 = phi i8 [ 1, %start ], [ 1, %start ], [ 3, %default ], [ 4, %case ] + br label %succ + +succ: ; preds = %block, %case, %start, %start + %phi2 = phi i8 [ %phi1, %block ], [ 3, %start ], [ 3, %start ], [ 4, %case ] + ret i8 %phi2 +} From de9cf0d88c281866bb3a46e269fddb605cce9621 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 15:45:25 +0800 Subject: [PATCH 07/11] Regenerate the test cases --- .../Transforms/JumpThreading/common-preds.ll | 24 ++++------ .../SimplifyCFG/merge-phi-values.ll | 48 +++++++------------ 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll index 507f8137efcba..a79c2e83080e1 100644 --- a/llvm/test/Transforms/JumpThreading/common-preds.ll +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -17,17 +17,15 @@ define i64 @bar(i64 %0, i1 %1, i64 %num) { ; CHECK: case1: ; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]] ; CHECK: case2: -; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[FOO_THREAD]] -; CHECK: foo.thread: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] -; CHECK-NEXT: br label [[SUCC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2]] +; 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 [[PHI2]] +; CHECK-NEXT: ret i64 [[PHI25]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; @@ -73,18 +71,14 @@ define i64 @multicase(i64 %0, i1 %1, i64 %num) { ; CHECK-NEXT: i64 2, label [[SUCC:%.*]] ; CHECK-NEXT: i64 3, label [[SUCC]] ; CHECK-NEXT: ] -; CHECK: default: -; CHECK-NEXT: br label [[FOO]] -; CHECK: foo: -; CHECK-NEXT: [[PHI1:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 0, [[ENTRY]] ], [ 1, [[DEFAULT]] ] -; CHECK-NEXT: br label [[SUCC]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY]] ], [ [[NUM]], [[ENTRY]] ], [ [[PHI1]], [[FOO]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY:%.*]] ], [ [[NUM]], [[ENTRY]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2:%.*]] +; CHECK-NEXT: br i1 [[COND2]], label [[FOO]], label [[DEFAULT]] ; CHECK: exit: +; CHECK-NEXT: [[PHI23:%.*]] = phi i64 [ [[PHI2]], [[SUCC]] ], [ 0, [[ENTRY]] ], [ 0, [[ENTRY]] ] ; CHECK-NEXT: call void @foo() -; CHECK-NEXT: ret i64 [[PHI2]] +; CHECK-NEXT: ret i64 [[PHI23]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll index bce04f2d2f2dc..ea109083512e0 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll @@ -19,14 +19,14 @@ define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[CASE1]]: -; CHECK-NEXT: br label %[[CASE0]] +; 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]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ] ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -60,7 +60,7 @@ 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 %[[SINK:.*]] +; 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) @@ -68,16 +68,16 @@ define i8 @phis_of_if(i8 noundef %arg, i1 %cond) { ; 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-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 [ 0, %[[START]] ], [ 1, %[[CASE0]] ], [ 2, %[[CASE1]] ] +; 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]] ], [ [[PHI1]], %[[SINK]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ 0, %[[START]] ], [ [[PHI1]], %[[SINK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -121,12 +121,12 @@ define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) { ; CHECK: [[CASE1]]: ; CHECK-NEXT: br i1 [[TMP1]], label %[[SUCC]], label %[[FOO_THREAD]] ; CHECK: [[CASE2]]: -; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[FOO_THREAD]] +; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[SUCC]] ; CHECK: [[FOO_THREAD]]: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; 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]] ], [ [[PHI1_PH]], %[[FOO_THREAD]] ] +; 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]]: @@ -172,20 +172,10 @@ exit2: ; preds = %succ, %case2, %2 define i8 @multicase_dest(i8 noundef %arg) { ; CHECK-LABEL: define i8 @multicase_dest( ; CHECK-SAME: i8 noundef [[ARG:%.*]]) { -; CHECK-NEXT: [[START:.*]]: -; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ -; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] -; CHECK-NEXT: i8 1, label %[[BLOCK]] -; CHECK-NEXT: i8 2, label %[[SUCC:.*]] -; CHECK-NEXT: i8 3, label %[[SUCC]] -; CHECK-NEXT: ] -; CHECK: [[DEFAULT]]: -; CHECK-NEXT: br label %[[BLOCK]] -; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ] -; CHECK-NEXT: br label %[[SUCC]] -; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] +; CHECK-NEXT: [[START:.*:]] +; CHECK-NEXT: [[SWITCH_AND:%.*]] = and i8 [[ARG]], -2 +; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i8 [[SWITCH_AND]], 0 +; CHECK-NEXT: [[PHI2:%.*]] = select i1 [[SWITCH_SELECTCMP]], i8 1, i8 3 ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -212,22 +202,18 @@ define i8 @multicase_dest2(i8 noundef %arg, i1 %cond) { ; CHECK-LABEL: define i8 @multicase_dest2( ; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[START:.*]]: -; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ +; CHECK-NEXT: switch i8 [[ARG]], label %[[SUCC:.*]] [ ; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] ; CHECK-NEXT: i8 1, label %[[BLOCK]] -; CHECK-NEXT: i8 2, label %[[SUCC:.*]] -; CHECK-NEXT: i8 3, label %[[SUCC]] ; CHECK-NEXT: i8 4, label %[[CASE:.*]] ; CHECK-NEXT: ] -; CHECK: [[DEFAULT]]: -; CHECK-NEXT: br label %[[BLOCK]] ; CHECK: [[CASE]]: ; CHECK-NEXT: br i1 [[COND]], label %[[BLOCK]], label %[[SUCC]] ; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 4, %[[CASE]] ] ; CHECK-NEXT: br label %[[SUCC]] ; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 4, %[[CASE]] ], [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: From 876f598f9a3e92afbcd730be80be32113b420d57 Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 16:00:43 +0800 Subject: [PATCH 08/11] Handle case that all preds are the same common pred --- llvm/lib/Transforms/Utils/Local.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index ab33c21690551..9ba9ddb4305d5 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1029,8 +1029,9 @@ CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ, 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(); + // them to Succ, useless they are the same block (e.g., multi-case dest in + // switch) + return CommonPreds.size() < BBPreds.size() || CommonPreds.size() == 1; } /// Check whether removing \p BB will make the phis in its \p Succ have too From dfb3514ebf22c86952553315715529adfb81ebfe Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 16:01:00 +0800 Subject: [PATCH 09/11] Add new testcase --- .../Transforms/JumpThreading/common-preds.ll | 74 ++++++++++++++-- .../SimplifyCFG/merge-phi-values.ll | 87 +++++++++++++++---- 2 files changed, 135 insertions(+), 26 deletions(-) diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll index a79c2e83080e1..e9599a6e741b1 100644 --- a/llvm/test/Transforms/JumpThreading/common-preds.ll +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -17,15 +17,17 @@ define i64 @bar(i64 %0, i1 %1, i64 %num) { ; CHECK: case1: ; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]] ; CHECK: case2: -; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]] +; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[FOO_THREAD]] +; CHECK: foo.thread: +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] +; CHECK-NEXT: br label [[SUCC]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[FOO_THREAD]], label [[EXIT2]] +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], 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-NEXT: ret i64 [[PHI2]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; @@ -71,14 +73,18 @@ define i64 @multicase(i64 %0, i1 %1, i64 %num) { ; CHECK-NEXT: i64 2, label [[SUCC:%.*]] ; CHECK-NEXT: i64 3, label [[SUCC]] ; CHECK-NEXT: ] +; CHECK: default: +; CHECK-NEXT: br label [[FOO]] +; CHECK: foo: +; CHECK-NEXT: [[PHI1:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 0, [[ENTRY]] ], [ 1, [[DEFAULT]] ] +; CHECK-NEXT: br label [[SUCC]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY:%.*]] ], [ [[NUM]], [[ENTRY]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY]] ], [ [[NUM]], [[ENTRY]] ], [ [[PHI1]], [[FOO]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[FOO]], label [[DEFAULT]] +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2:%.*]] ; CHECK: exit: -; CHECK-NEXT: [[PHI23:%.*]] = phi i64 [ [[PHI2]], [[SUCC]] ], [ 0, [[ENTRY]] ], [ 0, [[ENTRY]] ] ; CHECK-NEXT: call void @foo() -; CHECK-NEXT: ret i64 [[PHI23]] +; CHECK-NEXT: ret i64 [[PHI2]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; @@ -111,5 +117,55 @@ exit2: ; preds = %succ, %foo ret i64 0 } +define i64 @multicase2(i64 %0, i1 %1, i64 %num) { +; CHECK-LABEL: @multicase2( +; CHECK-NEXT: entry: +; CHECK-NEXT: switch i64 [[TMP0:%.*]], label [[UNREACHABLE:%.*]] [ +; CHECK-NEXT: i64 0, label [[EXIT:%.*]] +; CHECK-NEXT: i64 1, label [[EXIT]] +; CHECK-NEXT: i64 2, label [[SUCC:%.*]] +; CHECK-NEXT: i64 3, label [[SUCC]] +; CHECK-NEXT: ] +; CHECK: unreachable: +; CHECK-NEXT: unreachable +; CHECK: succ: +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY:%.*]] ], [ [[NUM]], [[ENTRY]] ] +; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 +; CHECK-NEXT: br i1 [[COND2]], label [[EXIT]], label [[EXIT2:%.*]] +; CHECK: exit: +; CHECK-NEXT: [[PHI23:%.*]] = phi i64 [ [[PHI2]], [[SUCC]] ], [ 0, [[ENTRY]] ], [ 0, [[ENTRY]] ] +; CHECK-NEXT: call void @foo() +; CHECK-NEXT: ret i64 [[PHI23]] +; CHECK: exit2: +; CHECK-NEXT: ret i64 0 +; +entry: + switch i64 %0, label %unreachable [ + i64 0, label %foo + i64 1, label %foo + i64 2, label %succ + i64 3, label %succ + ] + +unreachable: ; preds = %entry + unreachable + +foo: ; preds = %entry, %entry + %phi1 = phi i64 [ 0, %entry ], [ 0, %entry ] + %cond1 = icmp ult i64 %phi1, 2 + br i1 %cond1, label %succ, label %exit2 + +succ: ; preds = %foo, %entry, %entry + %phi2 = phi i64 [ %num, %entry ], [ %num, %entry ], [ %phi1, %foo ] + %cond2 = icmp eq i64 %phi2, 0 + br i1 %cond2, label %exit, label %exit2 + +exit: ; preds = %succ + call void @foo() + ret i64 %phi2 + +exit2: ; preds = %succ, %foo + 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 index ea109083512e0..cbce38da15094 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll @@ -19,14 +19,14 @@ define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[CASE1]]: -; CHECK-NEXT: br label %[[END]] +; CHECK-NEXT: br label %[[CASE0]] ; CHECK: [[CASE2]]: ; CHECK-NEXT: br i1 [[COND]], label %[[CASE0]], label %[[END]] ; CHECK: [[CASE0]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -60,7 +60,7 @@ 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-NEXT: br i1 [[COND]], label %[[BRANCH:.*]], label %[[SINK:.*]] ; CHECK: [[BRANCH]]: ; CHECK-NEXT: [[COND0:%.*]] = icmp sgt i8 [[ARG]], 0 ; CHECK-NEXT: call void @use(i8 1) @@ -68,16 +68,16 @@ define i8 @phis_of_if(i8 noundef %arg, i1 %cond) { ; 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-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: [[PHI1:%.*]] = phi i8 [ 0, %[[START]] ], [ 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: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ [[PHI1]], %[[SINK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -121,12 +121,12 @@ define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) { ; 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-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[FOO_THREAD]] ; CHECK: [[FOO_THREAD]]: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 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: [[PHI2:%.*]] = phi i64 [ [[NUM]], %[[CASE1]] ], [ [[NUM]], %[[CASE0]] ], [ [[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]]: @@ -172,10 +172,20 @@ exit2: ; preds = %succ, %case2, %2 define i8 @multicase_dest(i8 noundef %arg) { ; CHECK-LABEL: define i8 @multicase_dest( ; CHECK-SAME: i8 noundef [[ARG:%.*]]) { -; CHECK-NEXT: [[START:.*:]] -; CHECK-NEXT: [[SWITCH_AND:%.*]] = and i8 [[ARG]], -2 -; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i8 [[SWITCH_AND]], 0 -; CHECK-NEXT: [[PHI2:%.*]] = select i1 [[SWITCH_SELECTCMP]], i8 1, i8 3 +; CHECK-NEXT: [[START:.*]]: +; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ +; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] +; CHECK-NEXT: i8 1, label %[[BLOCK]] +; CHECK-NEXT: i8 2, label %[[SUCC:.*]] +; CHECK-NEXT: i8 3, label %[[SUCC]] +; CHECK-NEXT: ] +; CHECK: [[DEFAULT]]: +; CHECK-NEXT: br label %[[BLOCK]] +; CHECK: [[BLOCK]]: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ] +; CHECK-NEXT: br label %[[SUCC]] +; CHECK: [[SUCC]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -202,18 +212,22 @@ define i8 @multicase_dest2(i8 noundef %arg, i1 %cond) { ; CHECK-LABEL: define i8 @multicase_dest2( ; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[START:.*]]: -; CHECK-NEXT: switch i8 [[ARG]], label %[[SUCC:.*]] [ +; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ ; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] ; CHECK-NEXT: i8 1, label %[[BLOCK]] +; CHECK-NEXT: i8 2, label %[[SUCC:.*]] +; CHECK-NEXT: i8 3, label %[[SUCC]] ; CHECK-NEXT: i8 4, label %[[CASE:.*]] ; CHECK-NEXT: ] +; CHECK: [[DEFAULT]]: +; CHECK-NEXT: br label %[[BLOCK]] ; CHECK: [[CASE]]: ; CHECK-NEXT: br i1 [[COND]], label %[[BLOCK]], label %[[SUCC]] ; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ], [ 4, %[[CASE]] ] ; CHECK-NEXT: br label %[[SUCC]] ; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 4, %[[CASE]] ], [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ], [ 4, %[[CASE]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -239,3 +253,42 @@ succ: ; preds = %block, %case, %star %phi2 = phi i8 [ %phi1, %block ], [ 3, %start ], [ 3, %start ], [ 4, %case ] ret i8 %phi2 } + +define i8 @multicase_dest3(i8 noundef %arg, i1 %cond) { +; CHECK-LABEL: define i8 @multicase_dest3( +; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) { +; CHECK-NEXT: [[START:.*]]: +; CHECK-NEXT: switch i8 [[ARG]], label %[[UNREACHABLE:.*]] [ +; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] +; CHECK-NEXT: i8 1, label %[[BLOCK]] +; CHECK-NEXT: i8 2, label %[[SUCC:.*]] +; CHECK-NEXT: i8 3, label %[[SUCC]] +; CHECK-NEXT: ] +; CHECK: [[UNREACHABLE]]: +; CHECK-NEXT: unreachable +; CHECK: [[BLOCK]]: +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ] +; CHECK-NEXT: br label %[[SUCC]] +; CHECK: [[SUCC]]: +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] +; CHECK-NEXT: ret i8 [[PHI2]] +; +start: + switch i8 %arg, label %unreachable [ + i8 0, label %block + i8 1, label %block + i8 2, label %succ + i8 3, label %succ + ] + +unreachable: ; preds = %start + unreachable + +block: ; preds = %start, %start + %phi1 = phi i8 [ 1, %start ], [ 1, %start ] + br label %succ + +succ: ; preds = %block, %start, %start + %phi2 = phi i8 [ %phi1, %block ], [ 3, %start ], [ 3, %start ] + ret i8 %phi2 +} From 39ec0c6d84b7971b7712692ea71c075088bec43e Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 16:02:25 +0800 Subject: [PATCH 10/11] Regenerate the tests --- .../Transforms/JumpThreading/common-preds.ll | 24 ++++----- .../SimplifyCFG/merge-phi-values.ll | 51 +++++++------------ 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/llvm/test/Transforms/JumpThreading/common-preds.ll b/llvm/test/Transforms/JumpThreading/common-preds.ll index e9599a6e741b1..04c06affb60ce 100644 --- a/llvm/test/Transforms/JumpThreading/common-preds.ll +++ b/llvm/test/Transforms/JumpThreading/common-preds.ll @@ -17,17 +17,15 @@ define i64 @bar(i64 %0, i1 %1, i64 %num) { ; CHECK: case1: ; CHECK-NEXT: br i1 [[TMP1]], label [[SUCC]], label [[FOO_THREAD]] ; CHECK: case2: -; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[FOO_THREAD]] -; CHECK: foo.thread: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, [[CASE2]] ], [ 0, [[CASE1]] ], [ 0, [[CASE0]] ] -; CHECK-NEXT: br label [[SUCC]] +; CHECK-NEXT: br i1 [[TMP1]], label [[EXIT2]], label [[EXIT2]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ], [ [[PHI1_PH]], [[FOO_THREAD]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[CASE1]] ], [ [[NUM]], [[CASE0]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2]] +; 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 [[PHI2]] +; CHECK-NEXT: ret i64 [[PHI25]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; @@ -73,18 +71,14 @@ define i64 @multicase(i64 %0, i1 %1, i64 %num) { ; CHECK-NEXT: i64 2, label [[SUCC:%.*]] ; CHECK-NEXT: i64 3, label [[SUCC]] ; CHECK-NEXT: ] -; CHECK: default: -; CHECK-NEXT: br label [[FOO]] -; CHECK: foo: -; CHECK-NEXT: [[PHI1:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ 0, [[ENTRY]] ], [ 1, [[DEFAULT]] ] -; CHECK-NEXT: br label [[SUCC]] ; CHECK: succ: -; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY]] ], [ [[NUM]], [[ENTRY]] ], [ [[PHI1]], [[FOO]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[NUM:%.*]], [[ENTRY:%.*]] ], [ [[NUM]], [[ENTRY]] ] ; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[PHI2]], 0 -; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[EXIT2:%.*]] +; CHECK-NEXT: br i1 [[COND2]], label [[FOO]], label [[DEFAULT]] ; CHECK: exit: +; CHECK-NEXT: [[PHI23:%.*]] = phi i64 [ [[PHI2]], [[SUCC]] ], [ 0, [[ENTRY]] ], [ 0, [[ENTRY]] ] ; CHECK-NEXT: call void @foo() -; CHECK-NEXT: ret i64 [[PHI2]] +; CHECK-NEXT: ret i64 [[PHI23]] ; CHECK: exit2: ; CHECK-NEXT: ret i64 0 ; diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll index cbce38da15094..e39aaaacd7a4b 100644 --- a/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll +++ b/llvm/test/Transforms/SimplifyCFG/merge-phi-values.ll @@ -19,14 +19,14 @@ define i8 @phis_of_switch(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[CASE1]]: -; CHECK-NEXT: br label %[[CASE0]] +; 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]] ], [ 2, %[[CASE1]] ], [ 3, %[[CASE2]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 3, %[[CASE2]] ] ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[CASE0]] ], [ 3, %[[START]] ], [ 4, %[[CASE2]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 4, %[[CASE2]] ], [ 2, %[[CASE1]] ], [ [[PHI1]], %[[CASE0]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -60,7 +60,7 @@ 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 %[[SINK:.*]] +; 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) @@ -68,16 +68,16 @@ define i8 @phis_of_if(i8 noundef %arg, i1 %cond) { ; 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-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 [ 0, %[[START]] ], [ 1, %[[CASE0]] ], [ 2, %[[CASE1]] ] +; 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]] ], [ [[PHI1]], %[[SINK]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ 0, %[[START]] ], [ [[PHI1]], %[[SINK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -121,12 +121,12 @@ define i64 @from_jump_threading(i64 %0, i1 %1, i64 %num) { ; CHECK: [[CASE1]]: ; CHECK-NEXT: br i1 [[TMP1]], label %[[SUCC]], label %[[FOO_THREAD]] ; CHECK: [[CASE2]]: -; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[FOO_THREAD]] +; CHECK-NEXT: br i1 [[TMP1]], label %[[COMMON_RET]], label %[[SUCC]] ; CHECK: [[FOO_THREAD]]: -; CHECK-NEXT: [[PHI1_PH:%.*]] = phi i64 [ 1, %[[CASE2]] ], [ 0, %[[CASE1]] ], [ 0, %[[CASE0]] ] +; 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]] ], [ [[PHI1_PH]], %[[FOO_THREAD]] ] +; 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]]: @@ -172,20 +172,10 @@ exit2: ; preds = %succ, %case2, %2 define i8 @multicase_dest(i8 noundef %arg) { ; CHECK-LABEL: define i8 @multicase_dest( ; CHECK-SAME: i8 noundef [[ARG:%.*]]) { -; CHECK-NEXT: [[START:.*]]: -; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ -; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] -; CHECK-NEXT: i8 1, label %[[BLOCK]] -; CHECK-NEXT: i8 2, label %[[SUCC:.*]] -; CHECK-NEXT: i8 3, label %[[SUCC]] -; CHECK-NEXT: ] -; CHECK: [[DEFAULT]]: -; CHECK-NEXT: br label %[[BLOCK]] -; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ] -; CHECK-NEXT: br label %[[SUCC]] -; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] +; CHECK-NEXT: [[START:.*:]] +; CHECK-NEXT: [[SWITCH_AND:%.*]] = and i8 [[ARG]], -2 +; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i8 [[SWITCH_AND]], 0 +; CHECK-NEXT: [[PHI2:%.*]] = select i1 [[SWITCH_SELECTCMP]], i8 1, i8 3 ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -212,22 +202,18 @@ define i8 @multicase_dest2(i8 noundef %arg, i1 %cond) { ; CHECK-LABEL: define i8 @multicase_dest2( ; CHECK-SAME: i8 noundef [[ARG:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[START:.*]]: -; CHECK-NEXT: switch i8 [[ARG]], label %[[DEFAULT:.*]] [ +; CHECK-NEXT: switch i8 [[ARG]], label %[[SUCC:.*]] [ ; CHECK-NEXT: i8 0, label %[[BLOCK:.*]] ; CHECK-NEXT: i8 1, label %[[BLOCK]] -; CHECK-NEXT: i8 2, label %[[SUCC:.*]] -; CHECK-NEXT: i8 3, label %[[SUCC]] ; CHECK-NEXT: i8 4, label %[[CASE:.*]] ; CHECK-NEXT: ] -; CHECK: [[DEFAULT]]: -; CHECK-NEXT: br label %[[BLOCK]] ; CHECK: [[CASE]]: ; CHECK-NEXT: br i1 [[COND]], label %[[BLOCK]], label %[[SUCC]] ; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 3, %[[DEFAULT]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ], [ 4, %[[CASE]] ] ; CHECK-NEXT: br label %[[SUCC]] ; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ], [ 4, %[[CASE]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 4, %[[CASE]] ], [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: @@ -267,10 +253,9 @@ define i8 @multicase_dest3(i8 noundef %arg, i1 %cond) { ; CHECK: [[UNREACHABLE]]: ; CHECK-NEXT: unreachable ; CHECK: [[BLOCK]]: -; CHECK-NEXT: [[PHI1:%.*]] = phi i8 [ 1, %[[START]] ], [ 1, %[[START]] ] ; CHECK-NEXT: br label %[[SUCC]] ; CHECK: [[SUCC]]: -; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ [[PHI1]], %[[BLOCK]] ], [ 3, %[[START]] ], [ 3, %[[START]] ] +; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, %[[START]] ], [ 3, %[[START]] ], [ 1, %[[BLOCK]] ] ; CHECK-NEXT: ret i8 [[PHI2]] ; start: From 4f64ddfdced65ee17ab5b14a3b519e8e8312eb0f Mon Sep 17 00:00:00 2001 From: Camsyn Date: Fri, 7 Nov 2025 16:15:50 +0800 Subject: [PATCH 11/11] Fix comments --- llvm/lib/Transforms/Utils/Local.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 9ba9ddb4305d5..829f9b8dfa759 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1001,8 +1001,9 @@ static void replaceUndefValuesInPhi(PHINode *PN, } } -// Only when there exists other incoming blocks besides the common predecessors -// of BB and Succ, return true. +// The function gets all the common predecessors of BB and Succ, and returns +// true only if 1) all the common predecessors are the same, or 2) there +// exists other incoming blocks besides the common predecessors. // Only handles cases when BB can't be merged while its predecessors can be // redirected. static bool