[llvm] [SimplifyCFG][Local] Redirect other phi values from BB to Succ except commom preds (PR #166390)

Kunqiu Chen via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 7 00:16:10 PST 2025


https://github.com/Camsyn updated https://github.com/llvm/llvm-project/pull/166390

>From 149ff264994f1764cb3dc76576d6e501cff45373 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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<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;
     });

>From 3649a41f1fdb52fbd5c65caf172534689dc72a36 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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<Instruction>(U.getUser()))
         return !CommonPreds.contains(UseInst->getParent()) &&
                BBPreds.contains(UseInst->getParent());

>From 9d3b70971fd52841abeff3f925ffbbda9811a1b8 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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 <camsyn at foxmail.com>
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



More information about the llvm-commits mailing list