Index: lib/Transforms/Scalar/LoopSimplifyCFG.cpp =================================================================== --- lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -45,6 +45,8 @@ "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, @@ -232,6 +234,114 @@ "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: + /// + /// 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: + /// 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 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() { @@ -313,14 +423,6 @@ 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() != @@ -342,6 +444,7 @@ << "\n"); // Make the actual transforms. + handleDeadExits(); foldTerminators(); if (!DeadLoopBlocks.empty()) { Index: test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll =================================================================== --- test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll +++ test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll @@ -236,24 +236,25 @@ 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-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: [[I_LCSSA:%.*]] = phi i32 [ [[I]], [[HEADER]] ] ; CHECK-NEXT: br label [[DUMMY:%.*]] ; CHECK: dummy: ; CHECK-NEXT: br label [[EXIT:%.*]] -; CHECK: backedge: -; 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: 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 @@ define i32 @dead_exit_test_switch_loop(i32 %end) { ; CHECK-LABEL: @dead_exit_test_switch_loop( ; CHECK-NEXT: preheader: -; 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: 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_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: [[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_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: 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 @@ 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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:%.*]]