[LoopSimplifyCFG] Delete dead exiting edges

This patch teaches LoopSimplifyCFG to remove dead exiting edges
from loops.

Differential Revision: https://reviews.llvm.org/D54025
Reviewed By: fedor.sergeev

llvm-svn: 350049
This commit is contained in:
Max Kazantsev 2018-12-24 07:41:33 +00:00
parent e20bf9ab91
commit edabb9ae56
2 changed files with 195 additions and 114 deletions

View File

@ -48,6 +48,8 @@ STATISTIC(NumTerminatorsFolded,
"Number of terminators folded to unconditional branches");
STATISTIC(NumLoopBlocksDeleted,
"Number of loop blocks deleted");
STATISTIC(NumLoopExitsDeleted,
"Number of loop exiting edges deleted");
/// If \p BB is a switch or a conditional branch, but only one of its successors
/// can be reached from this block in runtime, return this successor. Otherwise,
@ -271,6 +273,114 @@ private:
"All blocks that stay in loop should be live!");
}
/// We need to preserve static reachibility of all loop exit blocks (this is)
/// required by loop pass manager. In order to do it, we make the following
/// trick:
///
/// preheader:
/// <preheader code>
/// br label %loop_header
///
/// loop_header:
/// ...
/// br i1 false, label %dead_exit, label %loop_block
/// ...
///
/// We cannot simply remove edge from the loop to dead exit because in this
/// case dead_exit (and its successors) may become unreachable. To avoid that,
/// we insert the following fictive preheader:
///
/// preheader:
/// <preheader code>
/// switch i32 0, label %preheader-split,
/// [i32 1, label %dead_exit_1],
/// [i32 2, label %dead_exit_2],
/// ...
/// [i32 N, label %dead_exit_N],
///
/// preheader-split:
/// br label %loop_header
///
/// loop_header:
/// ...
/// br i1 false, label %dead_exit_N, label %loop_block
/// ...
///
/// Doing so, we preserve static reachibility of all dead exits and can later
/// remove edges from the loop to these blocks.
void handleDeadExits() {
// If no dead exits, nothing to do.
if (DeadExitBlocks.empty())
return;
// Construct split preheader and the dummy switch to thread edges from it to
// dead exits.
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
BasicBlock *Preheader = L.getLoopPreheader();
BasicBlock *NewPreheader = Preheader->splitBasicBlock(
Preheader->getTerminator(),
Twine(Preheader->getName()).concat("-split"));
DTU.deleteEdge(Preheader, L.getHeader());
DTU.insertEdge(NewPreheader, L.getHeader());
DTU.insertEdge(Preheader, NewPreheader);
IRBuilder<> Builder(Preheader->getTerminator());
SwitchInst *DummySwitch =
Builder.CreateSwitch(Builder.getInt32(0), NewPreheader);
Preheader->getTerminator()->eraseFromParent();
unsigned DummyIdx = 1;
for (BasicBlock *BB : DeadExitBlocks) {
SmallVector<Instruction *, 4> DeadPhis;
for (auto &PN : BB->phis())
DeadPhis.push_back(&PN);
// Eliminate all Phis from dead exits.
for (Instruction *PN : DeadPhis) {
PN->replaceAllUsesWith(UndefValue::get(PN->getType()));
PN->eraseFromParent();
}
assert(DummyIdx != 0 && "Too many dead exits!");
DummySwitch->addCase(Builder.getInt32(DummyIdx++), BB);
DTU.insertEdge(Preheader, BB);
++NumLoopExitsDeleted;
}
assert(L.getLoopPreheader() == NewPreheader && "Malformed CFG?");
if (Loop *OuterLoop = LI.getLoopFor(Preheader)) {
OuterLoop->addBasicBlockToLoop(NewPreheader, LI);
// When we break dead edges, the outer loop may become unreachable from
// the current loop. We need to fix loop info accordingly. For this, we
// find the most nested loop that still contains L and remove L from all
// loops that are inside of it.
Loop *StillReachable = nullptr;
for (BasicBlock *BB : LiveExitBlocks) {
Loop *BBL = LI.getLoopFor(BB);
if (BBL && BBL->contains(L.getHeader()))
if (!StillReachable ||
BBL->getLoopDepth() > StillReachable->getLoopDepth())
StillReachable = BBL;
}
// Okay, our loop is no longer in the outer loop (and maybe not in some of
// its parents as well). Make the fixup.
if (StillReachable != OuterLoop) {
LI.changeLoopFor(NewPreheader, StillReachable);
for (Loop *NotContaining = OuterLoop; NotContaining != StillReachable;
NotContaining = NotContaining->getParentLoop()) {
NotContaining->removeBlockFromLoop(NewPreheader);
for (auto *BB : L.blocks())
NotContaining->removeBlockFromLoop(BB);
}
OuterLoop->removeChildLoop(&L);
if (StillReachable)
StillReachable->addChildLoop(&L);
else
LI.addTopLevelLoop(&L);
}
}
}
/// Delete loop blocks that have become unreachable after folding. Make all
/// relevant updates to DT and LI.
void deleteDeadLoopBlocks() {
@ -381,14 +491,6 @@ public:
return false;
}
// TODO: Support dead loop exits.
if (!DeadExitBlocks.empty()) {
LLVM_DEBUG(dbgs() << "Give up constant terminator folding in loop "
<< L.getHeader()->getName()
<< ": we don't currently support dead loop exits.\n");
return false;
}
// TODO: Support blocks that are not dead, but also not in loop after the
// folding.
if (BlocksInLoopAfterFolding.size() + DeadLoopBlocks.size() !=
@ -410,6 +512,7 @@ public:
<< "\n");
// Make the actual transforms.
handleDeadExits();
foldTerminators();
if (!DeadLoopBlocks.empty()) {

View File

@ -236,24 +236,25 @@ exit:
define i32 @dead_exit_test_branch_loop(i32 %end) {
; CHECK-LABEL: @dead_exit_test_branch_loop(
; CHECK-NEXT: preheader:
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[DEAD:%.*]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER:%.*]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[DEAD:%.*]]
; CHECK: dead:
; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i32 [ [[I]], [[HEADER]] ]
; CHECK-NEXT: br label [[DUMMY:%.*]]
; CHECK: dummy:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[HEADER]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: dead:
; CHECK-NEXT: br label [[DUMMY:%.*]]
; CHECK: dummy:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[HEADER]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I_LCSSA]], [[DUMMY]] ], [ [[I_INC_LCSSA]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ undef, [[DUMMY]] ], [ [[I_INC_LCSSA]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i32 [[I_1]]
;
preheader:
@ -284,28 +285,27 @@ exit:
define i32 @dead_exit_test_switch_loop(i32 %end) {
; CHECK-LABEL: @dead_exit_test_switch_loop(
; CHECK-NEXT: preheader:
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[DEAD:%.*]]
; CHECK-NEXT: i32 2, label [[DEAD]]
; CHECK-NEXT: i32 3, label [[DEAD]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER:%.*]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 1, label [[DEAD:%.*]] [
; CHECK-NEXT: i32 0, label [[DEAD]]
; CHECK-NEXT: i32 1, label [[BACKEDGE]]
; CHECK-NEXT: i32 2, label [[DEAD]]
; CHECK-NEXT: ]
; CHECK: dead:
; CHECK-NEXT: [[I_LCSSA:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I]], [[HEADER]] ], [ [[I]], [[HEADER]] ]
; CHECK-NEXT: br label [[DUMMY:%.*]]
; CHECK: dummy:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[HEADER]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: dead:
; CHECK-NEXT: br label [[DUMMY:%.*]]
; CHECK: dummy:
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit.loopexit:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[HEADER]] ]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I_LCSSA]], [[DUMMY]] ], [ [[I_INC_LCSSA]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ undef, [[DUMMY]] ], [ [[I_INC_LCSSA]], [[EXIT_LOOPEXIT]] ]
; CHECK-NEXT: ret i32 [[I_1]]
;
preheader:
@ -553,21 +553,18 @@ exit:
define i32 @inf_loop_test_branch_loop(i32 %end) {
; CHECK-LABEL: @inf_loop_test_branch_loop(
; CHECK-NEXT: preheader:
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[EXIT:%.*]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER:%.*]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[DEAD:%.*]]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 true, label [[HEADER]], label [[EXIT:%.*]]
; CHECK-NEXT: br label [[HEADER]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA]]
; CHECK-NEXT: ret i32 undef
;
preheader:
br label %header
@ -596,25 +593,18 @@ exit:
define i32 @inf_loop_test_switch_loop(i32 %end) {
; CHECK-LABEL: @inf_loop_test_switch_loop(
; CHECK-NEXT: preheader:
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[EXIT:%.*]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER:%.*]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 1, label [[DEAD:%.*]] [
; CHECK-NEXT: i32 0, label [[DEAD]]
; CHECK-NEXT: i32 1, label [[BACKEDGE]]
; CHECK-NEXT: i32 2, label [[DEAD]]
; CHECK-NEXT: ]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 true, label [[HEADER]], label [[EXIT:%.*]]
; CHECK-NEXT: br label [[HEADER]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA]]
; CHECK-NEXT: ret i32 undef
;
preheader:
br label %header
@ -1206,25 +1196,23 @@ define i32 @full_sub_loop_test_branch_loop_inverse_2(i32 %end) {
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer_header:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[J_INC:%.*]], [[OUTER_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[OUTER_HEADER]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[I]], [[I]]
; CHECK-NEXT: br i1 false, label [[BACKEDGE]], label [[DEAD:%.*]]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: br i1 true, label [[HEADER]], label [[OUTER_BACKEDGE]]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_2]], 1
; CHECK-NEXT: br label [[HEADER]]
; CHECK: outer_backedge:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[J_INC]] = add i32 [[J]], 1
; CHECK-NEXT: [[CMP_J:%.*]] = icmp slt i32 [[J_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP_J]], label [[OUTER_HEADER]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ [[I_INC_LCSSA]], [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ undef, [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA_LCSSA]]
;
entry:
@ -1269,29 +1257,23 @@ define i32 @full_sub_loop_test_switch_loop_inverse_2(i32 %end) {
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer_header:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[J_INC:%.*]], [[OUTER_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[OUTER_HEADER]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[I]], [[I]]
; CHECK-NEXT: switch i32 1, label [[DEAD:%.*]] [
; CHECK-NEXT: i32 0, label [[BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: switch i32 1, label [[HEADER]] [
; CHECK-NEXT: i32 0, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_2]], 1
; CHECK-NEXT: br label [[HEADER]]
; CHECK: outer_backedge:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[J_INC]] = add i32 [[J]], 1
; CHECK-NEXT: [[CMP_J:%.*]] = icmp slt i32 [[J_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP_J]], label [[OUTER_HEADER]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ [[I_INC_LCSSA]], [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ undef, [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA_LCSSA]]
;
entry:
@ -1337,25 +1319,22 @@ define i32 @full_sub_loop_test_branch_loop_inverse_3(i32 %end) {
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer_header:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[J_INC:%.*]], [[OUTER_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[OUTER_HEADER]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[I]], [[I]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[DEAD:%.*]]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: br i1 true, label [[HEADER]], label [[OUTER_BACKEDGE]]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[HEADER]]
; CHECK: outer_backedge:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[J_INC]] = add i32 [[J]], 1
; CHECK-NEXT: [[CMP_J:%.*]] = icmp slt i32 [[J_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP_J]], label [[OUTER_HEADER]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ [[I_INC_LCSSA]], [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ undef, [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA_LCSSA]]
;
entry:
@ -1400,29 +1379,22 @@ define i32 @full_sub_loop_test_switch_loop_inverse_3(i32 %end) {
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer_header:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[J_INC:%.*]], [[OUTER_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[PREHEADER_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: preheader-split:
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[OUTER_HEADER]] ], [ [[I_INC:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[PREHEADER_SPLIT]] ], [ [[I_INC:%.*]], [[HEADER]] ]
; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[I]], [[I]]
; CHECK-NEXT: switch i32 1, label [[BACKEDGE]] [
; CHECK-NEXT: i32 0, label [[DEAD:%.*]]
; CHECK-NEXT: ]
; CHECK: dead:
; CHECK-NEXT: [[I_2:%.*]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[I_1:%.*]] = phi i32 [ [[I]], [[HEADER]] ], [ [[I_2]], [[DEAD]] ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I_1]], 1
; CHECK-NEXT: switch i32 1, label [[HEADER]] [
; CHECK-NEXT: i32 0, label [[OUTER_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK-NEXT: [[I_INC]] = add i32 [[I]], 1
; CHECK-NEXT: br label [[HEADER]]
; CHECK: outer_backedge:
; CHECK-NEXT: [[I_INC_LCSSA:%.*]] = phi i32 [ [[I_INC]], [[BACKEDGE]] ]
; CHECK-NEXT: [[J_INC]] = add i32 [[J]], 1
; CHECK-NEXT: [[CMP_J:%.*]] = icmp slt i32 [[J_INC]], [[END:%.*]]
; CHECK-NEXT: br i1 [[CMP_J]], label [[OUTER_HEADER]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ [[I_INC_LCSSA]], [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: [[I_INC_LCSSA_LCSSA:%.*]] = phi i32 [ undef, [[OUTER_BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[I_INC_LCSSA_LCSSA]]
;
entry:
@ -1470,13 +1442,17 @@ define i32 @exit_branch_from_inner_to_grandparent(i1 %cond1, i1 %cond2, i32 %N)
; CHECK-NEXT: br label [[LOOP_2:%.*]]
; CHECK: loop_2:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[LOOP_1]] ], [ [[J_NEXT:%.*]], [[LOOP_2_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[LOOP_2_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[LOOP_2_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: loop_2-split:
; CHECK-NEXT: br label [[LOOP_3:%.*]]
; CHECK: loop_3:
; CHECK-NEXT: [[K:%.*]] = phi i32 [ 0, [[LOOP_2]] ], [ [[K_NEXT:%.*]], [[LOOP_3_BACKEDGE:%.*]] ]
; CHECK-NEXT: [[K:%.*]] = phi i32 [ 0, [[LOOP_2_SPLIT]] ], [ [[K_NEXT:%.*]], [[LOOP_3_BACKEDGE:%.*]] ]
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LOOP_3_BACKEDGE]], label [[LOOP_1_BACKEDGE_LOOPEXIT:%.*]]
; CHECK: loop_3_backedge:
; CHECK-NEXT: [[K_NEXT]] = add i32 [[K]], 1
; CHECK-NEXT: br i1 true, label [[LOOP_3]], label [[LOOP_2_BACKEDGE]]
; CHECK-NEXT: br label [[LOOP_3]]
; CHECK: loop_2_backedge:
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1
; CHECK-NEXT: [[C_2:%.*]] = icmp slt i32 [[J_NEXT]], [[N:%.*]]
@ -1535,15 +1511,17 @@ define i32 @exit_switch_from_inner_to_grandparent(i1 %cond1, i1 %cond2, i32 %N)
; CHECK-NEXT: br label [[LOOP_2:%.*]]
; CHECK: loop_2:
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 0, [[LOOP_1]] ], [ [[J_NEXT:%.*]], [[LOOP_2_BACKEDGE:%.*]] ]
; CHECK-NEXT: switch i32 0, label [[LOOP_2_SPLIT:%.*]] [
; CHECK-NEXT: i32 1, label [[LOOP_2_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK: loop_2-split:
; CHECK-NEXT: br label [[LOOP_3:%.*]]
; CHECK: loop_3:
; CHECK-NEXT: [[K:%.*]] = phi i32 [ 0, [[LOOP_2]] ], [ [[K_NEXT:%.*]], [[LOOP_3_BACKEDGE:%.*]] ]
; CHECK-NEXT: [[K:%.*]] = phi i32 [ 0, [[LOOP_2_SPLIT]] ], [ [[K_NEXT:%.*]], [[LOOP_3_BACKEDGE:%.*]] ]
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LOOP_3_BACKEDGE]], label [[LOOP_1_BACKEDGE_LOOPEXIT:%.*]]
; CHECK: loop_3_backedge:
; CHECK-NEXT: [[K_NEXT]] = add i32 [[K]], 1
; CHECK-NEXT: switch i32 1, label [[LOOP_3]] [
; CHECK-NEXT: i32 0, label [[LOOP_2_BACKEDGE]]
; CHECK-NEXT: ]
; CHECK-NEXT: br label [[LOOP_3]]
; CHECK: loop_2_backedge:
; CHECK-NEXT: [[J_NEXT]] = add i32 [[J]], 1
; CHECK-NEXT: [[C_2:%.*]] = icmp slt i32 [[J_NEXT]], [[N:%.*]]