[llvm] r313708 - Tighten the invariants around LoopBase::invalidate

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 19 19:31:57 PDT 2017


Author: sanjoy
Date: Tue Sep 19 19:31:57 2017
New Revision: 313708

URL: http://llvm.org/viewvc/llvm-project?rev=313708&view=rev
Log:
Tighten the invariants around LoopBase::invalidate

Summary:
With this change:
 - Methods in LoopBase trip an assert if the receiver has been invalidated
 - LoopBase::clear frees up the memory held the LoopBase instance

This change also shuffles things around as necessary to work with this stricter invariant.

Reviewers: chandlerc

Subscribers: mehdi_amini, mcrosier, llvm-commits

Differential Revision: https://reviews.llvm.org/D38055

Modified:
    llvm/trunk/include/llvm/Analysis/LoopInfo.h
    llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h
    llvm/trunk/include/llvm/Transforms/Scalar/LoopPassManager.h
    llvm/trunk/include/llvm/Transforms/Utils/UnrollLoop.h
    llvm/trunk/lib/Analysis/LoopInfo.cpp
    llvm/trunk/lib/Analysis/LoopPass.cpp
    llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp
    llvm/trunk/lib/Transforms/Utils/LoopUnroll.cpp
    llvm/trunk/test/Transforms/LoopUnroll/unroll-loop-invalidation.ll

Modified: llvm/trunk/include/llvm/Analysis/LoopInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfo.h?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LoopInfo.h (original)
+++ llvm/trunk/include/llvm/Analysis/LoopInfo.h Tue Sep 19 19:31:57 2017
@@ -81,6 +81,14 @@ template <class BlockT, class LoopT> cla
   const LoopBase<BlockT, LoopT> &
   operator=(const LoopBase<BlockT, LoopT> &) = delete;
 
+  void clear() {
+    IsInvalid = true;
+    SubLoops.clear();
+    Blocks.clear();
+    DenseBlockSet.clear();
+    ParentLoop = nullptr;
+  }
+
 public:
   /// This creates an empty loop.
   LoopBase() : ParentLoop(nullptr) {}
@@ -89,20 +97,25 @@ public:
   /// 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 {
+    assert(!isInvalid() && "Loop not in a valid state!");
     if (L == this)
       return true;
     if (!L)
@@ -111,7 +124,10 @@ public:
   }
 
   /// Return true if the specified basic block is in this loop.
-  bool contains(const BlockT *BB) const { return DenseBlockSet.count(BB); }
+  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 <class InstT> bool contains(const InstT *Inst) const {
@@ -119,38 +135,50 @@ public:
   }
 
   /// Return the loops contained entirely within this loop.
-  const std::vector<LoopT *> &getSubLoops() const { return SubLoops; }
-  std::vector<LoopT *> &getSubLoopsVector() { return SubLoops; }
+  const std::vector<LoopT *> &getSubLoops() const {
+    assert(!isInvalid() && "Loop not in a valid state!");
+    return SubLoops;
+  }
+  std::vector<LoopT *> &getSubLoopsVector() {
+    assert(!isInvalid() && "Loop not in a valid state!");
+    return SubLoops;
+  }
   typedef typename std::vector<LoopT *>::const_iterator iterator;
   typedef
       typename std::vector<LoopT *>::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(); }
+  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<BlockT *> &getBlocks() const { return Blocks; }
+  const std::vector<BlockT *> &getBlocks() const {
+    assert(!isInvalid() && "Loop not in a valid state!");
+    return Blocks;
+  }
   typedef typename std::vector<BlockT *>::const_iterator block_iterator;
-  block_iterator block_begin() const { return Blocks.begin(); }
-  block_iterator block_end() const { return Blocks.end(); }
+  block_iterator block_begin() const { return getBlocks().begin(); }
+  block_iterator block_end() const { return getBlocks().end(); }
   inline iterator_range<block_iterator> 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 { return Blocks.size(); }
-
   /// Invalidate the loop, indicating that it is no longer a loop.
-  void invalidate() { IsInvalid = true; }
+  unsigned getNumBlocks() const {
+    assert(!isInvalid() && "Loop not in a valid state!");
+    return Blocks.size();
+  }
 
   /// 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 {
+    assert(!isInvalid() && "Loop not in a valid state!");
     for (const auto &Succ : children<const BlockT *>(BB)) {
       if (!contains(Succ))
         return true;
@@ -163,6 +191,7 @@ public:
   /// 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();
@@ -173,6 +202,7 @@ public:
 
   /// 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();
 
@@ -235,6 +265,7 @@ public:
   /// 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<BlockT *> &LoopLatches) const {
+    assert(!isInvalid() && "Loop not in a valid state!");
     BlockT *H = getHeader();
     for (const auto Pred : children<Inverse<BlockT *>>(H))
       if (contains(Pred))
@@ -261,6 +292,7 @@ public:
   /// 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<LoopT *>(this);
     SubLoops.push_back(NewChild);
@@ -269,6 +301,7 @@ public:
   /// 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!");
@@ -281,21 +314,27 @@ public:
   /// 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) { Blocks.reserve(size); }
+  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) {
+    assert(!isInvalid() && "Loop not in a valid state!");
     if (Blocks[0] == BB)
       return;
     for (unsigned i = 0;; ++i) {
@@ -312,6 +351,7 @@ public:
   /// 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);
@@ -494,6 +534,8 @@ public:
   LocRange getLocRange() const;
 
   StringRef getName() const {
+    if (isInvalid())
+      return "<invalidated loop>";
     if (BasicBlock *Header = getHeader())
       if (Header->hasName())
         return Header->getName();
@@ -673,6 +715,9 @@ public:
   void print(raw_ostream &OS) const;
 
   void verify(const DominatorTreeBase<BlockT, false> &DomTree) const;
+
+protected:
+  static void clearLoop(LoopT &L) { L.clear(); }
 };
 
 // Implementation in LoopInfoImpl.h

Modified: llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h (original)
+++ llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h Tue Sep 19 19:31:57 2017
@@ -34,6 +34,7 @@ namespace llvm {
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::getExitingBlocks(
     SmallVectorImpl<BlockT *> &ExitingBlocks) const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   for (const auto BB : blocks())
     for (const auto &Succ : children<BlockT *>(BB))
       if (!contains(Succ)) {
@@ -47,6 +48,7 @@ void LoopBase<BlockT, LoopT>::getExiting
 /// return that block. Otherwise return null.
 template <class BlockT, class LoopT>
 BlockT *LoopBase<BlockT, LoopT>::getExitingBlock() const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   SmallVector<BlockT *, 8> ExitingBlocks;
   getExitingBlocks(ExitingBlocks);
   if (ExitingBlocks.size() == 1)
@@ -60,6 +62,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExit
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::getExitBlocks(
     SmallVectorImpl<BlockT *> &ExitBlocks) const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   for (const auto BB : blocks())
     for (const auto &Succ : children<BlockT *>(BB))
       if (!contains(Succ))
@@ -71,6 +74,7 @@ void LoopBase<BlockT, LoopT>::getExitBlo
 /// return that block. Otherwise return null.
 template <class BlockT, class LoopT>
 BlockT *LoopBase<BlockT, LoopT>::getExitBlock() const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   SmallVector<BlockT *, 8> ExitBlocks;
   getExitBlocks(ExitBlocks);
   if (ExitBlocks.size() == 1)
@@ -82,6 +86,7 @@ BlockT *LoopBase<BlockT, LoopT>::getExit
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::getExitEdges(
     SmallVectorImpl<Edge> &ExitEdges) const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   for (const auto BB : blocks())
     for (const auto &Succ : children<BlockT *>(BB))
       if (!contains(Succ))
@@ -99,6 +104,7 @@ void LoopBase<BlockT, LoopT>::getExitEdg
 ///
 template <class BlockT, class LoopT>
 BlockT *LoopBase<BlockT, LoopT>::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)
@@ -126,6 +132,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoop
 ///
 template <class BlockT, class LoopT>
 BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   // Keep track of nodes outside the loop branching to the header...
   BlockT *Out = nullptr;
 
@@ -148,6 +155,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoop
 /// A latch block is a block that contains a branch back to the header.
 template <class BlockT, class LoopT>
 BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   BlockT *Header = getHeader();
   BlockT *Latch = nullptr;
   for (const auto Pred : children<Inverse<BlockT *>>(Header)) {
@@ -174,6 +182,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoop
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::addBasicBlockToLoop(
     BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LIB) {
+  assert(!isInvalid() && "Loop not in a valid state!");
 #ifndef NDEBUG
   if (!Blocks.empty()) {
     auto SameHeader = LIB[getHeader()];
@@ -203,6 +212,7 @@ void LoopBase<BlockT, LoopT>::addBasicBl
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::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<LoopT *>::iterator I = find(SubLoops, OldChild);
@@ -215,6 +225,7 @@ void LoopBase<BlockT, LoopT>::replaceChi
 /// verifyLoop - Verify loop structure
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::verifyLoop() const {
+  assert(!isInvalid() && "Loop not in a valid state!");
 #ifndef NDEBUG
   assert(!Blocks.empty() && "Loop header is missing");
 
@@ -301,6 +312,7 @@ void LoopBase<BlockT, LoopT>::verifyLoop
 template <class BlockT, class LoopT>
 void LoopBase<BlockT, LoopT>::verifyLoopNest(
     DenseSet<const LoopT *> *Loops) const {
+  assert(!isInvalid() && "Loop not in a valid state!");
   Loops->insert(static_cast<const LoopT *>(this));
   // Verify this loop.
   verifyLoop();

Modified: llvm/trunk/include/llvm/Transforms/Scalar/LoopPassManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar/LoopPassManager.h?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Scalar/LoopPassManager.h (original)
+++ llvm/trunk/include/llvm/Transforms/Scalar/LoopPassManager.h Tue Sep 19 19:31:57 2017
@@ -166,7 +166,8 @@ public:
   /// 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;

Modified: llvm/trunk/include/llvm/Transforms/Utils/UnrollLoop.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/UnrollLoop.h?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/UnrollLoop.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/UnrollLoop.h Tue Sep 19 19:31:57 2017
@@ -39,13 +39,29 @@ const Loop* addClonedBlockToLoopInfo(Bas
                                      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,

Modified: llvm/trunk/lib/Analysis/LoopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopInfo.cpp?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopInfo.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopInfo.cpp Tue Sep 19 19:31:57 2017
@@ -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"
@@ -619,9 +620,11 @@ bool LoopInfo::invalidate(Function &F, c
 
 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::clearLoop(*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.

Modified: llvm/trunk/lib/Analysis/LoopPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPass.cpp?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopPass.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopPass.cpp Tue Sep 19 19:31:57 2017
@@ -198,9 +198,7 @@ bool LPPassManager::runOnFunction(Functi
       LoopWasDeleted = CurrentLoop->isInvalid();
 
       if (Changed)
-        dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG,
-                     LoopWasDeleted ? "<deleted>"
-                                    : CurrentLoop->getHeader()->getName());
+        dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG, CurrentLoop->getName());
       dumpPreservedSet(P);
 
       if (LoopWasDeleted) {

Modified: llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/LoopUnrollPass.cpp Tue Sep 19 19:31:57 2017
@@ -1045,18 +1045,19 @@ static bool tryToUnrollLoop(
     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;

Modified: llvm/trunk/lib/Transforms/Utils/LoopUnroll.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/LoopUnroll.cpp?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/LoopUnroll.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/LoopUnroll.cpp Tue Sep 19 19:31:57 2017
@@ -255,8 +255,7 @@ static bool isEpilogProfitable(Loop *L)
   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 @@ static bool isEpilogProfitable(Loop *L)
 /// 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 @@ bool llvm::UnrollLoop(Loop *L, unsigned
     // 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 @@ bool llvm::UnrollLoop(Loop *L, unsigned
   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 @@ bool llvm::UnrollLoop(Loop *L, unsigned
   // 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 @@ bool llvm::UnrollLoop(Loop *L, unsigned
       DEBUG(
           dbgs() << "Wont unroll; remainder loop could not be generated"
                     "when assuming runtime trip count\n");
-      return false;
+      return LoopUnrollStatus::Unmodified;
     }
   }
 
@@ -864,7 +861,8 @@ bool llvm::UnrollLoop(Loop *L, unsigned
     }
   }
 
-  return true;
+  return CompletelyUnroll ? LoopUnrollStatus::FullyUnrolled
+                          : LoopUnrollStatus::PartiallyUnrolled;
 }
 
 /// Given an llvm.loop loop id metadata node, returns the loop hint metadata

Modified: llvm/trunk/test/Transforms/LoopUnroll/unroll-loop-invalidation.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LoopUnroll/unroll-loop-invalidation.ll?rev=313708&r1=313707&r2=313708&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LoopUnroll/unroll-loop-invalidation.ll (original)
+++ llvm/trunk/test/Transforms/LoopUnroll/unroll-loop-invalidation.ll Tue Sep 19 19:31:57 2017
@@ -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: <invalidated loop>
+; CHECK: Clearing all analysis results for: <invalidated loop>
 ; CHECK: Invalidating all non-preserved analyses for: test
 ; CHECK: Invalidating all non-preserved analyses for: inner1.header
 ; CHECK: Invalidating analysis: LoopAccessAnalysis on inner1.header




More information about the llvm-commits mailing list