23#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24#define LLVM_ADT_GENERICCYCLEIMPL_H
31#define DEBUG_TYPE "generic-cycle-impl"
35template <
typename ContextT>
42 while (Depth < C->
Depth)
47template <
typename ContextT>
52 size_t NumExitBlocks = 0;
60 auto ExitEndIt = TmpStorage.
begin() + NumExitBlocks;
61 if (std::find(TmpStorage.
begin(), ExitEndIt, Succ) == ExitEndIt)
62 TmpStorage[NumExitBlocks++] = Succ;
66 TmpStorage.
resize(NumExitBlocks);
70template <
typename ContextT>
85template <
typename ContextT>
87 BlockT *Predecessor = getCyclePredecessor();
91 assert(isReducible() &&
"Cycle Predecessor must be in a reducible cycle!");
97 if (!Predecessor->isLegalToHoistInto())
103template <
typename ContextT>
111 BlockT *Header = getHeader();
114 if (Out && Out != Pred)
131 assert(!Entries.empty() &&
"Cycle must have one or more entries.");
134 for (
BlockT *Entry : entries()) {
135 assert(Entries.insert(Entry).second);
141 getExitBlocks(ExitBBs);
152 "Cycle block has no in-cycle successors!");
156 "Cycle block has no in-cycle predecessors!");
159 for (
BlockT *
B : llvm::inverse_children<BlockT *>(BB))
163 if (Entries.contains(BB)) {
164 assert(!OutsideCyclePreds.
empty() &&
"Entry is unreachable!");
165 }
else if (!OutsideCyclePreds.
empty()) {
169 BlockT *EntryBB = &BB->getParent()->front();
172 "Non-entry block reachable from outside!");
175 "Cycle contains function entry block!");
180 if (VisitedBBs.
size() != getNumBlocks()) {
181 dbgs() <<
"The following blocks are unreachable in the cycle:\n ";
184 if (!VisitedBBs.
count(BB)) {
186 BB->printAsOperand(
dbgs());
200template <
typename ContextT>
206 for (
BlockT *BB : Child->blocks()) {
208 "Cycle does not contain all the blocks of a subcycle!");
216 "Cycle is not a subcycle of its parent!");
223 using BlockT =
typename ContextT::BlockT;
225 using CycleT =
typename CycleInfoT::CycleT;
234 explicit DFSInfo(
unsigned Start) : Start(Start) {}
236 explicit operator bool()
const {
return Start; }
240 bool isAncestorOf(
const DFSInfo &
Other)
const {
254 void run(BlockT *EntryBlock);
259 void dfs(BlockT *EntryBlock);
262template <
typename ContextT>
266 if (
Cycle != BlockMapTopLevel.end())
267 return Cycle->second;
270 if (MapIt == BlockMap.end())
273 auto *
C = MapIt->second;
274 while (
C->ParentCycle)
280template <
typename ContextT>
283 assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
284 "NewParent and Child must be both top level cycle!\n");
285 auto &CurrentContainer =
286 Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
288 return Child ==
Ptr.get();
290 assert(Pos != CurrentContainer.end());
291 NewParent->Children.push_back(std::move(*Pos));
292 *Pos = std::move(CurrentContainer.back());
293 CurrentContainer.pop_back();
294 Child->ParentCycle = NewParent;
298 for (
auto &It : BlockMapTopLevel)
299 if (It.second == Child)
300 It.second = NewParent;
303template <
typename ContextT>
304void GenericCycleInfo<ContextT>::addBlockToCycle(BlockT *
Block, CycleT *
Cycle) {
312 while (ParentCycle) {
322template <
typename ContextT>
330 for (BlockT *HeaderCandidate :
llvm::reverse(BlockPreorder)) {
331 const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
334 const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
337 if (CandidateInfo.isAncestorOf(PredDFSInfo))
340 if (Worklist.
empty()) {
346 <<
Info.Context.print(HeaderCandidate) <<
"\n");
347 std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
348 NewCycle->appendEntry(HeaderCandidate);
349 NewCycle->appendBlock(HeaderCandidate);
350 Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
355 auto ProcessPredecessors = [&](BlockT *
Block) {
358 bool IsEntry =
false;
360 const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
361 if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
363 }
else if (!PredDFSInfo) {
374 NewCycle->appendEntry(
Block);
382 if (
Block == HeaderCandidate)
388 if (
auto *BlockParent =
Info.getTopLevelParentCycle(
Block)) {
391 if (BlockParent != NewCycle.get()) {
393 <<
"discovered child cycle "
394 <<
Info.Context.print(BlockParent->getHeader()) <<
"\n");
396 Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
398 for (
auto *ChildEntry : BlockParent->entries())
399 ProcessPredecessors(ChildEntry);
402 <<
"known child cycle "
403 <<
Info.Context.print(BlockParent->getHeader()) <<
"\n");
406 Info.BlockMap.try_emplace(
Block, NewCycle.get());
408 NewCycle->Blocks.insert(
Block);
409 ProcessPredecessors(
Block);
410 Info.BlockMapTopLevel.try_emplace(
Block, NewCycle.get());
412 }
while (!Worklist.
empty());
414 Info.TopLevelCycles.push_back(std::move(NewCycle));
418 for (
auto *TLC :
Info.toplevel_cycles()) {
420 <<
Info.Context.print(TLC->getHeader()) <<
"\n");
422 TLC->ParentCycle =
nullptr;
428template <
typename ContextT>
437template <
typename ContextT>
441 unsigned Counter = 0;
448 if (!BlockDFSInfo.count(
Block)) {
454 << TraverseStack.
size() <<
"\n");
459 bool Added = BlockDFSInfo.try_emplace(
Block, ++Counter).second;
462 BlockPreorder.push_back(
Block);
466 if (DFSTreeStack.
back() == TraverseStack.
size()) {
468 BlockDFSInfo.find(
Block)->second.End = Counter;
475 }
while (!TraverseStack.
empty());
479 errs() <<
"Preorder:\n";
480 for (
int i = 0, e = BlockPreorder.size(); i != e; ++i) {
481 errs() <<
" " << Info.Context.print(BlockPreorder[i]) <<
": " << i <<
"\n";
488 TopLevelCycles.clear();
490 BlockMapTopLevel.clear();
494template <
typename ContextT>
497 Context = ContextT(&
F);
501 Compute.
run(&
F.front());
504template <
typename ContextT>
509 CycleT *
Cycle = getSmallestCommonCycle(getCycle(Pred), getCycle(Succ));
513 addBlockToCycle(NewBlock,
Cycle);
521template <
typename ContextT>
524 return BlockMap.lookup(
Block);
531template <
typename ContextT>
540 while (
A->getDepth() >
B->getDepth())
541 A =
A->getParentCycle();
542 while (
B->getDepth() >
A->getDepth())
543 B =
B->getParentCycle();
549 A =
A->getParentCycle();
550 B =
B->getParentCycle();
560template <
typename ContextT>
572template <
typename ContextT>
577 for (
CycleT *TopCycle : toplevel_cycles()) {
587 auto MapIt = BlockMap.find(BB);
588 assert(MapIt != BlockMap.end());
598 verifyCycleNest(
true);
602template <
typename ContextT>
604 for (
const auto *TLC : toplevel_cycles()) {
606 for (
unsigned I = 0;
I <
Cycle->Depth; ++
I)
static const Function * getParent(const Value *V)
bbsections Prepares for basic block by splitting functions into clusters of basic blocks
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseSet and SmallDenseSet classes.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
DenseMap< Block *, BlockRelaxAux > Blocks
Find all cycles in a control-flow graph, including irreducible loops.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Implements a dense probed hash-table based set.
Helper class for computing cycle information.
void run(BlockT *EntryBlock)
Main function of the cycle info computations.
GenericCycleInfoCompute(CycleInfoT &Info)
static void updateDepth(CycleT *SubTree)
Recompute depth values of SubTree and all descendants.
Cycle information for a function.
typename ContextT::FunctionT FunctionT
void verify() const
Verify that the entire cycle tree well-formed.
void print(raw_ostream &Out) const
Print the cycle info.
CycleT * getSmallestCommonCycle(CycleT *A, CycleT *B) const
Find the innermost cycle containing both given cycles.
void clear()
Reset the object to its initial state.
void compute(FunctionT &F)
Compute the cycle info for a function.
void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New)
unsigned getCycleDepth(const BlockT *Block) const
get the depth for the cycle which containing a given block.
void verifyCycleNest(bool VerifyFull=false) const
Methods for debug and self-test.
typename ContextT::BlockT BlockT
CycleT * getTopLevelParentCycle(BlockT *Block)
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
A possibly irreducible generalization of a Loop.
BlockT * getHeader() const
void getExitingBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all blocks of this cycle that have successor outside of this cycle.
void verifyCycle() const
Verify that this is actually a well-formed cycle in the CFG.
void verifyCycleNest() const
Verify the parent-child relations of this cycle.
Printable print(const ContextT &Ctx) const
iterator_range< const_block_iterator > blocks() const
BlockT * getCyclePreheader() const
Return the preheader block for this cycle.
const_block_iterator block_begin() const
void getExitBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all of the successor blocks of this cycle.
BlockT * getCyclePredecessor() const
If the cycle has exactly one entry with exactly one predecessor, return it, otherwise return nullptr.
bool contains(const BlockT *Block) const
Return whether Block is contained in the cycle.
typename ContextT::BlockT BlockT
const GenericCycle * getParentCycle() const
unsigned getDepth() const
const_block_iterator block_end() const
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< df_ext_iterator< T, SetTy > > depth_first_ext(const T &G, SetTy &S)
auto successors(const MachineBasicBlock *BB)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
auto predecessors(const MachineBasicBlock *BB)
iterator_range< typename GraphTraits< GraphType >::ChildIteratorType > children(const typename GraphTraits< GraphType >::NodeRef &G)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
iterator_range< df_iterator< T > > depth_first(const T &G)
unsigned succ_size(const MachineBasicBlock *BB)
std::pair< iterator, bool > insert(NodeRef N)