23#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24#define LLVM_ADT_GENERICCYCLEIMPL_H
31#define DEBUG_TYPE "generic-cycle-impl"
35template <
typename ContextT>
47template <
typename ContextT>
50 if (!ExitBlocksCache.empty()) {
51 TmpStorage = ExitBlocksCache;
57 size_t NumExitBlocks = 0;
61 for (
size_t Idx = NumExitBlocks, End = TmpStorage.
size(); Idx < End;
63 BlockT *Succ = TmpStorage[Idx];
65 auto ExitEndIt = TmpStorage.
begin() + NumExitBlocks;
66 if (std::find(TmpStorage.
begin(), ExitEndIt, Succ) == ExitEndIt)
67 TmpStorage[NumExitBlocks++] = Succ;
71 TmpStorage.
resize(NumExitBlocks);
73 ExitBlocksCache.append(TmpStorage.
begin(), TmpStorage.
end());
76template <
typename ContextT>
91template <
typename ContextT>
103 if (!Predecessor->isLegalToHoistInto())
109template <
typename ContextT>
120 if (Out && Out != Pred)
132 assert(!Blocks.empty() &&
"Cycle cannot be empty.");
135 assert(Blocks.insert(BB).second);
137 assert(!Entries.empty() &&
"Cycle must have one or more entries.");
141 assert(Entries.insert(Entry).second);
158 "Cycle block has no in-cycle successors!");
162 "Cycle block has no in-cycle predecessors!");
169 if (Entries.contains(BB)) {
170 assert(!OutsideCyclePreds.empty() &&
"Entry is unreachable!");
171 }
else if (!OutsideCyclePreds.empty()) {
175 BlockT *EntryBB = &BB->getParent()->front();
177 assert(!OutsideCyclePreds.contains(CB) &&
178 "Non-entry block reachable from outside!");
181 "Cycle contains function entry block!");
187 dbgs() <<
"The following blocks are unreachable in the cycle:\n ";
189 for (
auto *BB : Blocks) {
190 if (!VisitedBBs.
count(BB)) {
192 BB->printAsOperand(
dbgs());
206template <
typename ContextT>
210 for (GenericCycle *Child :
children()) {
212 for (
BlockT *BB : Child->blocks()) {
214 "Cycle does not contain all the blocks of a subcycle!");
216 assert(Child->Depth == Depth + 1);
222 "Cycle is not a subcycle of its parent!");
223 assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
224 "Top level cycle of parent cycle must be the same");
226 assert(TopLevelCycle ==
this &&
227 "Cycle without parent must be top-level cycle");
233template <
typename ContextT>
class GenericCycleInfoCompute {
234 using BlockT =
typename ContextT::BlockT;
235 using FunctionT =
typename ContextT::FunctionT;
237 using CycleT =
typename CycleInfoT::CycleT;
246 explicit DFSInfo(
unsigned Start) : Start(Start) {}
248 explicit operator bool()
const {
return Start; }
252 bool isAncestorOf(
const DFSInfo &
Other)
const {
253 return Start <=
Other.Start &&
Other.End <= End;
261 GenericCycleInfoCompute(
const GenericCycleInfoCompute &) =
delete;
262 GenericCycleInfoCompute &operator=(
const GenericCycleInfoCompute &) =
delete;
264 DFSInfo getDFSInfo(BlockT *
B)
const {
266 return BlockDFSInfo[
Number];
269 DFSInfo &getOrInsertDFSInfo(BlockT *
B) {
271 return BlockDFSInfo[
Number];
277 void run(FunctionT *
F);
282 void dfs(FunctionT *
F, BlockT *EntryBlock);
285template <
typename ContextT>
289 return Cycle ?
Cycle->TopLevelCycle :
nullptr;
292template <
typename ContextT>
293void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
295 assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
296 "NewParent and Child must be both top level cycle!\n");
297 auto &CurrentContainer =
298 Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
299 auto Pos =
llvm::find_if(CurrentContainer, [=](
const auto &Ptr) ->
bool {
300 return Child == Ptr.get();
303 NewParent->Children.push_back(std::move(*Pos));
304 *Pos = std::move(CurrentContainer.back());
305 CurrentContainer.pop_back();
306 Child->ParentCycle = NewParent;
307 Child->TopLevelCycle = NewParent;
309 Cycle->TopLevelCycle = NewParent;
311 NewParent->Blocks.insert_range(Child->
blocks());
312 NewParent->clearCache();
316template <
typename ContextT>
317void GenericCycleInfo<ContextT>::verifyBlockNumberEpoch(
319 assert(BlockNumberEpoch ==
321 "CycleInfo used with outdated block number epoch");
324template <
typename ContextT>
325void GenericCycleInfo<ContextT>::addToBlockMap(BlockT *
Block, CycleT *
Cycle) {
327 verifyBlockNumberEpoch(
Block->getParent());
332template <
typename ContextT>
336 if (
Number >= BlockMap.size())
346 while (ParentCycle) {
349 ParentCycle =
Cycle->getParentCycle();
356template <
typename ContextT>
359 LLVM_DEBUG(
errs() <<
"Entry block: " << Info.Context.print(EntryBlock)
365 for (BlockT *HeaderCandidate :
llvm::reverse(BlockPreorder)) {
366 const DFSInfo CandidateInfo = getDFSInfo(HeaderCandidate);
369 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
372 if (CandidateInfo.isAncestorOf(PredDFSInfo))
375 if (Worklist.
empty()) {
381 << Info.Context.print(HeaderCandidate) <<
"\n");
382 std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
383 NewCycle->appendEntry(HeaderCandidate);
384 NewCycle->appendBlock(HeaderCandidate);
385 Info.addToBlockMap(HeaderCandidate, NewCycle.get());
390 auto ProcessPredecessors = [&](BlockT *
Block) {
393 bool IsEntry =
false;
395 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
396 if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
398 }
else if (!PredDFSInfo) {
409 NewCycle->appendEntry(
Block);
417 if (
Block == HeaderCandidate)
423 if (
auto *BlockParent = Info.getTopLevelParentCycle(
Block)) {
426 if (BlockParent != NewCycle.get()) {
428 <<
"discovered child cycle "
429 << Info.Context.print(BlockParent->getHeader()) <<
"\n");
431 Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
433 for (
auto *ChildEntry : BlockParent->entries())
434 ProcessPredecessors(ChildEntry);
437 <<
"known child cycle "
438 << Info.Context.print(BlockParent->getHeader()) <<
"\n");
441 Info.addToBlockMap(
Block, NewCycle.get());
443 NewCycle->Blocks.insert(
Block);
444 ProcessPredecessors(
Block);
446 }
while (!Worklist.
empty());
448 Info.TopLevelCycles.push_back(std::move(NewCycle));
452 for (
auto *TLC : Info.toplevel_cycles()) {
454 << Info.Context.print(TLC->getHeader()) <<
"\n");
456 TLC->ParentCycle =
nullptr;
462template <
typename ContextT>
471template <
typename ContextT>
472void GenericCycleInfoCompute<ContextT>::dfs(FunctionT *
F, BlockT *EntryBlock) {
475 unsigned Counter = 0;
483 DFSInfo &Info = getOrInsertDFSInfo(
Block);
484 if (Info.Start == 0) {
485 Info.Start = ++Counter;
492 << TraverseStack.
size() <<
"\n");
497 BlockPreorder.push_back(
Block);
501 if (DFSTreeStack.
back() == TraverseStack.
size()) {
510 }
while (!TraverseStack.
empty());
514 errs() <<
"Preorder:\n";
515 for (
int i = 0, e = BlockPreorder.size(); i != e; ++i) {
516 errs() <<
" " << Info.Context.print(BlockPreorder[i]) <<
": " << i <<
"\n";
523 TopLevelCycles.clear();
528template <
typename ContextT>
531 Context = ContextT(&
F);
540template <
typename ContextT>
557template <
typename ContextT>
560 verifyBlockNumberEpoch(
Block->getParent());
562 return Number < BlockMap.size() ? BlockMap[
Number] :
nullptr;
569template <
typename ContextT>
578 while (
A->getDepth() >
B->getDepth())
579 A =
A->getParentCycle();
580 while (
B->getDepth() >
A->getDepth())
581 B =
B->getParentCycle();
587 A =
A->getParentCycle();
588 B =
B->getParentCycle();
598template <
typename ContextT>
609template <
typename ContextT>
614 return Cycle->getDepth();
621template <
typename ContextT>
631 Cycle->verifyCycle();
633 Cycle->verifyCycleNest();
637 assert(CycleInBlockMap !=
nullptr);
651template <
typename ContextT>
655 for (
unsigned I = 0;
I <
Cycle->Depth; ++
I)
658 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< ErlangGC > A("erlang", "erlang-compatible garbage collector")
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)
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 SSAContext::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.
void clearCache() const
Clear the cache of the cycle.
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.
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.
iterator_range< const_block_iterator > blocks() const
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.
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
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...
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)
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)
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.
iterator_range< df_iterator< T > > depth_first(const T &G)
std::pair< iterator, bool > insert(NodeRef N)