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 llvm-svn: 313708
This commit is contained in:
parent
b207d12456
commit
09613b122e
|
@ -81,6 +81,14 @@ template <class BlockT, class LoopT> class LoopBase {
|
|||
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
|
||||
|
|
|
@ -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>::getExitingBlocks(
|
|||
/// 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>::getExitingBlock() const {
|
|||
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>::getExitBlocks(
|
|||
/// 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>::getExitBlock() const {
|
|||
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>::getExitEdges(
|
|||
///
|
||||
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>::getLoopPreheader() const {
|
|||
///
|
||||
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>::getLoopPredecessor() const {
|
|||
/// 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>::getLoopLatch() const {
|
|||
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>::addBasicBlockToLoop(
|
|||
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>::replaceChildLoopWith(LoopT *OldChild,
|
|||
/// 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() const {
|
|||
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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -39,13 +39,29 @@ const Loop* addClonedBlockToLoopInfo(BasicBlock *OriginalBB,
|
|||
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,
|
||||
|
|
|
@ -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, const PreservedAnalyses &PA,
|
|||
|
||||
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.
|
||||
|
|
|
@ -198,9 +198,7 @@ bool LPPassManager::runOnFunction(Function &F) {
|
|||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 Count, unsigned TripCount, bool Force,
|
|||
// 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 Count, unsigned TripCount, bool Force,
|
|||
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 Count, unsigned TripCount, bool Force,
|
|||
// 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 Count, unsigned TripCount, bool Force,
|
|||
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 Count, unsigned TripCount, bool Force,
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return CompletelyUnroll ? LoopUnrollStatus::FullyUnrolled
|
||||
: LoopUnrollStatus::PartiallyUnrolled;
|
||||
}
|
||||
|
||||
/// Given an llvm.loop loop id metadata node, returns the loop hint metadata
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue