[llvm] fc6bdb8 - [SimplifyCFG] Reland transform for redirecting phis between unmergeable BB and SuccBB (#68473)

via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 28 02:10:25 PDT 2023


Author: XChy
Date: 2023-10-28T17:10:20+08:00
New Revision: fc6bdb8549842613da51b9d570b29e27cc709f69

URL: https://github.com/llvm/llvm-project/commit/fc6bdb8549842613da51b9d570b29e27cc709f69
DIFF: https://github.com/llvm/llvm-project/commit/fc6bdb8549842613da51b9d570b29e27cc709f69.diff

LOG: [SimplifyCFG] Reland transform for redirecting phis between unmergeable BB and SuccBB (#68473)

Reland #67275 with #68953 resolved.

Added: 
    llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll

Modified: 
    llvm/lib/Transforms/Utils/Local.cpp
    llvm/test/CodeGen/ARM/jump-table-islands.ll
    llvm/test/Transforms/JumpThreading/codesize-loop.ll
    llvm/test/Transforms/SimplifyCFG/branch-fold.ll
    llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
    llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index a255db7dafa79d0..aacf66bfe38eb91 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -850,17 +850,17 @@ static bool CanMergeValues(Value *First, Value *Second) {
 /// branch to Succ, into Succ.
 ///
 /// Assumption: Succ is the single successor for BB.
-static bool CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
+static bool
+CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ,
+                                const SmallPtrSetImpl<BasicBlock *> &BBPreds) {
   assert(*succ_begin(BB) == Succ && "Succ is not successor of BB!");
 
   LLVM_DEBUG(dbgs() << "Looking to fold " << BB->getName() << " into "
                     << Succ->getName() << "\n");
   // Shortcut, if there is only a single predecessor it must be BB and merging
   // is always safe
-  if (Succ->getSinglePredecessor()) return true;
-
-  // Make a list of the predecessors of BB
-  SmallPtrSet<BasicBlock*, 16> BBPreds(pred_begin(BB), pred_end(BB));
+  if (Succ->getSinglePredecessor())
+    return true;
 
   // Look at all the phi nodes in Succ, to see if they present a conflict when
   // merging these blocks
@@ -1000,6 +1000,35 @@ static void replaceUndefValuesInPhi(PHINode *PN,
   }
 }
 
+// Only when they shares a single common predecessor, 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,
+                                const SmallPtrSetImpl<BasicBlock *> &SuccPreds,
+                                BasicBlock *&CommonPred) {
+
+  // There must be phis in BB, otherwise BB will be merged into Succ directly
+  if (BB->phis().empty() || Succ->phis().empty())
+    return false;
+
+  // BB must have predecessors not shared that can be redirected to Succ
+  if (!BB->hasNPredecessorsOrMore(2))
+    return false;
+
+  // Get single common predecessors of both BB and Succ
+  for (BasicBlock *SuccPred : SuccPreds) {
+    if (BBPreds.count(SuccPred)) {
+      if (CommonPred)
+        return false;
+      CommonPred = SuccPred;
+    }
+  }
+
+  return true;
+}
+
 /// Replace a value flowing from a block to a phi with
 /// potentially multiple instances of that value flowing from the
 /// block's predecessors to the phi.
@@ -1007,9 +1036,11 @@ static void replaceUndefValuesInPhi(PHINode *PN,
 /// \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) {
+                                                PHINode *PN,
+                                                BasicBlock *CommonPred) {
   Value *OldVal = PN->removeIncomingValue(BB, false);
   assert(OldVal && "No entry in PHI for Pred BB!");
 
@@ -1037,26 +1068,39 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
       // will trigger asserts if we try to clean it up now, without also
       // simplifying the corresponding conditional branch).
       BasicBlock *PredBB = OldValPN->getIncomingBlock(i);
+
+      if (PredBB == CommonPred)
+        continue;
+
       Value *PredVal = OldValPN->getIncomingValue(i);
-      Value *Selected = selectIncomingValueForBlock(PredVal, PredBB,
-                                                    IncomingValues);
+      Value *Selected =
+          selectIncomingValueForBlock(PredVal, PredBB, IncomingValues);
 
       // And add a new incoming value for this predecessor for the
       // newly retargeted branch.
       PN->addIncoming(Selected, PredBB);
     }
+    if (CommonPred)
+      PN->addIncoming(OldValPN->getIncomingValueForBlock(CommonPred), BB);
+
   } else {
     for (unsigned i = 0, e = BBPreds.size(); i != e; ++i) {
       // Update existing incoming values in PN for this
       // predecessor of BB.
       BasicBlock *PredBB = BBPreds[i];
-      Value *Selected = selectIncomingValueForBlock(OldVal, PredBB,
-                                                    IncomingValues);
+
+      if (PredBB == CommonPred)
+        continue;
+
+      Value *Selected =
+          selectIncomingValueForBlock(OldVal, PredBB, IncomingValues);
 
       // And add a new incoming value for this predecessor for the
       // newly retargeted branch.
       PN->addIncoming(Selected, PredBB);
     }
+    if (CommonPred)
+      PN->addIncoming(OldVal, BB);
   }
 
   replaceUndefValuesInPhi(PN, IncomingValues);
@@ -1067,13 +1111,30 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
   assert(BB != &BB->getParent()->getEntryBlock() &&
          "TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
 
-  // We can't eliminate infinite loops.
+  // We can't simplify infinite loops.
   BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
-  if (BB == Succ) return false;
+  if (BB == Succ)
+    return false;
+
+  SmallPtrSet<BasicBlock *, 16> BBPreds(pred_begin(BB), pred_end(BB));
+  SmallPtrSet<BasicBlock *, 16> SuccPreds(pred_begin(Succ), pred_end(Succ));
 
-  // Check to see if merging these blocks would cause conflicts for any of the
-  // phi nodes in BB or Succ. If not, we can safely merge.
-  if (!CanPropagatePredecessorsForPHIs(BB, Succ)) return false;
+  // The single common predecessor of BB and Succ when BB cannot be killed
+  BasicBlock *CommonPred = nullptr;
+
+  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, SuccPreds, CommonPred);
+
+  if (!BBKillable && !BBPhisMergeable)
+    return false;
+
+  // Check to see if merging these blocks/phis would cause conflicts for any of
+  // the phi nodes in BB or Succ. If not, we can safely merge.
 
   // Check for cases where Succ has multiple predecessors and a PHI node in BB
   // has uses which will not disappear when the PHI nodes are merged.  It is
@@ -1102,6 +1163,11 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
     }
   }
 
+  if (BBPhisMergeable && CommonPred)
+    LLVM_DEBUG(dbgs() << "Found Common Predecessor between: " << BB->getName()
+                      << " and " << Succ->getName() << " : "
+                      << CommonPred->getName() << "\n");
+
   // 'BB' and 'BB->Pred' are loop latches, bail out to presrve inner loop
   // metadata.
   //
@@ -1174,25 +1240,37 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
           if (PredTI->hasMetadata(LLVMContext::MD_loop))
             return false;
 
-  LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+  if (BBKillable)
+    LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+  else if (BBPhisMergeable)
+    LLVM_DEBUG(dbgs() << "Merge Phis in Trivial BB: \n" << *BB);
 
   SmallVector<DominatorTree::UpdateType, 32> Updates;
+
   if (DTU) {
     // To avoid processing the same predecessor more than once.
     SmallPtrSet<BasicBlock *, 8> SeenPreds;
-    // All predecessors of BB will be moved to Succ.
-    SmallPtrSet<BasicBlock *, 8> PredsOfSucc(pred_begin(Succ), pred_end(Succ));
+    // All predecessors of BB (except the common predecessor) will be moved to
+    // Succ.
     Updates.reserve(Updates.size() + 2 * pred_size(BB) + 1);
-    for (auto *PredOfBB : predecessors(BB))
-      // This predecessor of BB may already have Succ as a successor.
-      if (!PredsOfSucc.contains(PredOfBB))
+
+    for (auto *PredOfBB : predecessors(BB)) {
+      // Do not modify those common predecessors of BB and Succ
+      if (!SuccPreds.contains(PredOfBB))
         if (SeenPreds.insert(PredOfBB).second)
           Updates.push_back({DominatorTree::Insert, PredOfBB, Succ});
+    }
+
     SeenPreds.clear();
+
     for (auto *PredOfBB : predecessors(BB))
-      if (SeenPreds.insert(PredOfBB).second)
+      // When BB cannot be killed, do not remove the edge between BB and
+      // CommonPred.
+      if (SeenPreds.insert(PredOfBB).second && PredOfBB != CommonPred)
         Updates.push_back({DominatorTree::Delete, PredOfBB, BB});
-    Updates.push_back({DominatorTree::Delete, BB, Succ});
+
+    if (BBKillable)
+      Updates.push_back({DominatorTree::Delete, BB, Succ});
   }
 
   if (isa<PHINode>(Succ->begin())) {
@@ -1204,21 +1282,19 @@ 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);
+      redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN, CommonPred);
     }
   }
 
   if (Succ->getSinglePredecessor()) {
     // BB is the only predecessor of Succ, so Succ will end up with exactly
     // the same predecessors BB had.
-
     // Copy over any phi, debug or lifetime instruction.
     BB->getTerminator()->eraseFromParent();
     Succ->splice(Succ->getFirstNonPHI()->getIterator(), BB);
   } else {
     while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
-      // We explicitly check for such uses in CanPropagatePredecessorsForPHIs.
+      // We explicitly check for such uses for merging phis.
       assert(PN->use_empty() && "There shouldn't be any uses here!");
       PN->eraseFromParent();
     }
@@ -1231,21 +1307,35 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
       for (BasicBlock *Pred : predecessors(BB))
         Pred->getTerminator()->setMetadata(LLVMContext::MD_loop, LoopMD);
 
-  // Everything that jumped to BB now goes to Succ.
-  BB->replaceAllUsesWith(Succ);
-  if (!Succ->hasName()) Succ->takeName(BB);
-
-  // Clear the successor list of BB to match updates applying to DTU later.
-  if (BB->getTerminator())
-    BB->back().eraseFromParent();
-  new UnreachableInst(BB->getContext(), BB);
-  assert(succ_empty(BB) && "The successor list of BB isn't empty before "
-                           "applying corresponding DTU updates.");
+  if (BBKillable) {
+    // Everything that jumped to BB now goes to Succ.
+    BB->replaceAllUsesWith(Succ);
+
+    if (!Succ->hasName())
+      Succ->takeName(BB);
+
+    // Clear the successor list of BB to match updates applying to DTU later.
+    if (BB->getTerminator())
+      BB->back().eraseFromParent();
+
+    new UnreachableInst(BB->getContext(), BB);
+    assert(succ_empty(BB) && "The successor list of BB isn't empty before "
+                             "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 {
+      if (Instruction *UseInst = dyn_cast<Instruction>(U.getUser()))
+        return UseInst->getParent() != CommonPred &&
+               BBPreds.contains(UseInst->getParent());
+      return false;
+    });
+  }
 
   if (DTU)
     DTU->applyUpdates(Updates);
 
-  DeleteDeadBlock(BB, DTU);
+  if (BBKillable)
+    DeleteDeadBlock(BB, DTU);
 
   return true;
 }

diff  --git a/llvm/test/CodeGen/ARM/jump-table-islands.ll b/llvm/test/CodeGen/ARM/jump-table-islands.ll
index c327affc04539b3..e774930bd2bb0b9 100644
--- a/llvm/test/CodeGen/ARM/jump-table-islands.ll
+++ b/llvm/test/CodeGen/ARM/jump-table-islands.ll
@@ -2,6 +2,8 @@
 
 %BigInt = type i8500
 
+declare void @use(%BigInt)
+
 define %BigInt @test_moved_jumptable(i1 %tst, i32 %sw, %BigInt %l) {
 ; CHECK-LABEL: test_moved_jumptable:
 
@@ -34,6 +36,8 @@ other:
 
 end:
   %val = phi %BigInt [ %l, %complex ], [ -1, %simple ]
+; Prevent SimplifyCFG from simplifying the phi node above.
+  call void @use(%BigInt %val)
   ret %BigInt %val
 }
 

diff  --git a/llvm/test/Transforms/JumpThreading/codesize-loop.ll b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
index a1a2b1dfd15edb2..f01c149ac45a396 100644
--- a/llvm/test/Transforms/JumpThreading/codesize-loop.ll
+++ b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
@@ -42,16 +42,14 @@ define i32 @test_minsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; OVERIDE-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; OVERIDE-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; OVERIDE-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE:       5:
+; OVERIDE-NEXT:    br label [[COND_END_THREAD]]
 ; OVERIDE:       cond.end.thread:
-; OVERIDE-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT:    br label [[TMP6]]
-; OVERIDE:       6:
-; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; OVERIDE-NEXT:    ret i32 0
 ;
 entry:
@@ -90,16 +88,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; DEFAULT-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; DEFAULT-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; DEFAULT-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; DEFAULT-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; DEFAULT-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; DEFAULT:       5:
+; DEFAULT-NEXT:    br label [[COND_END_THREAD]]
 ; DEFAULT:       cond.end.thread:
-; DEFAULT-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; DEFAULT-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; DEFAULT-NEXT:    br label [[TMP6]]
-; DEFAULT:       6:
-; DEFAULT-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; DEFAULT-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; DEFAULT-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; DEFAULT-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; DEFAULT-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; DEFAULT-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; DEFAULT-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; DEFAULT-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; DEFAULT-NEXT:    ret i32 0
 ;
 ; OVERIDE-LABEL: @test_optsize(
@@ -115,16 +111,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; OVERIDE-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; OVERIDE-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; OVERIDE-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE:       5:
+; OVERIDE-NEXT:    br label [[COND_END_THREAD]]
 ; OVERIDE:       cond.end.thread:
-; OVERIDE-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT:    br label [[TMP6]]
-; OVERIDE:       6:
-; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; OVERIDE-NEXT:    ret i32 0
 ;
 entry:

diff  --git a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
index b8b5aaa73cf501c..2f5fb4f33013d2e 100644
--- a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
+++ b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
@@ -114,3 +114,35 @@ bb0:
   call void @foo()
   ret void
 }
+
+define i8 @common_pred(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: @common_pred(
+; CHECK-NEXT:  Pred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[COMMONPRED:%.*]], label [[SUCC:%.*]]
+; CHECK:       CommonPred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C2:%.*]], i8 4, i8 1
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[PRED:%.*]] ], [ [[SPEC_SELECT]], [[COMMONPRED]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+Pred:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+CommonPred:
+call void @dummy()
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %Pred ], [1, %CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+declare void @dummy()

diff  --git a/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
new file mode 100644
index 000000000000000..0ffa53a5c9e1049
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
@@ -0,0 +1,327 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+; Test a bunch of cases where the combination of phis in switch should be merged into one phi
+
+declare void @use(i8)
+
+define i8 @phis_of_switch_minimal(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_minimal
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE01:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case01:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 3, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE01]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case01
+  i8 1, label %case1
+  i8 2, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case01
+
+case01:
+  %phi1 = phi i8 [ 2, %case1 ], [1, %start]
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case01 ], [ 3, %start ]
+  ret i8 %phi2
+}
+
+define i8 @phis_of_switch(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case012:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case012 ], [ 4, %start ]
+  ret i8 %phi2
+}
+
+define i8 @multiple_phis_of_switch(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @multiple_phis_of_switch
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case012:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2_1:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
+; CHECK-NEXT:    [[PHI2_2:%.*]] = phi i8 [ 5, [[START]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
+; CHECK-NEXT:    [[PHI2_3:%.*]] = phi i8 [ 3, [[START]] ], [ 6, [[CASE2]] ], [ 5, [[CASE1]] ], [ 4, [[CASE012]] ]
+; CHECK-NEXT:    call void @use(i8 [[PHI2_1]])
+; CHECK-NEXT:    call void @use(i8 [[PHI2_2]])
+; CHECK-NEXT:    call void @use(i8 [[PHI2_3]])
+; CHECK-NEXT:    ret i8 [[PHI2_1]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1_1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  %phi1_2 = phi i8 [ 6, %case2 ], [ 5, %case1 ], [4, %start]
+  br label %end
+
+end:
+  %phi2_1 = phi i8 [ %phi1_1, %case012 ], [ 4, %start ]
+  %phi2_2 = phi i8 [ %phi1_1, %case012 ], [ 5, %start ]
+  %phi2_3 = phi i8 [ %phi1_2, %case012 ], [ 3, %start ]
+  call void @use(i8 %phi2_1)
+  call void @use(i8 %phi2_2)
+  call void @use(i8 %phi2_3)
+  ret i8 %phi2_1
+}
+
+define i8 @phis_of_switch_multiple_stage0(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_multiple_stage0
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; 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 [[CASE0123:%.*]]
+; CHECK-NEXT:    i8 4, label [[CASE01234:%.*]]
+; CHECK-NEXT:    i8 5, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case0123:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       case01234:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI3:%.*]] = phi i8 [ 6, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ], [ 4, [[CASE0123]] ], [ 5, [[CASE01234]] ]
+; CHECK-NEXT:    ret i8 [[PHI3]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case0
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %case0123
+  i8 4, label %case01234
+  i8 5, label %end
+  ]
+unreachable:
+  unreachable
+
+case0:
+  br label %case0123
+
+case1:
+  br label %case0123
+
+case2:
+  br label %case0123
+
+case0123:
+  %phi1 = phi i8 [4, %start], [ 3, %case2 ], [ 2, %case1 ], [ 1, %case0 ]
+  br label %case01234
+
+case01234:
+  %phi2 = phi i8 [ %phi1, %case0123 ], [ 5, %start ]
+  br label %end
+
+end:
+  %phi3 = phi i8 [ %phi2, %case01234 ], [6, %start]
+  ret i8 %phi3
+}
+
+define i8 @phis_of_switch_multiple_stage1(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_multiple_stage1
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; 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 [[CASE012:%.*]]
+; CHECK-NEXT:    i8 3, label [[CASE3:%.*]]
+; CHECK-NEXT:    i8 4, label [[CASE4:%.*]]
+; CHECK-NEXT:    i8 5, label [[CASE345:%.*]]
+; CHECK-NEXT:    i8 6, label [[CASE0123456:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case012:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case3:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case4:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case345:
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case0123456:
+; CHECK-NEXT:    [[PHI1234567:%.*]] = phi i8 [ 7, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ], [ 3, [[CASE012]] ], [ 5, [[CASE4]] ], [ 4, [[CASE3]] ], [ 6, [[CASE345]] ]
+; CHECK-NEXT:    ret i8 [[PHI1234567]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case0
+  i8 1, label %case1
+  i8 2, label %case012
+  i8 3, label %case3
+  i8 4, label %case4
+  i8 5, label %case345
+  i8 6, label %case0123456
+  ]
+unreachable:
+  unreachable
+case0:
+  br label %case012
+
+case1:
+  br label %case012
+
+case012:
+  %phi123 = phi i8 [3, %start], [ 2, %case1 ], [ 1, %case0 ]
+  br label %case0123456
+
+case3:
+  br label %case345
+
+case4:
+  br label %case345
+
+case345:
+  %phi456 = phi i8 [6, %start], [ 5, %case4 ], [ 4, %case3 ]
+  br label %case0123456
+
+case0123456:
+  %phi1234567 = phi i8 [7, %start], [ %phi456, %case345 ], [ %phi123, %case012 ]
+  ret i8 %phi1234567
+
+}
+
+define i8 @phis_of_switch_extra_use_fail(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_extra_use_fail
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; 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 [[CASE012]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case012:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
+; CHECK-NEXT:    call void @use(i8 [[PHI1]])
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE012]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2 i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  call void @use(i8 %phi1)
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case012 ], [ 4, %start ]
+  ret i8 %phi2
+}

diff  --git a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
index eae851f2ddadae9..d63973eab71e474 100644
--- a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
+++ b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
@@ -1,4 +1,5 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+
 ; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops=false -S < %s | FileCheck %s
 ; RUN: opt -passes='simplifycfg<no-keep-loops>' -S < %s | FileCheck %s
 
@@ -7,11 +8,12 @@
 ; SimplifyCFG if-converts one of the phis, it should do both.
 
 define i32 @upper_bound(ptr %r, i32 %high, i32 %k) nounwind {
-; CHECK-LABEL: @upper_bound(
+; CHECK-LABEL: define i32 @upper_bound
+; CHECK-SAME: (ptr [[R:%.*]], i32 [[HIGH:%.*]], i32 [[K:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
 ; CHECK:       while.cond:
-; CHECK-NEXT:    [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH:%.*]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[WHILE_BODY:%.*]] ]
+; CHECK-NEXT:    [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[WHILE_BODY:%.*]] ]
 ; CHECK-NEXT:    [[LOW_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[SPEC_SELECT1:%.*]], [[WHILE_BODY]] ]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LOW_0]], [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[WHILE_BODY]], label [[WHILE_END:%.*]]
@@ -19,9 +21,9 @@ define i32 @upper_bound(ptr %r, i32 %high, i32 %k) nounwind {
 ; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[LOW_0]], [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[ADD]], 2
 ; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[DIV]] to i64
-; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[R:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[R]], i64 [[IDXPROM]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[K:%.*]], [[TMP0]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[K]], [[TMP0]]
 ; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[DIV]], 1
 ; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[CMP1]], i32 [[DIV]], i32 [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    [[SPEC_SELECT1]] = select i1 [[CMP1]], i32 [[LOW_0]], i32 [[ADD2]]
@@ -57,3 +59,270 @@ if.else:                                          ; preds = %while.body
 while.end:                                        ; preds = %while.cond
   ret i32 %low.0
 }
+
+define i32 @merge0(i1 %c1, i1 %c2, i1 %c3) {
+; CHECK-LABEL: define i32 @merge0
+; CHECK-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) {
+; CHECK-NEXT:  j2:
+; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[C2]], i32 0, i32 1
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C3]], i32 2, i32 3
+; CHECK-NEXT:    [[PHI2:%.*]] = select i1 [[C1]], i32 [[DOT]], i32 [[SPEC_SELECT]]
+; CHECK-NEXT:    ret i32 [[PHI2]]
+;
+  br i1 %c1, label %if1, label %else1
+
+if1:
+  br i1 %c2, label %if2, label %else2
+
+if2:
+  br label %j1 else2:
+  br label %j1
+
+else1:
+  br i1 %c3, label %j1, label %j2
+
+j1:
+  %phi1 = phi i32 [ 0, %if2 ], [ 1, %else2 ], [ 2, %else1 ]
+  br label %j2
+
+j2:
+  %phi2 = phi i32 [ %phi1, %j1 ], [ 3, %else1 ]
+  ret i32 %phi2
+}
+
+define i8 @merge1(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[SUCC:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_one_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_one_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[SUCC:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+  call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_two_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_two_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 123, label [[SUCC:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       case1:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 1, [[CASE1]] ], [ 2, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+call void @dummy()
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_all_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_all_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C1]], label [[COMMONPRED:%.*]], label [[SUCC:%.*]]
+; CHECK:       case1:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       case2:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       CommonPred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C2]], i8 4, i8 3
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[CASE2]] ], [ [[SPEC_SELECT]], [[COMMONPRED]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+call void @dummy()
+  br label %BB
+
+case2:
+call void @dummy()
+  br label %BB
+
+CommonPred:
+call void @dummy()
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+declare void @dummy()
+

diff  --git a/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll b/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
index eb0947397a6992b..63985ec565bb9ef 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
@@ -6,6 +6,9 @@ define i8 @test() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP2:%.*]]
 ; CHECK:       loop2:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[LOOP2]] ]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[PHI2]], 0
+; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[COND]], i8 0, i8 [[PHI2]]
 ; CHECK-NEXT:    br label [[LOOP2]]
 ;
 entry:


        


More information about the llvm-commits mailing list