23#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24#define LLVM_ADT_GENERICCYCLEIMPL_H
32#define DEBUG_TYPE "generic-cycle-impl"
36template <
typename ContextT>
39 return C && IdxBegin <=
C->IdxBegin &&
C->IdxEnd <= IdxEnd;
42template <
typename ContextT>
47template <
typename ContextT>
49 return CI->BlockLayout.begin() + IdxBegin;
52template <
typename ContextT>
54 return CI->BlockLayout.begin() + IdxEnd;
57template <
typename ContextT>
60 if (!ExitBlocksCache.empty()) {
61 TmpStorage.
append(ExitBlocksCache.begin(), ExitBlocksCache.end());
65 size_t NumExitBlocks = 0;
69 for (
size_t Idx = NumExitBlocks, End = ExitBlocksCache.size(); Idx < End;
71 BlockT *Succ = ExitBlocksCache[Idx];
73 auto ExitEndIt = ExitBlocksCache.begin() + NumExitBlocks;
74 if (std::find(ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
75 ExitBlocksCache[NumExitBlocks++] = Succ;
79 ExitBlocksCache.resize(NumExitBlocks);
82 TmpStorage.
append(ExitBlocksCache.begin(), ExitBlocksCache.end());
85template <
typename ContextT>
98template <
typename ContextT>
110 if (!Predecessor->isLegalToHoistInto())
116template <
typename ContextT>
127 if (Out && Out != Pred)
144 assert(!Entries.empty() &&
"Cycle must have one or more entries.");
148 assert(Entries.insert(Entry).second);
165 "Cycle block has no in-cycle successors!");
169 "Cycle block has no in-cycle predecessors!");
176 if (Entries.contains(BB)) {
177 assert(!OutsideCyclePreds.empty() &&
"Entry is unreachable!");
178 }
else if (!OutsideCyclePreds.empty()) {
182 BlockT *EntryBB = &BB->getParent()->front();
184 assert(!OutsideCyclePreds.contains(CB) &&
185 "Non-entry block reachable from outside!");
188 "Cycle contains function entry block!");
194 dbgs() <<
"The following blocks are unreachable in the cycle:\n ";
196 for (
auto *BB : Blocks) {
197 if (!VisitedBBs.
count(BB)) {
199 BB->printAsOperand(
dbgs());
213template <
typename ContextT>
217 for (GenericCycle *Child :
children()) {
219 for (
BlockT *BB : Child->blocks()) {
221 "Cycle does not contain all the blocks of a subcycle!");
223 assert(Child->Depth == Depth + 1);
229 "Cycle is not a subcycle of its parent!");
230 assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
231 "Top level cycle of parent cycle must be the same");
233 assert(TopLevelCycle ==
this &&
234 "Cycle without parent must be top-level cycle");
240template <
typename ContextT>
class GenericCycleInfoCompute {
241 using BlockT =
typename ContextT::BlockT;
242 using FunctionT =
typename ContextT::FunctionT;
244 using CycleT =
typename CycleInfoT::CycleT;
253 explicit DFSInfo(
unsigned Start) : Start(Start) {}
255 explicit operator bool()
const {
return Start; }
259 bool isAncestorOf(
const DFSInfo &
Other)
const {
260 return Start <=
Other.Start &&
Other.End <= End;
268 GenericCycleInfoCompute(
const GenericCycleInfoCompute &) =
delete;
269 GenericCycleInfoCompute &operator=(
const GenericCycleInfoCompute &) =
delete;
271 DFSInfo getDFSInfo(BlockT *
B)
const {
273 return BlockDFSInfo[
Number];
276 DFSInfo &getOrInsertDFSInfo(BlockT *
B) {
278 return BlockDFSInfo[
Number];
284 void run(FunctionT *
F);
289 void dfs(FunctionT *
F, BlockT *EntryBlock);
292template <
typename ContextT>
296 return Cycle ?
Cycle->TopLevelCycle :
nullptr;
299template <
typename ContextT>
300void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
302 assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
303 "NewParent and Child must be both top level cycle!\n");
304 auto &CurrentContainer =
305 Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
306 auto Pos =
llvm::find_if(CurrentContainer, [=](
const auto &Ptr) ->
bool {
307 return Child == Ptr.get();
309 assert(Pos != CurrentContainer.end());
310 NewParent->Children.push_back(std::move(*Pos));
311 *Pos = std::move(CurrentContainer.back());
312 CurrentContainer.pop_back();
313 Child->ParentCycle = NewParent;
314 Child->TopLevelCycle = NewParent;
316 Cycle->TopLevelCycle = NewParent;
323template <
typename ContextT>
324void GenericCycleInfo<ContextT>::verifyBlockNumberEpoch(
325 const FunctionT *Fn)
const {
328 "CycleInfo used with outdated block number epoch");
331template <
typename ContextT>
334 verifyBlockNumberEpoch(
Block->getParent());
339template <
typename ContextT>
343 if (
Number >= BlockMap.size())
349 unsigned Pos =
Cycle->IdxEnd;
350 BlockLayout.insert(BlockLayout.begin() + Pos,
Block);
352 while (!Worklist.empty()) {
353 CycleT *
C = Worklist.pop_back_val();
354 if (
C->IdxEnd <= Pos)
356 if (
C->IdxBegin >= Pos) {
360 for (
auto &Child :
C->Children)
361 Worklist.push_back(Child.get());
366 for (CycleT *
C =
Cycle;
C;
C =
C->getParentCycle()) {
372template <
typename ContextT>
374 if (TopLevelCycles.empty())
384 typename CycleT::const_child_iterator ChildCur, ChildEnd;
388 auto enter = [&](CycleT *
C) {
390 C->IdxBegin = Cursor;
391 Stack.push_back({
C,
C->child_begin(),
C->child_end()});
393 for (CycleT *TLC : toplevel_cycles()) {
395 while (!
Stack.empty()) {
397 if (
F.ChildCur !=
F.ChildEnd) {
398 enter(*
F.ChildCur++);
400 F.C->IdxEnd = Cursor;
407 BlockLayout.resize_for_overwrite(Cursor);
409 if (CycleT *
C = getCycle(
B))
410 BlockLayout[--
C->IdxBegin] =
B;
414template <
typename ContextT>
417 LLVM_DEBUG(
errs() <<
"Entry block: " << Info.Context.print(EntryBlock)
423 for (BlockT *HeaderCandidate :
llvm::reverse(BlockPreorder)) {
424 const DFSInfo CandidateInfo = getDFSInfo(HeaderCandidate);
427 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
430 if (CandidateInfo.isAncestorOf(PredDFSInfo))
433 if (Worklist.
empty()) {
439 << Info.Context.print(HeaderCandidate) <<
"\n");
440 std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
441 NewCycle->CI = &Info;
442 NewCycle->appendEntry(HeaderCandidate);
443 Info.addToBlockMap(HeaderCandidate, NewCycle.get());
452 auto ProcessPredecessors = [&](BlockT *
Block) {
455 bool IsEntry =
false;
457 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
458 if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
460 }
else if (!PredDFSInfo) {
471 NewCycle->appendEntry(
Block);
479 if (
Block == HeaderCandidate)
485 if (
auto *BlockParent = Info.getTopLevelParentCycle(
Block)) {
488 if (BlockParent != NewCycle.get()) {
490 <<
"discovered child cycle "
491 << Info.Context.print(BlockParent->getHeader()) <<
"\n");
493 Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
495 for (
auto *ChildEntry : BlockParent->entries())
496 ProcessPredecessors(ChildEntry);
499 <<
"known child cycle "
500 << Info.Context.print(BlockParent->getHeader()) <<
"\n");
503 Info.addToBlockMap(
Block, NewCycle.get());
505 ProcessPredecessors(
Block);
507 }
while (!Worklist.
empty());
509 Info.TopLevelCycles.push_back(std::move(NewCycle));
513 for (
auto *TLC : Info.toplevel_cycles()) {
515 << Info.Context.print(TLC->getHeader()) <<
"\n");
517 TLC->ParentCycle =
nullptr;
523 Info.layoutBlocks(BlockPreorder);
527template <
typename ContextT>
536template <
typename ContextT>
537void GenericCycleInfoCompute<ContextT>::dfs(FunctionT *
F, BlockT *EntryBlock) {
543 using SuccIt =
decltype(
successors(EntryBlock).begin());
546 std::reverse_iterator<SuccIt> Cur, End;
549 unsigned Counter = 0;
551 auto open = [&](BlockT *
Block) {
552 getOrInsertDFSInfo(
Block).Start = ++Counter;
553 BlockPreorder.push_back(
Block);
555 <<
", preorder number: " << Counter <<
"\n");
557 Stack.push_back({
Block, std::make_reverse_iterator(Succs.end()),
558 std::make_reverse_iterator(Succs.begin())});
562 while (!
Stack.empty()) {
563 Frame &Top =
Stack.back();
564 BlockT *
Next =
nullptr;
565 while (Top.Cur != Top.End) {
566 BlockT *Succ = *Top.Cur++;
567 if (getOrInsertDFSInfo(Succ).Start == 0) {
572 <<
Info.Context.print(Succ) <<
"\n");
579 getOrInsertDFSInfo(Top.Block).End = Counter;
581 <<
" ended at " << Counter <<
"\n");
587 errs() <<
"Preorder:\n";
588 for (
int I = 0,
E = BlockPreorder.size();
I !=
E; ++
I)
589 errs() <<
" " <<
Info.Context.print(BlockPreorder[
I]) <<
": " <<
I
596 TopLevelCycles.clear();
602template <
typename ContextT>
605 Context = ContextT(&
F);
614template <
typename ContextT>
631template <
typename ContextT>
634 verifyBlockNumberEpoch(
Block->getParent());
636 return Number < BlockMap.size() ? BlockMap[
Number] :
nullptr;
643template <
typename ContextT>
652 while (
A->getDepth() >
B->getDepth())
653 A =
A->getParentCycle();
654 while (
B->getDepth() >
A->getDepth())
655 B =
B->getParentCycle();
661 A =
A->getParentCycle();
662 B =
B->getParentCycle();
672template <
typename ContextT>
683template <
typename ContextT>
688 return Cycle->getDepth();
695template <
typename ContextT>
705 Cycle->verifyCycle();
707 Cycle->verifyCycleNest();
711 assert(CycleInBlockMap !=
nullptr);
725template <
typename ContextT>
729 for (
unsigned I = 0;
I <
Cycle->Depth; ++
I)
732 Out <<
Cycle->print(Context) <<
'\n';
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static const Function * getParent(const Value *V)
bbsections Prepares for basic block by splitting functions into clusters of basic blocks
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
Find all cycles in a control-flow graph, including irreducible loops.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Implements a dense probed hash-table based set.
GenericCycleInfoCompute(CycleInfoT &Info)
void run(FunctionT *F)
Main function of the cycle info computations.
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 addBlockToCycle(BlockT *Block, CycleT *Cycle)
Assumes that Cycle is the innermost cycle containing Block.
iterator_range< const_toplevel_iterator > toplevel_cycles() const
CycleT * getTopLevelParentCycle(const BlockT *Block) const
friend class GenericCycleInfoCompute
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.
GenericCycle< ContextT > CycleT
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 * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
BlockT * getHeader() const
bool isReducible() const
Whether the cycle is a natural loop.
void getExitingBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all blocks of this cycle that have successor outside of this cycle.
const_block_iterator block_begin() const
void verifyCycle() const
Verify that this is actually a well-formed cycle in the CFG.
iterator_range< const_entry_iterator > entries() const
void verifyCycleNest() const
Verify the parent-child relations of this cycle.
BlockT * getCyclePreheader() const
Return the preheader block for this cycle.
void getExitBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all of the successor blocks of this cycle.
typename SmallVector< BlockT *, 8 >::const_iterator const_block_iterator
Iteration over blocks in the cycle (including entry blocks).
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. O(1).
const_block_iterator block_end() const
typename ContextT::BlockT BlockT
size_t getNumBlocks() const
A helper class to return the specified delimiter string after the first invocation of operator String...
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...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
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)
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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto succ_size(const MachineBasicBlock *BB)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
iterator_range< typename GraphTraits< Inverse< GraphType > >::ChildIteratorType > inverse_children(const typename GraphTraits< GraphType >::NodeRef &G)
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
iterator_range< df_iterator< T > > depth_first(const T &G)
std::pair< iterator, bool > insert(NodeRef N)