23#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24#define LLVM_ADT_GENERICCYCLEIMPL_H
34#define DEBUG_TYPE "generic-cycle-impl"
38template <
typename ContextT>
41 if (ExitBlocksCaches.empty())
42 ExitBlocksCaches.resize(NumCycles);
43 auto &Cache = ExitBlocksCaches[
C.Index];
49 Cache.push_back(Succ);
51 TmpStorage.
append(Cache.begin(), Cache.end());
54template <
typename ContextT>
67template <
typename ContextT>
80 if (!Predecessor->isLegalToHoistInto())
86template <
typename ContextT>
98 if (Out && Out != Pred)
107template <
typename ContextT>
136 "Cycle block has no in-cycle successors!");
140 "Cycle block has no in-cycle predecessors!");
148 assert(!OutsideCyclePreds.empty() &&
"Entry is unreachable!");
149 }
else if (!OutsideCyclePreds.empty()) {
153 BlockT *EntryBB = &BB->getParent()->front();
155 assert(!OutsideCyclePreds.contains(CB) &&
156 "Non-entry block reachable from outside!");
159 "Cycle contains function entry block!");
165 dbgs() <<
"The following blocks are unreachable in the cycle:\n ";
167 for (
auto *BB : Blocks) {
168 if (!VisitedBBs.
count(BB)) {
170 BB->printAsOperand(
dbgs());
181template <
typename ContextT>
184 const CycleT &Cyc = deref(
C);
190 "Cycle does not contain all the blocks of a subcycle!");
196 if (Cyc.hasParent()) {
198 "Cycle is not a subcycle of its parent!");
204template <
typename ContextT>
class GenericCycleInfoCompute {
205 using BlockT =
typename ContextT::BlockT;
206 using FunctionT =
typename ContextT::FunctionT;
208 using CycleT =
typename CycleInfoT::CycleT;
213 static constexpr unsigned NoCycle = ~0u;
215 static constexpr unsigned NoBlock = ~0u;
233 unsigned LoopHeader = 0;
235 BlockT *getBlock()
const {
return BlockAndHeader.
getPointer(); }
237 void setHeader() { BlockAndHeader.
setInt(
true); }
239 bool visited()
const {
return BlockAndHeader.
getOpaqueValue() !=
nullptr; }
246 unsigned NextSibling;
254 unsigned NumHeaders = 0;
259 GenericCycleInfoCompute(
const GenericCycleInfoCompute &) =
delete;
260 GenericCycleInfoCompute &operator=(
const GenericCycleInfoCompute &) =
delete;
262 static unsigned num(
const BlockT *
B) {
272 void tagLoopHeader(
unsigned B,
unsigned H) {
276 unsigned IH =
info(
B).LoopHeader;
293 void dfs(BlockT *EntryBlock);
302template <
typename ContextT>
306 verifyBlockNumberEpoch(
Block->getParent());
311template <
typename ContextT>
313 CycleT &Cyc = deref(
C);
316 if (
Number >= BlockMap.size())
323 unsigned Pos = Cyc.IdxEnd;
324 BlockLayout.insert(BlockLayout.begin() + Pos,
Block);
325 for (
unsigned I = 0;
I != NumCycles; ++
I) {
326 CycleT &
X = Cycles[
I];
327 if (
X.IdxBegin >= Pos) {
332 if (
X.EntryBegin >= Pos)
340 if (!ExitBlocksCaches.empty())
341 ExitBlocksCaches[
I.Index].clear();
349template <
typename ContextT>
352 unsigned N = Build.size();
354 Info.Cycles = std::make_unique<CycleT[]>(
N);
366 unsigned Cursor = 0, NextID = 0;
367 auto enter = [&](
unsigned C,
CycleRef Parent) {
368 unsigned ID = NextID++;
371 Flat.Parent = Parent;
372 Flat.Depth = Parent ?
Info.deref(Parent).Depth + 1 : 1;
374 Flat.EntryBegin = Cursor;
376 Cursor += Build[
C].OwnCount;
377 Flat.IdxBegin = Cursor;
378 Stack.push_back({
ID, Build[
C].ChildHead});
380 for (
auto TLC = TopHead; TLC != NoCycle; TLC = Build[TLC].NextSibling) {
382 while (!
Stack.empty()) {
384 if (
F.Child != NoCycle) {
385 unsigned C =
F.Child;
386 F.Child = Build[
C].NextSibling;
390 Flat.IdxEnd = Cursor;
391 Flat.NumDescendants = NextID -
F.Flat - 1;
398 Info.BlockLayout.resize_for_overwrite(Cursor);
400 BlockInfo &BI =
info(
N);
401 if (BI.LoopIdx == NoCycle)
403 unsigned Flat = FlatIdx[BI.LoopIdx];
405 Info.BlockLayout[--
Info.Cycles[
Flat].IdxBegin] = BI.getBlock();
410template <
typename ContextT>
426 unsigned TopHead = NoCycle;
427 for (
unsigned N : Preorder) {
428 BlockInfo &BI =
info(
N);
430 unsigned I = Build.
size();
432 unsigned &Head = BI.LoopHeader != NoBlock
433 ? Build[
info(BI.LoopHeader).LoopIdx].ChildHead
438 << Info.Context.print(BI.getBlock()) <<
"\n");
439 }
else if (BI.LoopHeader != NoBlock) {
440 BI.LoopIdx =
info(BI.LoopHeader).LoopIdx;
441 ++Build[BI.LoopIdx].OwnCount;
443 BI.LoopIdx = NoCycle;
446 flatten(Build, TopHead);
447 if (Reentries.empty())
457 for (
auto &[
H,
B] : Reentries)
460 unsigned PrevH = NoBlock;
461 for (
unsigned I = 0,
E = Reentries.size();
I !=
E; ++
I) {
462 if (
I && Reentries[
I] == Reentries[
I - 1])
464 auto [
H, R] = Reentries[
I];
465 CycleT &Cyc = Info.deref(Info.BlockMap[
H]);
467 BlockT *Header = Info.BlockLayout[Cyc.EntryBegin];
468 Cyc.EntryBegin = Info.BlockLayout.size();
469 Info.BlockLayout.push_back(Header);
472 Info.BlockLayout.push_back(
info(Preorder[R]).getBlock());
473 Cyc.EntrySize = Info.BlockLayout.size() - Cyc.EntryBegin;
480template <
typename ContextT>
481void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
485 using SuccIt =
decltype(
successors(EntryBlock).begin());
488 std::reverse_iterator<SuccIt> Cur, End;
491 unsigned Counter = 0;
494 auto open = [&](BlockT *
Block) {
496 Preorder[Counter] =
N;
497 BlockInfo &BI =
info(
N);
498 BI.BlockAndHeader.setPointerAndInt(
Block,
false);
500 BI.LoopHeader = NoBlock;
502 Stack.push_back({
N, std::make_reverse_iterator(Succs.end()),
503 std::make_reverse_iterator(Succs.begin())});
507 while (!
Stack.empty()) {
508 Frame &Top =
Stack.back();
509 if (Top.Cur != Top.End) {
510 unsigned B0 = Top.Block;
511 BlockT *B1P = *Top.Cur++;
512 unsigned B1 = num(B1P);
513 BlockInfo &B1Info =
info(B1);
514 if (!B1Info.visited()) {
517 }
else if (B1Info.Pos > 0) {
519 if (!B1Info.isHeader()) {
523 tagLoopHeader(B0, B1);
529 for (
unsigned H = B1Info.LoopHeader;
H != NoBlock;
531 if (
info(
H).Pos > 0) {
532 tagLoopHeader(B0,
H);
540 unsigned B0 = Top.Block;
544 if (!
Stack.empty() &&
info(B0).LoopHeader != NoBlock)
545 tagLoopHeader(
Stack.back().Block,
info(B0).LoopHeader);
557 ExitBlocksCaches.clear();
561template <
typename ContextT>
564 Context = ContextT(&
F);
573template <
typename ContextT>
590template <
typename ContextT>
619template <
typename ContextT>
630template <
typename ContextT>
658template <
typename ContextT>
669template <
typename ContextT>
679 Out <<
' ' << Context.print(
Block);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static const Function * getParent(const Value *V)
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.
This file defines the PointerIntPair class.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's preorder index.
Implements a dense probed hash-table based set.
GenericCycleInfoCompute(CycleInfoT &Info)
void run(FunctionT *F)
Main function of the cycle info computations.
Cycle information for a function.
typename SSAContext::FunctionT FunctionT
void verify() const
Verify that the entire cycle tree well-formed.
void getExitingBlocks(CycleRef C, SmallVectorImpl< BlockT * > &TmpStorage) const
Return all blocks of C that have a successor outside of C.
void verifyCycle(CycleRef C) const
Verify that C is actually a well-formed cycle in the CFG.
bool isReducible(CycleRef C) const
BlockT * getCyclePreheader(CycleRef C) const
Return the preheader block for C.
CycleRef getSmallestCommonCycle(CycleRef A, CycleRef B) const
Find the innermost cycle containing both given cycles.
CycleRef getParentCycle(CycleRef C) const
BlockT * getCyclePredecessor(CycleRef C) const
If C has exactly one entry with exactly one predecessor, return it, otherwise return nullptr.
friend class GenericCycleInfoCompute
void verifyCycleNest(CycleRef C) const
Verify the parent-child relations of C.
void print(raw_ostream &Out) const
Print the cycle info.
ArrayRef< BlockT * > getEntries(CycleRef C) const
void clear()
Reset the object to its initial state.
void addBlockToCycle(BlockT *Block, CycleRef C)
Assumes that C is the innermost cycle containing Block.
ArrayRef< BlockT * > getBlocks(CycleRef C) const
Return the blocks of C, including those of nested cycles.
Printable printEntries(CycleRef C, const ContextT &Ctx) const
unsigned getDepth(CycleRef C) const
void compute(FunctionT &F)
Compute the cycle info for a function.
void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New)
void getExitBlocks(CycleRef C, SmallVectorImpl< BlockT * > &TmpStorage) const
Return all of the successor blocks of C: the blocks outside of C which are branched to from within it...
size_t getNumBlocks(CycleRef C) const
bool isEntry(CycleRef C, const BlockT *Block) const
BlockT * getHeader(CycleRef C) const
typename ContextT::BlockT BlockT
CycleRef getCycle(const BlockT *Block) const
Find the innermost cycle containing Block.
A helper class to return the specified delimiter string after the first invocation of operator String...
PointerIntPair - This class implements a pair of a pointer and small integer.
void setInt(IntType IntVal) &
void * getOpaqueValue() const
PointerTy getPointer() const
Simple wrapper around std::function<void(raw_ostream&)>.
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 resize_for_overwrite(size_type N)
Like resize, but T is POD, the new values won't be initialized.
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void truncate(size_type N)
Like resize, but requires that N is less than size().
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ 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)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
auto successors(const MachineBasicBlock *BB)
static bool isHeader(StringRef S)
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)
void sort(IteratorTy Start, IteratorTy End)
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...
iterator_range< typename GraphTraits< Inverse< GraphType > >::ChildIteratorType > inverse_children(const typename GraphTraits< GraphType >::NodeRef &G)
ArrayRef(const T &OneElt) -> ArrayRef< T >
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)
Binary functor that adapts to any other binary functor after dereferencing operands.
std::pair< iterator, bool > insert(NodeRef N)