[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