Index: llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ llvm/trunk/lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -406,15 +406,32 @@ DeadLoopBlocks.end()); MSSAU->removeBlocks(DeadLoopBlocksSet); } + + // The function LI.erase has some invariants that need to be preserved when + // it tries to remove a loop which is not the top-level loop. In particular, + // it requires loop's preheader to be strictly in loop's parent. We cannot + // just remove blocks one by one, because after removal of preheader we may + // break this invariant for the dead loop. So we detatch and erase all dead + // loops beforehand. + for (auto *BB : DeadLoopBlocks) + if (LI.isLoopHeader(BB)) { + assert(LI.getLoopFor(BB) != &L && "Attempt to remove current loop!"); + Loop *DL = LI.getLoopFor(BB); + if (DL->getParentLoop()) { + for (auto *PL = DL->getParentLoop(); PL; PL = PL->getParentLoop()) + for (auto *BB : DL->getBlocks()) + PL->removeBlockFromLoop(BB); + DL->getParentLoop()->removeChildLoop(DL); + LI.addTopLevelLoop(DL); + } + LI.erase(DL); + } + for (auto *BB : DeadLoopBlocks) { assert(BB != L.getHeader() && "Header of the current loop cannot be dead!"); LLVM_DEBUG(dbgs() << "Deleting dead loop block " << BB->getName() << "\n"); - if (LI.isLoopHeader(BB)) { - assert(LI.getLoopFor(BB) != &L && "Attempt to remove current loop!"); - LI.erase(LI.getLoopFor(BB)); - } LI.removeBlock(BB); } Index: llvm/trunk/test/Transforms/LoopSimplifyCFG/update_parents.ll =================================================================== --- llvm/trunk/test/Transforms/LoopSimplifyCFG/update_parents.ll +++ llvm/trunk/test/Transforms/LoopSimplifyCFG/update_parents.ll @@ -1,5 +1,4 @@ -; XFAIL: * -; REQUIRES: asserts +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -enable-loop-simplifycfg-term-folding=true -loop-simplifycfg -debug-only=loop-simplifycfg -verify-loop-info -verify-dom-info -verify-loop-lcssa 2>&1 < %s | FileCheck %s ; RUN: opt -S -enable-loop-simplifycfg-term-folding=true -passes='require,loop(simplify-cfg)' -debug-only=loop-simplifycfg -verify-loop-info -verify-dom-info -verify-loop-lcssa 2>&1 < %s | FileCheck %s ; RUN: opt -S -enable-loop-simplifycfg-term-folding=true -loop-simplifycfg -enable-mssa-loop-dependency=true -verify-memoryssa -debug-only=loop-simplifycfg -verify-loop-info -verify-dom-info -verify-loop-lcssa 2>&1 < %s | FileCheck %s @@ -7,8 +6,24 @@ target triple = "x86_64-unknown-linux-gnu" define void @test() { - ; CHECK-LABEL: @test( +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1.loopexit: +; CHECK-NEXT: br label [[BB1]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB2:%.*]] +; CHECK: bb2.loopexit: +; CHECK-NEXT: br label [[BB2]] +; CHECK: bb2: +; CHECK-NEXT: switch i32 0, label [[BB2_SPLIT:%.*]] [ +; CHECK-NEXT: i32 1, label [[BB1_LOOPEXIT:%.*]] +; CHECK-NEXT: i32 2, label [[BB2_LOOPEXIT:%.*]] +; CHECK-NEXT: ] +; CHECK: bb2-split: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb3: +; CHECK-NEXT: br label [[BB3]] +; br label %bb1 @@ -32,8 +47,24 @@ } define void @test_many_subloops(i1 %c) { - ; CHECK-LABEL: @test_many_subloops( +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1.loopexit: +; CHECK-NEXT: br label [[BB1]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB2:%.*]] +; CHECK: bb2.loopexit: +; CHECK-NEXT: br label [[BB2]] +; CHECK: bb2: +; CHECK-NEXT: switch i32 0, label [[BB2_SPLIT:%.*]] [ +; CHECK-NEXT: i32 1, label [[BB1_LOOPEXIT:%.*]] +; CHECK-NEXT: i32 2, label [[BB2_LOOPEXIT:%.*]] +; CHECK-NEXT: ] +; CHECK: bb2-split: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb3: +; CHECK-NEXT: br label [[BB3]] +; br label %bb1