[llvm] [FixIrreducible][UnifyLoopExits] Support switch statements (PR #206567)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 19 11:43:08 PDT 2026


https://github.com/hertelukas updated https://github.com/llvm/llvm-project/pull/206567

>From 49815f928db5f523b2381f0f85e47093b3c7ef35 Mon Sep 17 00:00:00 2001
From: Lukas <dev at lukas-hertel.de>
Date: Sun, 28 Jun 2026 17:43:33 +0200
Subject: [PATCH 1/5] [FixIrreducible] Support switch statements

Reuse the approach for callbr terminators for switches. Branches,
entering irreducible loops through switches, are split and replaced
with unconditional branches into the loop.

Assisted-by: LLM (Adapted callbr test structure to switch)
---
 .../llvm/Transforms/Utils/BasicBlockUtils.h   |  27 +-
 llvm/lib/Transforms/Utils/BasicBlockUtils.cpp |  60 +-
 llvm/lib/Transforms/Utils/FixIrreducible.cpp  |  62 +-
 llvm/lib/Transforms/Utils/UnifyLoopExits.cpp  |  58 +-
 llvm/test/Transforms/FixIrreducible/switch.ll | 960 +++++++++++++++++-
 .../FixIrreducible/unsupported-terminator.ll  |  25 +-
 6 files changed, 1052 insertions(+), 140 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
index 3088b96bf7a32..be0567a1b1db2 100644
--- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
@@ -268,19 +268,20 @@ LLVM_ABI BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
                                MemorySSAUpdater *MSSAU = nullptr,
                                const Twine &BBName = "");
 
-/// \brief Create a new intermediate target block for a callbr edge.
+/// \brief Create a new intermediate target block for a callbr and switch edges.
 ///
-/// Create a new basic block between a callbr instruction and one of its
-/// successors. The new block replaces the original successor in the callbr
-/// instruction and unconditionally branches to the original successor. This
-/// is useful for normalizing control flow, e.g., when transforming
-/// irreducible loops.
+/// Create a new basic block between a callbr or switch instruction and one of
+/// its successors. The new block replaces the original successor in the
+/// callbr/switch instruction and unconditionally branches to the original
+/// successor. This is useful for normalizing control flow, e.g., when
+/// transforming irreducible loops.
 ///
-/// \param CallBrBlock    block containing the callbr instruction
+/// \param MultiBrBlock   block containing the callbr or switch instruction
 /// \param Succ           original successor block
-/// \param SuccIdx        index of the original successor in the callbr
+/// \param SuccIdx        index of the original successor in the terminator
 ///                       instruction
-/// \param CallBrTarget   optional \p BasicBlock generated by \c SplitCallBrEdge
+/// \param BrTarget       optional \p BasicBlock generated by \c
+/// SplitMultiBrEdge
 ///                       to reuse for the split
 /// \param DTU            optional \p DomTreeUpdater for updating the
 ///                       dominator tree
@@ -294,10 +295,10 @@ LLVM_ABI BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
 /// \note This function updates PHI nodes, dominator tree, loop info, and
 /// cycle info as needed.
 LLVM_ABI BasicBlock *
-SplitCallBrEdge(BasicBlock *CallBrBlock, BasicBlock *Succ, unsigned SuccIdx,
-                BasicBlock *CallBrTarget = nullptr,
-                DomTreeUpdater *DTU = nullptr, CycleInfo *CI = nullptr,
-                LoopInfo *LI = nullptr, bool *UpdatedLI = nullptr);
+SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ, unsigned SuccIdx,
+                 BasicBlock *BrTarget = nullptr, DomTreeUpdater *DTU = nullptr,
+                 CycleInfo *CI = nullptr, LoopInfo *LI = nullptr,
+                 bool *UpdatedLI = nullptr);
 
 /// Sets the unwind edge of an instruction to a particular successor.
 LLVM_ABI void setUnwindEdgeTo(Instruction *TI, BasicBlock *Succ);
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index 5d1faec67bddd..e12d1919e2f4f 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -733,67 +733,67 @@ static bool updateCycleLoopInfo(TI *LCI, BasicBlock *CallBrBlock,
   return true;
 }
 
-BasicBlock *llvm::SplitCallBrEdge(BasicBlock *CallBrBlock, BasicBlock *Succ,
-                                  unsigned SuccIdx, BasicBlock *CallBrTarget,
-                                  DomTreeUpdater *DTU, CycleInfo *CI,
-                                  LoopInfo *LI, bool *UpdatedLI) {
-  CallBrInst *CallBr = dyn_cast<CallBrInst>(CallBrBlock->getTerminator());
-  assert(CallBr && "expected callbr terminator");
-  assert(SuccIdx < CallBr->getNumSuccessors() &&
-         Succ == CallBr->getSuccessor(SuccIdx) && "invalid successor index");
+BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
+                                   unsigned SuccIdx, BasicBlock *BrTarget,
+                                   DomTreeUpdater *DTU, CycleInfo *CI,
+                                   LoopInfo *LI, bool *UpdatedLI) {
+  Instruction *Term = MultiBrBlock->getTerminator();
+  assert(Term && "expected terminator");
+  assert(SuccIdx < Term->getNumSuccessors() &&
+         Succ == Term->getSuccessor(SuccIdx) && "invalid successor index");
 
   if (UpdatedLI)
     *UpdatedLI = false;
 
-  bool ReusesCallBrTarget = CallBrTarget;
-  // Create a new block between callbr and the specified successor.
+  bool ReusesCallBrTarget = BrTarget;
+
+  // Create a new block between terminator and the specified successor.
   // splitBlockBefore cannot be re-used here since it cannot split if the split
   // point is a PHI node (because BasicBlock::splitBasicBlockBefore cannot
   // handle that). But we don't need to rewire every part of a potential PHI
-  // node. We only care about the edge between CallBrBlock and the original
+  // node. We only care about the edge between MultiBrBlock and the original
   // successor.
   if (!ReusesCallBrTarget) {
-    CallBrTarget = BasicBlock::Create(CallBrBlock->getContext(),
-                                      CallBrBlock->getName() + ".target." +
-                                          Succ->getName(),
-                                      CallBrBlock->getParent());
+    BrTarget = BasicBlock::Create(MultiBrBlock->getContext(),
+                                  MultiBrBlock->getName() + ".target." +
+                                      Succ->getName(),
+                                  MultiBrBlock->getParent());
     // Jump from the new target block to the original successor.
-    UncondBrInst::Create(Succ, CallBrTarget);
+    UncondBrInst::Create(Succ, BrTarget);
     // Replace a single incoming value with the callbr target block. We cannot
     // use replacePhiUsesWith, as this would replace the value for every edge
     // from the callbr block to succ.
     for (PHINode &PN : Succ->phis()) {
-      int BBIdx = PN.getBasicBlockIndex(CallBrBlock);
+      int BBIdx = PN.getBasicBlockIndex(MultiBrBlock);
       assert(BBIdx != -1 && "expected incoming value form callbr block");
-      PN.setIncomingBlock(BBIdx, CallBrTarget);
+      PN.setIncomingBlock(BBIdx, BrTarget);
     }
 
-    bool Updated = updateCycleLoopInfo<LoopInfo, Loop>(LI, CallBrBlock,
-                                                       CallBrTarget, Succ);
+    bool Updated =
+        updateCycleLoopInfo<LoopInfo, Loop>(LI, MultiBrBlock, BrTarget, Succ);
     if (UpdatedLI)
       *UpdatedLI = Updated;
-    updateCycleLoopInfo<CycleInfo, CycleRef>(CI, CallBrBlock, CallBrTarget,
-                                             Succ);
+    updateCycleLoopInfo<CycleInfo, CycleRef>(CI, MultiBrBlock, BrTarget, Succ);
   } else {
     for (PHINode &PN : Succ->phis())
-      PN.removeIncomingValue(CallBrBlock, false);
+      PN.removeIncomingValue(MultiBrBlock, false);
   }
 
   // Rewire control flow from callbr to the new target block.
-  CallBr->setSuccessor(SuccIdx, CallBrTarget);
+  Term->setSuccessor(SuccIdx, BrTarget);
 
   if (DTU) {
     if (!ReusesCallBrTarget)
-      DTU->applyUpdates({{DominatorTree::Insert, CallBrBlock, CallBrTarget}});
-    if (DTU->getDomTree().dominates(CallBrBlock, Succ)) {
-      if (!is_contained(successors(CallBrBlock), Succ))
-        DTU->applyUpdates({{DominatorTree::Delete, CallBrBlock, Succ}});
+      DTU->applyUpdates({{DominatorTree::Insert, MultiBrBlock, BrTarget}});
+    if (DTU->getDomTree().dominates(MultiBrBlock, Succ)) {
+      if (!is_contained(successors(MultiBrBlock), Succ))
+        DTU->applyUpdates({{DominatorTree::Delete, MultiBrBlock, Succ}});
       if (!ReusesCallBrTarget)
-        DTU->applyUpdates({{DominatorTree::Insert, CallBrTarget, Succ}});
+        DTU->applyUpdates({{DominatorTree::Insert, BrTarget, Succ}});
     }
   }
 
-  return CallBrTarget;
+  return BrTarget;
 }
 
 void llvm::setUnwindEdgeTo(Instruction *TI, BasicBlock *Succ) {
diff --git a/llvm/lib/Transforms/Utils/FixIrreducible.cpp b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
index 77e8cb838ca75..c4f7460ef0c98 100644
--- a/llvm/lib/Transforms/Utils/FixIrreducible.cpp
+++ b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
@@ -76,16 +76,15 @@
 // a PHINode in a header. Hence the above handling of PHINodes is sufficient and
 // no further processing is required to restore SSA.
 //
-// Limitation: The pass cannot handle switch statements and indirect
-//             branches. Both must be lowered to plain branches first.
+// Limitation: The pass cannot handle indirect branches. They must be lowered to
+//             plain branches first.
 //
-// CallBr support: CallBr is handled as a more general branch instruction which
-// can have multiple successors. The pass redirects the edges to intermediate
-// target blocks that unconditionally branch to the original callbr target
-// blocks. This allows the control flow hub to know to which of the original
-// target blocks to jump to.
-// Example input CFG:
-//                        Entry (callbr)
+// CallBr and Switch support: CallBr and Switch terminators are handled as a
+// more general branch instruction which can have multiple successors. The pass
+// redirects the edges to intermediate target blocks that unconditionally branch
+// to the original target blocks. This allows the control flow hub to know to
+// which of the original target blocks to jump to. Example input CFG:
+//                        Entry (callbr/switch)
 //                       /     \
 //                      v       v
 //                      H ----> B
@@ -95,7 +94,7 @@
 //                             Exit
 //
 // becomes:
-//                        Entry (callbr)
+//                        Entry (callbr/switch)
 //                       /     \
 //                      v       v
 //                 target.H   target.B
@@ -110,7 +109,7 @@
 // Note
 // OUTPUT CFG: Converted to a natural loop with a new header N.
 //
-//                        Entry (callbr)
+//                        Entry (callbr/switch)
 //                       /     \
 //                      v       v
 //                 target.H   target.B
@@ -133,6 +132,7 @@
 #include "llvm/Analysis/CycleAnalysis.h"
 #include "llvm/Analysis/DomTreeUpdater.h"
 #include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -308,13 +308,15 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(P->getTerminator())) {
+    } else if (isa<CallBrInst>(P->getTerminator()) ||
+               isa<SwitchInst>(P->getTerminator())) {
       BasicBlock *NewSucc = nullptr;
-      for (unsigned I = 0; I < CallBr->getNumSuccessors(); ++I) {
-        BasicBlock *Succ = CallBr->getSuccessor(I);
+      Instruction *Term = P->getTerminator();
+      for (unsigned I = 0; I < Term->getNumSuccessors(); ++I) {
+        BasicBlock *Succ = Term->getSuccessor(I);
         if (Succ != Header)
           continue;
-        NewSucc = SplitCallBrEdge(P, Succ, I, NewSucc, &DTU, &CI, LI);
+        NewSucc = SplitMultiBrEdge(P, Succ, I, NewSucc, &DTU, &CI, LI);
         LLVM_DEBUG(dbgs() << "Added internal branch: "
                           << printBasicBlock(NewSucc) << " -> "
                           << printBasicBlock(Succ) << '\n');
@@ -322,8 +324,9 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
       if (NewSucc)
         CHub.addBranch(NewSucc, Header);
     } else {
-      reportFatalUsageError("unsupported block terminator: fix-irreducible "
-                            "only supports br and callbr instructions");
+      reportFatalUsageError(
+          "unsupported block terminator: fix-irreducible "
+          "only supports br, callbr, and switch instructions");
     }
   }
 
@@ -355,31 +358,32 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(P->getTerminator())) {
-      SmallDenseMap<BasicBlock *, BasicBlock *> CallBrTargets;
-      for (unsigned I = 0; I < CallBr->getNumSuccessors(); ++I) {
-        BasicBlock *Succ = CallBr->getSuccessor(I);
+    } else if (isa<CallBrInst>(P->getTerminator()) ||
+               isa<SwitchInst>(P->getTerminator())) {
+      SmallDenseMap<BasicBlock *, BasicBlock *> MultiBrTargets;
+      Instruction *Term = P->getTerminator();
+      for (unsigned I = 0; I < Term->getNumSuccessors(); ++I) {
+        BasicBlock *Succ = Term->getSuccessor(I);
         if (!CI.contains(C, Succ))
           continue;
-        auto It = CallBrTargets.find(Succ);
+        auto It = MultiBrTargets.find(Succ);
         BasicBlock *ExistingTarget =
-            (It != CallBrTargets.end()) ? It->second : nullptr;
+            (It != MultiBrTargets.end()) ? It->second : nullptr;
 
         BasicBlock *NewSucc =
-            SplitCallBrEdge(P, Succ, I, ExistingTarget, &DTU, &CI, LI);
-
+            SplitMultiBrEdge(P, Succ, I, ExistingTarget, &DTU, &CI, LI);
         if (!ExistingTarget) {
           CHub.addBranch(NewSucc, Succ);
-          CallBrTargets[Succ] = NewSucc;
+          MultiBrTargets[Succ] = NewSucc;
         }
-
         LLVM_DEBUG(dbgs() << "Added external branch: "
                           << printBasicBlock(NewSucc) << " -> "
                           << printBasicBlock(Succ) << '\n');
       }
     } else {
-      reportFatalUsageError("unsupported block terminator: fix-irreducible "
-                            "only supports br and callbr instructions");
+      reportFatalUsageError(
+          "unsupported block terminator: fix-irreducible "
+          "only supports br, callbr, and switch instructions");
     }
   }
 
diff --git a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
index c31d1dd13e1ea..11a7d233d1bc0 100644
--- a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
+++ b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
@@ -13,10 +13,10 @@
 // Limitation: This assumes that all terminators in the CFG are direct branches
 //             (the "br" instruction). The presence of any other control flow
 //             such as indirectbr or switch will cause an assert.
-//             The callbr terminator is supported by creating intermediate
-//             target blocks that unconditionally branch to the original target
-//             blocks. These intermediate target blocks can then be redirected
-//             through the ControlFlowHub as usual.
+//             The callbr and switch terminators are supported by creating
+//             intermediate target blocks that unconditionally branch to the
+//             original target blocks. These intermediate target blocks can then
+//             be redirected through the ControlFlowHub as usual.
 //
 //===----------------------------------------------------------------------===//
 
@@ -27,6 +27,7 @@
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Dominators.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Transforms/Utils.h"
@@ -160,7 +161,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
     return false;
 
   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
-  SmallVector<BasicBlock *, 8> CallBrTargetBlocksToFix;
+  SmallVector<BasicBlock *, 8> MultiBrTargetBlocksToFix;
 
   // Redirect exiting edges through a control flow hub.
   ControlFlowHub CHub;
@@ -188,41 +189,44 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (CallBrInst *CallBr = dyn_cast<CallBrInst>(BB->getTerminator())) {
-      SmallDenseMap<BasicBlock *, BasicBlock *> CallBrTargets;
-      for (unsigned J = 0; J < CallBr->getNumSuccessors(); ++J) {
-        BasicBlock *Succ = CallBr->getSuccessor(J);
+    } else if (isa<CallBrInst>(BB->getTerminator()) ||
+               isa<SwitchInst>(BB->getTerminator())) {
+      SmallDenseMap<BasicBlock *, BasicBlock *> BrTargets;
+      Instruction *Term = BB->getTerminator();
+      for (unsigned J = 0; J < Term->getNumSuccessors(); ++J) {
+        BasicBlock *Succ = Term->getSuccessor(J);
         if (L->contains(Succ))
           continue;
         bool UpdatedLI;
-        auto It = CallBrTargets.find(Succ);
+        auto It = BrTargets.find(Succ);
         BasicBlock *ExistingTarget =
-            (It != CallBrTargets.end()) ? It->second : nullptr;
-        BasicBlock *NewSucc = SplitCallBrEdge(BB, Succ, J, ExistingTarget, &DTU,
-                                              nullptr, &LI, &UpdatedLI);
+            (It != BrTargets.end()) ? It->second : nullptr;
+        BasicBlock *NewSucc = SplitMultiBrEdge(BB, Succ, J, ExistingTarget,
+                                               &DTU, nullptr, &LI, &UpdatedLI);
 
         if (!ExistingTarget) {
-          // SplitCallBrEdge modifies the CFG because it creates an intermediate
-          // block. So we need to set the changed flag no matter what the
-          // ControlFlowHub is going to do later.
+          // SplitMutliBrEdge modifies the CFG because it creates an
+          // intermediate block. So we need to set the changed flag no matter
+          // what the ControlFlowHub is going to do later.
           Changed = true;
-          // Even if CallBr and Succ do not have a common parent loop, we need
-          // to add the new target block to the parent loop of the current loop.
+          // Even if the terminator and Succ do not have a common parent loop,
+          // we need to add the new target block to the parent loop of the
+          // current loop.
           if (!UpdatedLI)
-            CallBrTargetBlocksToFix.push_back(NewSucc);
+            MultiBrTargetBlocksToFix.push_back(NewSucc);
           // ExitingBlocks is later used to restore SSA, so we need to make sure
           // that the blocks used for phi nodes in the guard blocks match the
-          // predecessors of the guard blocks, which, in the case of callbr, are
-          // the new intermediate target blocks instead of the callbr blocks
-          // themselves. If only one exiting block is generated, the callbr
-          // block itself is overwritten, while further blocks are appended as
-          // additional exiting blocks.
-          if (CallBrTargets.empty())
+          // predecessors of the guard blocks, which, in the case of callbr or
+          // switch terminator, are the new intermediate target blocks instead
+          // of themselves. If only one exiting block is generated, the
+          // branchning block itself is overwritten, while further blocks are
+          // appended as additional exiting blocks.
+          if (BrTargets.empty())
             ExitingBlocks[I] = NewSucc;
           else
             ExitingBlocks.push_back(NewSucc);
           CHub.addBranch(NewSucc, Succ);
-          CallBrTargets[Succ] = NewSucc;
+          BrTargets[Succ] = NewSucc;
         }
         LLVM_DEBUG(dbgs() << "Added exiting branch: "
                           << printBasicBlock(NewSucc) << " -> "
@@ -263,7 +267,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
     for (auto *G : GuardBlocks) {
       ParentLoop->addBasicBlockToLoop(G, LI);
     }
-    for (auto *C : CallBrTargetBlocksToFix) {
+    for (auto *C : MultiBrTargetBlocksToFix) {
       ParentLoop->addBasicBlockToLoop(C, LI);
     }
     ParentLoop->verifyLoop();
diff --git a/llvm/test/Transforms/FixIrreducible/switch.ll b/llvm/test/Transforms/FixIrreducible/switch.ll
index 4d3d9498b284d..0da0a0d28735c 100644
--- a/llvm/test/Transforms/FixIrreducible/switch.ll
+++ b/llvm/test/Transforms/FixIrreducible/switch.ll
@@ -1,31 +1,145 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -lowerswitch -fix-irreducible --verify-loop-info -S | FileCheck %s
-; RUN: opt < %s -passes='lower-switch,fix-irreducible,verify<loops>' -S | FileCheck %s
-; RUN: opt < %s -passes='lower-switch,verify<loops>,fix-irreducible,verify<loops>' -S | FileCheck %s
-
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes='fix-irreducible,verify<loops>' -S | FileCheck %s
+; RUN: opt < %s -passes='verify<loops>,fix-irreducible,verify<loops>' -S | FileCheck %s
+; RUN: opt < %s -passes='print<cycles>' -disable-output 2>&1 | FileCheck %s --check-prefix CYCLES-BEFORE
+; RUN: opt < %s -passes='fix-irreducible,print<cycles>' -disable-output 2>&1 | FileCheck %s --check-prefix CYCLES-AFTER
+; CYCLES-BEFORE:      CycleInfo for function: loop_1
+; CYCLES-BEFORE-NEXT:    depth=1: entries(B A)
+; CYCLES-AFTER:       CycleInfo for function: loop_1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) B A B.target.B
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_entry
+; CYCLES-BEFORE-NEXT:    depth=1: entries(indirect fallthrough)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_entry
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) indirect fallthrough
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_entry_targets_with_phi_nodes
+; CYCLES-BEFORE-NEXT:    depth=1: entries(block1 block)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_entry_targets_with_phi_nodes
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) block1 block
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_entry_multiple_targets
+; CYCLES-BEFORE-NEXT:    depth=1: entries(indirect fallthrough)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_entry_multiple_targets
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) indirect fallthrough
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_entry_multiple_targets1
+; CYCLES-BEFORE-NEXT:    depth=1: entries(indirect1 indirect fallthrough)
+; CYCLES-BEFORE-NEXT:        depth=2: entries(indirect fallthrough)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_entry_multiple_targets1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) indirect1 indirect fallthrough irr.guard1 irr.guard2
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) indirect fallthrough
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_header_no_indirect
+; CYCLES-BEFORE-NEXT:    depth=1: entries(fallthrough switch_bb)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_header_no_indirect
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) fallthrough switch_bb switch_bb.target.fallthrough
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_header
+; CYCLES-BEFORE-NEXT:    depth=1: entries(fallthrough switch_bb)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_header
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) fallthrough switch_bb switch_bb.target.fallthrough
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_header_multiple_targets
+; CYCLES-BEFORE-NEXT:    depth=1: entries(fallthrough switch_bb) indirect1
+; CYCLES-BEFORE-NEXT:        depth=2: entries(switch_bb) indirect1
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_header_multiple_targets
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) fallthrough switch_bb indirect1 switch_bb.target.fallthrough
+; CYCLES-AFTER-NEXT:         depth=2: entries(switch_bb) indirect1
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_regular
+; CYCLES-BEFORE-NEXT:    depth=1: entries(fallthrough2 fallthrough1)
+; CYCLES-BEFORE-NEXT:    depth=1: entries(indirect2 indirect1)
+; CYCLES-BEFORE-NEXT:    depth=1: entries(noswitch2 noswitch1)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_regular
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) fallthrough2 fallthrough1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard1) indirect2 indirect1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard2) noswitch2 noswitch1
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_regular1
+; CYCLES-BEFORE-NEXT:    depth=1: entries(switch_bb noswitch)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_regular1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) switch_bb noswitch
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_header_and_regular
+; CYCLES-BEFORE-NEXT:    depth=1: entries(switch_header) switch_regular mid
+; CYCLES-BEFORE-NEXT:        depth=2: entries(switch_regular mid)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_header_and_regular
+; CYCLES-AFTER-NEXT:     depth=1: entries(switch_header) switch_regular mid switch_header.target.mid switch_header.target.switch_regular irr.guard
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard) switch_regular mid
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_only
+; CYCLES-BEFORE-NEXT:    depth=1: entries(switch_block switch_header)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_only
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) switch_block switch_header switch_header.target.switch_block
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: entry_multiple_switch
+; CYCLES-BEFORE-NEXT:    depth=1: entries(sw2 block block1)
+; CYCLES-BEFORE-NEXT:        depth=2: entries(block block1)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: entry_multiple_switch
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw2 block block1 irr.guard1 sw2.target.block1 sw2.target.block irr.guard2
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) block block1
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_exit_with_separate_entries
+; CYCLES-BEFORE-NEXT:    depth=1: entries(l2 l1) sw
+; CYCLES-BEFORE-NEXT:        depth=2: entries(l1 sw)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_exit_with_separate_entries
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l2 l1 sw sw.target.l1 irr.guard1
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard1) l1 sw sw.target.l1
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_exit_with_separate_entries1
+; CYCLES-BEFORE-NEXT:    depth=1: entries(loop2 loop1) sw
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_exit_with_separate_entries1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) loop2 loop1 sw sw.target.loop2
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_only_multiple
+; CYCLES-BEFORE-NEXT:    depth=1: entries(sw3 sw1 sw2)
+; CYCLES-BEFORE-NEXT:        depth=2: entries(sw1 sw2)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_only_multiple
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw3 sw1 sw2 sw2.target.sw3 sw1.target.sw3 irr.guard1 sw2.target.sw1 sw3.target.sw1 irr.guard2
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) sw1 sw2 sw2.target.sw1
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_bypass
+; CYCLES-BEFORE-NEXT:    depth=1: entries(l1 sw) l2
+; CYCLES-BEFORE-NEXT:        depth=2: entries(sw l2)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_bypass
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l1 sw l2 sw.target.l1 irr.guard1
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard1) sw l2
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_multiple_with_exit
+; CYCLES-BEFORE-NEXT:    depth=1: entries(l3 l1 l2)
+; CYCLES-BEFORE-NEXT:        depth=2: entries(l1 l2)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_multiple_with_exit
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l3 l1 l2 irr.guard1 irr.guard2
+; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) l1 l2
+;
+; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_nested
+; CYCLES-BEFORE-NEXT:    depth=1: entries(bb bh)
+; CYCLES-BEFORE-NEXT:    depth=1: entries(b h)
+; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_nested
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) bb bh
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard1) b h
+;
 define void @loop_1(i32 %Value, i1 %PredEntry, i1 %PredD) {
-; CHECK-LABEL: @loop_1(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[PREDENTRY_INV:%.*]] = xor i1 [[PREDENTRY:%.*]], true
-; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
-; CHECK:       A:
-; CHECK-NEXT:    br label [[IRR_GUARD]]
-; CHECK:       B:
-; CHECK-NEXT:    br label [[NODEBLOCK:%.*]]
-; CHECK:       NodeBlock:
-; CHECK-NEXT:    [[PIVOT:%.*]] = icmp slt i32 [[VALUE:%.*]], 1
-; CHECK-NEXT:    br i1 [[PIVOT]], label [[LEAFBLOCK:%.*]], label [[LEAFBLOCK1:%.*]]
-; CHECK:       LeafBlock1:
-; CHECK-NEXT:    [[SWITCHLEAF2:%.*]] = icmp eq i32 [[VALUE]], 1
-; CHECK-NEXT:    br i1 [[SWITCHLEAF2]], label [[IRR_GUARD]], label [[EXIT:%.*]]
-; CHECK:       LeafBlock:
-; CHECK-NEXT:    [[SWITCHLEAF:%.*]] = icmp eq i32 [[VALUE]], 0
-; CHECK-NEXT:    br i1 [[SWITCHLEAF]], label [[A:%.*]], label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    ret void
-; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[LEAFBLOCK1]] ], [ true, [[A]] ], [ [[PREDENTRY_INV]], [[ENTRY:%.*]] ]
-; CHECK-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[A]]
+; CHECK-LABEL: define void @loop_1(
+; CHECK-SAME: i32 [[VALUE:%.*]], i1 [[PREDENTRY:%.*]], i1 [[PREDD:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[PREDENTRY_INV:%.*]] = xor i1 [[PREDENTRY]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[A:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[B:.*]]:
+; CHECK-NEXT:    switch i32 [[VALUE]], label %[[EXIT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[A]]
+; CHECK-NEXT:      i32 1, label %[[B_TARGET_B:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[B_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, %[[B_TARGET_B]] ], [ true, %[[A]] ], [ [[PREDENTRY_INV]], %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B]], label %[[B]], label %[[A]]
 ;
 entry:
   br i1 %PredEntry, label %A, label %B
@@ -42,3 +156,795 @@ B:
 exit:
   ret void
 }
+
+define void @switch_entry(i32 %val, i1 %c) {
+; CHECK-LABEL: define void @switch_entry(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_INDIRECT:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
+; CHECK:       [[INDIRECT:.*]]:
+; CHECK-NEXT:    br label %[[FALLTHROUGH]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[ENTRY_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_INDIRECT]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[FALLTHROUGH]] ], [ false, %[[ENTRY_TARGET_FALLTHROUGH]] ], [ true, %[[ENTRY_TARGET_INDIRECT]] ]
+; CHECK-NEXT:    br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[FALLTHROUGH]]
+;
+entry:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  ]
+fallthrough:
+  br i1 %c, label %indirect, label %ret
+indirect:
+  br label %fallthrough
+ret:
+  ret void
+}
+
+define i32 @switch_entry_targets_with_phi_nodes(i32 %val, i1 %c) {
+; CHECK-LABEL: define i32 @switch_entry_targets_with_phi_nodes(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_BLOCK:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_BLOCK1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BLOCK:.*]]:
+; CHECK-NEXT:    [[A:%.*]] = phi i32 [ 1, %[[BLOCK1:.*]] ], [ [[A_MOVED:%.*]], %[[IRR_GUARD:.*]] ]
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[BLOCK1]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[BLOCK]], label %[[RET:.*]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret i32 [[B_MOVED:%.*]]
+; CHECK:       [[ENTRY_TARGET_BLOCK]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_BLOCK1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[A_MOVED]] = phi i32 [ poison, %[[BLOCK]] ], [ 42, %[[ENTRY_TARGET_BLOCK]] ], [ poison, %[[ENTRY_TARGET_BLOCK1]] ]
+; CHECK-NEXT:    [[B_MOVED]] = phi i32 [ [[A]], %[[BLOCK]] ], [ poison, %[[ENTRY_TARGET_BLOCK]] ], [ 43, %[[ENTRY_TARGET_BLOCK1]] ]
+; CHECK-NEXT:    [[GUARD_BLOCK1:%.*]] = phi i1 [ true, %[[BLOCK]] ], [ false, %[[ENTRY_TARGET_BLOCK]] ], [ true, %[[ENTRY_TARGET_BLOCK1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_BLOCK1]], label %[[BLOCK1]], label %[[BLOCK]]
+;
+entry:
+  switch i32 %val, label %block [
+  i32 0, label %block1
+  ]
+block:
+  %a = phi i32 [42, %entry], [1, %block1]
+  br label %block1
+block1:
+  %b = phi i32 [43, %entry], [%a, %block]
+  br i1 %c, label %block, label %ret
+ret:
+  ret i32 %b
+}
+
+define void @switch_entry_multiple_targets(i32 %val, i1 %c) {
+; CHECK-LABEL: define void @switch_entry_multiple_targets(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_INDIRECT:.*]]
+; CHECK-NEXT:      i32 1, label %[[INDIRECT1:.*]]
+; CHECK-NEXT:      i32 2, label %[[INDIRECT2:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
+; CHECK:       [[INDIRECT:.*]]:
+; CHECK-NEXT:    br label %[[FALLTHROUGH]]
+; CHECK:       [[INDIRECT1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[INDIRECT2]]:
+; CHECK-NEXT:    br label %[[RET]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[ENTRY_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_INDIRECT]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[FALLTHROUGH]] ], [ true, %[[INDIRECT1]] ], [ false, %[[ENTRY_TARGET_FALLTHROUGH]] ], [ true, %[[ENTRY_TARGET_INDIRECT]] ]
+; CHECK-NEXT:    br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[FALLTHROUGH]]
+;
+entry:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  i32 1, label %indirect1
+  i32 2, label %indirect2
+  ]
+fallthrough:
+  br i1 %c, label %indirect, label %ret
+indirect:
+  br label %fallthrough
+indirect1:
+  br label %indirect
+indirect2:
+  br label %ret
+ret:
+  ret void
+}
+
+define void @switch_entry_multiple_targets1(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_entry_multiple_targets1(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_INDIRECT:.*]]
+; CHECK-NEXT:      i32 1, label %[[ENTRY_TARGET_INDIRECT1:.*]]
+; CHECK-NEXT:      i32 2, label %[[INDIRECT2:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD2:.*]], label %[[RET:.*]]
+; CHECK:       [[INDIRECT:.*]]:
+; CHECK-NEXT:    br i1 [[D]], label %[[FALLTHROUGH]], label %[[IRR_GUARD:.*]]
+; CHECK:       [[INDIRECT1:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[INDIRECT2]]:
+; CHECK-NEXT:    br label %[[RET]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[ENTRY_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_INDIRECT]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_INDIRECT1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_INDIRECT1:%.*]] = phi i1 [ true, %[[INDIRECT]] ], [ false, %[[ENTRY_TARGET_FALLTHROUGH]] ], [ false, %[[ENTRY_TARGET_INDIRECT]] ], [ true, %[[ENTRY_TARGET_INDIRECT1]] ]
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ false, %[[INDIRECT]] ], [ true, %[[ENTRY_TARGET_FALLTHROUGH]] ], [ false, %[[ENTRY_TARGET_INDIRECT]] ], [ false, %[[ENTRY_TARGET_INDIRECT1]] ]
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH_INV:%.*]] = xor i1 [[GUARD_FALLTHROUGH]], true
+; CHECK-NEXT:    br i1 [[GUARD_INDIRECT1]], label %[[INDIRECT1]], label %[[IRR_GUARD1:.*]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[IRR_GUARD2]]:
+; CHECK-NEXT:    [[GUARD_INDIRECT:%.*]] = phi i1 [ true, %[[FALLTHROUGH]] ], [ [[GUARD_FALLTHROUGH_INV]], %[[IRR_GUARD1]] ], [ true, %[[INDIRECT1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_INDIRECT]], label %[[INDIRECT]], label %[[FALLTHROUGH]]
+;
+entry:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  i32 1, label %indirect1
+  i32 2, label %indirect2
+  ]
+fallthrough:
+  br i1 %c, label %indirect, label %ret
+indirect:
+  br i1 %d, label %fallthrough, label %indirect1
+indirect1:
+  br label %indirect
+indirect2:
+  br label %ret
+ret:
+  ret void
+}
+
+define void @switch_header_no_indirect(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_header_no_indirect(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:    [[D_INV:%.*]] = xor i1 [[D]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SWITCH_BB:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_BB_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[SWITCH_BB]], label %[[RET:.*]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_BB_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[SWITCH_BB_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
+; CHECK-NEXT:    br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[SWITCH_BB]]
+;
+  br i1 %d, label %switch_bb, label %fallthrough
+switch_bb:
+  switch i32 %val, label %fallthrough []
+fallthrough:
+  br i1 %c, label %switch_bb, label %ret
+ret:
+  ret void
+}
+
+define void @switch_header(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_header(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:    [[D_INV:%.*]] = xor i1 [[D]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SWITCH_BB:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_BB_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[INDIRECT:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[INDIRECT]]:
+; CHECK-NEXT:    br label %[[RET:.*]]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[SWITCH_BB]], label %[[RET]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_BB_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[SWITCH_BB_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
+; CHECK-NEXT:    br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[SWITCH_BB]]
+;
+  br i1 %d, label %switch_bb, label %fallthrough
+switch_bb:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  ]
+indirect:
+  br label %ret
+fallthrough:
+  br i1 %c, label %switch_bb, label %ret
+ret:
+  ret void
+}
+
+define void @switch_header_multiple_targets(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_header_multiple_targets(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:    [[D_INV:%.*]] = xor i1 [[D]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SWITCH_BB:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_BB_TARGET_FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[INDIRECT:.*]]
+; CHECK-NEXT:      i32 1, label %[[INDIRECT1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[INDIRECT]]:
+; CHECK-NEXT:    br label %[[RET:.*]]
+; CHECK:       [[INDIRECT1]]:
+; CHECK-NEXT:    br label %[[SWITCH_BB]]
+; CHECK:       [[FALLTHROUGH:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[SWITCH_BB]], label %[[RET]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_BB_TARGET_FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH:%.*]] = phi i1 [ true, %[[SWITCH_BB_TARGET_FALLTHROUGH]] ], [ [[D_INV]], [[TMP0:%.*]] ]
+; CHECK-NEXT:    br i1 [[GUARD_FALLTHROUGH]], label %[[FALLTHROUGH]], label %[[SWITCH_BB]]
+;
+  br i1 %d, label %switch_bb, label %fallthrough
+switch_bb:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  i32 1, label %indirect1
+  ]
+indirect:
+  br label %ret
+indirect1:
+  br label %switch_bb
+fallthrough:
+  br i1 %c, label %switch_bb, label %ret
+ret:
+  ret void
+}
+
+define void @switch_regular(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_regular(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:    [[C_INV:%.*]] = xor i1 [[C]], true
+; CHECK-NEXT:    br i1 [[D]], label %[[SWITCH_BB:.*]], label %[[NOSWITCH:.*]]
+; CHECK:       [[SWITCH_BB]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[FALLTHROUGH:.*]] [
+; CHECK-NEXT:      i32 0, label %[[INDIRECT:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[FALLTHROUGH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[FALLTHROUGH1:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[FALLTHROUGH2:.*]]:
+; CHECK-NEXT:    br i1 [[D]], label %[[FALLTHROUGH1]], label %[[RET:.*]]
+; CHECK:       [[INDIRECT]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1:.*]]
+; CHECK:       [[INDIRECT1:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1]]
+; CHECK:       [[INDIRECT2:.*]]:
+; CHECK-NEXT:    br i1 [[D]], label %[[INDIRECT1]], label %[[RET]]
+; CHECK:       [[NOSWITCH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2:.*]]
+; CHECK:       [[NOSWITCH1:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[NOSWITCH2:.*]]:
+; CHECK-NEXT:    br i1 [[D]], label %[[NOSWITCH1]], label %[[RET]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_FALLTHROUGH2:%.*]] = phi i1 [ true, %[[FALLTHROUGH1]] ], [ [[C_INV]], %[[FALLTHROUGH]] ]
+; CHECK-NEXT:    br i1 [[GUARD_FALLTHROUGH2]], label %[[FALLTHROUGH2]], label %[[FALLTHROUGH1]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    [[GUARD_INDIRECT2:%.*]] = phi i1 [ true, %[[INDIRECT1]] ], [ [[C_INV]], %[[INDIRECT]] ]
+; CHECK-NEXT:    br i1 [[GUARD_INDIRECT2]], label %[[INDIRECT2]], label %[[INDIRECT1]]
+; CHECK:       [[IRR_GUARD2]]:
+; CHECK-NEXT:    [[GUARD_NOSWITCH2:%.*]] = phi i1 [ true, %[[NOSWITCH1]] ], [ [[C_INV]], %[[NOSWITCH]] ]
+; CHECK-NEXT:    br i1 [[GUARD_NOSWITCH2]], label %[[NOSWITCH2]], label %[[NOSWITCH1]]
+;
+  br i1 %d, label %switch_bb, label %noswitch
+switch_bb:
+  switch i32 %val, label %fallthrough [
+  i32 0, label %indirect
+  ]
+fallthrough:
+  br i1 %c, label %fallthrough1, label %fallthrough2
+fallthrough1:
+  br label %fallthrough2
+fallthrough2:
+  br i1 %d, label %fallthrough1, label %ret
+indirect:
+  br i1 %c, label %indirect1, label %indirect2
+indirect1:
+  br label %indirect2
+indirect2:
+  br i1 %d, label %indirect1, label %ret
+noswitch:
+  br i1 %c, label %noswitch1, label %noswitch2
+noswitch1:
+  br label %noswitch2
+noswitch2:
+  br i1 %d, label %noswitch1, label %ret
+ret:
+  ret void
+}
+
+define void @switch_regular1(i32 %val, i1 %c) {
+; CHECK-LABEL: define void @switch_regular1(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:    [[C_INV:%.*]] = xor i1 [[C]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[NOSWITCH:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[SWITCH_BB:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[RET:.*]] [
+; CHECK-NEXT:      i32 0, label %[[NOSWITCH]]
+; CHECK-NEXT:    ]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_SWITCH_BB:%.*]] = phi i1 [ true, %[[NOSWITCH]] ], [ [[C_INV]], [[TMP0:%.*]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SWITCH_BB]], label %[[SWITCH_BB]], label %[[NOSWITCH]]
+;
+  br i1 %c, label %noswitch, label %switch_bb
+noswitch:
+  br label %switch_bb
+switch_bb:
+  switch i32 %val, label %ret [
+  i32 0, label %noswitch
+  ]
+ret:
+  ret void
+}
+
+define void @switch_header_and_regular(i32 %val, i1 %c) {
+; CHECK-LABEL: define void @switch_header_and_regular(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:    br label %[[SWITCH_HEADER:.*]]
+; CHECK:       [[SWITCH_HEADER]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_HEADER_TARGET_MID:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SWITCH_HEADER_TARGET_SWITCH_REGULAR:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[MID:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD:.*]], label %[[RET:.*]]
+; CHECK:       [[SWITCH_REGULAR:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_HEADER]] [
+; CHECK-NEXT:      i32 0, label %[[MID]]
+; CHECK-NEXT:    ]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_HEADER_TARGET_MID]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[SWITCH_HEADER_TARGET_SWITCH_REGULAR]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_SWITCH_REGULAR:%.*]] = phi i1 [ true, %[[MID]] ], [ false, %[[SWITCH_HEADER_TARGET_MID]] ], [ true, %[[SWITCH_HEADER_TARGET_SWITCH_REGULAR]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SWITCH_REGULAR]], label %[[SWITCH_REGULAR]], label %[[MID]]
+;
+  br label %switch_header
+switch_header:
+  switch i32 %val, label %mid [
+  i32 0, label %switch_regular
+  ]
+mid:
+  br i1 %c, label %switch_regular, label %ret
+switch_regular:
+  switch i32 %val, label %switch_header [
+  i32 0, label %mid
+  ]
+ret:
+  ret void
+}
+
+define void @switch_only(i32 %val, i1 %c) {
+; CHECK-LABEL: define void @switch_only(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[SWITCH_ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_ENTRY_TARGET_SWITCH_HEADER:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SWITCH_ENTRY_TARGET_SWITCH_BLOCK:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[SWITCH_HEADER:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_HEADER_TARGET_SWITCH_BLOCK:.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       [[SWITCH_BLOCK:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SWITCH_HEADER]] [
+; CHECK-NEXT:      i32 0, label %[[RET:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SWITCH_HEADER_TARGET_SWITCH_BLOCK]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SWITCH_ENTRY_TARGET_SWITCH_HEADER]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[SWITCH_ENTRY_TARGET_SWITCH_BLOCK]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_SWITCH_BLOCK:%.*]] = phi i1 [ true, %[[SWITCH_HEADER_TARGET_SWITCH_BLOCK]] ], [ false, %[[SWITCH_ENTRY_TARGET_SWITCH_HEADER]] ], [ true, %[[SWITCH_ENTRY_TARGET_SWITCH_BLOCK]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SWITCH_BLOCK]], label %[[SWITCH_BLOCK]], label %[[SWITCH_HEADER]]
+;
+switch_entry:
+  switch i32 %val, label %switch_header [
+  i32 0, label %switch_block
+  ]
+switch_header:
+  switch i32 %val, label %switch_block []
+switch_block:
+  switch i32 %val, label %switch_header [
+  i32 0, label %ret
+  ]
+ret:
+  ret void
+}
+
+define void @entry_multiple_switch(i32 %val, i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define void @entry_multiple_switch(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br i1 [[A]], label %[[SW1:.*]], label %[[IRR_GUARD:.*]]
+; CHECK:       [[SW1]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SW1_TARGET_BLOCK:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW1_TARGET_SW2:.*]]
+; CHECK-NEXT:      i32 1, label %[[SW1_TARGET_BLOCK1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BLOCK:.*]]:
+; CHECK-NEXT:    br i1 [[B]], label %[[IRR_GUARD]], label %[[BLOCK1:.*]]
+; CHECK:       [[SW2:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SW2_TARGET_BLOCK1:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW2_TARGET_BLOCK:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BLOCK1]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD2:.*]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SW1_TARGET_BLOCK]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[SW1_TARGET_SW2]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[SW1_TARGET_BLOCK1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_SW2:%.*]] = phi i1 [ true, %[[BLOCK]] ], [ false, %[[SW1_TARGET_BLOCK]] ], [ true, %[[SW1_TARGET_SW2]] ], [ false, %[[SW1_TARGET_BLOCK1]] ], [ true, %[[ENTRY]] ]
+; CHECK-NEXT:    [[GUARD_BLOCK:%.*]] = phi i1 [ false, %[[BLOCK]] ], [ true, %[[SW1_TARGET_BLOCK]] ], [ false, %[[SW1_TARGET_SW2]] ], [ false, %[[SW1_TARGET_BLOCK1]] ], [ false, %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SW2]], label %[[SW2]], label %[[IRR_GUARD1:.*]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[SW2_TARGET_BLOCK1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[SW2_TARGET_BLOCK]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[IRR_GUARD2]]:
+; CHECK-NEXT:    [[GUARD_BLOCK3:%.*]] = phi i1 [ true, %[[BLOCK1]] ], [ [[GUARD_BLOCK]], %[[IRR_GUARD1]] ], [ false, %[[SW2_TARGET_BLOCK1]] ], [ true, %[[SW2_TARGET_BLOCK]] ]
+; CHECK-NEXT:    br i1 [[GUARD_BLOCK3]], label %[[BLOCK]], label %[[BLOCK1]]
+;
+entry:
+  br i1 %a, label %sw1, label %sw2
+sw1:
+  switch i32 %val, label %block [
+  i32 0, label %sw2
+  i32 1, label %block1
+  ]
+block:
+  br i1 %b, label %sw2, label %block1
+sw2:
+  switch i32 %val, label %block1 [
+  i32 0, label %block
+  ]
+block1:
+  br i1 %c, label %block, label %exit
+exit:
+  ret void
+}
+
+define void @switch_exit_with_separate_entries(i32 %val, i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define void @switch_exit_with_separate_entries(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[C_INV:%.*]] = xor i1 [[C]], true
+; CHECK-NEXT:    [[A_INV:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[L1:.*]]:
+; CHECK-NEXT:    br i1 [[B]], label %[[SW:.*]], label %[[IRR_GUARD]]
+; CHECK:       [[L2:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1:.*]]
+; CHECK:       [[SW]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[EXIT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW_TARGET_L1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_L2:%.*]] = phi i1 [ true, %[[L1]] ], [ [[A_INV]], %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_L2]], label %[[L2]], label %[[IRR_GUARD1]]
+; CHECK:       [[SW_TARGET_L1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    [[GUARD_L1:%.*]] = phi i1 [ true, %[[SW_TARGET_L1]] ], [ true, %[[IRR_GUARD]] ], [ [[C_INV]], %[[L2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_L1]], label %[[L1]], label %[[SW]]
+;
+entry:
+  br i1 %a, label %l1, label %l2
+l1:
+  br i1 %b, label %sw, label %l2
+l2:
+  br i1 %c, label %sw, label %l1
+sw:
+  switch i32 %val, label %exit [
+  i32 0, label %l1
+  ]
+exit:
+  ret void
+}
+
+define void @switch_exit_with_separate_entries1(i32 %val, i1 %a, i1 %b) {
+; CHECK-LABEL: define void @switch_exit_with_separate_entries1(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[A_INV:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[LOOP1:.*]]:
+; CHECK-NEXT:    br i1 [[B]], label %[[SW:.*]], label %[[IRR_GUARD]]
+; CHECK:       [[LOOP2:.*]]:
+; CHECK-NEXT:    br label %[[LOOP1]]
+; CHECK:       [[SW]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[EXIT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW_TARGET_LOOP2:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SW_TARGET_LOOP2]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_LOOP2:%.*]] = phi i1 [ true, %[[SW_TARGET_LOOP2]] ], [ true, %[[LOOP1]] ], [ [[A_INV]], %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_LOOP2]], label %[[LOOP2]], label %[[LOOP1]]
+;
+entry:
+  br i1 %a, label %loop1, label %loop2
+loop1:
+  br i1 %b, label %sw, label %loop2
+loop2:
+  br label %loop1
+sw:
+  switch i32 %val, label %exit [
+  i32 0, label %loop2
+  ]
+exit:
+  ret void
+}
+
+define void @switch_only_multiple(i32 %val, i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define void @switch_only_multiple(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_SW1:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_SW2:.*]]
+; CHECK-NEXT:      i32 1, label %[[ENTRY_TARGET_SW3:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[SW1:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SW2:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW1_TARGET_SW3:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[SW2]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SW2_TARGET_SW3:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW2_TARGET_SW1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[SW3:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[SW3_TARGET_SW1:.*]] [
+; CHECK-NEXT:      i32 0, label %[[EXIT:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SW2_TARGET_SW3]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SW1_TARGET_SW3]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_SW1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_SW2]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_SW3]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_SW3:%.*]] = phi i1 [ true, %[[SW2_TARGET_SW3]] ], [ true, %[[SW1_TARGET_SW3]] ], [ false, %[[ENTRY_TARGET_SW1]] ], [ false, %[[ENTRY_TARGET_SW2]] ], [ true, %[[ENTRY_TARGET_SW3]] ]
+; CHECK-NEXT:    [[GUARD_SW1:%.*]] = phi i1 [ false, %[[SW2_TARGET_SW3]] ], [ false, %[[SW1_TARGET_SW3]] ], [ true, %[[ENTRY_TARGET_SW1]] ], [ false, %[[ENTRY_TARGET_SW2]] ], [ false, %[[ENTRY_TARGET_SW3]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SW3]], label %[[SW3]], label %[[IRR_GUARD1:.*]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2:.*]]
+; CHECK:       [[SW2_TARGET_SW1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[SW3_TARGET_SW1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[IRR_GUARD2]]:
+; CHECK-NEXT:    [[GUARD_SW13:%.*]] = phi i1 [ true, %[[SW2_TARGET_SW1]] ], [ [[GUARD_SW1]], %[[IRR_GUARD1]] ], [ true, %[[SW3_TARGET_SW1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SW13]], label %[[SW1]], label %[[SW2]]
+;
+entry:
+  switch i32 %val, label %sw1 [
+  i32 0, label %sw2
+  i32 1, label %sw3
+  ]
+sw1:
+  switch i32 %val, label %sw2 [
+  i32 0, label %sw3
+  ]
+sw2:
+  switch i32 %val, label %sw3 [
+  i32 0, label %sw1
+  ]
+sw3:
+  switch i32 %val, label %sw1 [
+  i32 0, label %exit
+  ]
+exit:
+  ret void
+}
+
+define void @switch_bypass(i32 %val, i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define void @switch_bypass(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[B_INV:%.*]] = xor i1 [[B]], true
+; CHECK-NEXT:    [[A_INV:%.*]] = xor i1 [[A]], true
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[SW:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[L2:.*]] [
+; CHECK-NEXT:      i32 0, label %[[SW_TARGET_L1:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[L1:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1:.*]]
+; CHECK:       [[L2]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD1]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[SW_TARGET_L1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_L1:%.*]] = phi i1 [ true, %[[SW_TARGET_L1]] ], [ [[A_INV]], %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_L1]], label %[[L1]], label %[[IRR_GUARD1]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    [[GUARD_SW:%.*]] = phi i1 [ true, %[[L2]] ], [ true, %[[IRR_GUARD]] ], [ [[B_INV]], %[[L1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_SW]], label %[[SW]], label %[[L2]]
+;
+entry:
+  br i1 %a, label %sw, label %l1
+sw:
+  switch i32 %val, label %l2 [
+  i32 0, label %l1
+  ]
+l1:
+  br i1 %b, label %l2, label %sw
+l2:
+  br i1 %c, label %sw, label %exit
+exit:
+  ret void
+}
+
+define void @switch_multiple_with_exit(i32 %val, i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define void @switch_multiple_with_exit(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_L1:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_L2:.*]]
+; CHECK-NEXT:      i32 1, label %[[EXIT:.*]]
+; CHECK-NEXT:      i32 2, label %[[ENTRY_TARGET_L3:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[L1:.*]]:
+; CHECK-NEXT:    br i1 [[A]], label %[[L2:.*]], label %[[IRR_GUARD:.*]]
+; CHECK:       [[L2]]:
+; CHECK-NEXT:    br i1 [[B]], label %[[IRR_GUARD2:.*]], label %[[EXIT]]
+; CHECK:       [[L3:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[IRR_GUARD2]], label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[ENTRY_TARGET_L1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_L2]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_L3]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_L3:%.*]] = phi i1 [ true, %[[L1]] ], [ false, %[[ENTRY_TARGET_L1]] ], [ false, %[[ENTRY_TARGET_L2]] ], [ true, %[[ENTRY_TARGET_L3]] ]
+; CHECK-NEXT:    [[GUARD_L1:%.*]] = phi i1 [ false, %[[L1]] ], [ true, %[[ENTRY_TARGET_L1]] ], [ false, %[[ENTRY_TARGET_L2]] ], [ false, %[[ENTRY_TARGET_L3]] ]
+; CHECK-NEXT:    br i1 [[GUARD_L3]], label %[[L3]], label %[[IRR_GUARD1:.*]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD2]]
+; CHECK:       [[IRR_GUARD2]]:
+; CHECK-NEXT:    [[GUARD_L13:%.*]] = phi i1 [ true, %[[L2]] ], [ [[GUARD_L1]], %[[IRR_GUARD1]] ], [ true, %[[L3]] ]
+; CHECK-NEXT:    br i1 [[GUARD_L13]], label %[[L1]], label %[[L2]]
+;
+entry:
+  switch i32 %val, label %l1 [
+  i32 0, label %l2
+  i32 1, label %exit
+  i32 2, label %l3
+  ]
+l1:
+  br i1 %a, label %l2, label %l3
+l2:
+  br i1 %b, label %l1, label %exit
+l3:
+  br i1 %c, label %l1, label %exit
+exit:
+  ret void
+}
+
+define void @switch_nested(i32 %val, i1 %c, i1 %d) {
+; CHECK-LABEL: define void @switch_nested(
+; CHECK-SAME: i32 [[VAL:%.*]], i1 [[C:%.*]], i1 [[D:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[ENTRY_TARGET_H:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_B:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[H:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1:.*]]
+; CHECK:       [[B:.*]]:
+; CHECK-NEXT:    switch i32 [[VAL]], label %[[H]] [
+; CHECK-NEXT:      i32 0, label %[[B_TARGET_BH:.*]]
+; CHECK-NEXT:      i32 1, label %[[B_TARGET_BB:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BH:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[BB:.*]]:
+; CHECK-NEXT:    br i1 [[C]], label %[[BH]], label %[[RET:.*]]
+; CHECK:       [[RET]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[B_TARGET_BH]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[B_TARGET_BB]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[GUARD_BB:%.*]] = phi i1 [ true, %[[BH]] ], [ false, %[[B_TARGET_BH]] ], [ true, %[[B_TARGET_BB]] ]
+; CHECK-NEXT:    br i1 [[GUARD_BB]], label %[[BB]], label %[[BH]]
+; CHECK:       [[ENTRY_TARGET_H]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1]]
+; CHECK:       [[ENTRY_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD1]]
+; CHECK:       [[IRR_GUARD1]]:
+; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, %[[H]] ], [ false, %[[ENTRY_TARGET_H]] ], [ true, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B]], label %[[B]], label %[[H]]
+;
+entry:
+  switch i32 %val, label %h [
+  i32 0, label %b
+  ]
+h:
+  br label %b
+b:
+  switch i32 %val, label %h [
+  i32 0, label %bh
+  i32 1, label %bb
+  ]
+bh:
+  br label %bb
+bb:
+  br i1 %c, label %bh, label %ret
+ret:
+  ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CYCLES-AFTER: {{.*}}
+; CYCLES-BEFORE: {{.*}}
diff --git a/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll b/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
index f1be342c3d324..02a4ec802cd33 100644
--- a/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
+++ b/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
@@ -1,19 +1,16 @@
 ; RUN: not opt < %s -passes=fix-irreducible -S 2>&1 | FileCheck %s
-; CHECK: LLVM ERROR: unsupported block terminator: fix-irreducible only supports br and callbr instructions
+; CHECK: LLVM ERROR: unsupported block terminator: fix-irreducible only supports br, callbr, and switch instructions
 
-define void @loop_1(i32 %Value, i1 %PredEntry) {
+define i32 @test(i1 %cond) {
 entry:
-  br i1 %PredEntry, label %A, label %B
+  %target = select i1 %cond,
+                   ptr blockaddress(@test, %then),
+                   ptr blockaddress(@test, %else)
+  indirectbr ptr %target, [label %then, label %else]
 
-A:
-  br label %B
+then:
+  br label %else
 
-B:
-  switch i32 %Value, label %exit [
-    i32 0, label %A
-    i32 1, label %B
-  ]
-
-exit:
-  ret void
-}
+else:
+  br label %then
+}
\ No newline at end of file

>From a46d89d031b0d86fee5906bdc885e1d85e6387d3 Mon Sep 17 00:00:00 2001
From: Lukas <dev at lukas-hertel.de>
Date: Sat, 4 Jul 2026 10:29:28 +0200
Subject: [PATCH 2/5] Address review feedback and add switch tests

---
 .../llvm/Transforms/Utils/BasicBlockUtils.h   |   2 +-
 .../Transforms/FixIrreducible/bug45623.ll     | 131 ++-
 llvm/test/Transforms/FixIrreducible/nested.ll | 869 ++++++++++++++++--
 .../Transforms/FixIrreducible/unreachable.ll  |  23 +
 .../FixIrreducible/unsupported-terminator.ll  |   2 +-
 llvm/test/Transforms/UnifyLoopExits/basic.ll  | 170 +++-
 .../UnifyLoopExits/integer_guards.ll          | 503 +++++++++-
 llvm/test/Transforms/UnifyLoopExits/nested.ll | 168 +++-
 .../Transforms/UnifyLoopExits/restore-ssa.ll  | 275 +++++-
 llvm/test/Transforms/UnifyLoopExits/switch.ll |  29 +
 .../Transforms/UnifyLoopExits/undef-phis.ll   |  81 +-
 11 files changed, 2109 insertions(+), 144 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
index be0567a1b1db2..7503248046395 100644
--- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
@@ -268,7 +268,7 @@ LLVM_ABI BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
                                MemorySSAUpdater *MSSAU = nullptr,
                                const Twine &BBName = "");
 
-/// \brief Create a new intermediate target block for a callbr and switch edges.
+/// \brief Create a new intermediate target block for a callbr or switch edge.
 ///
 /// Create a new basic block between a callbr or switch instruction and one of
 /// its successors. The new block replaces the original successor in the
diff --git a/llvm/test/Transforms/FixIrreducible/bug45623.ll b/llvm/test/Transforms/FixIrreducible/bug45623.ll
index b6dd6fb9e6fcb..d03d1a1aaf9a9 100644
--- a/llvm/test/Transforms/FixIrreducible/bug45623.ll
+++ b/llvm/test/Transforms/FixIrreducible/bug45623.ll
@@ -98,16 +98,16 @@ define void @tre_tnfa_run_backtrack_callbr(i1 %arg) {
 ; CHECK-NEXT:            to label [[RETRY:%.*]] []
 ; CHECK:       retry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG:%.*]])
-; CHECK-NEXT:            to label [[RETRY_TARGET_BACKTRACK:%.*]] [label %retry.target.while.body248]
+; CHECK-NEXT:            to label [[RETRY_TARGET_BACKTRACK:%.*]] [label [[RETRY_TARGET_WHILE_BODY248:%.*]]]
 ; CHECK:       while.body248:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG]])
-; CHECK-NEXT:            to label [[IF_THEN250:%.*]] [label %if.end275]
+; CHECK-NEXT:            to label [[IF_THEN250:%.*]] [label [[IF_END275:%.*]]]
 ; CHECK:       if.then250:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[FOR_COND264:%.*]] []
 ; CHECK:       for.cond264:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG]])
-; CHECK-NEXT:            to label [[FOR_BODY267:%.*]] [label %backtrack]
+; CHECK-NEXT:            to label [[FOR_BODY267:%.*]] [label [[BACKTRACK:%.*]]]
 ; CHECK:       for.body267:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[FOR_COND264]] []
@@ -116,22 +116,22 @@ define void @tre_tnfa_run_backtrack_callbr(i1 %arg) {
 ; CHECK-NEXT:            to label [[FOR_COND342:%.*]] []
 ; CHECK:       for.cond342:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG]])
-; CHECK-NEXT:            to label [[FOR_BODY345:%.*]] [label %for.end580]
+; CHECK-NEXT:            to label [[FOR_BODY345:%.*]] [label [[FOR_END580:%.*]]]
 ; CHECK:       for.body345:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[FOR_COND342]] []
 ; CHECK:       for.end580:
 ; CHECK-NEXT:    callbr void asm "", ""()
-; CHECK-NEXT:            to label [[BACKTRACK:%.*]] []
+; CHECK-NEXT:            to label [[BACKTRACK]] []
 ; CHECK:       backtrack:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG]])
-; CHECK-NEXT:            to label [[IF_THEN595:%.*]] [label %if.else629]
+; CHECK-NEXT:            to label [[IF_THEN595:%.*]] [label [[IF_ELSE629:%.*]]]
 ; CHECK:       if.then595:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[FOR_COND616:%.*]] []
 ; CHECK:       for.cond616:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[ARG]])
-; CHECK-NEXT:            to label [[FOR_BODY619:%.*]] [label %for.end626]
+; CHECK-NEXT:            to label [[FOR_BODY619:%.*]] [label [[FOR_END626:%.*]]]
 ; CHECK:       for.body619:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[FOR_COND616]] []
@@ -148,7 +148,7 @@ define void @tre_tnfa_run_backtrack_callbr(i1 %arg) {
 ; CHECK:       retry.target.while.body248:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_WHILE_BODY248:%.*]] = phi i1 [ true, [[FOR_END626_TARGET_WHILE_BODY248]] ], [ false, [[RETRY_TARGET_BACKTRACK]] ], [ true, [[RETRY_TARGET_WHILE_BODY248:%.*]] ]
+; CHECK-NEXT:    [[GUARD_WHILE_BODY248:%.*]] = phi i1 [ true, [[FOR_END626_TARGET_WHILE_BODY248]] ], [ false, [[RETRY_TARGET_BACKTRACK]] ], [ true, [[RETRY_TARGET_WHILE_BODY248]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_WHILE_BODY248]], label [[WHILE_BODY248:%.*]], label [[BACKTRACK]]
 ;
 entry:
@@ -199,3 +199,118 @@ for.end626:                                       ; preds = %for.cond616
 if.else629:                                       ; preds = %backtrack
   callbr void asm "", ""() to label %retry []
 }
+
+define void @tre_tnfa_run_backtrack_switch(i32 %arg) {
+; CHECK-LABEL: @tre_tnfa_run_backtrack_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[ARG:%.*]], label [[RETRY:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       retry:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[RETRY_TARGET_BACKTRACK:%.*]] [
+; CHECK-NEXT:      i32 0, label [[RETRY_TARGET_WHILE_BODY248:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       while.body248:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[IF_THEN250:%.*]] [
+; CHECK-NEXT:      i32 0, label [[IF_END275:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.then250:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND264:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.cond264:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_BODY267:%.*]] [
+; CHECK-NEXT:      i32 0, label [[BACKTRACK:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       for.body267:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND264]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.end275:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND342:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.cond342:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_BODY345:%.*]] [
+; CHECK-NEXT:      i32 0, label [[FOR_END580:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       for.body345:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND342]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.end580:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[BACKTRACK]] [
+; CHECK-NEXT:    ]
+; CHECK:       backtrack:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[IF_THEN595:%.*]] [
+; CHECK-NEXT:      i32 0, label [[IF_ELSE629:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.then595:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND616:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.cond616:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_BODY619:%.*]] [
+; CHECK-NEXT:      i32 0, label [[FOR_END626:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       for.body619:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_COND616]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.end626:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[FOR_END626_TARGET_WHILE_BODY248:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.else629:
+; CHECK-NEXT:    switch i32 [[ARG]], label [[RETRY]] [
+; CHECK-NEXT:    ]
+; CHECK:       for.end626.target.while.body248:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       retry.target.backtrack:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       retry.target.while.body248:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_WHILE_BODY248:%.*]] = phi i1 [ true, [[FOR_END626_TARGET_WHILE_BODY248]] ], [ false, [[RETRY_TARGET_BACKTRACK]] ], [ true, [[RETRY_TARGET_WHILE_BODY248]] ]
+; CHECK-NEXT:    br i1 [[GUARD_WHILE_BODY248]], label [[WHILE_BODY248:%.*]], label [[BACKTRACK]]
+;
+entry:
+  switch i32 %arg, label %retry []
+
+retry:
+  switch i32 %arg, label %backtrack [ i32 0, label %while.body248 ]
+
+while.body248:                                    ; preds = %for.end626, %retry
+  switch i32 %arg, label %if.then250 [ i32 0, label %if.end275 ]
+
+if.then250:                                       ; preds = %while.body248
+  switch i32 %arg, label %for.cond264 []
+
+for.cond264:                                      ; preds = %for.body267, %if.then250
+  switch i32 %arg, label %for.body267 [ i32 0, label %backtrack ]
+
+for.body267:                                      ; preds = %for.cond264
+  switch i32 %arg, label %for.cond264 []
+
+if.end275:                                        ; preds = %while.body248
+  switch i32 %arg, label %for.cond342 []
+
+for.cond342:                                      ; preds = %for.body345, %if.end275
+  switch i32 %arg, label %for.body345 [ i32 0, label %for.end580 ]
+
+for.body345:                                      ; preds = %for.cond342
+  switch i32 %arg, label %for.cond342 []
+
+for.end580:                                       ; preds = %for.cond342
+  switch i32 %arg, label %backtrack []
+
+backtrack:                                        ; preds = %for.end580, %for.cond264, %retry
+  switch i32 %arg, label %if.then595 [ i32 0, label %if.else629 ]
+
+if.then595:                                       ; preds = %backtrack
+  switch i32 %arg, label %for.cond616 []
+
+for.cond616:                                      ; preds = %for.body619, %if.then595
+  switch i32 %arg, label %for.body619 [ i32 0, label %for.end626 ]
+
+for.body619:                                      ; preds = %for.cond616
+  switch i32 %arg, label %for.cond616 []
+
+for.end626:                                       ; preds = %for.cond616
+  switch i32 %arg, label %while.body248 []
+
+if.else629:                                       ; preds = %backtrack
+  switch i32 %arg, label %retry []
+}
diff --git a/llvm/test/Transforms/FixIrreducible/nested.ll b/llvm/test/Transforms/FixIrreducible/nested.ll
index c9161cc14f208..a739d093f5583 100644
--- a/llvm/test/Transforms/FixIrreducible/nested.ll
+++ b/llvm/test/Transforms/FixIrreducible/nested.ll
@@ -54,22 +54,22 @@ define void @nested_irr_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pr
 ; CHECK-LABEL: @nested_irr_top_level_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[ENTRY_TARGET_A1:%.*]] [label %entry.target.A2]
+; CHECK-NEXT:            to label [[ENTRY_TARGET_A1:%.*]] [label [[ENTRY_TARGET_A2:%.*]]]
 ; CHECK:       A1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[A1_TARGET_B1:%.*]] [label %A1.target.B2]
+; CHECK-NEXT:            to label [[A1_TARGET_B1:%.*]] [label [[A1_TARGET_B2:%.*]]]
 ; CHECK:       B1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[B1_TARGET_B2:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[B1_TARGET_B2:%.*]] [label [[A3:%.*]]]
 ; CHECK:       B2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[B1:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[B1:%.*]] [label [[A3]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED4:%.*]])
-; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label [[EXIT:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED5:%.*]])
-; CHECK-NEXT:            to label [[A1:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[A1:%.*]] [label [[EXIT]]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       A3.target.A2:
@@ -79,7 +79,7 @@ define void @nested_irr_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pr
 ; CHECK:       entry.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
 ; CHECK:       B1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
@@ -88,7 +88,7 @@ define void @nested_irr_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pr
 ; CHECK:       A1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       irr.guard1:
-; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
 ;
 entry:
@@ -113,6 +113,75 @@ exit:
   ret void
 }
 
+define void @nested_irr_top_level_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5) {
+; CHECK-LABEL: @nested_irr_top_level_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[ENTRY_TARGET_A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[ENTRY_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[A1_TARGET_B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A1_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B1:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[B1_TARGET_B2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B2:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED4:%.*]], label [[A3_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED5:%.*]], label [[A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A3.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       entry.target.A1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       entry.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
+; CHECK:       B1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
+; CHECK:       A1.target.B1:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       A1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       irr.guard1:
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
+;
+entry:
+  switch i1 %Pred0, label %A1 [ i1 0, label %A2 ]
+
+A1:
+  switch i1 %Pred1, label %B1 [ i1 0, label %B2 ]
+
+B1:
+  switch i1 %Pred2, label %B2 [ i1 0, label %A3 ]
+
+B2:
+  switch i1 %Pred3, label %B1 [ i1 0, label %A3 ]
+
+A3:
+  switch i1 %Pred4, label %A2 [ i1 0, label %exit ]
+
+A2:
+  switch i1 %Pred5, label %A1 [ i1 0, label %exit ]
+
+exit:
+  ret void
+}
+
 define void @nested_irr_in_loop(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6) {
 ; CHECK-LABEL: @nested_irr_in_loop(
 ; CHECK-NEXT:  entry:
@@ -176,25 +245,25 @@ define void @nested_irr_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK-NEXT:    br label [[H1:%.*]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label %H1.target.A2]
+; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label [[H1_TARGET_A2:%.*]]]
 ; CHECK:       A1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[A1_TARGET_B1:%.*]] [label %A1.target.B2]
+; CHECK-NEXT:            to label [[A1_TARGET_B1:%.*]] [label [[A1_TARGET_B2:%.*]]]
 ; CHECK:       B1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[B1_TARGET_B2:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[B1_TARGET_B2:%.*]] [label [[A3:%.*]]]
 ; CHECK:       B2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[B1:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[B1:%.*]] [label [[A3]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED4:%.*]])
-; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label %L1]
+; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label [[L1:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED5:%.*]])
-; CHECK-NEXT:            to label [[A1:%.*]] [label %L1]
+; CHECK-NEXT:            to label [[A1:%.*]] [label [[L1]]]
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED6:%.*]])
-; CHECK-NEXT:            to label [[EXIT:%.*]] [label %H1]
+; CHECK-NEXT:            to label [[EXIT:%.*]] [label [[H1]]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       A3.target.A2:
@@ -204,7 +273,7 @@ define void @nested_irr_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK:       H1.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
 ; CHECK:       B1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
@@ -213,7 +282,7 @@ define void @nested_irr_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK:       A1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       irr.guard1:
-; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
 ;
 entry:
@@ -244,6 +313,87 @@ exit:
   ret void
 }
 
+define void @nested_irr_in_loop_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6) {
+; CHECK-LABEL: @nested_irr_in_loop_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[H1:%.*]]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[H1_TARGET_A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H1_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[A1_TARGET_B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A1_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B1:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[B1_TARGET_B2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B2:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED4:%.*]], label [[A3_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED5:%.*]], label [[A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L1]]
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED6:%.*]], label [[EXIT:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H1]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A3.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       H1.target.A1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       H1.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
+; CHECK:       B1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
+; CHECK:       A1.target.B1:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       A1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       irr.guard1:
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[B1_TARGET_B2]] ], [ false, [[A1_TARGET_B1]] ], [ true, [[A1_TARGET_B2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
+;
+entry:
+  br label %H1
+
+H1:
+  switch i1 %Pred0, label %A1 [ i1 0, label %A2 ]
+
+A1:
+  switch i1 %Pred1, label %B1 [ i1 0, label %B2 ]
+
+B1:
+  switch i1 %Pred2, label %B2 [ i1 0, label %A3 ]
+
+B2:
+  switch i1 %Pred3, label %B1 [ i1 0, label %A3 ]
+
+A3:
+  switch i1 %Pred4, label %A2 [ i1 0, label %L1 ]
+
+A2:
+  switch i1 %Pred5, label %A1 [ i1 0, label %L1 ]
+
+L1:
+  switch i1 %Pred6, label %exit [ i1 0, label %H1 ]
+
+exit:
+  ret void
+}
+
 define void @loop_in_irr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr(
 ; CHECK-NEXT:  entry:
@@ -291,7 +441,7 @@ define void @loop_in_irr_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[ENTRY_TARGET_A1:%.*]] [label %entry.target.A2]
+; CHECK-NEXT:            to label [[ENTRY_TARGET_A1:%.*]] [label [[ENTRY_TARGET_A2:%.*]]]
 ; CHECK:       A1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[H1:%.*]] []
@@ -300,10 +450,10 @@ define void @loop_in_irr_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-NEXT:            to label [[L1:%.*]] []
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[H1]] [label %A3]
+; CHECK-NEXT:            to label [[H1]] [label [[A3:%.*]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label [[EXIT:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[A1:%.*]] []
@@ -316,7 +466,7 @@ define void @loop_in_irr_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK:       entry.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
 ;
 entry:
@@ -341,6 +491,63 @@ exit:
   ret void
 }
 
+define void @loop_in_irr_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
+; CHECK-LABEL: @loop_in_irr_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[ENTRY_TARGET_A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[ENTRY_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[L1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[H1]] [
+; CHECK-NEXT:      i1 false, label [[A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A3_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[A1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A3.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       entry.target.A1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       entry.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_A1]] ], [ true, [[ENTRY_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
+;
+entry:
+  switch i1 %Pred0, label %A1 [ i1 0, label %A2 ]
+
+A1:
+  switch i1 %Pred0, label %H1 []
+
+H1:
+  switch i1 %Pred0, label %L1 []
+
+L1:
+  switch i1 %Pred1, label %H1 [ i1 0, label %A3 ]
+
+A3:
+  switch i1 %Pred2, label %A2 [ i1 0, label %exit ]
+
+A2:
+  switch i1 %Pred0, label %A1 []
+
+exit:
+  ret void
+}
+
 define void @loop_in_irr_shared_entry(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr_shared_entry(
 ; CHECK-NEXT:  entry:
@@ -383,16 +590,16 @@ define void @loop_in_irr_shared_entry_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr_shared_entry_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[ENTRY_TARGET_H1:%.*]] [label %entry.target.A2]
+; CHECK-NEXT:            to label [[ENTRY_TARGET_H1:%.*]] [label [[ENTRY_TARGET_A2:%.*]]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[L1:%.*]] []
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[H1:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[H1:%.*]] [label [[A3:%.*]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[A3_TARGET_A2:%.*]] [label [[EXIT:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[H1]] []
@@ -405,7 +612,7 @@ define void @loop_in_irr_shared_entry_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK:       entry.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_H1]] ], [ true, [[ENTRY_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_H1]] ], [ true, [[ENTRY_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[H1]]
 ;
 entry:
@@ -427,6 +634,57 @@ exit:
   ret void
 }
 
+define void @loop_in_irr_shared_entry_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
+; CHECK-LABEL: @loop_in_irr_shared_entry_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[ENTRY_TARGET_H1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[ENTRY_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[L1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[H1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A3_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H1]] [
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A3.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       entry.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       entry.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A3_TARGET_A2]] ], [ false, [[ENTRY_TARGET_H1]] ], [ true, [[ENTRY_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[H1]]
+;
+entry:
+  switch i1 %Pred0, label %H1 [ i1 0, label %A2 ]
+
+H1:
+  switch i1 %Pred0, label %L1 []
+
+L1:
+  switch i1 %Pred1, label %H1 [ i1 0, label %A3 ]
+
+A3:
+  switch i1 %Pred2, label %A2 [ i1 0, label %exit ]
+
+A2:
+  switch i1 %Pred0, label %H1 []
+
+exit:
+  ret void
+}
+
 define void @loop_in_irr_shared_header(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr_shared_header(
 ; CHECK-NEXT:  entry:
@@ -469,16 +727,16 @@ define void @loop_in_irr_shared_header_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK-LABEL: @loop_in_irr_shared_header_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[ENTRY_TARGET_A2:%.*]] [label %entry.target.H1]
+; CHECK-NEXT:            to label [[ENTRY_TARGET_A2:%.*]] [label [[ENTRY_TARGET_H1:%.*]]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[L1:%.*]] []
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[L1_TARGET_H1:%.*]] [label %A3]
+; CHECK-NEXT:            to label [[L1_TARGET_H1:%.*]] [label [[A3:%.*]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A2:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[A2:%.*]] [label [[EXIT:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[A2_TARGET_H1:%.*]] []
@@ -493,7 +751,7 @@ define void @loop_in_irr_shared_header_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
 ; CHECK:       entry.target.H1:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[L1_TARGET_H1]] ], [ false, [[ENTRY_TARGET_A2]] ], [ true, [[ENTRY_TARGET_H1:%.*]] ]
+; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[L1_TARGET_H1]] ], [ false, [[ENTRY_TARGET_A2]] ], [ true, [[ENTRY_TARGET_H1]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_H1]], label [[H1:%.*]], label [[A2]]
 ;
 entry:
@@ -515,6 +773,59 @@ exit:
   ret void
 }
 
+define void @loop_in_irr_shared_header_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2) {
+; CHECK-LABEL: @loop_in_irr_shared_header_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[ENTRY_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[ENTRY_TARGET_H1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[L1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[L1_TARGET_H1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[A2_TARGET_H1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A2.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       L1.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       entry.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       entry.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[L1_TARGET_H1]] ], [ false, [[ENTRY_TARGET_A2]] ], [ true, [[ENTRY_TARGET_H1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_H1]], label [[H1:%.*]], label [[A2]]
+;
+entry:
+  switch i1 %Pred0, label %A2 [ i1 0, label %H1 ]
+
+H1:
+  switch i1 %Pred0, label %L1 []
+
+L1:
+  switch i1 %Pred1, label %H1 [ i1 0, label %A3 ]
+
+A3:
+  switch i1 %Pred2, label %A2 [ i1 0, label %exit ]
+
+A2:
+  switch i1 %Pred0, label %H1 []
+
+exit:
+  ret void
+}
+
 define void @loop_irr_loop_shared_header(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3) {
 ; CHECK-LABEL: @loop_irr_loop_shared_header(
 ; CHECK-NEXT:  entry:
@@ -565,19 +876,19 @@ define void @loop_irr_loop_shared_header_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2,
 ; CHECK-NEXT:            to label [[H2:%.*]] []
 ; CHECK:       H2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[H2_TARGET_A2:%.*]] [label %H2.target.H1]
+; CHECK-NEXT:            to label [[H2_TARGET_A2:%.*]] [label [[H2_TARGET_H1:%.*]]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[A3:%.*]] [label %H1.target.H1]
+; CHECK-NEXT:            to label [[A3:%.*]] [label [[H1_TARGET_H1:%.*]]]
 ; CHECK:       A3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A2:%.*]] [label %L2]
+; CHECK-NEXT:            to label [[A2:%.*]] [label [[L2:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[A2_TARGET_H1:%.*]] []
 ; CHECK:       L2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[H2]] [label %exit]
+; CHECK-NEXT:            to label [[H2]] [label [[EXIT:%.*]]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       A2.target.H1:
@@ -589,7 +900,7 @@ define void @loop_irr_loop_shared_header_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2,
 ; CHECK:       H2.target.H1:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[H1_TARGET_H1:%.*]] ], [ false, [[H2_TARGET_A2]] ], [ true, [[H2_TARGET_H1:%.*]] ]
+; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[H1_TARGET_H1]] ], [ false, [[H2_TARGET_A2]] ], [ true, [[H2_TARGET_H1]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_H1]], label [[H1:%.*]], label [[A2]]
 ;
 entry:
@@ -614,6 +925,66 @@ exit:
   ret void
 }
 
+define void @loop_irr_loop_shared_header_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3) {
+; CHECK-LABEL: @loop_irr_loop_shared_header_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[H2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       H2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H2_TARGET_A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H2_TARGET_H1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[A3:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H1_TARGET_H1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A3:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A2:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[A2_TARGET_H1:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L2:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[H2]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A2.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       H1.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       H2.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       H2.target.H1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_H1:%.*]] = phi i1 [ true, [[A2_TARGET_H1]] ], [ true, [[H1_TARGET_H1]] ], [ false, [[H2_TARGET_A2]] ], [ true, [[H2_TARGET_H1]] ]
+; CHECK-NEXT:    br i1 [[GUARD_H1]], label [[H1:%.*]], label [[A2]]
+;
+entry:
+  switch i1 %Pred0, label %H2 []
+
+H2:
+  switch i1 %Pred0, label %A2 [ i1 0, label %H1 ]
+
+H1:
+  switch i1 %Pred1, label %A3 [ i1 0, label %H1 ]
+
+A3:
+  switch i1 %Pred2, label %A2 [ i1 0, label %L2 ]
+
+A2:
+  switch i1 %Pred0, label %H1 []
+
+L2:
+  switch i1 %Pred3, label %H2 [ i1 0, label %exit ]
+
+exit:
+  ret void
+}
+
 define void @siblings_top_level(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6) {
 ; CHECK-LABEL: @siblings_top_level(
 ; CHECK-NEXT:  entry:
@@ -685,22 +1056,22 @@ define void @siblings_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK-LABEL: @siblings_top_level_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[H1:%.*]] [label %fork1]
+; CHECK-NEXT:            to label [[H1:%.*]] [label [[FORK1:%.*]]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label %H1.target.A2]
+; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label [[H1_TARGET_A2:%.*]]]
 ; CHECK:       A1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[A1_TARGET_A2:%.*]] []
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A1:%.*]] [label %L1]
+; CHECK-NEXT:            to label [[A1:%.*]] [label [[L1:%.*]]]
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[H1]] [label %exit]
+; CHECK-NEXT:            to label [[H1]] [label [[EXIT:%.*]]]
 ; CHECK:       fork1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED4:%.*]])
-; CHECK-NEXT:            to label [[FORK1_TARGET_B1:%.*]] [label %fork1.target.B2]
+; CHECK-NEXT:            to label [[FORK1_TARGET_B1:%.*]] [label [[FORK1_TARGET_B2:%.*]]]
 ; CHECK:       B1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[H2:%.*]] []
@@ -709,10 +1080,10 @@ define void @siblings_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK-NEXT:            to label [[L2:%.*]] []
 ; CHECK:       L2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED5:%.*]])
-; CHECK-NEXT:            to label [[H2]] [label %L2.target.B2]
+; CHECK-NEXT:            to label [[H2]] [label [[L2_TARGET_B2:%.*]]]
 ; CHECK:       B2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED6:%.*]])
-; CHECK-NEXT:            to label [[B1:%.*]] [label %exit]
+; CHECK-NEXT:            to label [[B1:%.*]] [label [[EXIT]]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       A1.target.A2:
@@ -722,7 +1093,7 @@ define void @siblings_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK:       H1.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
 ; CHECK:       L2.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
@@ -731,7 +1102,7 @@ define void @siblings_top_level_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred
 ; CHECK:       fork1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       irr.guard1:
-; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2:%.*]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
 ;
 entry:
@@ -768,6 +1139,100 @@ exit:
   ret void
 }
 
+define void @siblings_top_level_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6) {
+; CHECK-LABEL: @siblings_top_level_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[H1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[FORK1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[H1_TARGET_A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H1_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[A1_TARGET_A2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[H1]] [
+; CHECK-NEXT:      i1 false, label [[EXIT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       fork1:
+; CHECK-NEXT:    switch i1 [[PRED4:%.*]], label [[FORK1_TARGET_B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[FORK1_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       H2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[L2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L2:
+; CHECK-NEXT:    switch i1 [[PRED5:%.*]], label [[H2]] [
+; CHECK-NEXT:      i1 false, label [[L2_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B2:
+; CHECK-NEXT:    switch i1 [[PRED6:%.*]], label [[B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[EXIT]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A1.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       H1.target.A1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       H1.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
+; CHECK:       L2.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
+; CHECK:       fork1.target.B1:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       fork1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       irr.guard1:
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
+;
+entry:
+  switch i1 %Pred0, label %H1 [ i1 0, label %fork1 ]
+
+H1:
+  switch i1 %Pred1, label %A1 [ i1 0, label %A2 ]
+
+A1:
+  switch i1 %Pred0, label %A2 []
+
+A2:
+  switch i1 %Pred2, label %A1 [ i1 0, label %L1 ]
+
+L1:
+  switch i1 %Pred3, label %H1 [ i1 0, label %exit ]
+
+fork1:
+  switch i1 %Pred4, label %B1 [ i1 0, label %B2 ]
+
+B1:
+  switch i1 %Pred0, label %H2 []
+
+H2:
+  switch i1 %Pred0, label %L2 []
+
+L2:
+  switch i1 %Pred5, label %H2 [ i1 0, label %B2 ]
+
+B2:
+  switch i1 %Pred6, label %B1 [ i1 0, label %exit ]
+
+exit:
+  ret void
+}
+
 define void @siblings_in_loop(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6, i1 %Pred7) {
 ; CHECK-LABEL: @siblings_in_loop(
 ; CHECK-NEXT:  entry:
@@ -852,22 +1317,22 @@ define void @siblings_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3,
 ; CHECK-NEXT:            to label [[H0:%.*]] []
 ; CHECK:       H0:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[H1:%.*]] [label %fork1]
+; CHECK-NEXT:            to label [[H1:%.*]] [label [[FORK1:%.*]]]
 ; CHECK:       H1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label %H1.target.A2]
+; CHECK-NEXT:            to label [[H1_TARGET_A1:%.*]] [label [[H1_TARGET_A2:%.*]]]
 ; CHECK:       A1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[A1_TARGET_A2:%.*]] []
 ; CHECK:       A2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[A1:%.*]] [label %L1]
+; CHECK-NEXT:            to label [[A1:%.*]] [label [[L1:%.*]]]
 ; CHECK:       L1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[H1]] [label %L0]
+; CHECK-NEXT:            to label [[H1]] [label [[L0:%.*]]]
 ; CHECK:       fork1:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED4:%.*]])
-; CHECK-NEXT:            to label [[FORK1_TARGET_B1:%.*]] [label %fork1.target.B2]
+; CHECK-NEXT:            to label [[FORK1_TARGET_B1:%.*]] [label [[FORK1_TARGET_B2:%.*]]]
 ; CHECK:       B1:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[H2:%.*]] []
@@ -876,13 +1341,13 @@ define void @siblings_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3,
 ; CHECK-NEXT:            to label [[L2:%.*]] []
 ; CHECK:       L2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED5:%.*]])
-; CHECK-NEXT:            to label [[H2]] [label %L2.target.B2]
+; CHECK-NEXT:            to label [[H2]] [label [[L2_TARGET_B2:%.*]]]
 ; CHECK:       B2:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED6:%.*]])
-; CHECK-NEXT:            to label [[B1:%.*]] [label %L0]
+; CHECK-NEXT:            to label [[B1:%.*]] [label [[L0]]]
 ; CHECK:       L0:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED7:%.*]])
-; CHECK-NEXT:            to label [[EXIT:%.*]] [label %H0]
+; CHECK-NEXT:            to label [[EXIT:%.*]] [label [[H0]]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       A1.target.A2:
@@ -892,7 +1357,7 @@ define void @siblings_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3,
 ; CHECK:       H1.target.A2:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
 ; CHECK:       L2.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
@@ -901,7 +1366,7 @@ define void @siblings_in_loop_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3,
 ; CHECK:       fork1.target.B2:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       irr.guard1:
-; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2:%.*]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
 ;
 entry:
@@ -944,6 +1409,113 @@ exit:
   ret void
 }
 
+define void @siblings_in_loop_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6, i1 %Pred7) {
+; CHECK-LABEL: @siblings_in_loop_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[H0:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       H0:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[FORK1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H1:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[H1_TARGET_A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H1_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[A1_TARGET_A2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[A1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       L1:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[H1]] [
+; CHECK-NEXT:      i1 false, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       fork1:
+; CHECK-NEXT:    switch i1 [[PRED4:%.*]], label [[FORK1_TARGET_B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[FORK1_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B1:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[H2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       H2:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[L2:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       L2:
+; CHECK-NEXT:    switch i1 [[PRED5:%.*]], label [[H2]] [
+; CHECK-NEXT:      i1 false, label [[L2_TARGET_B2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B2:
+; CHECK-NEXT:    switch i1 [[PRED6:%.*]], label [[B1:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L0]]
+; CHECK-NEXT:    ]
+; CHECK:       L0:
+; CHECK-NEXT:    switch i1 [[PRED7:%.*]], label [[EXIT:%.*]] [
+; CHECK-NEXT:      i1 false, label [[H0]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A1.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       H1.target.A1:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       H1.target.A2:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_A2:%.*]] = phi i1 [ true, [[A1_TARGET_A2]] ], [ false, [[H1_TARGET_A1]] ], [ true, [[H1_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A2]], label [[A2:%.*]], label [[A1]]
+; CHECK:       L2.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1:%.*]]
+; CHECK:       fork1.target.B1:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       fork1.target.B2:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       irr.guard1:
+; CHECK-NEXT:    [[GUARD_B2:%.*]] = phi i1 [ true, [[L2_TARGET_B2]] ], [ false, [[FORK1_TARGET_B1]] ], [ true, [[FORK1_TARGET_B2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B2]], label [[B2:%.*]], label [[B1]]
+;
+entry:
+  switch i1 %Pred0, label %H0 []
+
+H0:
+  switch i1 %Pred0, label %H1 [ i1 0, label %fork1 ]
+
+H1:
+  switch i1 %Pred1, label %A1 [ i1 0, label %A2 ]
+
+A1:
+  switch i1 %Pred0, label %A2 []
+
+A2:
+  switch i1 %Pred2, label %A1 [ i1 0, label %L1 ]
+
+L1:
+  switch i1 %Pred3, label %H1 [ i1 0, label %L0 ]
+
+fork1:
+  switch i1 %Pred4, label %B1 [ i1 0, label %B2 ]
+
+B1:
+  switch i1 %Pred0, label %H2 []
+
+H2:
+  switch i1 %Pred0, label %L2 []
+
+L2:
+  switch i1 %Pred5, label %H2 [ i1 0, label %B2 ]
+
+B2:
+  switch i1 %Pred6, label %B1 [ i1 0, label %L0 ]
+
+L0:
+  switch i1 %Pred7, label %exit [ i1 0, label %H0 ]
+
+exit:
+  ret void
+}
+
 define void @irr_in_irr_shared_entry(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6, i1 %Pred7, i1 %Pred8, i1 %Pred9, i1 %Pred10, i1 %Pred11, i1 %Pred12, i1 %Pred13) {
 ; CHECK-LABEL: @irr_in_irr_shared_entry(
 ; CHECK-NEXT:  entry:
@@ -1063,10 +1635,10 @@ define void @irr_in_irr_shared_entry_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1
 ; CHECK-LABEL: @irr_in_irr_shared_entry_callbr(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED0:%.*]])
-; CHECK-NEXT:            to label [[IF_END:%.*]] [label %if.then]
+; CHECK-NEXT:            to label [[IF_END:%.*]] [label [[IF_THEN:%.*]]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED1:%.*]])
-; CHECK-NEXT:            to label [[IF_THEN7:%.*]] [label %if.else]
+; CHECK-NEXT:            to label [[IF_THEN7:%.*]] [label [[IF_ELSE:%.*]]]
 ; CHECK:       if.then7:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[IF_END16:%.*]] []
@@ -1075,49 +1647,49 @@ define void @irr_in_irr_shared_entry_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1
 ; CHECK-NEXT:            to label [[IF_END16]] []
 ; CHECK:       if.end16:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED2:%.*]])
-; CHECK-NEXT:            to label [[WHILE_COND_PREHEADER:%.*]] [label %if.then39]
+; CHECK-NEXT:            to label [[WHILE_COND_PREHEADER:%.*]] [label [[IF_THEN39:%.*]]]
 ; CHECK:       while.cond.preheader:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[WHILE_COND:%.*]] []
 ; CHECK:       while.cond:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED3:%.*]])
-; CHECK-NEXT:            to label [[WHILE_COND_TARGET_COND_TRUE49:%.*]] [label %lor.rhs]
+; CHECK-NEXT:            to label [[WHILE_COND_TARGET_COND_TRUE49:%.*]] [label [[LOR_RHS:%.*]]]
 ; CHECK:       cond.true49:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED4:%.*]])
-; CHECK-NEXT:            to label [[IF_THEN69:%.*]] [label %cond.true49.target.while.body63]
+; CHECK-NEXT:            to label [[IF_THEN69:%.*]] [label [[COND_TRUE49_TARGET_WHILE_BODY63:%.*]]]
 ; CHECK:       while.body63:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED5:%.*]])
-; CHECK-NEXT:            to label [[EXIT:%.*]] [label %while.cond47]
+; CHECK-NEXT:            to label [[EXIT:%.*]] [label [[WHILE_COND47:%.*]]]
 ; CHECK:       while.cond47:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED6:%.*]])
-; CHECK-NEXT:            to label [[COND_TRUE49:%.*]] [label %while.cond47.target.cond.end61]
+; CHECK-NEXT:            to label [[COND_TRUE49:%.*]] [label [[WHILE_COND47_TARGET_COND_END61:%.*]]]
 ; CHECK:       cond.end61:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED7:%.*]])
-; CHECK-NEXT:            to label [[COND_END61_TARGET_WHILE_BODY63:%.*]] [label %while.cond]
+; CHECK-NEXT:            to label [[COND_END61_TARGET_WHILE_BODY63:%.*]] [label [[WHILE_COND]]]
 ; CHECK:       if.then69:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED8:%.*]])
-; CHECK-NEXT:            to label [[EXIT]] [label %while.cond]
+; CHECK-NEXT:            to label [[EXIT]] [label [[WHILE_COND]]]
 ; CHECK:       lor.rhs:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED9:%.*]])
-; CHECK-NEXT:            to label [[LOR_RHS_TARGET_COND_END61:%.*]] [label %while.end76]
+; CHECK-NEXT:            to label [[LOR_RHS_TARGET_COND_END61:%.*]] [label [[WHILE_END76:%.*]]]
 ; CHECK:       while.end76:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[EXIT]] []
 ; CHECK:       if.then39:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED10:%.*]])
-; CHECK-NEXT:            to label [[EXIT]] [label %if.end.i145]
+; CHECK-NEXT:            to label [[EXIT]] [label [[IF_END_I145:%.*]]]
 ; CHECK:       if.end.i145:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED11:%.*]])
-; CHECK-NEXT:            to label [[EXIT]] [label %if.end8.i149]
+; CHECK-NEXT:            to label [[EXIT]] [label [[IF_END8_I149:%.*]]]
 ; CHECK:       if.end8.i149:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[EXIT]] []
 ; CHECK:       if.then:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED12:%.*]])
-; CHECK-NEXT:            to label [[EXIT]] [label %if.end.i]
+; CHECK-NEXT:            to label [[EXIT]] [label [[IF_END_I:%.*]]]
 ; CHECK:       if.end.i:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PRED13:%.*]])
-; CHECK-NEXT:            to label [[EXIT]] [label %if.end8.i]
+; CHECK-NEXT:            to label [[EXIT]] [label [[IF_END8_I:%.*]]]
 ; CHECK:       if.end8.i:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[EXIT]] []
@@ -1130,14 +1702,14 @@ define void @irr_in_irr_shared_entry_callbr(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1
 ; CHECK:       while.cond.target.cond.true49:
 ; CHECK-NEXT:    br label [[IRR_GUARD]]
 ; CHECK:       irr.guard:
-; CHECK-NEXT:    [[GUARD_COND_END61:%.*]] = phi i1 [ true, [[WHILE_COND47_TARGET_COND_END61:%.*]] ], [ true, [[LOR_RHS_TARGET_COND_END61]] ], [ false, [[WHILE_COND_TARGET_COND_TRUE49]] ]
+; CHECK-NEXT:    [[GUARD_COND_END61:%.*]] = phi i1 [ true, [[WHILE_COND47_TARGET_COND_END61]] ], [ true, [[LOR_RHS_TARGET_COND_END61]] ], [ false, [[WHILE_COND_TARGET_COND_TRUE49]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_COND_END61]], label [[COND_END61:%.*]], label [[IRR_GUARD1:%.*]]
 ; CHECK:       cond.true49.target.while.body63:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       cond.end61.target.while.body63:
 ; CHECK-NEXT:    br label [[IRR_GUARD1]]
 ; CHECK:       irr.guard1:
-; CHECK-NEXT:    [[GUARD_WHILE_BODY63:%.*]] = phi i1 [ true, [[COND_TRUE49_TARGET_WHILE_BODY63:%.*]] ], [ true, [[COND_END61_TARGET_WHILE_BODY63]] ], [ false, [[IRR_GUARD]] ]
+; CHECK-NEXT:    [[GUARD_WHILE_BODY63:%.*]] = phi i1 [ true, [[COND_TRUE49_TARGET_WHILE_BODY63]] ], [ true, [[COND_END61_TARGET_WHILE_BODY63]] ], [ false, [[IRR_GUARD]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_WHILE_BODY63]], label [[WHILE_BODY63:%.*]], label [[COND_TRUE49]]
 ;
 entry:
@@ -1203,3 +1775,162 @@ if.end8.i:
 exit:
   ret void
 }
+
+define void @irr_in_irr_shared_entry_switch(i1 %Pred0, i1 %Pred1, i1 %Pred2, i1 %Pred3, i1 %Pred4, i1 %Pred5, i1 %Pred6, i1 %Pred7, i1 %Pred8, i1 %Pred9, i1 %Pred10, i1 %Pred11, i1 %Pred12, i1 %Pred13) {
+; CHECK-LABEL: @irr_in_irr_shared_entry_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED0:%.*]], label [[IF_END:%.*]] [
+; CHECK-NEXT:      i1 false, label [[IF_THEN:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.end:
+; CHECK-NEXT:    switch i1 [[PRED1:%.*]], label [[IF_THEN7:%.*]] [
+; CHECK-NEXT:      i1 false, label [[IF_ELSE:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.then7:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[IF_END16:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.else:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[IF_END16]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.end16:
+; CHECK-NEXT:    switch i1 [[PRED2:%.*]], label [[WHILE_COND_PREHEADER:%.*]] [
+; CHECK-NEXT:      i1 false, label [[IF_THEN39:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       while.cond.preheader:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[WHILE_COND:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       while.cond:
+; CHECK-NEXT:    switch i1 [[PRED3:%.*]], label [[WHILE_COND_TARGET_COND_TRUE49:%.*]] [
+; CHECK-NEXT:      i1 false, label [[LOR_RHS:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       cond.true49:
+; CHECK-NEXT:    switch i1 [[PRED4:%.*]], label [[IF_THEN69:%.*]] [
+; CHECK-NEXT:      i1 false, label [[COND_TRUE49_TARGET_WHILE_BODY63:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       while.body63:
+; CHECK-NEXT:    switch i1 [[PRED5:%.*]], label [[EXIT:%.*]] [
+; CHECK-NEXT:      i1 false, label [[WHILE_COND47:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       while.cond47:
+; CHECK-NEXT:    switch i1 [[PRED6:%.*]], label [[COND_TRUE49:%.*]] [
+; CHECK-NEXT:      i1 false, label [[WHILE_COND47_TARGET_COND_END61:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       cond.end61:
+; CHECK-NEXT:    switch i1 [[PRED7:%.*]], label [[COND_END61_TARGET_WHILE_BODY63:%.*]] [
+; CHECK-NEXT:      i1 false, label [[WHILE_COND]]
+; CHECK-NEXT:    ]
+; CHECK:       if.then69:
+; CHECK-NEXT:    switch i1 [[PRED8:%.*]], label [[EXIT]] [
+; CHECK-NEXT:      i1 false, label [[WHILE_COND]]
+; CHECK-NEXT:    ]
+; CHECK:       lor.rhs:
+; CHECK-NEXT:    switch i1 [[PRED9:%.*]], label [[LOR_RHS_TARGET_COND_END61:%.*]] [
+; CHECK-NEXT:      i1 false, label [[WHILE_END76:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       while.end76:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[EXIT]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.then39:
+; CHECK-NEXT:    switch i1 [[PRED10:%.*]], label [[EXIT]] [
+; CHECK-NEXT:      i1 false, label [[IF_END_I145:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.end.i145:
+; CHECK-NEXT:    switch i1 [[PRED11:%.*]], label [[EXIT]] [
+; CHECK-NEXT:      i1 false, label [[IF_END8_I149:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.end8.i149:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[EXIT]] [
+; CHECK-NEXT:    ]
+; CHECK:       if.then:
+; CHECK-NEXT:    switch i1 [[PRED12:%.*]], label [[EXIT]] [
+; CHECK-NEXT:      i1 false, label [[IF_END_I:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.end.i:
+; CHECK-NEXT:    switch i1 [[PRED13:%.*]], label [[EXIT]] [
+; CHECK-NEXT:      i1 false, label [[IF_END8_I:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       if.end8.i:
+; CHECK-NEXT:    switch i1 [[PRED0]], label [[EXIT]] [
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       while.cond47.target.cond.end61:
+; CHECK-NEXT:    br label [[IRR_GUARD:%.*]]
+; CHECK:       lor.rhs.target.cond.end61:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       while.cond.target.cond.true49:
+; CHECK-NEXT:    br label [[IRR_GUARD]]
+; CHECK:       irr.guard:
+; CHECK-NEXT:    [[GUARD_COND_END61:%.*]] = phi i1 [ true, [[WHILE_COND47_TARGET_COND_END61]] ], [ true, [[LOR_RHS_TARGET_COND_END61]] ], [ false, [[WHILE_COND_TARGET_COND_TRUE49]] ]
+; CHECK-NEXT:    br i1 [[GUARD_COND_END61]], label [[COND_END61:%.*]], label [[IRR_GUARD1:%.*]]
+; CHECK:       cond.true49.target.while.body63:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       cond.end61.target.while.body63:
+; CHECK-NEXT:    br label [[IRR_GUARD1]]
+; CHECK:       irr.guard1:
+; CHECK-NEXT:    [[GUARD_WHILE_BODY63:%.*]] = phi i1 [ true, [[COND_TRUE49_TARGET_WHILE_BODY63]] ], [ true, [[COND_END61_TARGET_WHILE_BODY63]] ], [ false, [[IRR_GUARD]] ]
+; CHECK-NEXT:    br i1 [[GUARD_WHILE_BODY63]], label [[WHILE_BODY63:%.*]], label [[COND_TRUE49]]
+;
+entry:
+  switch i1 %Pred0, label %if.end [ i1 0, label %if.then ]
+
+if.end:
+  switch i1 %Pred1, label %if.then7 [ i1 0, label %if.else ]
+
+if.then7:
+  switch i1 %Pred0, label %if.end16 []
+
+if.else:
+  switch i1 %Pred0, label %if.end16 []
+
+if.end16:
+  switch i1 %Pred2, label %while.cond.preheader [ i1 0, label %if.then39 ]
+
+while.cond.preheader:
+  switch i1 %Pred0, label %while.cond []
+
+while.cond:
+  switch i1 %Pred3, label %cond.true49 [ i1 0, label %lor.rhs ]
+
+cond.true49:
+  switch i1 %Pred4, label %if.then69 [ i1 0, label %while.body63 ]
+
+while.body63:
+  switch i1 %Pred5, label %exit [ i1 0, label %while.cond47 ]
+
+while.cond47:
+  switch i1 %Pred6, label %cond.true49 [ i1 0, label %cond.end61 ]
+
+cond.end61:
+  switch i1 %Pred7, label %while.body63 [ i1 0, label %while.cond ]
+
+if.then69:
+  switch i1 %Pred8, label %exit [ i1 0, label %while.cond ]
+
+lor.rhs:
+  switch i1 %Pred9, label %cond.end61 [ i1 0, label %while.end76 ]
+
+while.end76:
+  switch i1 %Pred0, label %exit []
+
+if.then39:
+  switch i1 %Pred10, label %exit [ i1 0, label %if.end.i145 ]
+
+if.end.i145:
+  switch i1 %Pred11, label %exit [ i1 0, label %if.end8.i149 ]
+
+if.end8.i149:
+  switch i1 %Pred0, label %exit []
+
+if.then:
+  switch i1 %Pred12, label %exit [ i1 0, label %if.end.i ]
+
+if.end.i:
+  switch i1 %Pred13, label %exit [ i1 0, label %if.end8.i ]
+
+if.end8.i:
+  switch i1 %Pred0, label %exit []
+
+exit:
+  ret void
+}
diff --git a/llvm/test/Transforms/FixIrreducible/unreachable.ll b/llvm/test/Transforms/FixIrreducible/unreachable.ll
index 845cf507c7fc0..02a23a97380f8 100644
--- a/llvm/test/Transforms/FixIrreducible/unreachable.ll
+++ b/llvm/test/Transforms/FixIrreducible/unreachable.ll
@@ -48,3 +48,26 @@ loop.latch:
 loop.exit:
   ret void
 }
+
+; CHECK-LABEL: @unreachable_switch(
+; CHECK: entry:
+; CHECK-NOT: irr.guard:
+define void @unreachable_switch(i32 %n, i1 %arg) {
+entry:
+  switch i32 %n, label %loop.body []
+
+loop.body:
+  switch i32 %n, label %inner.block []
+
+unreachable.block:
+  switch i32 %n, label %inner.block []
+
+inner.block:
+  switch i1 %arg, label %loop.exit [ i1 0, label %loop.latch ]
+
+loop.latch:
+  switch i32 %n, label %loop.body []
+
+loop.exit:
+  ret void
+}
diff --git a/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll b/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
index 02a4ec802cd33..80711a8ddaedf 100644
--- a/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
+++ b/llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
@@ -13,4 +13,4 @@ then:
 
 else:
   br label %then
-}
\ No newline at end of file
+}
diff --git a/llvm/test/Transforms/UnifyLoopExits/basic.ll b/llvm/test/Transforms/UnifyLoopExits/basic.ll
index 5771453574626..461bd3ee9c23d 100644
--- a/llvm/test/Transforms/UnifyLoopExits/basic.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/basic.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes='lower-switch,unify-loop-exits' -S | FileCheck %s
+; RUN: opt < %s -passes='unify-loop-exits' -S | FileCheck %s
 
 define void @loop_1(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) {
 ; CHECK-LABEL: @loop_1(
@@ -73,7 +73,7 @@ define void @loop_1_callbr(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) {
 ; CHECK:       F:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       G:
-; CHECK-NEXT:    br label [[Y:%.*]]
+; CHECK-NEXT:    br label [[F:%.*]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       B.target.E:
@@ -83,8 +83,8 @@ define void @loop_1_callbr(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) {
 ; CHECK:       D.target.F:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[B_TARGET_E]] ], [ false, [[C_TARGET_F]] ], [ false, [[D_TARGET_F]] ]
-; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[Y]]
+; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[B_TARGET_E]] ], [ false, [[C_TARGET_F]] ], [ false, [[D_TARGET_F]] ]
+; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[F]]
 ;
 entry:
   br i1 %PredEntry, label %A, label %G
@@ -114,6 +114,72 @@ exit:
   ret void
 }
 
+define void @loop_1_switch(i1 %PredEntry, i1 %PredB, i1 %PredC, i1 %PredD) {
+; CHECK-LABEL: @loop_1_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:      i1 false, label [[G:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    br label [[B:%.*]]
+; CHECK:       B:
+; CHECK-NEXT:    switch i1 [[PREDB:%.*]], label [[C:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B_TARGET_E:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    switch i1 [[PREDC:%.*]], label [[D:%.*]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_F:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    switch i1 [[PREDD:%.*]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[D_TARGET_F:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       E:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       F:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       G:
+; CHECK-NEXT:    br label [[F:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       B.target.E:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       C.target.F:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       D.target.F:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[B_TARGET_E]] ], [ false, [[C_TARGET_F]] ], [ false, [[D_TARGET_F]] ]
+; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[F]]
+;
+entry:
+  switch i1 %PredEntry, label %A [ i1 0, label %G ]
+
+A:
+  br label %B
+
+B:
+  switch i1 %PredB, label %C [ i1 0, label %E ]
+
+C:
+  switch i1 %PredC, label %D [ i1 0, label %F ]
+
+D:
+  switch i1 %PredD, label %A [ i1 0, label %F ]
+
+E:
+  br label %exit
+
+F:
+  br label %exit
+
+G:
+  br label %F
+
+exit:
+  ret void
+}
+
 define void @loop_2(i1 %PredA, i1 %PredB, i1 %PredC) {
 ; CHECK-LABEL: @loop_2(
 ; CHECK-NEXT:  entry:
@@ -233,6 +299,73 @@ exit:
   ret void
 }
 
+define void @loop_2_switch(i1 %PredA, i1 %PredB, i1 %PredC) {
+; CHECK-LABEL: @loop_2_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[A:%.*]]
+; CHECK:       A:
+; CHECK-NEXT:    switch i1 [[PREDA:%.*]], label [[B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A_TARGET_X:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    switch i1 [[PREDB:%.*]], label [[C:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B_TARGET_Y:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    switch i1 [[PREDC:%.*]], label [[D:%.*]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_Z:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    br label [[A]]
+; CHECK:       X:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       Y:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       Z:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       A.target.X:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       B.target.Y:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       C.target.Z:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[A_TARGET_X]] ], [ false, [[B_TARGET_Y]] ], [ false, [[C_TARGET_Z]] ]
+; CHECK-NEXT:    [[GUARD_Y:%.*]] = phi i1 [ false, [[A_TARGET_X]] ], [ true, [[B_TARGET_Y]] ], [ false, [[C_TARGET_Z]] ]
+; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
+; CHECK:       loop.exit.guard1:
+; CHECK-NEXT:    br i1 [[GUARD_Y]], label [[Y:%.*]], label [[Z:%.*]]
+;
+entry:
+  br label %A
+
+A:
+  switch i1 %PredA, label %B [ i1 0, label %X ]
+
+B:
+  switch i1 %PredB, label %C [ i1 0, label %Y ]
+
+C:
+  switch i1 %PredC, label %D [ i1 0, label %Z ]
+
+D:
+  br label %A
+
+X:
+  br label %exit
+
+Y:
+  br label %exit
+
+Z:
+  br label %exit
+
+exit:
+  ret void
+}
+
 ; Test that UnifyLoopExits handles callbr with duplicate successors correctly.
 ; The exit block appears twice as a successor of the callbr instruction.
 define void @callbr_duplicate_successors() {
@@ -257,3 +390,32 @@ loop:
 exit:
   ret void
 }
+
+define void @switch_duplicate_successors(i1 %Pred) {
+; CHECK-LABEL: @switch_duplicate_successors(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[LOOP_TARGET_EXIT:%.*]] [
+; CHECK-NEXT:      i1 false, label [[LOOP]]
+; CHECK-NEXT:      i1 true, label [[LOOP_TARGET_EXIT1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+; CHECK:       loop.target.exit:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       loop.target.exit1:
+; CHECK-NEXT:    br label [[EXIT]]
+;
+entry:
+  br label %loop
+
+loop:
+  switch i1 %Pred, label %exit [
+  i1 0, label %loop
+  i1 1, label %exit
+  ]
+
+exit:
+  ret void
+}
diff --git a/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll b/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll
index be982d5d043f9..5cded19c06d97 100644
--- a/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/integer_guards.ll
@@ -78,7 +78,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; CHECK:       A:
 ; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label %C]
+; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label [[C]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[D:%.*]]
@@ -86,7 +86,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %C.target.E]
+; CHECK-NEXT:            to label [[A]] [label [[C_TARGET_E:%.*]]]
 ; CHECK:       D:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       E:
@@ -96,7 +96,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; CHECK:       C.target.E:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_E:%.*]] ]
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_E]] ]
 ; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
 ; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[E]]
 ;
@@ -106,7 +106,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; BOOLEAN:       A:
 ; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label %C]
+; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label [[C]]]
 ; BOOLEAN:       B:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[D:%.*]]
@@ -114,7 +114,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
 ; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; BOOLEAN-NEXT:            to label [[A]] [label %C.target.E]
+; BOOLEAN-NEXT:            to label [[A]] [label [[C_TARGET_E:%.*]]]
 ; BOOLEAN:       D:
 ; BOOLEAN-NEXT:    unreachable
 ; BOOLEAN:       E:
@@ -124,7 +124,7 @@ define void @loop_two_exits_callbr(i1 %PredEntry, i1 %PredA) {
 ; BOOLEAN:       C.target.E:
 ; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; BOOLEAN:       loop.exit.guard:
-; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_E:%.*]] ]
+; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_E]] ]
 ; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[E]]
 ;
 entry:
@@ -150,6 +150,93 @@ E:
   ret void
 }
 
+define void @loop_two_exits_switch(i1 %PredEntry, i1 %PredA) {
+; CHECK-LABEL: @loop_two_exits_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:      i1 false, label [[E:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
+; CHECK-NEXT:    switch i1 [[PREDA:%.*]], label [[A_TARGET_B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[C]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; CHECK-NEXT:    br label [[D:%.*]]
+; CHECK:       C:
+; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_E:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    unreachable
+; CHECK:       E:
+; CHECK-NEXT:    ret void
+; CHECK:       A.target.B:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       C.target.E:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_E]] ]
+; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
+; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[E]]
+;
+; BOOLEAN-LABEL: @loop_two_exits_switch(
+; BOOLEAN-NEXT:  entry:
+; BOOLEAN-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[E:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       A:
+; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[C:%.*]] ]
+; BOOLEAN-NEXT:    switch i1 [[PREDA:%.*]], label [[A_TARGET_B:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[C]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       B:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[D:%.*]]
+; BOOLEAN:       C:
+; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
+; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
+; BOOLEAN-NEXT:    switch i1 [[CMP]], label [[A]] [
+; BOOLEAN-NEXT:      i1 false, label [[C_TARGET_E:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       D:
+; BOOLEAN-NEXT:    unreachable
+; BOOLEAN:       E:
+; BOOLEAN-NEXT:    ret void
+; BOOLEAN:       A.target.B:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; BOOLEAN:       C.target.E:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       loop.exit.guard:
+; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_E]] ]
+; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[E]]
+;
+entry:
+  switch i1 %PredEntry, label %A [ i1 0, label %E ]
+
+A:
+  %inc1 = phi i32 [ 0, %entry ], [ %inc2, %C ]
+  switch i1 %PredA, label %B [ i1 0, label %C ]
+
+B:
+  tail call fastcc void @check(i32 1) #0
+  br label %D
+
+C:
+  %inc2 = add i32 %inc1, 1
+  %cmp = icmp ult i32 %inc2, 10
+  switch i1 %cmp, label %A [ i1 0, label %E ]
+
+D:
+  unreachable
+
+E:
+  ret void
+}
+
 ; The loop exit blocks appear in an inner loop.
 
 define void @inner_loop(i1 %PredEntry, i1 %PredA, i1 %PredB) {
@@ -285,13 +372,13 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; CHECK:       B:
 ; CHECK-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; CHECK-NEXT:            to label [[D:%.*]] [label %B.target.B.target.C]
+; CHECK-NEXT:            to label [[D:%.*]] [label [[B_TARGET_B_TARGET_C:%.*]]]
 ; CHECK:       C:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[H:%.*]]
 ; CHECK:       D:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]])
-; CHECK-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label %F]
+; CHECK-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label [[F]]]
 ; CHECK:       E:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[H]]
@@ -299,12 +386,12 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; CHECK-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; CHECK-NEXT:            to label [[B]] [label %F.target.G]
+; CHECK-NEXT:            to label [[B]] [label [[F_TARGET_G:%.*]]]
 ; CHECK:       G:
 ; CHECK-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]])
-; CHECK-NEXT:            to label [[A]] [label %G.target.I]
+; CHECK-NEXT:            to label [[A]] [label [[G_TARGET_I:%.*]]]
 ; CHECK:       H:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       I:
@@ -316,7 +403,7 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; CHECK:       G.target.I:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_E:%.*]] ], [ 2, [[G_TARGET_I:%.*]] ]
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_E:%.*]] ], [ 2, [[G_TARGET_I]] ]
 ; CHECK-NEXT:    [[C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
 ; CHECK-NEXT:    br i1 [[C_PREDICATE]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
 ; CHECK:       loop.exit.guard1:
@@ -329,7 +416,7 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; CHECK:       F.target.G:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2]]
 ; CHECK:       loop.exit.guard2:
-; CHECK-NEXT:    [[MERGED_BB_IDX4:%.*]] = phi i32 [ 0, [[B_TARGET_B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_D_TARGET_E]] ], [ 2, [[F_TARGET_G:%.*]] ]
+; CHECK-NEXT:    [[MERGED_BB_IDX4:%.*]] = phi i32 [ 0, [[B_TARGET_B_TARGET_C]] ], [ 1, [[D_TARGET_D_TARGET_E]] ], [ 2, [[F_TARGET_G]] ]
 ; CHECK-NEXT:    [[B_TARGET_C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX4]], 0
 ; CHECK-NEXT:    br i1 [[B_TARGET_C_PREDICATE]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]]
 ; CHECK:       loop.exit.guard3:
@@ -345,13 +432,13 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; BOOLEAN:       B:
 ; BOOLEAN-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; BOOLEAN-NEXT:            to label [[D:%.*]] [label %B.target.B.target.C]
+; BOOLEAN-NEXT:            to label [[D:%.*]] [label [[B_TARGET_B_TARGET_C:%.*]]]
 ; BOOLEAN:       C:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[H:%.*]]
 ; BOOLEAN:       D:
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]])
-; BOOLEAN-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label %F]
+; BOOLEAN-NEXT:            to label [[D_TARGET_D_TARGET_E:%.*]] [label [[F]]]
 ; BOOLEAN:       E:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[H]]
@@ -359,12 +446,12 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; BOOLEAN-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
 ; BOOLEAN-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; BOOLEAN-NEXT:            to label [[B]] [label %F.target.G]
+; BOOLEAN-NEXT:            to label [[B]] [label [[F_TARGET_G:%.*]]]
 ; BOOLEAN:       G:
 ; BOOLEAN-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
 ; BOOLEAN-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]])
-; BOOLEAN-NEXT:            to label [[A]] [label %G.target.I]
+; BOOLEAN-NEXT:            to label [[A]] [label [[G_TARGET_I:%.*]]]
 ; BOOLEAN:       H:
 ; BOOLEAN-NEXT:    unreachable
 ; BOOLEAN:       I:
@@ -376,7 +463,7 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; BOOLEAN:       G.target.I:
 ; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; BOOLEAN:       loop.exit.guard:
-; BOOLEAN-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[B_TARGET_C:%.*]] ], [ false, [[D_TARGET_E:%.*]] ], [ false, [[G_TARGET_I:%.*]] ]
+; BOOLEAN-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[B_TARGET_C:%.*]] ], [ false, [[D_TARGET_E:%.*]] ], [ false, [[G_TARGET_I]] ]
 ; BOOLEAN-NEXT:    [[GUARD_E:%.*]] = phi i1 [ false, [[B_TARGET_C]] ], [ true, [[D_TARGET_E]] ], [ false, [[G_TARGET_I]] ]
 ; BOOLEAN-NEXT:    br i1 [[GUARD_C]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
 ; BOOLEAN:       loop.exit.guard1:
@@ -388,7 +475,7 @@ define void @inner_loop_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB) {
 ; BOOLEAN:       F.target.G:
 ; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2]]
 ; BOOLEAN:       loop.exit.guard2:
-; BOOLEAN-NEXT:    [[GUARD_B_TARGET_C:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_C:%.*]] ], [ false, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G:%.*]] ]
+; BOOLEAN-NEXT:    [[GUARD_B_TARGET_C:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_C]] ], [ false, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G]] ]
 ; BOOLEAN-NEXT:    [[GUARD_D_TARGET_E:%.*]] = phi i1 [ false, [[B_TARGET_B_TARGET_C]] ], [ true, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G]] ]
 ; BOOLEAN-NEXT:    br i1 [[GUARD_B_TARGET_C]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]]
 ; BOOLEAN:       loop.exit.guard3:
@@ -433,6 +520,176 @@ I:
   ret void
 }
 
+define void @inner_loop_switch(i1 %PredEntry, i1 %PredA, i1 %PredB) {
+; CHECK-LABEL: @inner_loop_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:      i1 false, label [[I:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ]
+; CHECK-NEXT:    br label [[B:%.*]]
+; CHECK:       B:
+; CHECK-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
+; CHECK-NEXT:    switch i1 [[PREDA:%.*]], label [[D:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B_TARGET_B_TARGET_C:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; CHECK-NEXT:    br label [[H:%.*]]
+; CHECK:       D:
+; CHECK-NEXT:    switch i1 [[PREDB:%.*]], label [[D_TARGET_D_TARGET_E:%.*]] [
+; CHECK-NEXT:      i1 false, label [[F]]
+; CHECK-NEXT:    ]
+; CHECK:       E:
+; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
+; CHECK-NEXT:    br label [[H]]
+; CHECK:       F:
+; CHECK-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
+; CHECK-NEXT:    switch i1 [[CMP1]], label [[B]] [
+; CHECK-NEXT:      i1 false, label [[F_TARGET_G:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       G:
+; CHECK-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
+; CHECK-NEXT:    switch i1 [[CMP2]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[G_TARGET_I:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       H:
+; CHECK-NEXT:    unreachable
+; CHECK:       I:
+; CHECK-NEXT:    ret void
+; CHECK:       B.target.C:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       D.target.E:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       G.target.I:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[B_TARGET_C:%.*]] ], [ 1, [[D_TARGET_E:%.*]] ], [ 2, [[G_TARGET_I]] ]
+; CHECK-NEXT:    [[C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
+; CHECK-NEXT:    br i1 [[C_PREDICATE]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
+; CHECK:       loop.exit.guard1:
+; CHECK-NEXT:    [[E_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1
+; CHECK-NEXT:    br i1 [[E_PREDICATE]], label [[E:%.*]], label [[I]]
+; CHECK:       B.target.B.target.C:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2:%.*]]
+; CHECK:       D.target.D.target.E:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2]]
+; CHECK:       F.target.G:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD2]]
+; CHECK:       loop.exit.guard2:
+; CHECK-NEXT:    [[MERGED_BB_IDX4:%.*]] = phi i32 [ 0, [[B_TARGET_B_TARGET_C]] ], [ 1, [[D_TARGET_D_TARGET_E]] ], [ 2, [[F_TARGET_G]] ]
+; CHECK-NEXT:    [[B_TARGET_C_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX4]], 0
+; CHECK-NEXT:    br i1 [[B_TARGET_C_PREDICATE]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]]
+; CHECK:       loop.exit.guard3:
+; CHECK-NEXT:    [[D_TARGET_E_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX4]], 1
+; CHECK-NEXT:    br i1 [[D_TARGET_E_PREDICATE]], label [[D_TARGET_E]], label [[G]]
+;
+; BOOLEAN-LABEL: @inner_loop_switch(
+; BOOLEAN-NEXT:  entry:
+; BOOLEAN-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[I:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       A:
+; BOOLEAN-NEXT:    [[OUTER1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[OUTER2:%.*]], [[G:%.*]] ]
+; BOOLEAN-NEXT:    br label [[B:%.*]]
+; BOOLEAN:       B:
+; BOOLEAN-NEXT:    [[INNER1:%.*]] = phi i32 [ 0, [[A]] ], [ [[INNER2:%.*]], [[F:%.*]] ]
+; BOOLEAN-NEXT:    switch i1 [[PREDA:%.*]], label [[D:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[B_TARGET_B_TARGET_C:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       C:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[H:%.*]]
+; BOOLEAN:       D:
+; BOOLEAN-NEXT:    switch i1 [[PREDB:%.*]], label [[D_TARGET_D_TARGET_E:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[F]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       E:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[H]]
+; BOOLEAN:       F:
+; BOOLEAN-NEXT:    [[INNER2]] = add i32 [[INNER1]], 1
+; BOOLEAN-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[INNER2]], 20
+; BOOLEAN-NEXT:    switch i1 [[CMP1]], label [[B]] [
+; BOOLEAN-NEXT:      i1 false, label [[F_TARGET_G:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       G:
+; BOOLEAN-NEXT:    [[OUTER2]] = add i32 [[OUTER1]], 1
+; BOOLEAN-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[OUTER2]], 10
+; BOOLEAN-NEXT:    switch i1 [[CMP2]], label [[A]] [
+; BOOLEAN-NEXT:      i1 false, label [[G_TARGET_I:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       H:
+; BOOLEAN-NEXT:    unreachable
+; BOOLEAN:       I:
+; BOOLEAN-NEXT:    ret void
+; BOOLEAN:       B.target.C:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; BOOLEAN:       D.target.E:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       G.target.I:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       loop.exit.guard:
+; BOOLEAN-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[B_TARGET_C:%.*]] ], [ false, [[D_TARGET_E:%.*]] ], [ false, [[G_TARGET_I]] ]
+; BOOLEAN-NEXT:    [[GUARD_E:%.*]] = phi i1 [ false, [[B_TARGET_C]] ], [ true, [[D_TARGET_E]] ], [ false, [[G_TARGET_I]] ]
+; BOOLEAN-NEXT:    br i1 [[GUARD_C]], label [[C:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
+; BOOLEAN:       loop.exit.guard1:
+; BOOLEAN-NEXT:    br i1 [[GUARD_E]], label [[E:%.*]], label [[I]]
+; BOOLEAN:       B.target.B.target.C:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2:%.*]]
+; BOOLEAN:       D.target.D.target.E:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2]]
+; BOOLEAN:       F.target.G:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD2]]
+; BOOLEAN:       loop.exit.guard2:
+; BOOLEAN-NEXT:    [[GUARD_B_TARGET_C:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_C]] ], [ false, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G]] ]
+; BOOLEAN-NEXT:    [[GUARD_D_TARGET_E:%.*]] = phi i1 [ false, [[B_TARGET_B_TARGET_C]] ], [ true, [[D_TARGET_D_TARGET_E]] ], [ false, [[F_TARGET_G]] ]
+; BOOLEAN-NEXT:    br i1 [[GUARD_B_TARGET_C]], label [[B_TARGET_C]], label [[LOOP_EXIT_GUARD3:%.*]]
+; BOOLEAN:       loop.exit.guard3:
+; BOOLEAN-NEXT:    br i1 [[GUARD_D_TARGET_E]], label [[D_TARGET_E]], label [[G]]
+;
+entry:
+  switch i1 %PredEntry, label %A [ i1 0, label %I ]
+
+A:
+  %outer1 = phi i32 [ 0, %entry ], [ %outer2, %G ]
+  br label %B
+
+B:
+  %inner1 = phi i32 [ 0, %A ], [ %inner2, %F ]
+  switch i1 %PredA, label %D [ i1 0, label %C ]
+
+C:
+  tail call fastcc void @check(i32 1) #0
+  br label %H
+
+D:
+  switch i1 %PredB, label %E [ i1 0, label %F ]
+
+E:
+  tail call fastcc void @check(i32 2) #0
+  br label %H
+
+F:
+  %inner2 = add i32 %inner1, 1
+  %cmp1 = icmp ult i32 %inner2, 20
+  switch i1 %cmp1, label %B [ i1 0, label %G ]
+
+G:
+  %outer2 = add i32 %outer1, 1
+  %cmp2 = icmp ult i32 %outer2, 10
+  switch i1 %cmp2, label %A [ i1 0, label %I ]
+
+H:
+  unreachable
+
+I:
+  ret void
+}
+
 ; A loop with more exit blocks.
 
 define void @loop_five_exits(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredD) {
@@ -585,25 +842,25 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; CHECK:       A:
 ; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label %C]
+; CHECK-NEXT:            to label [[A_TARGET_B:%.*]] [label [[C:%.*]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[J:%.*]]
 ; CHECK:       C:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]])
-; CHECK-NEXT:            to label [[C_TARGET_D:%.*]] [label %E]
+; CHECK-NEXT:            to label [[C_TARGET_D:%.*]] [label [[E:%.*]]]
 ; CHECK:       D:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[J]]
 ; CHECK:       E:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]])
-; CHECK-NEXT:            to label [[E_TARGET_F:%.*]] [label %G]
+; CHECK-NEXT:            to label [[E_TARGET_F:%.*]] [label [[G:%.*]]]
 ; CHECK:       F:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[K:%.*]]
 ; CHECK:       G:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDD:%.*]])
-; CHECK-NEXT:            to label [[G_TARGET_H:%.*]] [label %I]
+; CHECK-NEXT:            to label [[G_TARGET_H:%.*]] [label [[I]]]
 ; CHECK:       H:
 ; CHECK-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
 ; CHECK-NEXT:    br label [[K]]
@@ -611,7 +868,7 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %I.target.L]
+; CHECK-NEXT:            to label [[A]] [label [[I_TARGET_L:%.*]]]
 ; CHECK:       J:
 ; CHECK-NEXT:    br label [[L]]
 ; CHECK:       K:
@@ -629,7 +886,7 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; CHECK:       I.target.L:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_D]] ], [ 2, [[E_TARGET_F]] ], [ 3, [[G_TARGET_H]] ], [ 4, [[I_TARGET_L:%.*]] ]
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_D]] ], [ 2, [[E_TARGET_F]] ], [ 3, [[G_TARGET_H]] ], [ 4, [[I_TARGET_L]] ]
 ; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
 ; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
 ; CHECK:       loop.exit.guard1:
@@ -648,25 +905,25 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; BOOLEAN:       A:
 ; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA:%.*]])
-; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label %C]
+; BOOLEAN-NEXT:            to label [[A_TARGET_B:%.*]] [label [[C:%.*]]]
 ; BOOLEAN:       B:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[J:%.*]]
 ; BOOLEAN:       C:
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB:%.*]])
-; BOOLEAN-NEXT:            to label [[C_TARGET_D:%.*]] [label %E]
+; BOOLEAN-NEXT:            to label [[C_TARGET_D:%.*]] [label [[E:%.*]]]
 ; BOOLEAN:       D:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[J]]
 ; BOOLEAN:       E:
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDC:%.*]])
-; BOOLEAN-NEXT:            to label [[E_TARGET_F:%.*]] [label %G]
+; BOOLEAN-NEXT:            to label [[E_TARGET_F:%.*]] [label [[G:%.*]]]
 ; BOOLEAN:       F:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[K:%.*]]
 ; BOOLEAN:       G:
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDD:%.*]])
-; BOOLEAN-NEXT:            to label [[G_TARGET_H:%.*]] [label %I]
+; BOOLEAN-NEXT:            to label [[G_TARGET_H:%.*]] [label [[I]]]
 ; BOOLEAN:       H:
 ; BOOLEAN-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
 ; BOOLEAN-NEXT:    br label [[K]]
@@ -674,7 +931,7 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
 ; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
 ; BOOLEAN-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; BOOLEAN-NEXT:            to label [[A]] [label %I.target.L]
+; BOOLEAN-NEXT:            to label [[A]] [label [[I_TARGET_L:%.*]]]
 ; BOOLEAN:       J:
 ; BOOLEAN-NEXT:    br label [[L]]
 ; BOOLEAN:       K:
@@ -692,7 +949,7 @@ define void @loop_five_exits_callbr(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %Pre
 ; BOOLEAN:       I.target.L:
 ; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; BOOLEAN:       loop.exit.guard:
-; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L:%.*]] ]
+; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
 ; BOOLEAN-NEXT:    [[GUARD_D:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ true, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
 ; BOOLEAN-NEXT:    [[GUARD_F:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ true, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
 ; BOOLEAN-NEXT:    [[GUARD_H:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ true, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
@@ -751,6 +1008,192 @@ L:
   ret void
 }
 
+define void @loop_five_exits_switch(i1 %PredEntry, i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredD) {
+; CHECK-LABEL: @loop_five_exits_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:      i1 false, label [[L:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
+; CHECK-NEXT:    switch i1 [[PREDA:%.*]], label [[A_TARGET_B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[C:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; CHECK-NEXT:    br label [[J:%.*]]
+; CHECK:       C:
+; CHECK-NEXT:    switch i1 [[PREDB:%.*]], label [[C_TARGET_D:%.*]] [
+; CHECK-NEXT:      i1 false, label [[E:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
+; CHECK-NEXT:    br label [[J]]
+; CHECK:       E:
+; CHECK-NEXT:    switch i1 [[PREDC:%.*]], label [[E_TARGET_F:%.*]] [
+; CHECK-NEXT:      i1 false, label [[G:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       F:
+; CHECK-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
+; CHECK-NEXT:    br label [[K:%.*]]
+; CHECK:       G:
+; CHECK-NEXT:    switch i1 [[PREDD:%.*]], label [[G_TARGET_H:%.*]] [
+; CHECK-NEXT:      i1 false, label [[I]]
+; CHECK-NEXT:    ]
+; CHECK:       H:
+; CHECK-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
+; CHECK-NEXT:    br label [[K]]
+; CHECK:       I:
+; CHECK-NEXT:    [[INC2]] = add i32 [[INC1]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[I_TARGET_L:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       J:
+; CHECK-NEXT:    br label [[L]]
+; CHECK:       K:
+; CHECK-NEXT:    br label [[L]]
+; CHECK:       L:
+; CHECK-NEXT:    ret void
+; CHECK:       A.target.B:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       C.target.D:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       E.target.F:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       G.target.H:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       I.target.L:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MERGED_BB_IDX:%.*]] = phi i32 [ 0, [[A_TARGET_B]] ], [ 1, [[C_TARGET_D]] ], [ 2, [[E_TARGET_F]] ], [ 3, [[G_TARGET_H]] ], [ 4, [[I_TARGET_L]] ]
+; CHECK-NEXT:    [[B_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 0
+; CHECK-NEXT:    br i1 [[B_PREDICATE]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
+; CHECK:       loop.exit.guard1:
+; CHECK-NEXT:    [[D_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 1
+; CHECK-NEXT:    br i1 [[D_PREDICATE]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
+; CHECK:       loop.exit.guard2:
+; CHECK-NEXT:    [[F_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 2
+; CHECK-NEXT:    br i1 [[F_PREDICATE]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]]
+; CHECK:       loop.exit.guard3:
+; CHECK-NEXT:    [[H_PREDICATE:%.*]] = icmp eq i32 [[MERGED_BB_IDX]], 3
+; CHECK-NEXT:    br i1 [[H_PREDICATE]], label [[H:%.*]], label [[L]]
+;
+; BOOLEAN-LABEL: @loop_five_exits_switch(
+; BOOLEAN-NEXT:  entry:
+; BOOLEAN-NEXT:    switch i1 [[PREDENTRY:%.*]], label [[A:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[L:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       A:
+; BOOLEAN-NEXT:    [[INC1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[I:%.*]] ]
+; BOOLEAN-NEXT:    switch i1 [[PREDA:%.*]], label [[A_TARGET_B:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[C:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       B:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 1) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[J:%.*]]
+; BOOLEAN:       C:
+; BOOLEAN-NEXT:    switch i1 [[PREDB:%.*]], label [[C_TARGET_D:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[E:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       D:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 2) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[J]]
+; BOOLEAN:       E:
+; BOOLEAN-NEXT:    switch i1 [[PREDC:%.*]], label [[E_TARGET_F:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[G:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       F:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 3) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[K:%.*]]
+; BOOLEAN:       G:
+; BOOLEAN-NEXT:    switch i1 [[PREDD:%.*]], label [[G_TARGET_H:%.*]] [
+; BOOLEAN-NEXT:      i1 false, label [[I]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       H:
+; BOOLEAN-NEXT:    tail call fastcc void @check(i32 4) #[[ATTR0]]
+; BOOLEAN-NEXT:    br label [[K]]
+; BOOLEAN:       I:
+; BOOLEAN-NEXT:    [[INC2]] = add i32 [[INC1]], 1
+; BOOLEAN-NEXT:    [[CMP:%.*]] = icmp ult i32 [[INC2]], 10
+; BOOLEAN-NEXT:    switch i1 [[CMP]], label [[A]] [
+; BOOLEAN-NEXT:      i1 false, label [[I_TARGET_L:%.*]]
+; BOOLEAN-NEXT:    ]
+; BOOLEAN:       J:
+; BOOLEAN-NEXT:    br label [[L]]
+; BOOLEAN:       K:
+; BOOLEAN-NEXT:    br label [[L]]
+; BOOLEAN:       L:
+; BOOLEAN-NEXT:    ret void
+; BOOLEAN:       A.target.B:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; BOOLEAN:       C.target.D:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       E.target.F:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       G.target.H:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       I.target.L:
+; BOOLEAN-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; BOOLEAN:       loop.exit.guard:
+; BOOLEAN-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
+; BOOLEAN-NEXT:    [[GUARD_D:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ true, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
+; BOOLEAN-NEXT:    [[GUARD_F:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ true, [[E_TARGET_F]] ], [ false, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
+; BOOLEAN-NEXT:    [[GUARD_H:%.*]] = phi i1 [ false, [[A_TARGET_B]] ], [ false, [[C_TARGET_D]] ], [ false, [[E_TARGET_F]] ], [ true, [[G_TARGET_H]] ], [ false, [[I_TARGET_L]] ]
+; BOOLEAN-NEXT:    br i1 [[GUARD_B]], label [[B:%.*]], label [[LOOP_EXIT_GUARD1:%.*]]
+; BOOLEAN:       loop.exit.guard1:
+; BOOLEAN-NEXT:    br i1 [[GUARD_D]], label [[D:%.*]], label [[LOOP_EXIT_GUARD2:%.*]]
+; BOOLEAN:       loop.exit.guard2:
+; BOOLEAN-NEXT:    br i1 [[GUARD_F]], label [[F:%.*]], label [[LOOP_EXIT_GUARD3:%.*]]
+; BOOLEAN:       loop.exit.guard3:
+; BOOLEAN-NEXT:    br i1 [[GUARD_H]], label [[H:%.*]], label [[L]]
+;
+entry:
+  switch i1 %PredEntry, label %A [ i1 0, label %L ]
+
+A:
+  %inc1 = phi i32 [ 0, %entry ], [ %inc2, %I ]
+  switch i1 %PredA, label %B [ i1 0, label %C ]
+
+B:
+  tail call fastcc void @check(i32 1) #0
+  br label %J
+
+C:
+  switch i1 %PredB, label %D [ i1 0, label %E ]
+
+D:
+  tail call fastcc void @check(i32 2) #0
+  br label %J
+
+E:
+  switch i1 %PredC, label %F [ i1 0, label %G ]
+
+F:
+  tail call fastcc void @check(i32 3) #0
+  br label %K
+
+G:
+  switch i1 %PredD, label %H [ i1 0, label %I ]
+
+H:
+  tail call fastcc void @check(i32 4) #0
+  br label %K
+
+I:
+  %inc2 = add i32 %inc1, 1
+  %cmp = icmp ult i32 %inc2, 10
+  switch i1 %cmp, label %A [ i1 0, label %L ]
+
+J:
+  br label %L
+
+K:
+  br label %L
+
+L:
+  ret void
+}
 
 declare void @check(i32 noundef %i) #0
 
diff --git a/llvm/test/Transforms/UnifyLoopExits/nested.ll b/llvm/test/Transforms/UnifyLoopExits/nested.ll
index 2ec576a2efa89..2383667b434a0 100644
--- a/llvm/test/Transforms/UnifyLoopExits/nested.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/nested.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes='lower-switch,unify-loop-exits' -S | FileCheck %s
+; RUN: opt < %s -passes='unify-loop-exits' -S | FileCheck %s
 
 define void @nested(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %X, i32 %Y, i32 %Z) {
 ; CHECK-LABEL: @nested(
@@ -92,10 +92,10 @@ define void @nested_callbr(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %
 ; CHECK-NEXT:    br label [[B3:%.*]]
 ; CHECK:       B3:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB3:%.*]])
-; CHECK-NEXT:            to label [[B4:%.*]] [label %B3.target.A3]
+; CHECK-NEXT:            to label [[B4:%.*]] [label [[B3_TARGET_A3:%.*]]]
 ; CHECK:       B4:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDB4:%.*]])
-; CHECK-NEXT:            to label [[B1]] [label %B4.target.A2]
+; CHECK-NEXT:            to label [[B1]] [label [[B4_TARGET_A2:%.*]]]
 ; CHECK:       A2:
 ; CHECK-NEXT:    br label [[A4:%.*]]
 ; CHECK:       A3:
@@ -103,10 +103,10 @@ define void @nested_callbr(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %
 ; CHECK:       A4:
 ; CHECK-NEXT:    [[A4_PHI:%.*]] = phi i32 [ [[Y:%.*]], [[A3:%.*]] ], [ [[X_INC_MOVED:%.*]], [[A2:%.*]] ]
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA4:%.*]])
-; CHECK-NEXT:            to label [[A4_TARGET_C:%.*]] [label %A5]
+; CHECK-NEXT:            to label [[A4_TARGET_C:%.*]] [label [[A5:%.*]]]
 ; CHECK:       A5:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[PREDA3:%.*]])
-; CHECK-NEXT:            to label [[A5_TARGET_EXIT:%.*]] [label %A1]
+; CHECK-NEXT:            to label [[A5_TARGET_EXIT:%.*]] [label [[A1]]]
 ; CHECK:       C:
 ; CHECK-NEXT:    br label [[EXIT:%.*]]
 ; CHECK:       exit:
@@ -125,7 +125,7 @@ define void @nested_callbr(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %
 ; CHECK:       B4.target.A2:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]]
 ; CHECK:       loop.exit.guard1:
-; CHECK-NEXT:    [[X_INC_MOVED]] = phi i32 [ [[X_INC]], [[B3_TARGET_A3:%.*]] ], [ [[X_INC]], [[B4_TARGET_A2:%.*]] ]
+; CHECK-NEXT:    [[X_INC_MOVED]] = phi i32 [ [[X_INC]], [[B3_TARGET_A3]] ], [ [[X_INC]], [[B4_TARGET_A2]] ]
 ; CHECK-NEXT:    [[GUARD_A3:%.*]] = phi i1 [ true, [[B3_TARGET_A3]] ], [ false, [[B4_TARGET_A2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_A3]], label [[A3]], label [[A2]]
 ;
@@ -169,6 +169,100 @@ exit:
   ret void
 }
 
+define void @nested_switch(i1 %PredB3, i1 %PredB4, i1 %PredA4, i1 %PredA3, i32 %X, i32 %Y, i32 %Z) {
+; CHECK-LABEL: @nested_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[A1:%.*]]
+; CHECK:       A1:
+; CHECK-NEXT:    br label [[B1:%.*]]
+; CHECK:       B1:
+; CHECK-NEXT:    br label [[B2:%.*]]
+; CHECK:       B2:
+; CHECK-NEXT:    [[X_INC:%.*]] = add i32 [[X:%.*]], 1
+; CHECK-NEXT:    br label [[B3:%.*]]
+; CHECK:       B3:
+; CHECK-NEXT:    switch i1 [[PREDB3:%.*]], label [[B4:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B3_TARGET_A3:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B4:
+; CHECK-NEXT:    switch i1 [[PREDB4:%.*]], label [[B1]] [
+; CHECK-NEXT:      i1 false, label [[B4_TARGET_A2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A2:
+; CHECK-NEXT:    br label [[A4:%.*]]
+; CHECK:       A3:
+; CHECK-NEXT:    br label [[A4]]
+; CHECK:       A4:
+; CHECK-NEXT:    [[A4_PHI:%.*]] = phi i32 [ [[Y:%.*]], [[A3:%.*]] ], [ [[X_INC_MOVED:%.*]], [[A2:%.*]] ]
+; CHECK-NEXT:    switch i1 [[PREDA4:%.*]], label [[A4_TARGET_C:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A5:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A5:
+; CHECK-NEXT:    switch i1 [[PREDA3:%.*]], label [[A5_TARGET_EXIT:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A1]]
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[EXIT_PHI:%.*]] = phi i32 [ [[Z:%.*]], [[C:%.*]] ], [ [[EXIT_PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ]
+; CHECK-NEXT:    ret void
+; CHECK:       A4.target.C:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       A5.target.exit:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[EXIT_PHI_MOVED]] = phi i32 [ poison, [[A4_TARGET_C]] ], [ [[A4_PHI]], [[A5_TARGET_EXIT]] ]
+; CHECK-NEXT:    [[GUARD_C:%.*]] = phi i1 [ true, [[A4_TARGET_C]] ], [ false, [[A5_TARGET_EXIT]] ]
+; CHECK-NEXT:    br i1 [[GUARD_C]], label [[C]], label [[EXIT]]
+; CHECK:       B3.target.A3:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1:%.*]]
+; CHECK:       B4.target.A2:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]]
+; CHECK:       loop.exit.guard1:
+; CHECK-NEXT:    [[X_INC_MOVED]] = phi i32 [ [[X_INC]], [[B3_TARGET_A3]] ], [ [[X_INC]], [[B4_TARGET_A2]] ]
+; CHECK-NEXT:    [[GUARD_A3:%.*]] = phi i1 [ true, [[B3_TARGET_A3]] ], [ false, [[B4_TARGET_A2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_A3]], label [[A3]], label [[A2]]
+;
+entry:
+  br label %A1
+
+A1:
+  br label %B1
+
+B1:
+  br label %B2
+
+B2:
+  %X.inc = add i32 %X, 1
+  br label %B3
+
+B3:
+  switch i1 %PredB3, label %B4 [ i1 0, label %A3 ]
+
+B4:
+  switch i1 %PredB4, label %B1 [ i1 0, label %A2 ]
+
+A2:
+  br label %A4
+
+A3:
+  br label %A4
+
+A4:
+  %A4.phi = phi i32 [%Y, %A3], [%X.inc, %A2]
+  switch i1 %PredA4, label %C [ i1 0, label %A5 ]
+
+A5:
+  switch i1 %PredA3, label %exit [ i1 0, label %A1 ]
+
+C:
+  br label %exit
+
+exit:
+  %exit.phi = phi i32 [%A4.phi, %A5], [%Z, %C]
+  ret void
+}
+
 ; Here, the newly created target loop that connects b to r1 needs to be part of
 ; the parent loop (the outer loop b participates in). Otherwise, it will be
 ; regarded as an additional loop entry point to this outer loop.
@@ -180,13 +274,13 @@ define void @nested_callbr_multiple_exits() {
 ; CHECK-NEXT:            to label [[B:%.*]] []
 ; CHECK:       b:
 ; CHECK-NEXT:    callbr void asm "", "!i"()
-; CHECK-NEXT:            to label [[C:%.*]] [label %b.target.b.target.r1]
+; CHECK-NEXT:            to label [[C:%.*]] [label [[B_TARGET_B_TARGET_R1:%.*]]]
 ; CHECK:       c:
 ; CHECK-NEXT:    callbr void asm "", "!i"()
-; CHECK-NEXT:            to label [[C_TARGET_E:%.*]] [label %b]
+; CHECK-NEXT:            to label [[C_TARGET_E:%.*]] [label [[B]]]
 ; CHECK:       e:
 ; CHECK-NEXT:    callbr void asm "", "!i"()
-; CHECK-NEXT:            to label [[A]] [label %e.target.r2]
+; CHECK-NEXT:            to label [[A]] [label [[E_TARGET_R2:%.*]]]
 ; CHECK:       r1:
 ; CHECK-NEXT:    ret void
 ; CHECK:       r2:
@@ -196,14 +290,14 @@ define void @nested_callbr_multiple_exits() {
 ; CHECK:       e.target.r2:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[GUARD_R1:%.*]] = phi i1 [ true, [[B_TARGET_R1:%.*]] ], [ false, [[E_TARGET_R2:%.*]] ]
+; CHECK-NEXT:    [[GUARD_R1:%.*]] = phi i1 [ true, [[B_TARGET_R1:%.*]] ], [ false, [[E_TARGET_R2]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_R1]], label [[R1:%.*]], label [[R2:%.*]]
 ; CHECK:       b.target.b.target.r1:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1:%.*]]
 ; CHECK:       c.target.e:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]]
 ; CHECK:       loop.exit.guard1:
-; CHECK-NEXT:    [[GUARD_B_TARGET_R1:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_R1:%.*]] ], [ false, [[C_TARGET_E]] ]
+; CHECK-NEXT:    [[GUARD_B_TARGET_R1:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_R1]] ], [ false, [[C_TARGET_E]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_B_TARGET_R1]], label [[B_TARGET_R1]], label [[E:%.*]]
 ;
   br label %a
@@ -220,3 +314,55 @@ r1:
 r2:
   ret void
 }
+
+define void @nested_switch_multiple_exits(i1 %PredA, i1 %PredB, i1 %PredC, i1 %PredE) {
+; CHECK-LABEL: @nested_switch_multiple_exits(
+; CHECK-NEXT:    br label [[A:%.*]]
+; CHECK:       a:
+; CHECK-NEXT:    switch i1 [[PREDA:%.*]], label [[B:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       b:
+; CHECK-NEXT:    switch i1 [[PREDB:%.*]], label [[C:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B_TARGET_B_TARGET_R1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       c:
+; CHECK-NEXT:    switch i1 [[PREDC:%.*]], label [[C_TARGET_E:%.*]] [
+; CHECK-NEXT:      i1 false, label [[B]]
+; CHECK-NEXT:    ]
+; CHECK:       e:
+; CHECK-NEXT:    switch i1 [[PREDE:%.*]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[E_TARGET_R2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       r1:
+; CHECK-NEXT:    ret void
+; CHECK:       r2:
+; CHECK-NEXT:    ret void
+; CHECK:       b.target.r1:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       e.target.r2:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[GUARD_R1:%.*]] = phi i1 [ true, [[B_TARGET_R1:%.*]] ], [ false, [[E_TARGET_R2]] ]
+; CHECK-NEXT:    br i1 [[GUARD_R1]], label [[R1:%.*]], label [[R2:%.*]]
+; CHECK:       b.target.b.target.r1:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1:%.*]]
+; CHECK:       c.target.e:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD1]]
+; CHECK:       loop.exit.guard1:
+; CHECK-NEXT:    [[GUARD_B_TARGET_R1:%.*]] = phi i1 [ true, [[B_TARGET_B_TARGET_R1]] ], [ false, [[C_TARGET_E]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B_TARGET_R1]], label [[B_TARGET_R1]], label [[E:%.*]]
+;
+  br label %a
+a:
+  switch i1 %PredA, label %b []
+b:
+  switch i1 %PredB, label %c [ i1 0, label %r1 ]
+c:
+  switch i1 %PredC, label %e [ i1 0, label %b ]
+e:
+  switch i1 %PredE, label %a [ i1 0, label %r2 ]
+r1:
+  ret void
+r2:
+  ret void
+}
diff --git a/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll b/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll
index ffe8026a535c0..5e8202eca56f3 100644
--- a/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes='lower-switch,unify-loop-exits' -S | FileCheck %s
+; RUN: opt < %s -passes='unify-loop-exits' -S | FileCheck %s
 
 ; Loop consists of A and B:
 ; - A is the header
@@ -66,12 +66,12 @@ define i32 @exiting-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr
 ; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return]
+; CHECK-NEXT:            to label [[B:%.*]] [label [[A_TARGET_RETURN:%.*]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %B.target.C]
+; CHECK-NEXT:            to label [[A]] [label [[B_TARGET_C:%.*]]]
 ; CHECK:       C:
 ; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
 ; CHECK-NEXT:    callbr void asm "", ""()
@@ -84,7 +84,7 @@ define i32 @exiting-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr
 ; CHECK:       B.target.C:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[B_TARGET_C:%.*]] ]
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[B_TARGET_C]] ]
 ; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A_TARGET_RETURN]] ], [ poison, [[B_TARGET_C]] ]
 ; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[B_TARGET_C]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]]
@@ -111,6 +111,62 @@ return:
   ret i32 %phi
 }
 
+define i32 @exiting-used-in-exit_switch(ptr %arg1, ptr %arg2, i1 %Pred) local_unnamed_addr align 2 {
+; CHECK-LABEL: @exiting-used-in-exit_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP1]], label [[B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A_TARGET_RETURN:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[B_TARGET_C:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
+; CHECK-NEXT:    switch i1 [[PRED]], label [[RETURN:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       return:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[INC]], [[C:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+; CHECK:       A.target.return:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       B.target.C:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[B_TARGET_C]] ]
+; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A_TARGET_RETURN]] ], [ poison, [[B_TARGET_C]] ]
+; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[B_TARGET_C]] ]
+; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]]
+;
+entry:
+  switch i1 %Pred, label %A []
+
+A:
+  %mytmp42 = load i32, ptr %arg1, align 4
+  %cmp1 = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp1, label %B [ i1 0, label %return ]
+
+B:
+  %mytmp41 = load i32, ptr %arg2, align 4
+  %cmp = icmp slt i32 %mytmp41, 0
+  switch i1 %cmp, label %A [ i1 0, label %C ]
+
+C:
+  %inc = add i32 %mytmp41, 1
+  switch i1 %Pred, label %return []
+
+return:
+  %phi = phi i32 [ %inc, %C ], [ %mytmp42, %A ]
+  ret i32 %phi
+}
+
 ; Loop consists of A, B and C:
 ; - A is the header
 ; - A and C are exiting blocks
@@ -175,7 +231,7 @@ define i32 @internal-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_add
 ; CHECK:       A:
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return]
+; CHECK-NEXT:            to label [[B:%.*]] [label [[A_TARGET_RETURN:%.*]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
 ; CHECK-NEXT:    callbr void asm "", ""()
@@ -183,7 +239,7 @@ define i32 @internal-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_add
 ; CHECK:       C:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %C.target.D]
+; CHECK-NEXT:            to label [[A]] [label [[C_TARGET_D:%.*]]]
 ; CHECK:       D:
 ; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
 ; CHECK-NEXT:    callbr void asm "", ""()
@@ -195,7 +251,7 @@ define i32 @internal-used-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_add
 ; CHECK:       C.target.D:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ]
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
 ; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]]
 ;
@@ -223,6 +279,65 @@ return:
   ret i32 0
 }
 
+define i32 @internal-used-in-exit_switch(ptr %arg1, ptr %arg2, i1 %Pred) local_unnamed_addr align 2 {
+; CHECK-LABEL: @internal-used-in-exit_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
+; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP1]], label [[B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A_TARGET_RETURN:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
+; CHECK-NEXT:    switch i1 [[PRED]], label [[C:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_D:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
+; CHECK-NEXT:    switch i1 [[PRED]], label [[RETURN:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       return:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       A.target.return:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       C.target.D:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
+; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ]
+; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]]
+;
+entry:
+  %mytmp42 = load i32, ptr %arg1, align 4
+  switch i1 %Pred, label %A []
+
+A:
+  %cmp1 = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp1, label %B [ i1 0, label %return ]
+
+B:
+  %mytmp41 = load i32, ptr %arg2, align 4
+  switch i1 %Pred, label %C []
+
+C:
+  %cmp = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp, label %A [ i1 0, label %D ]
+
+D:
+  %inc = add i32 %mytmp41, 1
+  switch i1 %Pred, label %return []
+
+return:
+  ret i32 0
+}
+
 ; Loop consists of A, B and C:
 ; - A is the header
 ; - A and C are exiting blocks
@@ -289,12 +404,12 @@ define i32 @mixed-use-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr al
 ; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP2]])
-; CHECK-NEXT:            to label [[A:%.*]] [label %return]
+; CHECK-NEXT:            to label [[A:%.*]] [label [[RETURN:%.*]]]
 ; CHECK:       A:
 ; CHECK-NEXT:    [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.return]
+; CHECK-NEXT:            to label [[B:%.*]] [label [[A_TARGET_RETURN:%.*]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
 ; CHECK-NEXT:    callbr void asm "", ""()
@@ -302,10 +417,10 @@ define i32 @mixed-use-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr al
 ; CHECK:       C:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %C.target.D]
+; CHECK-NEXT:            to label [[A]] [label [[C_TARGET_D:%.*]]]
 ; CHECK:       D:
 ; CHECK-NEXT:    callbr void asm "", ""()
-; CHECK-NEXT:            to label [[RETURN:%.*]] []
+; CHECK-NEXT:            to label [[RETURN]] []
 ; CHECK:       return:
 ; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ]
 ; CHECK-NEXT:    ret i32 [[PHI]]
@@ -314,7 +429,7 @@ define i32 @mixed-use-in-exit_callbr(ptr %arg1, ptr %arg2) local_unnamed_addr al
 ; CHECK:       C.target.D:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ]
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
 ; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A_TARGET_RETURN]] ], [ poison, [[C_TARGET_D]] ]
 ; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]]
@@ -345,6 +460,71 @@ return:
   ret i32 %phi
 }
 
+define i32 @mixed-use-in-exit_switch(ptr %arg1, ptr %arg2, i1 %Pred) local_unnamed_addr align 2 {
+; CHECK-LABEL: @mixed-use-in-exit_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP2]], label [[A:%.*]] [
+; CHECK-NEXT:      i1 false, label [[RETURN:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP1]], label [[B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A_TARGET_RETURN:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
+; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[C:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_D:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    switch i1 [[PRED]], label [[RETURN]] [
+; CHECK-NEXT:    ]
+; CHECK:       return:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD:%.*]] ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+; CHECK:       A.target.return:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       C.target.D:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_RETURN]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
+; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A_TARGET_RETURN]] ], [ poison, [[C_TARGET_D]] ]
+; CHECK-NEXT:    [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A_TARGET_RETURN]] ], [ false, [[C_TARGET_D]] ]
+; CHECK-NEXT:    br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]]
+;
+entry:
+  %mytmp42 = load i32, ptr %arg1, align 4
+  %cmp2 = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp2, label %A [ i1 0, label %return ]
+
+A:
+  %mytmp43 = add i32 %mytmp42, 1
+  %cmp1 = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp1, label %B [ i1 0, label %return ]
+
+B:
+  %mytmp41 = load i32, ptr %arg2, align 4
+  switch i1 %Pred, label %C []
+
+C:
+  %cmp = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp, label %A [ i1 0, label %D ]
+
+D:
+  switch i1 %Pred, label %return []
+
+return:
+  %phi = phi i32 [ %mytmp41, %D ], [ %mytmp43, %A ], [%mytmp42, %entry]
+  ret i32 %phi
+}
+
 ; Loop consists of A, B and C:
 ; - A is the header
 ; - A and C are exiting blocks
@@ -419,7 +599,7 @@ define i32 @phi-via-external-block_callbr(ptr %arg1, ptr %arg2) local_unnamed_ad
 ; CHECK:       A:
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP1]])
-; CHECK-NEXT:            to label [[B:%.*]] [label %A.target.E]
+; CHECK-NEXT:            to label [[B:%.*]] [label [[A_TARGET_E:%.*]]]
 ; CHECK:       B:
 ; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
 ; CHECK-NEXT:    callbr void asm "", ""()
@@ -427,7 +607,7 @@ define i32 @phi-via-external-block_callbr(ptr %arg1, ptr %arg2) local_unnamed_ad
 ; CHECK:       C:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[CMP]])
-; CHECK-NEXT:            to label [[A]] [label %C.target.D]
+; CHECK-NEXT:            to label [[A]] [label [[C_TARGET_D:%.*]]]
 ; CHECK:       D:
 ; CHECK-NEXT:    callbr void asm "", ""()
 ; CHECK-NEXT:            to label [[RETURN:%.*]] []
@@ -442,7 +622,7 @@ define i32 @phi-via-external-block_callbr(ptr %arg1, ptr %arg2) local_unnamed_ad
 ; CHECK:       C.target.D:
 ; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
 ; CHECK:       loop.exit.guard:
-; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_E:%.*]] ], [ [[MYTMP41]], [[C_TARGET_D:%.*]] ]
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_E]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
 ; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[A_TARGET_E]] ], [ false, [[C_TARGET_D]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E]], label [[D]]
 ;
@@ -472,3 +652,68 @@ return:
   %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ]
   ret i32 %phi
 }
+
+define i32 @phi-via-external-block_switch(ptr %arg1, ptr %arg2, i1 %Pred) local_unnamed_addr align 2 {
+; CHECK-LABEL: @phi-via-external-block_switch(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
+; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[A:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       A:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP1]], label [[B:%.*]] [
+; CHECK-NEXT:      i1 false, label [[A_TARGET_E:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       B:
+; CHECK-NEXT:    [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
+; CHECK-NEXT:    switch i1 [[PRED]], label [[C:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       C:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
+; CHECK-NEXT:    switch i1 [[CMP]], label [[A]] [
+; CHECK-NEXT:      i1 false, label [[C_TARGET_D:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       D:
+; CHECK-NEXT:    switch i1 [[PRED]], label [[RETURN:%.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       E:
+; CHECK-NEXT:    switch i1 [[PRED]], label [[RETURN]] [
+; CHECK-NEXT:    ]
+; CHECK:       return:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[E:%.*]] ]
+; CHECK-NEXT:    ret i32 [[PHI]]
+; CHECK:       A.target.E:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD:%.*]]
+; CHECK:       C.target.D:
+; CHECK-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; CHECK:       loop.exit.guard:
+; CHECK-NEXT:    [[MYTMP41_MOVED]] = phi i32 [ poison, [[A_TARGET_E]] ], [ [[MYTMP41]], [[C_TARGET_D]] ]
+; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, [[A_TARGET_E]] ], [ false, [[C_TARGET_D]] ]
+; CHECK-NEXT:    br i1 [[GUARD_E]], label [[E]], label [[D]]
+;
+entry:
+  %mytmp42 = load i32, ptr %arg1, align 4
+  switch i1 %Pred, label %A []
+
+A:
+  %cmp1 = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp1, label %B [ i1 0, label %E ]
+
+B:
+  %mytmp41 = load i32, ptr %arg2, align 4
+  switch i1 %Pred, label %C []
+
+C:
+  %cmp = icmp slt i32 %mytmp42, 0
+  switch i1 %cmp, label %A [ i1 0, label %D ]
+
+D:
+  switch i1 %Pred, label %return []
+
+E:
+  switch i1 %Pred, label %return []
+
+return:
+  %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ]
+  ret i32 %phi
+}
diff --git a/llvm/test/Transforms/UnifyLoopExits/switch.ll b/llvm/test/Transforms/UnifyLoopExits/switch.ll
index 887a6f5d08e9b..7ab6de7651bd9 100644
--- a/llvm/test/Transforms/UnifyLoopExits/switch.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/switch.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes='lower-switch,unify-loop-exits' -S | FileCheck %s
+; RUN: opt < %s -passes='unify-loop-exits' -S | FileCheck %s --check-prefix=NOLOWER
 
 define void @loop_1(i32 %Value, i1 %PredEntry, i1 %PredD) {
 ; CHECK-LABEL: @loop_1(
@@ -34,6 +35,34 @@ define void @loop_1(i32 %Value, i1 %PredEntry, i1 %PredD) {
 ; CHECK-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[LEAFBLOCK1]] ], [ true, [[LEAFBLOCK]] ], [ false, [[D]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[Y:%.*]]
 ;
+; NOLOWER-LABEL: @loop_1(
+; NOLOWER-NEXT:  entry:
+; NOLOWER-NEXT:    br i1 [[PREDENTRY:%.*]], label [[A:%.*]], label [[G:%.*]]
+; NOLOWER:       A:
+; NOLOWER-NEXT:    br label [[B:%.*]]
+; NOLOWER:       B:
+; NOLOWER-NEXT:    switch i32 [[VALUE:%.*]], label [[B_TARGET_X:%.*]] [
+; NOLOWER-NEXT:      i32 0, label [[C:%.*]]
+; NOLOWER-NEXT:      i32 1, label [[D:%.*]]
+; NOLOWER-NEXT:    ]
+; NOLOWER:       C:
+; NOLOWER-NEXT:    br label [[D]]
+; NOLOWER:       D:
+; NOLOWER-NEXT:    br i1 [[PREDD:%.*]], label [[A]], label [[LOOP_EXIT_GUARD:%.*]]
+; NOLOWER:       X:
+; NOLOWER-NEXT:    br label [[EXIT:%.*]]
+; NOLOWER:       Y:
+; NOLOWER-NEXT:    br label [[EXIT]]
+; NOLOWER:       G:
+; NOLOWER-NEXT:    br label [[EXIT]]
+; NOLOWER:       exit:
+; NOLOWER-NEXT:    ret void
+; NOLOWER:       B.target.X:
+; NOLOWER-NEXT:    br label [[LOOP_EXIT_GUARD]]
+; NOLOWER:       loop.exit.guard:
+; NOLOWER-NEXT:    [[GUARD_X:%.*]] = phi i1 [ true, [[B_TARGET_X]] ], [ false, [[D]] ]
+; NOLOWER-NEXT:    br i1 [[GUARD_X]], label [[X:%.*]], label [[Y:%.*]]
+;
 entry:
   br i1 %PredEntry, label %A, label %G
 
diff --git a/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll b/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll
index e65e2549a21c8..af7d1a912be70 100644
--- a/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/undef-phis.ll
@@ -70,28 +70,28 @@ define fastcc void @undef_phi_callbr(i64 %i5247, i1 %i4530, i1 %i4936.not) {
 ; CHECK-NEXT:    [[TMP0:%.*]] = trunc i64 [[I5247]] to i32
 ; CHECK-NEXT:    [[I5290:%.*]] = icmp eq i32 [[TMP0]], 0
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I5290]])
-; CHECK-NEXT:            to label %[[MBB3932]] [label %mbb4321.target.mbb5291]
+; CHECK-NEXT:            to label %[[MBB3932]] [label %[[MBB4321_TARGET_MBB5291:.*]]]
 ; CHECK:       [[MBB4454]]:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I4530]])
-; CHECK-NEXT:            to label %[[MBB4535:.*]] [label %mbb4454.target.mbb4454.target.mbb4531]
+; CHECK-NEXT:            to label %[[MBB4535:.*]] [label %[[MBB4454_TARGET_MBB4454_TARGET_MBB4531:.*]]]
 ; CHECK:       [[MBB4531:.*]]:
 ; CHECK-NEXT:    ret void
 ; CHECK:       [[MBB4535]]:
 ; CHECK-NEXT:    callbr void asm "", "r,!i"(i1 [[I4936_NOT]])
-; CHECK-NEXT:            to label %[[MBB4535_TARGET_MBB4321:.*]] [label %mbb4454]
+; CHECK-NEXT:            to label %[[MBB4535_TARGET_MBB4321:.*]] [label %[[MBB4454]]]
 ; CHECK:       [[MBB5291:.*]]:
 ; CHECK-NEXT:    [[I5293:%.*]] = insertvalue [2 x i32] zeroinitializer, i32 [[DOTMOVED:%.*]], 1
 ; CHECK-NEXT:    store volatile [2 x i32] [[I5293]], ptr addrspace(5) null, align 4
 ; CHECK-NEXT:    ret void
 ; CHECK:       [[MBB4454_TARGET_MBB4531:.*]]:
 ; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD:.*]]
-; CHECK:       [[MBB4321_TARGET_MBB5291:.*]]:
+; CHECK:       [[MBB4321_TARGET_MBB5291]]:
 ; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
 ; CHECK:       [[LOOP_EXIT_GUARD]]:
 ; CHECK-NEXT:    [[DOTMOVED]] = phi i32 [ poison, %[[MBB4454_TARGET_MBB4531]] ], [ [[TMP0]], %[[MBB4321_TARGET_MBB5291]] ]
 ; CHECK-NEXT:    [[GUARD_MBB4531:%.*]] = phi i1 [ true, %[[MBB4454_TARGET_MBB4531]] ], [ false, %[[MBB4321_TARGET_MBB5291]] ]
 ; CHECK-NEXT:    br i1 [[GUARD_MBB4531]], label %[[MBB4531]], label %[[MBB5291]]
-; CHECK:       [[MBB4454_TARGET_MBB4454_TARGET_MBB4531:.*]]:
+; CHECK:       [[MBB4454_TARGET_MBB4454_TARGET_MBB4531]]:
 ; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1:.*]]
 ; CHECK:       [[MBB4535_TARGET_MBB4321]]:
 ; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1]]
@@ -124,3 +124,74 @@ mbb5291:                                           ; preds = %mbb4321
   store volatile [2 x i32] %i5293, ptr addrspace(5) null, align 4
   ret void
 }
+
+define fastcc void @undef_phi_switch(i64 %i5247, i1 %i4530, i1 %i4936.not, i1 %Pred) {
+; CHECK-LABEL: define fastcc void @undef_phi_switch(
+; CHECK-SAME: i64 [[I5247:%.*]], i1 [[I4530:%.*]], i1 [[I4936_NOT:%.*]], i1 [[PRED:%.*]]) {
+; CHECK-NEXT:  [[MBB:.*:]]
+; CHECK-NEXT:    switch i1 [[PRED]], label %[[MBB3932:.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       [[MBB3932]]:
+; CHECK-NEXT:    switch i1 [[PRED]], label %[[MBB4454:.*]] [
+; CHECK-NEXT:    ]
+; CHECK:       [[MBB4321:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = trunc i64 [[I5247]] to i32
+; CHECK-NEXT:    [[I5290:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT:    switch i1 [[I5290]], label %[[MBB3932]] [
+; CHECK-NEXT:      i1 false, label %[[MBB4321_TARGET_MBB5291:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[MBB4454]]:
+; CHECK-NEXT:    switch i1 [[I4530]], label %[[MBB4535:.*]] [
+; CHECK-NEXT:      i1 false, label %[[MBB4454_TARGET_MBB4454_TARGET_MBB4531:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[MBB4531:.*]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[MBB4535]]:
+; CHECK-NEXT:    switch i1 [[I4936_NOT]], label %[[MBB4535_TARGET_MBB4321:.*]] [
+; CHECK-NEXT:      i1 false, label %[[MBB4454]]
+; CHECK-NEXT:    ]
+; CHECK:       [[MBB5291:.*]]:
+; CHECK-NEXT:    [[I5293:%.*]] = insertvalue [2 x i32] zeroinitializer, i32 [[DOTMOVED:%.*]], 1
+; CHECK-NEXT:    store volatile [2 x i32] [[I5293]], ptr addrspace(5) null, align 4
+; CHECK-NEXT:    ret void
+; CHECK:       [[MBB4454_TARGET_MBB4531:.*]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD:.*]]
+; CHECK:       [[MBB4321_TARGET_MBB5291]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[LOOP_EXIT_GUARD]]:
+; CHECK-NEXT:    [[DOTMOVED]] = phi i32 [ poison, %[[MBB4454_TARGET_MBB4531]] ], [ [[TMP0]], %[[MBB4321_TARGET_MBB5291]] ]
+; CHECK-NEXT:    [[GUARD_MBB4531:%.*]] = phi i1 [ true, %[[MBB4454_TARGET_MBB4531]] ], [ false, %[[MBB4321_TARGET_MBB5291]] ]
+; CHECK-NEXT:    br i1 [[GUARD_MBB4531]], label %[[MBB4531]], label %[[MBB5291]]
+; CHECK:       [[MBB4454_TARGET_MBB4454_TARGET_MBB4531]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1:.*]]
+; CHECK:       [[MBB4535_TARGET_MBB4321]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD1]]
+; CHECK:       [[LOOP_EXIT_GUARD1]]:
+; CHECK-NEXT:    [[GUARD_MBB4454_TARGET_MBB4531:%.*]] = phi i1 [ true, %[[MBB4454_TARGET_MBB4454_TARGET_MBB4531]] ], [ false, %[[MBB4535_TARGET_MBB4321]] ]
+; CHECK-NEXT:    br i1 [[GUARD_MBB4454_TARGET_MBB4531]], label %[[MBB4454_TARGET_MBB4531]], label %[[MBB4321]]
+;
+mbb:
+  switch i1 %Pred, label %mbb3932 []
+
+mbb3932:                                           ; preds = %mbb4321, %mbb
+  switch i1 %Pred, label %mbb4454 []
+
+mbb4321:                                           ; preds = %mbb4535
+  %0 = trunc i64 %i5247 to i32
+  %i5290 = icmp eq i32 %0, 0
+  switch i1 %i5290, label %mbb3932 [ i1 0, label %mbb5291 ]
+
+mbb4454:                                           ; preds = %mbb4535, %mbb3932
+  switch i1 %i4530, label %mbb4535 [ i1 0, label %mbb4531 ]
+
+mbb4531:                                           ; preds = %mbb4454
+  ret void
+
+mbb4535:                                           ; preds = %mbb4454
+  switch i1 %i4936.not, label %mbb4321 [ i1 0, label %mbb4454 ]
+
+mbb5291:                                           ; preds = %mbb4321
+  %i5293 = insertvalue [2 x i32] zeroinitializer, i32 %0, 1
+  store volatile [2 x i32] %i5293, ptr addrspace(5) null, align 4
+  ret void
+}

>From 7d9078d3783a81ae3012001db59316f0327677ef Mon Sep 17 00:00:00 2001
From: Lukas <dev at lukas-hertel.de>
Date: Sun, 12 Jul 2026 20:17:41 +0200
Subject: [PATCH 3/5] Added tests for multiedges and fixed some naming

---
 llvm/lib/Transforms/Utils/BasicBlockUtils.cpp |  40 ++--
 llvm/lib/Transforms/Utils/UnifyLoopExits.cpp  |  12 +-
 .../Transforms/FixIrreducible/multiedge.ll    | 109 +++++++++++
 .../Transforms/UnifyLoopExits/multiedge.ll    | 171 ++++++++++++++++++
 4 files changed, 306 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index e12d1919e2f4f..5cbd7945cab11 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -703,31 +703,31 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
 }
 
 /// Helper function to update the cycle or loop information after inserting a
-/// new block between a callbr instruction and one of its target blocks.  Adds
-/// the new block to the innermost cycle or loop that the callbr instruction and
-/// the original target block share.
+/// new block between a callbr or switch instruction and one of its target
+/// blocks. Adds the new block to the innermost cycle or loop that the
+/// callbr/switch instruction and the original target block share.
 /// \p LCI            cycle or loop information to update
-/// \p CallBrBlock    block containing the callbr instruction
-/// \p CallBrTarget   new target block of the callbr instruction
-/// \p Succ           original target block of the callbr instruction
+/// \p MultiBrBlock   block containing the callbr/switch instruction
+/// \p BrTarget       new target block of the callbr/switch instruction
+/// \p Succ           original target block of the callbr/switch instruction
 template <typename TI, typename T>
-static bool updateCycleLoopInfo(TI *LCI, BasicBlock *CallBrBlock,
-                                BasicBlock *CallBrTarget, BasicBlock *Succ) {
+static bool updateCycleLoopInfo(TI *LCI, BasicBlock *MultiBrBlock,
+                                BasicBlock *BrTarget, BasicBlock *Succ) {
   static_assert(std::is_same_v<TI, CycleInfo> || std::is_same_v<TI, LoopInfo>,
                 "type must be CycleInfo or LoopInfo");
   if (!LCI)
     return false;
 
   if constexpr (std::is_same_v<TI, CycleInfo>) {
-    T LC = LCI->getSmallestCommonCycle(CallBrBlock, Succ);
+    T LC = LCI->getSmallestCommonCycle(MultiBrBlock, Succ);
     if (!LC)
       return false;
-    LCI->addBlockToCycle(CallBrTarget, LC);
+    LCI->addBlockToCycle(BrTarget, LC);
   } else {
-    T *LC = LCI->getSmallestCommonLoop(CallBrBlock, Succ);
+    T *LC = LCI->getSmallestCommonLoop(MultiBrBlock, Succ);
     if (!LC)
       return false;
-    LC->addBasicBlockToLoop(CallBrTarget, *LCI);
+    LC->addBasicBlockToLoop(BrTarget, *LCI);
   }
 
   return true;
@@ -745,7 +745,7 @@ BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
   if (UpdatedLI)
     *UpdatedLI = false;
 
-  bool ReusesCallBrTarget = BrTarget;
+  bool ReusesBrTarget = BrTarget;
 
   // Create a new block between terminator and the specified successor.
   // splitBlockBefore cannot be re-used here since it cannot split if the split
@@ -753,19 +753,19 @@ BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
   // handle that). But we don't need to rewire every part of a potential PHI
   // node. We only care about the edge between MultiBrBlock and the original
   // successor.
-  if (!ReusesCallBrTarget) {
+  if (!ReusesBrTarget) {
     BrTarget = BasicBlock::Create(MultiBrBlock->getContext(),
                                   MultiBrBlock->getName() + ".target." +
                                       Succ->getName(),
                                   MultiBrBlock->getParent());
     // Jump from the new target block to the original successor.
     UncondBrInst::Create(Succ, BrTarget);
-    // Replace a single incoming value with the callbr target block. We cannot
+    // Replace a single incoming value with the target block. We cannot
     // use replacePhiUsesWith, as this would replace the value for every edge
-    // from the callbr block to succ.
+    // from the MultiBrBlock to the successor.
     for (PHINode &PN : Succ->phis()) {
       int BBIdx = PN.getBasicBlockIndex(MultiBrBlock);
-      assert(BBIdx != -1 && "expected incoming value form callbr block");
+      assert(BBIdx != -1 && "expected incoming value form MultiBrBlock");
       PN.setIncomingBlock(BBIdx, BrTarget);
     }
 
@@ -779,16 +779,16 @@ BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
       PN.removeIncomingValue(MultiBrBlock, false);
   }
 
-  // Rewire control flow from callbr to the new target block.
+  // Rewire control flow from the MultiBrBlock to the new target block.
   Term->setSuccessor(SuccIdx, BrTarget);
 
   if (DTU) {
-    if (!ReusesCallBrTarget)
+    if (!ReusesBrTarget)
       DTU->applyUpdates({{DominatorTree::Insert, MultiBrBlock, BrTarget}});
     if (DTU->getDomTree().dominates(MultiBrBlock, Succ)) {
       if (!is_contained(successors(MultiBrBlock), Succ))
         DTU->applyUpdates({{DominatorTree::Delete, MultiBrBlock, Succ}});
-      if (!ReusesCallBrTarget)
+      if (!ReusesBrTarget)
         DTU->applyUpdates({{DominatorTree::Insert, BrTarget, Succ}});
     }
   }
diff --git a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
index 11a7d233d1bc0..81591423c1b76 100644
--- a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
+++ b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
@@ -257,12 +257,12 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
 
   // The guard blocks were created outside the loop, so they need to become
   // members of the parent loop.
-  // Same goes for the callbr target blocks.  Although we try to add them to the
-  // smallest common parent loop of the callbr block and the corresponding
-  // original target block, there might not have been such a loop, in which case
-  // the newly created callbr target blocks are not part of any loop. For nested
-  // loops, this might result in them leading to a loop with multiple entry
-  // points.
+  // Same goes for the callbr/switch target blocks. Although we try to add them
+  // to the smallest common parent loop of the branching block and the
+  // corresponding original target block, there might not have been such a loop,
+  // in which case the newly created target blocks are not part of any
+  // loop. For nested loops, this might result in them leading to a loop with
+  // multiple entry points.
   if (auto *ParentLoop = L->getParentLoop()) {
     for (auto *G : GuardBlocks) {
       ParentLoop->addBasicBlockToLoop(G, LI);
diff --git a/llvm/test/Transforms/FixIrreducible/multiedge.ll b/llvm/test/Transforms/FixIrreducible/multiedge.ll
index b61bfbdf814d2..6e92b4e7ad420 100644
--- a/llvm/test/Transforms/FixIrreducible/multiedge.ll
+++ b/llvm/test/Transforms/FixIrreducible/multiedge.ll
@@ -32,6 +32,42 @@ b:
   br label %a
 }
 
+define void @multiedge_external_switch(i32 %Pred) {
+; CHECK-LABEL: define void @multiedge_external_switch(
+; CHECK-SAME: i32 [[PRED:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 [[PRED]], label %[[ENTRY_TARGET_A:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_A]]
+; CHECK-NEXT:      i32 1, label %[[ENTRY_TARGET_B:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[A:.*]]:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 1, %[[B:.*]] ], [ [[PHI_MOVED:%.*]], %[[IRR_GUARD:.*]] ]
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[B]]:
+; CHECK-NEXT:    br label %[[A]]
+; CHECK:       [[ENTRY_TARGET_A]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[PHI_MOVED]] = phi i32 [ poison, %[[A]] ], [ 0, %[[ENTRY_TARGET_A]] ], [ poison, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, %[[A]] ], [ false, %[[ENTRY_TARGET_A]] ], [ true, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B]], label %[[B]], label %[[A]]
+;
+entry:
+  switch i32 %Pred, label %a [
+  i32 0, label %a
+  i32 1, label %b
+  ]
+
+a:
+  %phi = phi i32 [ 0, %entry ], [ 0, %entry ], [ 1, %b ]
+  br label %b
+
+b:
+  br label %a
+}
+
 define void @multiedge_internal_callbr() {
 ; CHECK-LABEL: define void @multiedge_internal_callbr() {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
@@ -59,6 +95,36 @@ b:
   br label %a
 }
 
+define void @multiedge_internal_switch() {
+; CHECK-LABEL: define void @multiedge_internal_switch() {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD:.*]]
+; CHECK:       [[A:.*]]:
+; CHECK-NEXT:    switch i32 0, label %[[A_TARGET_B:.*]] [
+; CHECK-NEXT:      i32 0, label %[[A_TARGET_B]]
+; CHECK-NEXT:    ]
+; CHECK:       [[B:.*]]:
+; CHECK-NEXT:    br label %[[A]]
+; CHECK:       [[A_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[PHI_MOVED:%.*]] = phi i1 [ true, %[[A_TARGET_B]] ], [ false, %[[ENTRY]] ]
+; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, %[[A_TARGET_B]] ], [ true, %[[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B]], label %[[B]], label %[[A]]
+;
+entry:
+  br i1 false, label %a, label %b
+
+a:
+  switch i32 0, label %b [
+  i32 0, label %b
+  ]
+
+b:
+  %phi = phi i1 [ false, %entry ], [ true, %a ], [ true, %a ]
+  br label %a
+}
+
 define void @multiedge_both_callbr() {
 ; CHECK-LABEL: define void @multiedge_both_callbr() {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
@@ -93,3 +159,46 @@ b:
   %phi.b = phi i32 [ 2, %entry ], [ 3, %a ], [ 3, %a ]
   br label %a
 }
+
+define void @multiedge_both_switch() {
+; CHECK-LABEL: define void @multiedge_both_switch() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    switch i32 0, label %[[ENTRY_TARGET_A:.*]] [
+; CHECK-NEXT:      i32 0, label %[[ENTRY_TARGET_A]]
+; CHECK-NEXT:      i32 1, label %[[ENTRY_TARGET_B:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[A:.*]]:
+; CHECK-NEXT:    [[PHI_A:%.*]] = phi i32 [ 1, %[[B:.*]] ], [ [[PHI_A_MOVED:%.*]], %[[IRR_GUARD:.*]] ]
+; CHECK-NEXT:    switch i32 0, label %[[A_TARGET_B:.*]] [
+; CHECK-NEXT:      i32 0, label %[[A_TARGET_B]]
+; CHECK-NEXT:    ]
+; CHECK:       [[B]]:
+; CHECK-NEXT:    br label %[[A]]
+; CHECK:       [[A_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_A]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[ENTRY_TARGET_B]]:
+; CHECK-NEXT:    br label %[[IRR_GUARD]]
+; CHECK:       [[IRR_GUARD]]:
+; CHECK-NEXT:    [[PHI_A_MOVED]] = phi i32 [ poison, %[[A_TARGET_B]] ], [ 0, %[[ENTRY_TARGET_A]] ], [ poison, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    [[PHI_B_MOVED:%.*]] = phi i32 [ 3, %[[A_TARGET_B]] ], [ poison, %[[ENTRY_TARGET_A]] ], [ 2, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    [[GUARD_B:%.*]] = phi i1 [ true, %[[A_TARGET_B]] ], [ false, %[[ENTRY_TARGET_A]] ], [ true, %[[ENTRY_TARGET_B]] ]
+; CHECK-NEXT:    br i1 [[GUARD_B]], label %[[B]], label %[[A]]
+;
+entry:
+  switch i32 0, label %a [
+  i32 0, label %a
+  i32 1, label %b
+  ]
+
+a:
+  %phi.a = phi i32 [ 0, %entry ], [ 0, %entry ], [ 1, %b ]
+  switch i32 0, label %b [
+  i32 0, label %b
+  ]
+
+b:
+  %phi.b = phi i32 [ 2, %entry ], [ 3, %a ], [ 3, %a ]
+  br label %a
+}
diff --git a/llvm/test/Transforms/UnifyLoopExits/multiedge.ll b/llvm/test/Transforms/UnifyLoopExits/multiedge.ll
index 2061a9aac042e..8b854ff769981 100644
--- a/llvm/test/Transforms/UnifyLoopExits/multiedge.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/multiedge.ll
@@ -63,6 +63,79 @@ exit:
   ret void
 }
 
+define void @loop_1_switch(i1 %PredEntry, i32 %PredB, i32 %PredC, i32 %PredD) {
+; CHECK-LABEL: define void @loop_1_switch(
+; CHECK-SAME: i1 [[PREDENTRY:%.*]], i32 [[PREDB:%.*]], i32 [[PREDC:%.*]], i32 [[PREDD:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 [[PREDENTRY]], label %[[A:.*]], label %[[G:.*]]
+; CHECK:       [[A]]:
+; CHECK-NEXT:    br label %[[B:.*]]
+; CHECK:       [[B]]:
+; CHECK-NEXT:    switch i32 [[PREDB]], label %[[C:.*]] [
+; CHECK-NEXT:      i32 0, label %[[B_TARGET_E:.*]]
+; CHECK-NEXT:      i32 1, label %[[B_TARGET_E]]
+; CHECK-NEXT:    ]
+; CHECK:       [[C]]:
+; CHECK-NEXT:    switch i32 [[PREDC]], label %[[D:.*]] [
+; CHECK-NEXT:      i32 0, label %[[C_TARGET_F:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[D]]:
+; CHECK-NEXT:    switch i32 [[PREDD]], label %[[A]] [
+; CHECK-NEXT:      i32 0, label %[[D_TARGET_F:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[E:.*]]:
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[F:.*]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[G]]:
+; CHECK-NEXT:    br label %[[F]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[B_TARGET_E]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD:.*]]
+; CHECK:       [[C_TARGET_F]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[D_TARGET_F]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[LOOP_EXIT_GUARD]]:
+; CHECK-NEXT:    [[GUARD_E:%.*]] = phi i1 [ true, %[[B_TARGET_E]] ], [ false, %[[C_TARGET_F]] ], [ false, %[[D_TARGET_F]] ]
+; CHECK-NEXT:    br i1 [[GUARD_E]], label %[[E]], label %[[F]]
+;
+entry:
+  br i1 %PredEntry, label %A, label %G
+
+A:
+  br label %B
+
+B:
+  switch i32 %PredB, label %C [
+  i32 0, label %E
+  i32 1, label %E
+  ]
+
+C:
+  switch i32 %PredC, label %D [
+  i32 0, label %F
+  ]
+
+D:
+  switch i32 %PredD, label %A [
+  i32 0, label %F
+  ]
+
+E:
+  br label %exit
+
+F:
+  br label %exit
+
+G:
+  br label %F
+
+exit:
+  ret void
+}
+
 define void @multiedge_both_callbr(i1 %Pred) {
 ; CHECK-LABEL: define void @multiedge_both_callbr(
 ; CHECK-SAME: i1 [[PRED:%.*]]) {
@@ -96,6 +169,47 @@ exit:
   ret void
 }
 
+define void @multiedge_both_switch(i32 %Pred) {
+; CHECK-LABEL: define void @multiedge_both_switch(
+; CHECK-SAME: i32 [[PRED:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    switch i32 [[PRED]], label %[[LOOP_NEXT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[LOOP_NEXT]]
+; CHECK-NEXT:    ]
+; CHECK:       [[LOOP_NEXT]]:
+; CHECK-NEXT:    [[PHI_INTERNAL:%.*]] = phi i32 [ 1, %[[LOOP]] ], [ 1, %[[LOOP]] ]
+; CHECK-NEXT:    switch i32 [[PRED]], label %[[LOOP]] [
+; CHECK-NEXT:      i32 0, label %[[LOOP_NEXT_TARGET_EXIT:.*]]
+; CHECK-NEXT:      i32 1, label %[[LOOP_NEXT_TARGET_EXIT]]
+; CHECK-NEXT:    ]
+; CHECK:       [[EXIT:.*]]:
+; CHECK-NEXT:    [[PHI_EXTERNAL:%.*]] = phi i32 [ 2, %[[LOOP_NEXT_TARGET_EXIT]] ]
+; CHECK-NEXT:    ret void
+; CHECK:       [[LOOP_NEXT_TARGET_EXIT]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+;
+entry:
+  br label %loop
+
+loop:
+  switch i32 %Pred, label %loop.next [
+  i32 0, label %loop.next
+  ]
+
+loop.next:
+  %phi.internal = phi i32 [ 1, %loop ], [ 1, %loop ]
+  switch i32 %Pred, label %loop [
+  i32 0, label %exit
+  i32 1, label %exit
+  ]
+
+exit:
+  %phi.external = phi i32 [ 2, %loop.next ], [ 2, %loop.next ]
+  ret void
+}
+
 define i32 @multiedge_restore_ssa_callbr() {
 ; CHECK-LABEL: define i32 @multiedge_restore_ssa_callbr() {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
@@ -142,3 +256,60 @@ exit1:                                            ; preds = %second_exiting, %he
   %use1 = or i32 %val, 0
   ret i32 0
 }
+
+define i32 @multiedge_restore_ssa_switch() {
+; CHECK-LABEL: define i32 @multiedge_restore_ssa_switch() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[HEADER:.*]]
+; CHECK:       [[HEADER]]:
+; CHECK-NEXT:    [[VAL:%.*]] = add i32 0, 0
+; CHECK-NEXT:    switch i32 0, label %[[HEADER_TARGET_EXIT1:.*]] [
+; CHECK-NEXT:      i32 0, label %[[HEADER_TARGET_COMMON_RET:.*]]
+; CHECK-NEXT:      i32 1, label %[[SECOND_EXITING:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[SECOND_EXITING]]:
+; CHECK-NEXT:    switch i32 0, label %[[HEADER]] [
+; CHECK-NEXT:      i32 0, label %[[SECOND_EXITING_TARGET_EXIT1:.*]]
+; CHECK-NEXT:      i32 1, label %[[SECOND_EXITING_TARGET_COMMON_RET:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[COMMON_RET:.*]]:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       [[EXIT1:.*]]:
+; CHECK-NEXT:    [[USE1:%.*]] = or i32 [[VAL_MOVED:%.*]], 0
+; CHECK-NEXT:    ret i32 0
+; CHECK:       [[HEADER_TARGET_EXIT1]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD:.*]]
+; CHECK:       [[HEADER_TARGET_COMMON_RET]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[SECOND_EXITING_TARGET_EXIT1]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[SECOND_EXITING_TARGET_COMMON_RET]]:
+; CHECK-NEXT:    br label %[[LOOP_EXIT_GUARD]]
+; CHECK:       [[LOOP_EXIT_GUARD]]:
+; CHECK-NEXT:    [[VAL_MOVED]] = phi i32 [ [[VAL]], %[[HEADER_TARGET_EXIT1]] ], [ [[VAL]], %[[SECOND_EXITING_TARGET_EXIT1]] ], [ [[VAL]], %[[HEADER_TARGET_COMMON_RET]] ], [ [[VAL]], %[[SECOND_EXITING_TARGET_COMMON_RET]] ]
+; CHECK-NEXT:    [[GUARD_EXIT1:%.*]] = phi i1 [ true, %[[HEADER_TARGET_EXIT1]] ], [ false, %[[HEADER_TARGET_COMMON_RET]] ], [ true, %[[SECOND_EXITING_TARGET_EXIT1]] ], [ false, %[[SECOND_EXITING_TARGET_COMMON_RET]] ]
+; CHECK-NEXT:    br i1 [[GUARD_EXIT1]], label %[[EXIT1]], label %[[COMMON_RET]]
+;
+entry:
+  br label %header
+
+header:                                           ; preds = %second_exiting, %entry
+  %val = add i32 0, 0
+  switch i32 0, label %exit1 [
+  i32 0, label %common.ret
+  i32 1, label %second_exiting
+  ]
+
+second_exiting:                                   ; preds = %header
+  switch i32 0, label %header [
+  i32 0, label %exit1
+  i32 1, label %common.ret
+  ]
+
+common.ret:                                       ; preds = %second_exiting, %header
+  ret i32 0
+
+exit1:                                            ; preds = %second_exiting, %header
+  %use1 = or i32 %val, 0
+  ret i32 0
+}

>From 26db602c25505427be581ce38659069b9dacad1c Mon Sep 17 00:00:00 2001
From: Lukas <dev at lukas-hertel.de>
Date: Sun, 12 Jul 2026 21:46:25 +0200
Subject: [PATCH 4/5] Remove multiedge in unify loop exits test

---
 llvm/test/Transforms/UnifyLoopExits/basic.ll | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/llvm/test/Transforms/UnifyLoopExits/basic.ll b/llvm/test/Transforms/UnifyLoopExits/basic.ll
index 461bd3ee9c23d..a6f8c5635439f 100644
--- a/llvm/test/Transforms/UnifyLoopExits/basic.ll
+++ b/llvm/test/Transforms/UnifyLoopExits/basic.ll
@@ -398,14 +398,12 @@ define void @switch_duplicate_successors(i1 %Pred) {
 ; CHECK:       loop:
 ; CHECK-NEXT:    switch i1 [[PRED:%.*]], label [[LOOP_TARGET_EXIT:%.*]] [
 ; CHECK-NEXT:      i1 false, label [[LOOP]]
-; CHECK-NEXT:      i1 true, label [[LOOP_TARGET_EXIT1:%.*]]
+; CHECK-NEXT:      i1 true, label [[LOOP_TARGET_EXIT]]
 ; CHECK-NEXT:    ]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
 ; CHECK:       loop.target.exit:
 ; CHECK-NEXT:    br label [[EXIT:%.*]]
-; CHECK:       loop.target.exit1:
-; CHECK-NEXT:    br label [[EXIT]]
 ;
 entry:
   br label %loop

>From 9704bf275793e87d52d394c91565172ed671ef6c Mon Sep 17 00:00:00 2001
From: Lukas <dev at lukas-hertel.de>
Date: Wed, 15 Jul 2026 21:59:19 +0200
Subject: [PATCH 5/5] address feedback: typos, hoist term initialization,
 llvm_unreachable

---
 llvm/lib/Transforms/Utils/BasicBlockUtils.cpp |  6 ++++--
 llvm/lib/Transforms/Utils/FixIrreducible.cpp  | 20 ++++++++----------
 llvm/lib/Transforms/Utils/UnifyLoopExits.cpp  | 21 ++++++++++---------
 llvm/test/Transforms/FixIrreducible/switch.ll | 14 ++++++-------
 4 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index 5cbd7945cab11..5ea4e21e5919c 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -738,7 +738,9 @@ BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
                                    DomTreeUpdater *DTU, CycleInfo *CI,
                                    LoopInfo *LI, bool *UpdatedLI) {
   Instruction *Term = MultiBrBlock->getTerminator();
-  assert(Term && "expected terminator");
+  assert((isa_and_present<SwitchInst>(Term) ||
+          isa_and_present<CallBrInst>(Term)) &&
+         "expected callbr or switch terminator");
   assert(SuccIdx < Term->getNumSuccessors() &&
          Succ == Term->getSuccessor(SuccIdx) && "invalid successor index");
 
@@ -765,7 +767,7 @@ BasicBlock *llvm::SplitMultiBrEdge(BasicBlock *MultiBrBlock, BasicBlock *Succ,
     // from the MultiBrBlock to the successor.
     for (PHINode &PN : Succ->phis()) {
       int BBIdx = PN.getBasicBlockIndex(MultiBrBlock);
-      assert(BBIdx != -1 && "expected incoming value form MultiBrBlock");
+      assert(BBIdx != -1 && "expected incoming value from MultiBrBlock");
       PN.setIncomingBlock(BBIdx, BrTarget);
     }
 
diff --git a/llvm/lib/Transforms/Utils/FixIrreducible.cpp b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
index c4f7460ef0c98..23f458c4a8991 100644
--- a/llvm/lib/Transforms/Utils/FixIrreducible.cpp
+++ b/llvm/lib/Transforms/Utils/FixIrreducible.cpp
@@ -292,13 +292,14 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
   }
 
   for (BasicBlock *P : Predecessors) {
-    if (isa<UncondBrInst>(P->getTerminator())) {
-      assert(P->getTerminator()->getSuccessor(0) == Header);
+    Instruction *Term = P->getTerminator();
+    if (isa<UncondBrInst>(Term)) {
+      assert(Term->getSuccessor(0) == Header);
       CHub.addBranch(P, Header);
 
       LLVM_DEBUG(dbgs() << "Added internal branch: " << printBasicBlock(P)
                         << " -> " << printBasicBlock(Header) << '\n');
-    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(P->getTerminator())) {
+    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(Term)) {
       BasicBlock *Succ0 = Branch->getSuccessor(0) == Header ? Header : nullptr;
       BasicBlock *Succ1 = Branch->getSuccessor(1) == Header ? Header : nullptr;
       assert(Succ0 || Succ1);
@@ -308,10 +309,8 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (isa<CallBrInst>(P->getTerminator()) ||
-               isa<SwitchInst>(P->getTerminator())) {
+    } else if (isa<CallBrInst>(Term) || isa<SwitchInst>(Term)) {
       BasicBlock *NewSucc = nullptr;
-      Instruction *Term = P->getTerminator();
       for (unsigned I = 0; I < Term->getNumSuccessors(); ++I) {
         BasicBlock *Succ = Term->getSuccessor(I);
         if (Succ != Header)
@@ -340,14 +339,15 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
   }
 
   for (BasicBlock *P : Predecessors) {
-    if (UncondBrInst *Branch = dyn_cast<UncondBrInst>(P->getTerminator())) {
+    Instruction *Term = P->getTerminator();
+    if (UncondBrInst *Branch = dyn_cast<UncondBrInst>(Term)) {
       BasicBlock *Succ0 = Branch->getSuccessor();
       Succ0 = CI.contains(C, Succ0) ? Succ0 : nullptr;
       CHub.addBranch(P, Succ0);
 
       LLVM_DEBUG(dbgs() << "Added external branch: " << printBasicBlock(P)
                         << " -> " << printBasicBlock(Succ0) << '\n');
-    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(P->getTerminator())) {
+    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(Term)) {
       BasicBlock *Succ0 = Branch->getSuccessor(0);
       Succ0 = CI.contains(C, Succ0) ? Succ0 : nullptr;
       BasicBlock *Succ1 = Branch->getSuccessor(1);
@@ -358,10 +358,8 @@ static bool fixIrreducible(CycleRef C, CycleInfo &CI, DominatorTree &DT,
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (isa<CallBrInst>(P->getTerminator()) ||
-               isa<SwitchInst>(P->getTerminator())) {
+    } else if (isa<CallBrInst>(Term) || isa<SwitchInst>(Term)) {
       SmallDenseMap<BasicBlock *, BasicBlock *> MultiBrTargets;
-      Instruction *Term = P->getTerminator();
       for (unsigned I = 0; I < Term->getNumSuccessors(); ++I) {
         BasicBlock *Succ = Term->getSuccessor(I);
         if (!CI.contains(C, Succ))
diff --git a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
index 81591423c1b76..ad90480a1136c 100644
--- a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
+++ b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
@@ -170,14 +170,15 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
   unsigned NumExitingBlocks = ExitingBlocks.size();
   for (unsigned I = 0; I < NumExitingBlocks; ++I) {
     BasicBlock *BB = ExitingBlocks[I];
-    if (UncondBrInst *Branch = dyn_cast<UncondBrInst>(BB->getTerminator())) {
+    Instruction *Term = BB->getTerminator();
+    if (UncondBrInst *Branch = dyn_cast<UncondBrInst>(Term)) {
       BasicBlock *Succ0 = Branch->getSuccessor(0);
       Succ0 = L->contains(Succ0) ? nullptr : Succ0;
       CHub.addBranch(BB, Succ0);
 
-      LLVM_DEBUG(dbgs() << "Added extiting branch: " << printBasicBlock(BB)
+      LLVM_DEBUG(dbgs() << "Added exiting branch: " << printBasicBlock(BB)
                         << " -> " << printBasicBlock(Succ0) << '\n');
-    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(BB->getTerminator())) {
+    } else if (CondBrInst *Branch = dyn_cast<CondBrInst>(Term)) {
       BasicBlock *Succ0 = Branch->getSuccessor(0);
       Succ0 = L->contains(Succ0) ? nullptr : Succ0;
 
@@ -185,14 +186,12 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
       Succ1 = L->contains(Succ1) ? nullptr : Succ1;
       CHub.addBranch(BB, Succ0, Succ1);
 
-      LLVM_DEBUG(dbgs() << "Added extiting branch: " << printBasicBlock(BB)
+      LLVM_DEBUG(dbgs() << "Added exiting branch: " << printBasicBlock(BB)
                         << " -> " << printBasicBlock(Succ0)
                         << (Succ0 && Succ1 ? " " : "") << printBasicBlock(Succ1)
                         << '\n');
-    } else if (isa<CallBrInst>(BB->getTerminator()) ||
-               isa<SwitchInst>(BB->getTerminator())) {
+    } else if (isa<CallBrInst>(Term) || isa<SwitchInst>(Term)) {
       SmallDenseMap<BasicBlock *, BasicBlock *> BrTargets;
-      Instruction *Term = BB->getTerminator();
       for (unsigned J = 0; J < Term->getNumSuccessors(); ++J) {
         BasicBlock *Succ = Term->getSuccessor(J);
         if (L->contains(Succ))
@@ -205,7 +204,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
                                                &DTU, nullptr, &LI, &UpdatedLI);
 
         if (!ExistingTarget) {
-          // SplitMutliBrEdge modifies the CFG because it creates an
+          // SplitMultiBrEdge modifies the CFG because it creates an
           // intermediate block. So we need to set the changed flag no matter
           // what the ControlFlowHub is going to do later.
           Changed = true;
@@ -219,7 +218,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
           // predecessors of the guard blocks, which, in the case of callbr or
           // switch terminator, are the new intermediate target blocks instead
           // of themselves. If only one exiting block is generated, the
-          // branchning block itself is overwritten, while further blocks are
+          // branching block itself is overwritten, while further blocks are
           // appended as additional exiting blocks.
           if (BrTargets.empty())
             ExitingBlocks[I] = NewSucc;
@@ -233,7 +232,9 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) {
                           << printBasicBlock(Succ) << '\n');
       }
     } else {
-      llvm_unreachable("unsupported block terminator");
+      reportFatalUsageError(
+          "unsupported block terminator: unify-loop-exits "
+          "only supports br, callbr, and switch instructions");
     }
   }
 
diff --git a/llvm/test/Transforms/FixIrreducible/switch.ll b/llvm/test/Transforms/FixIrreducible/switch.ll
index 0da0a0d28735c..39c80e3171bb7 100644
--- a/llvm/test/Transforms/FixIrreducible/switch.ll
+++ b/llvm/test/Transforms/FixIrreducible/switch.ll
@@ -27,7 +27,7 @@
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(indirect1 indirect fallthrough)
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(indirect fallthrough)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_entry_multiple_targets1
-; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) indirect1 indirect fallthrough irr.guard1 irr.guard2
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) indirect1 indirect fallthrough irr.guard2 irr.guard1
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) indirect fallthrough
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_header_no_indirect
@@ -65,7 +65,7 @@
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(switch_header) switch_regular mid
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(switch_regular mid)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_header_and_regular
-; CYCLES-AFTER-NEXT:     depth=1: entries(switch_header) switch_regular mid switch_header.target.mid switch_header.target.switch_regular irr.guard
+; CYCLES-AFTER-NEXT:     depth=1: entries(switch_header) switch_regular mid irr.guard switch_header.target.mid switch_header.target.switch_regular
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard) switch_regular mid
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_only
@@ -77,7 +77,7 @@
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(sw2 block block1)
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(block block1)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: entry_multiple_switch
-; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw2 block block1 irr.guard1 sw2.target.block1 sw2.target.block irr.guard2
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw2 block block1 irr.guard2 irr.guard1 sw2.target.block1 sw2.target.block
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) block block1
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_exit_with_separate_entries
@@ -96,21 +96,21 @@
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(sw3 sw1 sw2)
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(sw1 sw2)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_only_multiple
-; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw3 sw1 sw2 sw2.target.sw3 sw1.target.sw3 irr.guard1 sw2.target.sw1 sw3.target.sw1 irr.guard2
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) sw3 sw1 sw2 sw2.target.sw1 irr.guard2 sw2.target.sw3 sw1.target.sw3 irr.guard1 sw3.target.sw1
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) sw1 sw2 sw2.target.sw1
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_bypass
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(l1 sw) l2
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(sw l2)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_bypass
-; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l1 sw l2 sw.target.l1 irr.guard1
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l1 sw l2 irr.guard1 sw.target.l1
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard1) sw l2
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_multiple_with_exit
 ; CYCLES-BEFORE-NEXT:    depth=1: entries(l3 l1 l2)
 ; CYCLES-BEFORE-NEXT:        depth=2: entries(l1 l2)
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_multiple_with_exit
-; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l3 l1 l2 irr.guard1 irr.guard2
+; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) l3 l1 l2 irr.guard2 irr.guard1
 ; CYCLES-AFTER-NEXT:         depth=2: entries(irr.guard2) l1 l2
 ;
 ; CYCLES-BEFORE-NEXT: CycleInfo for function: switch_nested
@@ -119,7 +119,7 @@
 ; CYCLES-AFTER-NEXT:  CycleInfo for function: switch_nested
 ; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard) bb bh
 ; CYCLES-AFTER-NEXT:     depth=1: entries(irr.guard1) b h
-;
+
 define void @loop_1(i32 %Value, i1 %PredEntry, i1 %PredD) {
 ; CHECK-LABEL: define void @loop_1(
 ; CHECK-SAME: i32 [[VALUE:%.*]], i1 [[PREDENTRY:%.*]], i1 [[PREDD:%.*]]) {



More information about the llvm-commits mailing list