#ifndef LLVM_ANALYSIS_LOOPINFOIMPL_H
#define LLVM_ANALYSIS_LOOPINFOIMPL_H
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/Dominators.h"
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 (auto *Succ : children<BlockT *>(BB))
if (!contains(Succ)) {
ExitingBlocks.push_back(BB);
break;
}
}
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)
return ExitingBlocks[0];
return nullptr;
}
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 (auto *Succ : children<BlockT *>(BB))
if (!contains(Succ))
ExitBlocks.push_back(Succ);
}
template <class BlockT, class LoopT>
bool LoopBase<BlockT, LoopT>::hasNoExitBlocks() const {
SmallVector<BlockT *, 8> ExitBlocks;
getExitBlocks(ExitBlocks);
return ExitBlocks.empty();
}
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)
return ExitBlocks[0];
return nullptr;
}
template <class BlockT, class LoopT>
bool LoopBase<BlockT, LoopT>::hasDedicatedExits() const {
SmallVector<BlockT *, 4> UniqueExitBlocks;
getUniqueExitBlocks(UniqueExitBlocks);
for (BlockT *EB : UniqueExitBlocks)
for (BlockT *Predecessor : children<Inverse<BlockT *>>(EB))
if (!contains(Predecessor))
return false;
return true;
}
template <class BlockT, class LoopT, typename PredicateT>
void getUniqueExitBlocksHelper(const LoopT *L,
SmallVectorImpl<BlockT *> &ExitBlocks,
PredicateT Pred) {
assert(!L->isInvalid() && "Loop not in a valid state!");
SmallPtrSet<BlockT *, 32> Visited;
auto Filtered = make_filter_range(L->blocks(), Pred);
for (BlockT *BB : Filtered)
for (BlockT *Successor : children<BlockT *>(BB))
if (!L->contains(Successor))
if (Visited.insert(Successor).second)
ExitBlocks.push_back(Successor);
}
template <class BlockT, class LoopT>
void LoopBase<BlockT, LoopT>::getUniqueExitBlocks(
SmallVectorImpl<BlockT *> &ExitBlocks) const {
getUniqueExitBlocksHelper(this, ExitBlocks,
[](const BlockT *BB) { return true; });
}
template <class BlockT, class LoopT>
void LoopBase<BlockT, LoopT>::getUniqueNonLatchExitBlocks(
SmallVectorImpl<BlockT *> &ExitBlocks) const {
const BlockT *Latch = getLoopLatch();
assert(Latch && "Latch block must exists");
getUniqueExitBlocksHelper(this, ExitBlocks,
[Latch](const BlockT *BB) { return BB != Latch; });
}
template <class BlockT, class LoopT>
BlockT *LoopBase<BlockT, LoopT>::getUniqueExitBlock() const {
SmallVector<BlockT *, 8> UniqueExitBlocks;
getUniqueExitBlocks(UniqueExitBlocks);
if (UniqueExitBlocks.size() == 1)
return UniqueExitBlocks[0];
return nullptr;
}
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 (auto *Succ : children<BlockT *>(BB))
if (!contains(Succ))
ExitEdges.emplace_back(BB, Succ);
}
template <class BlockT, class LoopT>
BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
assert(!isInvalid() && "Loop not in a valid state!");
BlockT *Out = getLoopPredecessor();
if (!Out)
return nullptr;
if (!Out->isLegalToHoistInto())
return nullptr;
typedef GraphTraits<BlockT *> BlockTraits;
typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);
++SI;
if (SI != BlockTraits::child_end(Out))
return nullptr;
return Out;
}
template <class BlockT, class LoopT>
BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
assert(!isInvalid() && "Loop not in a valid state!");
BlockT *Out = nullptr;
BlockT *Header = getHeader();
for (const auto Pred : children<Inverse<BlockT *>>(Header)) {
if (!contains(Pred)) { if (Out && Out != Pred)
return nullptr; Out = Pred;
}
}
return Out;
}
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)) {
if (contains(Pred)) {
if (Latch)
return nullptr;
Latch = Pred;
}
}
return Latch;
}
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()];
assert(contains(SameHeader) && getHeader() == SameHeader->getHeader() &&
"Incorrect LI specified for this loop!");
}
#endif
assert(NewBB && "Cannot add a null basic block to the loop!");
assert(!LIB[NewBB] && "BasicBlock already in the loop!");
LoopT *L = static_cast<LoopT *>(this);
LIB.BBMap[NewBB] = L;
while (L) {
L->addBlockEntry(NewBB);
L = L->getParentLoop();
}
}
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);
assert(I != SubLoops.end() && "OldChild not in loop!");
*I = NewChild;
OldChild->ParentLoop = nullptr;
NewChild->ParentLoop = static_cast<LoopT *>(this);
}
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");
SmallVector<BlockT *, 8> ExitBBs;
getExitBlocks(ExitBBs);
df_iterator_default_set<BlockT *> VisitSet;
VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
df_ext_iterator<BlockT *, df_iterator_default_set<BlockT *>>
BI = df_ext_begin(getHeader(), VisitSet),
BE = df_ext_end(getHeader(), VisitSet);
SmallPtrSet<BlockT *, 8> VisitedBBs;
for (; BI != BE; ++BI) {
BlockT *BB = *BI;
assert(std::any_of(GraphTraits<BlockT *>::child_begin(BB),
GraphTraits<BlockT *>::child_end(BB),
[&](BlockT *B) { return contains(B); }) &&
"Loop block has no in-loop successors!");
assert(std::any_of(GraphTraits<Inverse<BlockT *>>::child_begin(BB),
GraphTraits<Inverse<BlockT *>>::child_end(BB),
[&](BlockT *B) { return contains(B); }) &&
"Loop block has no in-loop predecessors!");
SmallVector<BlockT *, 2> OutsideLoopPreds;
for (BlockT *B :
llvm::make_range(GraphTraits<Inverse<BlockT *>>::child_begin(BB),
GraphTraits<Inverse<BlockT *>>::child_end(BB)))
if (!contains(B))
OutsideLoopPreds.push_back(B);
if (BB == getHeader()) {
assert(!OutsideLoopPreds.empty() && "Loop is unreachable!");
} else if (!OutsideLoopPreds.empty()) {
BlockT *EntryBB = &BB->getParent()->front();
for (BlockT *CB : depth_first(EntryBB))
for (unsigned i = 0, e = OutsideLoopPreds.size(); i != e; ++i)
assert(CB != OutsideLoopPreds[i] &&
"Loop has multiple entry points!");
}
assert(BB != &getHeader()->getParent()->front() &&
"Loop contains function entry block!");
VisitedBBs.insert(BB);
}
if (VisitedBBs.size() != getNumBlocks()) {
dbgs() << "The following blocks are unreachable in the loop: ";
for (auto BB : Blocks) {
if (!VisitedBBs.count(BB)) {
dbgs() << *BB << "\n";
}
}
assert(false && "Unreachable block in loop");
}
for (iterator I = begin(), E = end(); I != E; ++I)
for (block_iterator BI = (*I)->block_begin(), BE = (*I)->block_end();
BI != BE; ++BI) {
assert(contains(*BI) &&
"Loop does not contain all the blocks of a subloop!");
}
if (ParentLoop) {
assert(is_contained(*ParentLoop, this) &&
"Loop is not a subloop of its parent!");
}
#endif
}
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));
verifyLoop();
for (iterator I = begin(), E = end(); I != E; ++I)
(*I)->verifyLoopNest(Loops);
}
template <class BlockT, class LoopT>
void LoopBase<BlockT, LoopT>::print(raw_ostream &OS, bool Verbose,
bool PrintNested, unsigned Depth) const {
OS.indent(Depth * 2);
if (static_cast<const LoopT *>(this)->isAnnotatedParallel())
OS << "Parallel ";
OS << "Loop at depth " << getLoopDepth() << " containing: ";
BlockT *H = getHeader();
for (unsigned i = 0; i < getBlocks().size(); ++i) {
BlockT *BB = getBlocks()[i];
if (!Verbose) {
if (i)
OS << ",";
BB->printAsOperand(OS, false);
} else
OS << "\n";
if (BB == H)
OS << "<header>";
if (isLoopLatch(BB))
OS << "<latch>";
if (isLoopExiting(BB))
OS << "<exiting>";
if (Verbose)
BB->print(OS);
}
if (PrintNested) {
OS << "\n";
for (iterator I = begin(), E = end(); I != E; ++I)
(*I)->print(OS, false, PrintNested, Depth + 2);
}
}
template <class BlockT, class LoopT>
static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT *> Backedges,
LoopInfoBase<BlockT, LoopT> *LI,
const DomTreeBase<BlockT> &DomTree) {
typedef GraphTraits<Inverse<BlockT *>> InvBlockTraits;
unsigned NumBlocks = 0;
unsigned NumSubloops = 0;
std::vector<BlockT *> ReverseCFGWorklist(Backedges.begin(), Backedges.end());
while (!ReverseCFGWorklist.empty()) {
BlockT *PredBB = ReverseCFGWorklist.back();
ReverseCFGWorklist.pop_back();
LoopT *Subloop = LI->getLoopFor(PredBB);
if (!Subloop) {
if (!DomTree.isReachableFromEntry(PredBB))
continue;
LI->changeLoopFor(PredBB, L);
++NumBlocks;
if (PredBB == L->getHeader())
continue;
ReverseCFGWorklist.insert(ReverseCFGWorklist.end(),
InvBlockTraits::child_begin(PredBB),
InvBlockTraits::child_end(PredBB));
} else {
Subloop = Subloop->getOutermostLoop();
if (Subloop == L)
continue;
Subloop->setParentLoop(L);
++NumSubloops;
NumBlocks += Subloop->getBlocksVector().capacity();
PredBB = Subloop->getHeader();
for (const auto Pred : children<Inverse<BlockT *>>(PredBB)) {
if (LI->getLoopFor(Pred) != Subloop)
ReverseCFGWorklist.push_back(Pred);
}
}
}
L->getSubLoopsVector().reserve(NumSubloops);
L->reserveBlocks(NumBlocks);
}
template <class BlockT, class LoopT> class PopulateLoopsDFS {
typedef GraphTraits<BlockT *> BlockTraits;
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
LoopInfoBase<BlockT, LoopT> *LI;
public:
PopulateLoopsDFS(LoopInfoBase<BlockT, LoopT> *li) : LI(li) {}
void traverse(BlockT *EntryBlock);
protected:
void insertIntoLoop(BlockT *Block);
};
template <class BlockT, class LoopT>
void PopulateLoopsDFS<BlockT, LoopT>::traverse(BlockT *EntryBlock) {
for (BlockT *BB : post_order(EntryBlock))
insertIntoLoop(BB);
}
template <class BlockT, class LoopT>
void PopulateLoopsDFS<BlockT, LoopT>::insertIntoLoop(BlockT *Block) {
LoopT *Subloop = LI->getLoopFor(Block);
if (Subloop && Block == Subloop->getHeader()) {
if (!Subloop->isOutermost())
Subloop->getParentLoop()->getSubLoopsVector().push_back(Subloop);
else
LI->addTopLevelLoop(Subloop);
Subloop->reverseBlock(1);
std::reverse(Subloop->getSubLoopsVector().begin(),
Subloop->getSubLoopsVector().end());
Subloop = Subloop->getParentLoop();
}
for (; Subloop; Subloop = Subloop->getParentLoop())
Subloop->addBlockEntry(Block);
}
template <class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::analyze(const DomTreeBase<BlockT> &DomTree) {
const DomTreeNodeBase<BlockT> *DomRoot = DomTree.getRootNode();
for (auto DomNode : post_order(DomRoot)) {
BlockT *Header = DomNode->getBlock();
SmallVector<BlockT *, 4> Backedges;
for (const auto Backedge : children<Inverse<BlockT *>>(Header)) {
if (DomTree.dominates(Header, Backedge) &&
DomTree.isReachableFromEntry(Backedge)) {
Backedges.push_back(Backedge);
}
}
if (!Backedges.empty()) {
LoopT *L = AllocateLoop(Header);
discoverAndMapSubloop(L, ArrayRef<BlockT *>(Backedges), this, DomTree);
}
}
PopulateLoopsDFS<BlockT, LoopT> DFS(this);
DFS.traverse(DomRoot->getBlock());
}
template <class BlockT, class LoopT>
SmallVector<LoopT *, 4>
LoopInfoBase<BlockT, LoopT>::getLoopsInPreorder() const {
SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
for (LoopT *RootL : reverse(*this)) {
auto PreOrderLoopsInRootL = RootL->getLoopsInPreorder();
PreOrderLoops.append(PreOrderLoopsInRootL.begin(),
PreOrderLoopsInRootL.end());
}
return PreOrderLoops;
}
template <class BlockT, class LoopT>
SmallVector<LoopT *, 4>
LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() const {
SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
for (LoopT *RootL : *this) {
assert(PreOrderWorklist.empty() &&
"Must start with an empty preorder walk worklist.");
PreOrderWorklist.push_back(RootL);
do {
LoopT *L = PreOrderWorklist.pop_back_val();
PreOrderWorklist.append(L->begin(), L->end());
PreOrderLoops.push_back(L);
} while (!PreOrderWorklist.empty());
}
return PreOrderLoops;
}
template <class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
for (unsigned i = 0; i < TopLevelLoops.size(); ++i)
TopLevelLoops[i]->print(OS);
#if 0#endif
}
template <typename T>
bool compareVectors(std::vector<T> &BB1, std::vector<T> &BB2) {
llvm::sort(BB1);
llvm::sort(BB2);
return BB1 == BB2;
}
template <class BlockT, class LoopT>
void addInnerLoopsToHeadersMap(DenseMap<BlockT *, const LoopT *> &LoopHeaders,
const LoopInfoBase<BlockT, LoopT> &LI,
const LoopT &L) {
LoopHeaders[L.getHeader()] = &L;
for (LoopT *SL : L)
addInnerLoopsToHeadersMap(LoopHeaders, LI, *SL);
}
#ifndef NDEBUG
template <class BlockT, class LoopT>
static void compareLoops(const LoopT *L, const LoopT *OtherL,
DenseMap<BlockT *, const LoopT *> &OtherLoopHeaders) {
BlockT *H = L->getHeader();
BlockT *OtherH = OtherL->getHeader();
assert(H == OtherH &&
"Mismatched headers even though found in the same map entry!");
assert(L->getLoopDepth() == OtherL->getLoopDepth() &&
"Mismatched loop depth!");
const LoopT *ParentL = L, *OtherParentL = OtherL;
do {
assert(ParentL->getHeader() == OtherParentL->getHeader() &&
"Mismatched parent loop headers!");
ParentL = ParentL->getParentLoop();
OtherParentL = OtherParentL->getParentLoop();
} while (ParentL);
for (const LoopT *SubL : *L) {
BlockT *SubH = SubL->getHeader();
const LoopT *OtherSubL = OtherLoopHeaders.lookup(SubH);
assert(OtherSubL && "Inner loop is missing in computed loop info!");
OtherLoopHeaders.erase(SubH);
compareLoops(SubL, OtherSubL, OtherLoopHeaders);
}
std::vector<BlockT *> BBs = L->getBlocks();
std::vector<BlockT *> OtherBBs = OtherL->getBlocks();
assert(compareVectors(BBs, OtherBBs) &&
"Mismatched basic blocks in the loops!");
const SmallPtrSetImpl<const BlockT *> &BlocksSet = L->getBlocksSet();
const SmallPtrSetImpl<const BlockT *> &OtherBlocksSet =
OtherL->getBlocksSet();
assert(BlocksSet.size() == OtherBlocksSet.size() &&
llvm::set_is_subset(BlocksSet, OtherBlocksSet) &&
"Mismatched basic blocks in BlocksSets!");
}
#endif
template <class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::verify(
const DomTreeBase<BlockT> &DomTree) const {
DenseSet<const LoopT *> Loops;
for (iterator I = begin(), E = end(); I != E; ++I) {
assert((*I)->isOutermost() && "Top-level loop has a parent!");
(*I)->verifyLoopNest(&Loops);
}
#ifndef NDEBUG
for (auto &Entry : BBMap) {
const BlockT *BB = Entry.first;
LoopT *L = Entry.second;
assert(Loops.count(L) && "orphaned loop");
assert(L->contains(BB) && "orphaned block");
for (LoopT *ChildLoop : *L)
assert(!ChildLoop->contains(BB) &&
"BBMap should point to the innermost loop containing BB");
}
LoopInfoBase<BlockT, LoopT> OtherLI;
OtherLI.analyze(DomTree);
DenseMap<BlockT *, const LoopT *> OtherLoopHeaders;
for (LoopT *L : OtherLI)
addInnerLoopsToHeadersMap(OtherLoopHeaders, OtherLI, *L);
for (LoopT *L : *this) {
BlockT *Header = L->getHeader();
const LoopT *OtherL = OtherLoopHeaders.lookup(Header);
assert(OtherL && "Top level loop is missing in computed loop info!");
OtherLoopHeaders.erase(Header);
compareLoops(L, OtherL, OtherLoopHeaders);
}
if (!OtherLoopHeaders.empty()) {
for (const auto &HeaderAndLoop : OtherLoopHeaders)
dbgs() << "Found new loop: " << *HeaderAndLoop.second << "\n";
llvm_unreachable("Found new loops when recomputing LoopInfo!");
}
#endif
}
}
#endif