Index: lib/Transforms/Scalar/LoopSimplifyCFG.cpp =================================================================== --- lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -87,6 +87,9 @@ // Whether or not the current loop will still exist after terminator constant // folding has been done. bool LoopIsLive = true; + // Whether or not this loop has live exit blocks to some loop other than its + // parent. It makes exiting edges updates a way more complicated. + bool NonTrivialExits = false; // The blocks of the original loop that will still be reachable from entry // after the constant folding. @@ -165,8 +168,12 @@ // Handle successors. auto ProcessSuccessor = [&](BasicBlock *Succ, bool IsLive) { if (!L.contains(Succ)) { - if (IsLive) + if (IsLive) { + Loop *SuccL = LI.getLoopFor(Succ); + if (SuccL && SuccL != L.getParentLoop()) + NonTrivialExits = true; LiveExitBlocks.insert(Succ); + } ExitBlocks.insert(Succ); } else if (IsLive) LiveLoopBlocks.insert(Succ); @@ -220,6 +227,105 @@ } } + /// 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 %new_preheader, + /// [i32 1, label %dead_exit_1], + /// [i32 2, label %dead_exit_2], + /// ... + /// [i32 N, label %dead_exit_N], + /// + /// new_preheader: + /// + /// br label %loop_header + /// + /// loop_header: + /// ... + /// br i1 false, label %dead_exit, 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; + + // Split preheader like this: + 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); + } + + 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. It means that current loop's blocks and its preheader + // will no longer be a part of the outer loop. We should detect this + // situation and update the loop info accordingly. + bool OuterLoopIsReached = false; + for (BasicBlock *BB : LiveExitBlocks) { + Loop *BBL = LI.getLoopFor(BB); + if (BBL) { + assert(BBL == OuterLoop && "We only support exits to outer loop!"); + OuterLoopIsReached = true; + break; + } + } + + if (!OuterLoopIsReached) { + LI.changeLoopFor(NewPreheader, nullptr); + for (auto *Parent = OuterLoop; Parent; Parent = Parent->getParentLoop()) { + Parent->removeBlockFromLoop(NewPreheader); + for (auto *BB : L.blocks()) + Parent->removeBlockFromLoop(BB); + } + } + + OuterLoop->removeChildLoop(&L); + LI.addTopLevelLoop(&L); + } + } + /// Delete loop blocks that have become unreachable after folding. Make all /// relevant updates to DT and LI. void deleteDeadLoopBlocks() { @@ -276,8 +382,8 @@ bool run() { assert(L.getLoopLatch() && "Should be single latch!"); - // TODO: Support dead loop exits. - if (!DeadExitBlocks.empty()) + // TODO: Support live exits to other loops than parent. + if (NonTrivialExits && !DeadExitBlocks.empty()) return false; // TODO: Support deletion of the current loop. @@ -298,10 +404,14 @@ LLVM_DEBUG(dump()); // Make the actual transforms. + handleDeadExits(); + foldTerminators(); deleteDeadLoopBlocks(); + assert(L.isLCSSAForm(DT) && "LCSSA broken?"); + return true; } }; Index: test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll =================================================================== --- test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll +++ test/Transforms/LoopSimplifyCFG/constant-fold-branch.ll @@ -196,24 +196,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: @@ -244,28 +245,25 @@ 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: ] +; 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-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: @@ -513,21 +511,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 @@ -556,25 +551,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 @@ -1070,25 +1058,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]], 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: @@ -1133,29 +1119,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]], 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: @@ -1201,25 +1181,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: @@ -1264,29 +1241,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: