[llvm] 9d2e7e6 - [FixIrreducible][UnifyLoopExits] Support switch statements (#206567)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 19 23:39:47 PDT 2026
Author: Lukas
Date: 2026-07-20T08:39:42+02:00
New Revision: 9d2e7e6836beadbe63380f64c716df2c086ff2ea
URL: https://github.com/llvm/llvm-project/commit/9d2e7e6836beadbe63380f64c716df2c086ff2ea
DIFF: https://github.com/llvm/llvm-project/commit/9d2e7e6836beadbe63380f64c716df2c086ff2ea.diff
LOG: [FixIrreducible][UnifyLoopExits] Support switch statements (#206567)
This builds on #149308, which implemented `callbr` support.
The same approach of splitting multi-branch edges entering irreducible
loops can be used for switches. It does not introduce any new switch
statements, but alleviates the requirement of having to run the
`LowerSwitch` pass first. This makes the pass usable for users other
than AMDGPU, which can handle switch statements (e.g., WebAssembly, see
[here](https://github.com/llvm/llvm-project/pull/181755#issuecomment-3936316307)).
I'm also implementing a flag into the `ControlFlowHub` to support
switches as well, for which I will open a separate PR. Currently the
`ControlFlowHub` creates a branch-sled, mimicking a `switch` (a series
of blocks consisting only of conditional branches, selectively entering
an irreducible loop at a certain point or continuing to the next
potential entry point). If the target can support switches, that should
be the clear goal here, as shown in the image below. This PR implements
the step from (a) to (b), whereas extending the `ControlFlowHub`
represents the step from (b) to (c). ((c) to (d) already exists through
`SwitchToLookup` and `SwitchToArithmetic`).
<img width="1055" height="432" alt="image"
src="https://github.com/user-attachments/assets/780b7894-1895-4137-8148-b2bbc7f73a8f"
/>
The test cases in `switch.ll` were adapted from the `callbr.ll` tests
using an LLM to ensure equivalent coverage. I've manually reviewed the
control flow and conditions for every case, and the final assertions
were generated using `update_test_checks.py`.
Added:
Modified:
llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
llvm/lib/Transforms/Utils/FixIrreducible.cpp
llvm/lib/Transforms/Utils/UnifyLoopExits.cpp
llvm/test/Transforms/FixIrreducible/bug45623.ll
llvm/test/Transforms/FixIrreducible/multiedge.ll
llvm/test/Transforms/FixIrreducible/nested.ll
llvm/test/Transforms/FixIrreducible/switch.ll
llvm/test/Transforms/FixIrreducible/unreachable.ll
llvm/test/Transforms/FixIrreducible/unsupported-terminator.ll
llvm/test/Transforms/UnifyLoopExits/basic.ll
llvm/test/Transforms/UnifyLoopExits/integer_guards.ll
llvm/test/Transforms/UnifyLoopExits/multiedge.ll
llvm/test/Transforms/UnifyLoopExits/nested.ll
llvm/test/Transforms/UnifyLoopExits/restore-ssa.ll
llvm/test/Transforms/UnifyLoopExits/switch.ll
llvm/test/Transforms/UnifyLoopExits/undef-phis.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
index 3088b96bf7a32..7503248046395 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 or switch edge.
///
-/// 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..5ea4e21e5919c 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -703,97 +703,99 @@ 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;
}
-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((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");
if (UpdatedLI)
*UpdatedLI = false;
- bool ReusesCallBrTarget = CallBrTarget;
- // Create a new block between callbr and the specified successor.
+ 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
// 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());
+ 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, CallBrTarget);
- // Replace a single incoming value with the callbr target block. We cannot
+ UncondBrInst::Create(Succ, BrTarget);
+ // 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(CallBrBlock);
- assert(BBIdx != -1 && "expected incoming value form callbr block");
- PN.setIncomingBlock(BBIdx, CallBrTarget);
+ int BBIdx = PN.getBasicBlockIndex(MultiBrBlock);
+ assert(BBIdx != -1 && "expected incoming value from MultiBrBlock");
+ 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);
+ // Rewire control flow from the MultiBrBlock to the new target block.
+ 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}});
- if (!ReusesCallBrTarget)
- DTU->applyUpdates({{DominatorTree::Insert, CallBrTarget, Succ}});
+ 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 (!ReusesBrTarget)
+ 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..23f458c4a8991 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"
@@ -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,13 +309,13 @@ 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>(Term) || isa<SwitchInst>(Term)) {
BasicBlock *NewSucc = nullptr;
- for (unsigned I = 0; I < CallBr->getNumSuccessors(); ++I) {
- BasicBlock *Succ = CallBr->getSuccessor(I);
+ 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 +323,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");
}
}
@@ -337,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);
@@ -355,31 +358,30 @@ 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>(Term) || isa<SwitchInst>(Term)) {
+ SmallDenseMap<BasicBlock *, BasicBlock *> MultiBrTargets;
+ 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..ad90480a1136c 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;
@@ -169,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;
@@ -184,52 +186,55 @@ 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 (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>(Term) || isa<SwitchInst>(Term)) {
+ SmallDenseMap<BasicBlock *, BasicBlock *> BrTargets;
+ 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.
+ // 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;
- // 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
+ // branching 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) << " -> "
<< printBasicBlock(Succ) << '\n');
}
} else {
- llvm_unreachable("unsupported block terminator");
+ reportFatalUsageError(
+ "unsupported block terminator: unify-loop-exits "
+ "only supports br, callbr, and switch instructions");
}
}
@@ -253,17 +258,17 @@ 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);
}
- for (auto *C : CallBrTargetBlocksToFix) {
+ for (auto *C : MultiBrTargetBlocksToFix) {
ParentLoop->addBasicBlockToLoop(C, LI);
}
ParentLoop->verifyLoop();
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/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/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/switch.ll b/llvm/test/Transforms/FixIrreducible/switch.ll
index 4d3d9498b284d..39c80e3171bb7 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.guard2 irr.guard1
+; 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 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
+; 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.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
+; 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.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 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.guard2 irr.guard1
+; 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/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 f1be342c3d324..80711a8ddaedf 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
}
diff --git a/llvm/test/Transforms/UnifyLoopExits/basic.ll b/llvm/test/Transforms/UnifyLoopExits/basic.ll
index 5771453574626..a6f8c5635439f 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,30 @@ 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_EXIT]]
+; CHECK-NEXT: ]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+; CHECK: loop.target.exit:
+; 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/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
+}
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
+}
More information about the llvm-commits
mailing list