Index: include/llvm/Analysis/LoopInfo.h =================================================================== --- include/llvm/Analysis/LoopInfo.h +++ include/llvm/Analysis/LoopInfo.h @@ -65,23 +65,31 @@ /// Instances of this class are used to represent loops that are detected in the /// flow graph. /// -template -class LoopBase { +template class LoopBase { LoopT *ParentLoop; // Loops contained entirely within this one. std::vector SubLoops; // The list of blocks in this loop. First entry is the header node. - std::vector Blocks; + std::vector Blocks; - SmallPtrSet DenseBlockSet; + SmallPtrSet DenseBlockSet; /// Indicator that this loop is no longer a valid loop. bool IsInvalid = false; LoopBase(const LoopBase &) = delete; - const LoopBase& - operator=(const LoopBase &) = delete; + const LoopBase & + operator=(const LoopBase &) = delete; + + void invalidate() { + IsInvalid = true; + SubLoops.clear(); + Blocks.clear(); + DenseBlockSet.clear(); + ParentLoop = nullptr; + } + public: /// This creates an empty loop. LoopBase() : ParentLoop(nullptr) {} @@ -90,72 +98,88 @@ /// for consistency with loop depth values used for basic blocks, where depth /// 0 is used for blocks not inside any loops. unsigned getLoopDepth() const { + assert(!isInvalid() && "Loop not in a valid state!"); unsigned D = 1; for (const LoopT *CurLoop = ParentLoop; CurLoop; CurLoop = CurLoop->ParentLoop) ++D; return D; } - BlockT *getHeader() const { return Blocks.front(); } + BlockT *getHeader() const { return getBlocks().front(); } LoopT *getParentLoop() const { return ParentLoop; } /// This is a raw interface for bypassing addChildLoop. - void setParentLoop(LoopT *L) { ParentLoop = L; } + void setParentLoop(LoopT *L) { + assert(!isInvalid() && "Loop not in a valid state!"); + ParentLoop = L; + } /// Return true if the specified loop is contained within in this loop. bool contains(const LoopT *L) const { - if (L == this) return true; - if (!L) return false; + assert(!isInvalid() && "Loop not in a valid state!"); + if (L == this) + return true; + if (!L) + return false; return contains(L->getParentLoop()); } /// Return true if the specified basic block is in this loop. bool contains(const BlockT *BB) const { + assert(!isInvalid() && "Loop not in a valid state!"); return DenseBlockSet.count(BB); } /// Return true if the specified instruction is in this loop. - template - bool contains(const InstT *Inst) const { + template bool contains(const InstT *Inst) const { return contains(Inst->getParent()); } /// Return the loops contained entirely within this loop. - const std::vector &getSubLoops() const { return SubLoops; } - std::vector &getSubLoopsVector() { return SubLoops; } + const std::vector &getSubLoops() const { + assert(!isInvalid() && "Loop not in a valid state!"); + return SubLoops; + } + std::vector &getSubLoopsVector() { + assert(!isInvalid() && "Loop not in a valid state!"); + return SubLoops; + } typedef typename std::vector::const_iterator iterator; - typedef typename std::vector::const_reverse_iterator - reverse_iterator; - iterator begin() const { return SubLoops.begin(); } - iterator end() const { return SubLoops.end(); } - reverse_iterator rbegin() const { return SubLoops.rbegin(); } - reverse_iterator rend() const { return SubLoops.rend(); } - bool empty() const { return SubLoops.empty(); } + typedef + typename std::vector::const_reverse_iterator reverse_iterator; + iterator begin() const { return getSubLoops().begin(); } + iterator end() const { return getSubLoops().end(); } + reverse_iterator rbegin() const { return getSubLoops().rbegin(); } + reverse_iterator rend() const { return getSubLoops().rend(); } + bool empty() const { return getSubLoops().empty(); } /// Get a list of the basic blocks which make up this loop. - const std::vector &getBlocks() const { return Blocks; } - typedef typename std::vector::const_iterator block_iterator; - block_iterator block_begin() const { return Blocks.begin(); } - block_iterator block_end() const { return Blocks.end(); } + const std::vector &getBlocks() const { + assert(!isInvalid() && "Loop not in a valid state!"); + return Blocks; + } + typedef typename std::vector::const_iterator block_iterator; + block_iterator block_begin() const { return getBlocks().begin(); } + block_iterator block_end() const { return getBlocks().end(); } inline iterator_range blocks() const { + assert(!isInvalid() && "Loop not in a valid state!"); return make_range(block_begin(), block_end()); } /// Get the number of blocks in this loop in constant time. unsigned getNumBlocks() const { + assert(!isInvalid() && "Loop not in a valid state!"); return Blocks.size(); } - /// Invalidate the loop, indicating that it is no longer a loop. - void invalidate() { IsInvalid = true; } - /// Return true if this loop is no longer valid. - bool isInvalid() { return IsInvalid; } + bool isInvalid() const { return IsInvalid; } /// True if terminator in the block can branch to another block that is /// outside of the current loop. bool isLoopExiting(const BlockT *BB) const { - for (const auto &Succ : children(BB)) { + assert(!isInvalid() && "Loop not in a valid state!"); + for (const auto &Succ : children(BB)) { if (!contains(Succ)) return true; } @@ -167,20 +191,22 @@ /// This function is useful when there are multiple latches in a loop /// because \fn getLoopLatch will return nullptr in that case. bool isLoopLatch(const BlockT *BB) const { + assert(!isInvalid() && "Loop not in a valid state!"); assert(contains(BB) && "block does not belong to the loop"); BlockT *Header = getHeader(); - auto PredBegin = GraphTraits >::child_begin(Header); - auto PredEnd = GraphTraits >::child_end(Header); + auto PredBegin = GraphTraits>::child_begin(Header); + auto PredEnd = GraphTraits>::child_end(Header); return std::find(PredBegin, PredEnd, BB) != PredEnd; } /// Calculate the number of back edges to the loop header. unsigned getNumBackEdges() const { + assert(!isInvalid() && "Loop not in a valid state!"); unsigned NumBackEdges = 0; BlockT *H = getHeader(); - for (const auto Pred : children >(H)) + for (const auto Pred : children>(H)) if (contains(Pred)) ++NumBackEdges; @@ -206,14 +232,14 @@ /// Return all of the successor blocks of this loop. These are the blocks /// _outside of the current loop_ which are branched to. - void getExitBlocks(SmallVectorImpl &ExitBlocks) const; + void getExitBlocks(SmallVectorImpl &ExitBlocks) const; /// If getExitBlocks would return exactly one block, return that block. /// Otherwise return null. BlockT *getExitBlock() const; /// Edge type. - typedef std::pair Edge; + typedef std::pair Edge; /// Return all pairs of (_inside_block_,_outside_block_). void getExitEdges(SmallVectorImpl &ExitEdges) const; @@ -239,8 +265,9 @@ /// Return all loop latch blocks of this loop. A latch block is a block that /// contains a branch back to the header. void getLoopLatches(SmallVectorImpl &LoopLatches) const { + assert(!isInvalid() && "Loop not in a valid state!"); BlockT *H = getHeader(); - for (const auto Pred : children>(H)) + for (const auto Pred : children>(H)) if (contains(Pred)) LoopLatches.push_back(Pred); } @@ -265,6 +292,7 @@ /// Add the specified loop to be a child of this loop. /// This updates the loop depth of the new child. void addChildLoop(LoopT *NewChild) { + assert(!isInvalid() && "Loop not in a valid state!"); assert(!NewChild->ParentLoop && "NewChild already has a parent!"); NewChild->ParentLoop = static_cast(this); SubLoops.push_back(NewChild); @@ -273,10 +301,11 @@ /// This removes the specified child from being a subloop of this loop. The /// loop is not deleted, as it will presumably be inserted into another loop. LoopT *removeChildLoop(iterator I) { + assert(!isInvalid() && "Loop not in a valid state!"); assert(I != SubLoops.end() && "Cannot remove end iterator!"); LoopT *Child = *I; assert(Child->ParentLoop == this && "Child is not a child of this loop!"); - SubLoops.erase(SubLoops.begin()+(I-begin())); + SubLoops.erase(SubLoops.begin() + (I - begin())); Child->ParentLoop = nullptr; return Child; } @@ -285,25 +314,30 @@ /// This should only be used by transformations that create new loops. Other /// transformations should use addBasicBlockToLoop. void addBlockEntry(BlockT *BB) { + assert(!isInvalid() && "Loop not in a valid state!"); Blocks.push_back(BB); DenseBlockSet.insert(BB); } /// interface to reverse Blocks[from, end of loop] in this loop void reverseBlock(unsigned from) { + assert(!isInvalid() && "Loop not in a valid state!"); std::reverse(Blocks.begin() + from, Blocks.end()); } /// interface to do reserve() for Blocks void reserveBlocks(unsigned size) { + assert(!isInvalid() && "Loop not in a valid state!"); Blocks.reserve(size); } /// This method is used to move BB (which must be part of this loop) to be the /// loop header of the loop (the block that dominates all others). void moveToHeader(BlockT *BB) { - if (Blocks[0] == BB) return; - for (unsigned i = 0; ; ++i) { + assert(!isInvalid() && "Loop not in a valid state!"); + if (Blocks[0] == BB) + return; + for (unsigned i = 0;; ++i) { assert(i != Blocks.size() && "Loop does not contain BB!"); if (Blocks[i] == BB) { Blocks[i] = Blocks[0]; @@ -317,6 +351,7 @@ /// Blocks as appropriate. This does not update the mapping in the LoopInfo /// class. void removeBlockFromLoop(BlockT *BB) { + assert(!isInvalid() && "Loop not in a valid state!"); auto I = find(Blocks, BB); assert(I != Blocks.end() && "N is not in this list!"); Blocks.erase(I); @@ -328,7 +363,7 @@ void verifyLoop() const; /// Verify loop structure of this loop and all nested loops. - void verifyLoopNest(DenseSet *Loops) const; + void verifyLoopNest(DenseSet *Loops) const; /// Print loop with all the BBs inside it. void print(raw_ostream &OS, unsigned Depth = 0, bool Verbose = false) const; @@ -503,6 +538,8 @@ LocRange getLocRange() const; StringRef getName() const { + if (isInvalid()) + return ""; if (BasicBlock *Header = getHeader()) if (Header->hasName()) return Header->getName(); @@ -683,6 +720,9 @@ void print(raw_ostream &OS) const; void verify(const DominatorTreeBase &DomTree) const; + +protected: + static void invalidateLoop(LoopT &L) { L.invalidate(); } }; // Implementation in LoopInfoImpl.h Index: include/llvm/Analysis/LoopInfoImpl.h =================================================================== --- include/llvm/Analysis/LoopInfoImpl.h +++ include/llvm/Analysis/LoopInfoImpl.h @@ -34,6 +34,7 @@ template void LoopBase:: getExitingBlocks(SmallVectorImpl &ExitingBlocks) const { + assert(!isInvalid() && "Loop not in a valid state!"); for (const auto BB : blocks()) for (const auto &Succ : children(BB)) if (!contains(Succ)) { @@ -47,6 +48,7 @@ /// return that block. Otherwise return null. template BlockT *LoopBase::getExitingBlock() const { + assert(!isInvalid() && "Loop not in a valid state!"); SmallVector ExitingBlocks; getExitingBlocks(ExitingBlocks); if (ExitingBlocks.size() == 1) @@ -60,6 +62,7 @@ template void LoopBase:: getExitBlocks(SmallVectorImpl &ExitBlocks) const { + assert(!isInvalid() && "Loop not in a valid state!"); for (const auto BB : blocks()) for (const auto &Succ : children(BB)) if (!contains(Succ)) @@ -71,6 +74,7 @@ /// return that block. Otherwise return null. template BlockT *LoopBase::getExitBlock() const { + assert(!isInvalid() && "Loop not in a valid state!"); SmallVector ExitBlocks; getExitBlocks(ExitBlocks); if (ExitBlocks.size() == 1) @@ -82,6 +86,7 @@ template void LoopBase:: getExitEdges(SmallVectorImpl &ExitEdges) const { + assert(!isInvalid() && "Loop not in a valid state!"); for (const auto BB : blocks()) for (const auto &Succ : children(BB)) if (!contains(Succ)) @@ -99,6 +104,7 @@ /// template BlockT *LoopBase::getLoopPreheader() const { + assert(!isInvalid() && "Loop not in a valid state!"); // Keep track of nodes outside the loop branching to the header... BlockT *Out = getLoopPredecessor(); if (!Out) return nullptr; @@ -125,6 +131,7 @@ /// template BlockT *LoopBase::getLoopPredecessor() const { + assert(!isInvalid() && "Loop not in a valid state!"); // Keep track of nodes outside the loop branching to the header... BlockT *Out = nullptr; @@ -147,6 +154,7 @@ /// A latch block is a block that contains a branch back to the header. template BlockT *LoopBase::getLoopLatch() const { + assert(!isInvalid() && "Loop not in a valid state!"); BlockT *Header = getHeader(); BlockT *Latch = nullptr; for (const auto Pred : children>(Header)) { @@ -172,6 +180,7 @@ template void LoopBase:: addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase &LIB) { + assert(!isInvalid() && "Loop not in a valid state!"); #ifndef NDEBUG if (!Blocks.empty()) { auto SameHeader = LIB[getHeader()]; @@ -201,6 +210,7 @@ template void LoopBase:: replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild) { + assert(!isInvalid() && "Loop not in a valid state!"); assert(OldChild->ParentLoop == this && "This loop is already broken!"); assert(!NewChild->ParentLoop && "NewChild already has a parent!"); typename std::vector::iterator I = find(SubLoops, OldChild); @@ -213,6 +223,7 @@ /// verifyLoop - Verify loop structure template void LoopBase::verifyLoop() const { + assert(!isInvalid() && "Loop not in a valid state!"); #ifndef NDEBUG assert(!Blocks.empty() && "Loop header is missing"); @@ -298,6 +309,7 @@ template void LoopBase::verifyLoopNest( DenseSet *Loops) const { + assert(!isInvalid() && "Loop not in a valid state!"); Loops->insert(static_cast(this)); // Verify this loop. verifyLoop(); Index: include/llvm/Transforms/Scalar/LoopPassManager.h =================================================================== --- include/llvm/Transforms/Scalar/LoopPassManager.h +++ include/llvm/Transforms/Scalar/LoopPassManager.h @@ -166,7 +166,8 @@ /// the rest of the pass management infrastructure. void markLoopAsDeleted(Loop &L) { LAM.clear(L); - assert(CurrentL->contains(&L) && "Cannot delete a loop outside of the " + assert(&L == CurrentL || + CurrentL->contains(&L) && "Cannot delete a loop outside of the " "subloop tree currently being processed."); if (&L == CurrentL) SkipCurrentLoop = true; Index: include/llvm/Transforms/Utils/UnrollLoop.h =================================================================== --- include/llvm/Transforms/Utils/UnrollLoop.h +++ include/llvm/Transforms/Utils/UnrollLoop.h @@ -39,13 +39,29 @@ BasicBlock *ClonedBB, LoopInfo *LI, NewLoopsMap &NewLoops); -bool UnrollLoop(Loop *L, unsigned Count, unsigned TripCount, bool Force, - bool AllowRuntime, bool AllowExpensiveTripCount, - bool PreserveCondBr, bool PreserveOnlyFirst, - unsigned TripMultiple, unsigned PeelCount, bool UnrollRemainder, - LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, - AssumptionCache *AC, OptimizationRemarkEmitter *ORE, - bool PreserveLCSSA); +/// Represents the result of a \c UnrollLoop invocation. +enum class LoopUnrollStatus { + /// The loop was not modified. + Unmodified, + + /// The loop was partially unrolled -- we still have a loop, but with a + /// smaller trip count. We may also have emitted epilogue loop if the loop + /// had a non-constant trip count. + PartiallyUnrolled, + + /// The loop was fully unrolled into straight-line code. We no longer have + /// any back-edges. + FullyUnrolled +}; + +LoopUnrollStatus UnrollLoop(Loop *L, unsigned Count, unsigned TripCount, + bool Force, bool AllowRuntime, + bool AllowExpensiveTripCount, bool PreserveCondBr, + bool PreserveOnlyFirst, unsigned TripMultiple, + unsigned PeelCount, bool UnrollRemainder, + LoopInfo *LI, ScalarEvolution *SE, + DominatorTree *DT, AssumptionCache *AC, + OptimizationRemarkEmitter *ORE, bool PreserveLCSSA); bool UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, bool AllowExpensiveTripCount, Index: lib/Analysis/LoopInfo.cpp =================================================================== --- lib/Analysis/LoopInfo.cpp +++ lib/Analysis/LoopInfo.cpp @@ -16,6 +16,7 @@ #include "llvm/Analysis/LoopInfo.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/LoopInfoImpl.h" #include "llvm/Analysis/LoopIterator.h" @@ -624,9 +625,11 @@ void LoopInfo::markAsErased(Loop *Unloop) { assert(!Unloop->isInvalid() && "Loop has already been erased!"); - Unloop->invalidate(); RemovedLoops.push_back(Unloop); + auto InvalidateOnExit = + make_scope_exit([&]() { BaseT::invalidateLoop(*Unloop); }); + // First handle the special case of no parent loop to simplify the algorithm. if (!Unloop->getParentLoop()) { // Since BBLoop had no parent, Unloop blocks are no longer in a loop. Index: lib/Analysis/LoopPass.cpp =================================================================== --- lib/Analysis/LoopPass.cpp +++ lib/Analysis/LoopPass.cpp @@ -198,9 +198,7 @@ LoopWasDeleted = CurrentLoop->isInvalid(); if (Changed) - dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG, - LoopWasDeleted ? "" - : CurrentLoop->getHeader()->getName()); + dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG, CurrentLoop->getName()); dumpPreservedSet(P); if (LoopWasDeleted) { Index: lib/Transforms/Scalar/LoopUnrollPass.cpp =================================================================== --- lib/Transforms/Scalar/LoopUnrollPass.cpp +++ lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -1045,18 +1045,19 @@ UP.Count = TripCount; // Unroll the loop. - if (!UnrollLoop(L, UP.Count, TripCount, UP.Force, UP.Runtime, - UP.AllowExpensiveTripCount, UseUpperBound, MaxOrZero, - TripMultiple, UP.PeelCount, UP.UnrollRemainder, - LI, &SE, &DT, &AC, &ORE, - PreserveLCSSA)) + LoopUnrollStatus UnrollStatus = UnrollLoop( + L, UP.Count, TripCount, UP.Force, UP.Runtime, UP.AllowExpensiveTripCount, + UseUpperBound, MaxOrZero, TripMultiple, UP.PeelCount, UP.UnrollRemainder, + LI, &SE, &DT, &AC, &ORE, PreserveLCSSA); + if (UnrollStatus == LoopUnrollStatus::Unmodified) return false; // If loop has an unroll count pragma or unrolled by explicitly set count // mark loop as unrolled to prevent unrolling beyond that requested. // If the loop was peeled, we already "used up" the profile information // we had, so we don't want to unroll or peel again. - if (IsCountSetExplicitly || UP.PeelCount) + if (UnrollStatus != LoopUnrollStatus::FullyUnrolled && + (IsCountSetExplicitly || UP.PeelCount)) SetLoopAlreadyUnrolled(L); return true; Index: lib/Transforms/Utils/LoopUnroll.cpp =================================================================== --- lib/Transforms/Utils/LoopUnroll.cpp +++ lib/Transforms/Utils/LoopUnroll.cpp @@ -255,8 +255,7 @@ return false; } -/// Unroll the given loop by Count. The loop must be in LCSSA form. Returns true -/// if unrolling was successful, or false if the loop was unmodified. Unrolling +/// Unroll the given loop by Count. The loop must be in LCSSA form. Unrolling /// can only fail when the loop's latch block is not terminated by a conditional /// branch instruction. However, if the trip count (and multiple) are not known, /// loop unrolling will mostly produce more code that is no faster. @@ -285,38 +284,36 @@ /// runtime-unroll the loop if computing RuntimeTripCount will be expensive and /// AllowExpensiveTripCount is false. /// -/// If we want to perform PGO-based loop peeling, PeelCount is set to the +/// If we want to perform PGO-based loop peeling, PeelCount is set to the /// number of iterations we want to peel off. /// /// The LoopInfo Analysis that is passed will be kept consistent. /// /// This utility preserves LoopInfo. It will also preserve ScalarEvolution and /// DominatorTree if they are non-null. -bool llvm::UnrollLoop(Loop *L, unsigned Count, unsigned TripCount, bool Force, - bool AllowRuntime, bool AllowExpensiveTripCount, - bool PreserveCondBr, bool PreserveOnlyFirst, - unsigned TripMultiple, unsigned PeelCount, - bool UnrollRemainder, LoopInfo *LI, - ScalarEvolution *SE, DominatorTree *DT, - AssumptionCache *AC, OptimizationRemarkEmitter *ORE, - bool PreserveLCSSA) { +LoopUnrollStatus llvm::UnrollLoop( + Loop *L, unsigned Count, unsigned TripCount, bool Force, bool AllowRuntime, + bool AllowExpensiveTripCount, bool PreserveCondBr, bool PreserveOnlyFirst, + unsigned TripMultiple, unsigned PeelCount, bool UnrollRemainder, + LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC, + OptimizationRemarkEmitter *ORE, bool PreserveLCSSA) { BasicBlock *Preheader = L->getLoopPreheader(); if (!Preheader) { DEBUG(dbgs() << " Can't unroll; loop preheader-insertion failed.\n"); - return false; + return LoopUnrollStatus::Unmodified; } BasicBlock *LatchBlock = L->getLoopLatch(); if (!LatchBlock) { DEBUG(dbgs() << " Can't unroll; loop exit-block-insertion failed.\n"); - return false; + return LoopUnrollStatus::Unmodified; } // Loops with indirectbr cannot be cloned. if (!L->isSafeToClone()) { DEBUG(dbgs() << " Can't unroll; Loop body cannot be cloned.\n"); - return false; + return LoopUnrollStatus::Unmodified; } // The current loop unroll pass can only unroll loops with a single latch @@ -330,7 +327,7 @@ // The loop-rotate pass can be helpful to avoid this in many cases. DEBUG(dbgs() << " Can't unroll; loop not terminated by a conditional branch.\n"); - return false; + return LoopUnrollStatus::Unmodified; } auto CheckSuccessors = [&](unsigned S1, unsigned S2) { @@ -340,14 +337,14 @@ if (!CheckSuccessors(0, 1) && !CheckSuccessors(1, 0)) { DEBUG(dbgs() << "Can't unroll; only loops with one conditional latch" " exiting the loop can be unrolled\n"); - return false; + return LoopUnrollStatus::Unmodified; } if (Header->hasAddressTaken()) { // The loop-rotate pass can be helpful to avoid this in many cases. DEBUG(dbgs() << " Won't unroll loop: address of header block is taken.\n"); - return false; + return LoopUnrollStatus::Unmodified; } if (TripCount != 0) @@ -363,7 +360,7 @@ // Don't enter the unroll code if there is nothing to do. if (TripCount == 0 && Count < 2 && PeelCount == 0) { DEBUG(dbgs() << "Won't unroll; almost nothing to do\n"); - return false; + return LoopUnrollStatus::Unmodified; } assert(Count > 0); @@ -439,7 +436,7 @@ DEBUG( dbgs() << "Wont unroll; remainder loop could not be generated" "when assuming runtime trip count\n"); - return false; + return LoopUnrollStatus::Unmodified; } } @@ -857,7 +854,8 @@ } } - return true; + return CompletelyUnroll ? LoopUnrollStatus::FullyUnrolled + : LoopUnrollStatus::PartiallyUnrolled; } /// Given an llvm.loop loop id metadata node, returns the loop hint metadata Index: test/Transforms/LoopUnroll/unroll-loop-invalidation.ll =================================================================== --- test/Transforms/LoopUnroll/unroll-loop-invalidation.ll +++ test/Transforms/LoopUnroll/unroll-loop-invalidation.ll @@ -22,8 +22,8 @@ ; CHECK: Running analysis: LoopAccessAnalysis on outer.header ; CHECK: Finished Loop pass manager run. ; CHECK: Running pass: LoopUnrollPass -; CHECK: Clearing all analysis results for: inner2.header -; CHECK: Clearing all analysis results for: outer.header +; CHECK: Clearing all analysis results for: +; CHECK: Clearing all analysis results for: ; CHECK: Invalidating all non-preserved analyses for: test ; CHECK: Invalidating all non-preserved analyses for: inner1.header ; CHECK: Invalidating analysis: LoopAccessAnalysis on inner1.header