LLVM 23.0.0git
GenericCycleImpl.h
Go to the documentation of this file.
1//===- GenericCycleImpl.h -------------------------------------*- C++ -*---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This template implementation resides in a separate file so that it
11/// does not get injected into every .cpp file that includes the
12/// generic header.
13///
14/// DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO.
15///
16/// This file should only be included by files that implement a
17/// specialization of the relevant templates. Currently these are:
18/// - llvm/lib/IR/CycleInfo.cpp
19/// - llvm/lib/CodeGen/MachineCycleAnalysis.cpp
20///
21//===----------------------------------------------------------------------===//
22
23#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24#define LLVM_ADT_GENERICCYCLEIMPL_H
25
26#include "llvm/ADT/DenseSet.h"
30
31#define DEBUG_TYPE "generic-cycle-impl"
32
33namespace llvm {
34
35template <typename ContextT>
36bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
37 if (!C)
38 return false;
39
40 if (Depth > C->Depth)
41 return false;
42 while (Depth < C->Depth)
43 C = C->ParentCycle;
44 return this == C;
45}
46
47template <typename ContextT>
49 SmallVectorImpl<BlockT *> &TmpStorage) const {
50 if (!ExitBlocksCache.empty()) {
51 TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
52 return;
53 }
54
55 size_t NumExitBlocks = 0;
56 for (BlockT *Block : blocks()) {
57 llvm::append_range(ExitBlocksCache, successors(Block));
58
59 for (size_t Idx = NumExitBlocks, End = ExitBlocksCache.size(); Idx < End;
60 ++Idx) {
61 BlockT *Succ = ExitBlocksCache[Idx];
62 if (!contains(Succ)) {
63 auto ExitEndIt = ExitBlocksCache.begin() + NumExitBlocks;
64 if (std::find(ExitBlocksCache.begin(), ExitEndIt, Succ) == ExitEndIt)
65 ExitBlocksCache[NumExitBlocks++] = Succ;
66 }
67 }
68
69 ExitBlocksCache.resize(NumExitBlocks);
70 }
71
72 TmpStorage.append(ExitBlocksCache.begin(), ExitBlocksCache.end());
73}
74
75template <typename ContextT>
77 SmallVectorImpl<BlockT *> &TmpStorage) const {
78 for (BlockT *Block : blocks()) {
79 for (BlockT *Succ : successors(Block)) {
80 if (!contains(Succ)) {
81 TmpStorage.push_back(Block);
82 break;
83 }
84 }
85 }
86}
87
88template <typename ContextT>
90 BlockT *Predecessor = getCyclePredecessor();
91 if (!Predecessor)
92 return nullptr;
93
94 assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
95
96 if (succ_size(Predecessor) != 1)
97 return nullptr;
98
99 // Make sure we are allowed to hoist instructions into the predecessor.
100 if (!Predecessor->isLegalToHoistInto())
101 return nullptr;
102
103 return Predecessor;
104}
105
106template <typename ContextT>
108 if (!isReducible())
109 return nullptr;
110
111 BlockT *Out = nullptr;
112
113 // Loop over the predecessors of the header node...
114 BlockT *Header = getHeader();
115 for (const auto Pred : predecessors(Header)) {
116 if (!contains(Pred)) {
117 if (Out && Out != Pred)
118 return nullptr;
119 Out = Pred;
120 }
121 }
122
123 return Out;
124}
125
126/// \brief Verify that this is actually a well-formed cycle in the CFG.
127template <typename ContextT> void GenericCycle<ContextT>::verifyCycle() const {
128#ifndef NDEBUG
129 assert(!Blocks.empty() && "Cycle cannot be empty.");
130 DenseSet<BlockT *> Blocks;
131 for (BlockT *BB : blocks()) {
132 assert(Blocks.insert(BB).second); // duplicates in block list?
133 }
134 assert(!Entries.empty() && "Cycle must have one or more entries.");
135
136 DenseSet<BlockT *> Entries;
137 for (BlockT *Entry : entries()) {
138 assert(Entries.insert(Entry).second); // duplicate entry?
139 assert(contains(Entry));
140 }
141
142 // Setup for using a depth-first iterator to visit every block in the cycle.
144 getExitBlocks(ExitBBs);
146 VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
147
148 // Keep track of the BBs visited.
149 SmallPtrSet<BlockT *, 8> VisitedBBs;
150
151 // Check the individual blocks.
152 for (BlockT *BB : depth_first_ext(getHeader(), VisitSet)) {
154 [&](BlockT *B) { return contains(B); }) &&
155 "Cycle block has no in-cycle successors!");
156
158 [&](BlockT *B) { return contains(B); }) &&
159 "Cycle block has no in-cycle predecessors!");
160
161 DenseSet<BlockT *> OutsideCyclePreds;
163 if (!contains(B))
164 OutsideCyclePreds.insert(B);
165
166 if (Entries.contains(BB)) {
167 assert(!OutsideCyclePreds.empty() && "Entry is unreachable!");
168 } else if (!OutsideCyclePreds.empty()) {
169 // A non-entry block shouldn't be reachable from outside the cycle,
170 // though it is permitted if the predecessor is not itself actually
171 // reachable.
172 BlockT *EntryBB = &BB->getParent()->front();
173 for (BlockT *CB : depth_first(EntryBB))
174 assert(!OutsideCyclePreds.contains(CB) &&
175 "Non-entry block reachable from outside!");
176 }
177 assert(BB != &getHeader()->getParent()->front() &&
178 "Cycle contains function entry block!");
179
180 VisitedBBs.insert(BB);
181 }
182
183 if (VisitedBBs.size() != getNumBlocks()) {
184 dbgs() << "The following blocks are unreachable in the cycle:\n ";
185 ListSeparator LS;
186 for (auto *BB : Blocks) {
187 if (!VisitedBBs.count(BB)) {
188 dbgs() << LS;
189 BB->printAsOperand(dbgs());
190 }
191 }
192 dbgs() << "\n";
193 llvm_unreachable("Unreachable block in cycle");
194 }
195
197#endif
198}
199
200/// \brief Verify the parent-child relations of this cycle.
201///
202/// Note that this does \em not check that cycle is really a cycle in the CFG.
203template <typename ContextT>
205#ifndef NDEBUG
206 // Check the subcycles.
207 for (GenericCycle *Child : children()) {
208 // Each block in each subcycle should be contained within this cycle.
209 for (BlockT *BB : Child->blocks()) {
210 assert(contains(BB) &&
211 "Cycle does not contain all the blocks of a subcycle!");
212 }
213 assert(Child->Depth == Depth + 1);
214 }
215
216 // Check the parent cycle pointer.
217 if (ParentCycle) {
218 assert(is_contained(ParentCycle->children(), this) &&
219 "Cycle is not a subcycle of its parent!");
220 assert(ParentCycle->TopLevelCycle == TopLevelCycle &&
221 "Top level cycle of parent cycle must be the same");
222 } else {
223 assert(TopLevelCycle == this &&
224 "Cycle without parent must be top-level cycle");
225 }
226#endif
227}
228
229/// \brief Helper class for computing cycle information.
230template <typename ContextT> class GenericCycleInfoCompute {
231 using BlockT = typename ContextT::BlockT;
232 using FunctionT = typename ContextT::FunctionT;
233 using CycleInfoT = GenericCycleInfo<ContextT>;
234 using CycleT = typename CycleInfoT::CycleT;
235
236 CycleInfoT &Info;
237
238 struct DFSInfo {
239 unsigned Start = 0; // DFS start; positive if block is found
240 unsigned End = 0; // DFS end
241
242 DFSInfo() = default;
243 explicit DFSInfo(unsigned Start) : Start(Start) {}
244
245 explicit operator bool() const { return Start; }
246
247 /// Whether this node is an ancestor (or equal to) the node \p Other
248 /// in the DFS tree.
249 bool isAncestorOf(const DFSInfo &Other) const {
250 return Start <= Other.Start && Other.End <= End;
251 }
252 };
253
254 // Indexed by block number.
255 SmallVector<DFSInfo, 8> BlockDFSInfo;
256 SmallVector<BlockT *, 8> BlockPreorder;
257
258 GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete;
259 GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete;
260
261 DFSInfo getDFSInfo(BlockT *B) const {
263 return BlockDFSInfo[Number];
264 }
265
266 DFSInfo &getOrInsertDFSInfo(BlockT *B) {
268 return BlockDFSInfo[Number];
269 }
270
271public:
272 GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {}
273
274 void run(FunctionT *F);
275
276 static void updateDepth(CycleT *SubTree);
277
278private:
279 void dfs(FunctionT *F, BlockT *EntryBlock);
280};
281
282template <typename ContextT>
284 const BlockT *Block) const -> CycleT * {
286 return Cycle ? Cycle->TopLevelCycle : nullptr;
287}
288
289template <typename ContextT>
290void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
291 CycleT *Child) {
292 assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
293 "NewParent and Child must be both top level cycle!\n");
294 auto &CurrentContainer =
295 Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
296 auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
297 return Child == Ptr.get();
298 });
299 assert(Pos != CurrentContainer.end());
300 NewParent->Children.push_back(std::move(*Pos));
301 *Pos = std::move(CurrentContainer.back());
302 CurrentContainer.pop_back();
303 Child->ParentCycle = NewParent;
304 Child->TopLevelCycle = NewParent;
305 for (CycleT *Cycle : depth_first(Child))
306 Cycle->TopLevelCycle = NewParent;
307
308 NewParent->Blocks.insert_range(Child->blocks());
309 NewParent->clearCache();
310 Child->clearCache();
312
313template <typename ContextT>
314void GenericCycleInfo<ContextT>::verifyBlockNumberEpoch(
315 const FunctionT *Fn) const {
316 assert(BlockNumberEpoch ==
318 "CycleInfo used with outdated block number epoch");
319}
320
321template <typename ContextT>
322void GenericCycleInfo<ContextT>::addToBlockMap(BlockT *Block, CycleT *Cycle) {
323 // The caller should ensure that BlockMap is large enough.
324 verifyBlockNumberEpoch(Block->getParent());
326 BlockMap[Number] = Cycle;
327}
328
329template <typename ContextT>
331 // Make sure BlockMap is large enough for the new block.
333 if (Number >= BlockMap.size())
334 BlockMap.resize(GraphTraits<FunctionT *>::getMaxNumber(Block->getParent()));
335
336 // FixMe: Appending NewBlock is fine as a set of blocks in a cycle. When
337 // printing, cycle NewBlock is at the end of list but it should be in the
338 // middle to represent actual traversal of a cycle.
339 Cycle->appendBlock(Block);
340 addToBlockMap(Block, Cycle);
341
342 CycleT *ParentCycle = Cycle->getParentCycle();
343 while (ParentCycle) {
344 Cycle = ParentCycle;
345 Cycle->appendBlock(Block);
346 ParentCycle = Cycle->getParentCycle();
347 }
348
349 Cycle->clearCache();
350}
351
352/// \brief Main function of the cycle info computations.
353template <typename ContextT>
355 BlockT *EntryBlock = GraphTraits<FunctionT *>::getEntryNode(F);
356 LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
357 << "\n");
358 dfs(F, EntryBlock);
359
361
362 for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
363 const DFSInfo CandidateInfo = getDFSInfo(HeaderCandidate);
364
365 for (BlockT *Pred : predecessors(HeaderCandidate)) {
366 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
367 // This automatically ignores unreachable predecessors since they have
368 // zeros in their DFSInfo.
369 if (CandidateInfo.isAncestorOf(PredDFSInfo))
370 Worklist.push_back(Pred);
371 }
372 if (Worklist.empty()) {
373 continue;
374 }
375
376 // Found a cycle with the candidate as its header.
377 LLVM_DEBUG(errs() << "Found cycle for header: "
378 << Info.Context.print(HeaderCandidate) << "\n");
379 std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
380 NewCycle->appendEntry(HeaderCandidate);
381 NewCycle->appendBlock(HeaderCandidate);
382 Info.addToBlockMap(HeaderCandidate, NewCycle.get());
383
384 // Helper function to process (non-back-edge) predecessors of a discovered
385 // block and either add them to the worklist or recognize that the given
386 // block is an additional cycle entry.
387 auto ProcessPredecessors = [&](BlockT *Block) {
388 LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
389
390 bool IsEntry = false;
391 for (BlockT *Pred : predecessors(Block)) {
392 const DFSInfo PredDFSInfo = getDFSInfo(Pred);
393 if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
394 Worklist.push_back(Pred);
395 } else if (!PredDFSInfo) {
396 // Ignore an unreachable predecessor. It will will incorrectly cause
397 // Block to be treated as a cycle entry.
398 LLVM_DEBUG(errs() << " skipped unreachable predecessor.\n");
399 } else {
400 IsEntry = true;
401 }
402 }
403 if (IsEntry) {
404 assert(!NewCycle->isEntry(Block));
405 LLVM_DEBUG(errs() << "append as entry\n");
406 NewCycle->appendEntry(Block);
407 } else {
408 LLVM_DEBUG(errs() << "append as child\n");
409 }
410 };
411
412 do {
413 BlockT *Block = Worklist.pop_back_val();
414 if (Block == HeaderCandidate)
415 continue;
416
417 // If the block has already been discovered by some cycle
418 // (possibly by ourself), then the outermost cycle containing it
419 // should become our child.
420 if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
421 LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
422
423 if (BlockParent != NewCycle.get()) {
425 << "discovered child cycle "
426 << Info.Context.print(BlockParent->getHeader()) << "\n");
427 // Make BlockParent the child of NewCycle.
428 Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
429
430 for (auto *ChildEntry : BlockParent->entries())
431 ProcessPredecessors(ChildEntry);
432 } else {
434 << "known child cycle "
435 << Info.Context.print(BlockParent->getHeader()) << "\n");
436 }
437 } else {
438 Info.addToBlockMap(Block, NewCycle.get());
439 assert(!is_contained(NewCycle->Blocks, Block));
440 NewCycle->Blocks.insert(Block);
441 ProcessPredecessors(Block);
442 }
443 } while (!Worklist.empty());
444
445 Info.TopLevelCycles.push_back(std::move(NewCycle));
446 }
447
448 // Fix top-level cycle links and compute cycle depths.
449 for (auto *TLC : Info.toplevel_cycles()) {
450 LLVM_DEBUG(errs() << "top-level cycle: "
451 << Info.Context.print(TLC->getHeader()) << "\n");
452
453 TLC->ParentCycle = nullptr;
454 updateDepth(TLC);
455 }
456}
457
458/// \brief Recompute depth values of \p SubTree and all descendants.
459template <typename ContextT>
461 for (CycleT *Cycle : depth_first(SubTree))
462 Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
463}
464
465/// \brief Compute a DFS of basic blocks starting at the function entry.
466///
467/// Fills BlockDFSInfo with start/end counters and BlockPreorder.
468template <typename ContextT>
469void GenericCycleInfoCompute<ContextT>::dfs(FunctionT *F, BlockT *EntryBlock) {
470 SmallVector<unsigned, 8> DFSTreeStack;
471 SmallVector<BlockT *, 8> TraverseStack;
472 unsigned Counter = 0;
473 TraverseStack.emplace_back(EntryBlock);
474
475 BlockDFSInfo.resize(GraphTraits<FunctionT *>::getMaxNumber(F));
476 do {
477 BlockT *Block = TraverseStack.back();
478 LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
479 << "\n");
480 DFSInfo &Info = getOrInsertDFSInfo(Block);
481 if (Info.Start == 0) {
482 Info.Start = ++Counter;
483
484 // We're visiting the block for the first time. Open its DFSInfo, add
485 // successors to the traversal stack, and remember the traversal stack
486 // depth at which the block was opened, so that we can correctly record
487 // its end time.
488 LLVM_DEBUG(errs() << " first encountered at depth "
489 << TraverseStack.size() << "\n");
490
491 DFSTreeStack.emplace_back(TraverseStack.size());
492 llvm::append_range(TraverseStack, successors(Block));
493
494 BlockPreorder.push_back(Block);
495 LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n");
496 } else {
497 assert(!DFSTreeStack.empty());
498 if (DFSTreeStack.back() == TraverseStack.size()) {
499 LLVM_DEBUG(errs() << " ended at " << Counter << "\n");
500 Info.End = Counter;
501 DFSTreeStack.pop_back();
502 } else {
503 LLVM_DEBUG(errs() << " already done\n");
504 }
505 TraverseStack.pop_back();
506 }
507 } while (!TraverseStack.empty());
508 assert(DFSTreeStack.empty());
509
511 errs() << "Preorder:\n";
512 for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
513 errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
514 }
515 );
516}
517
518/// \brief Reset the object to its initial state.
519template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
520 TopLevelCycles.clear();
521 BlockMap.clear();
522}
523
524/// \brief Compute the cycle info for a function.
525template <typename ContextT>
528 Context = ContextT(&F);
529 BlockNumberEpoch = GraphTraits<FunctionT *>::getNumberEpoch(&F);
530 BlockMap.resize(GraphTraits<FunctionT *>::getMaxNumber(&F));
531
532 LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
533 << "\n");
534 Compute.run(&F);
535}
536
537template <typename ContextT>
539 BlockT *NewBlock) {
540 // Edge Pred-Succ is replaced by edges Pred-NewBlock and NewBlock-Succ, all
541 // cycles that had blocks Pred and Succ also get NewBlock.
543 if (!Cycle)
544 return;
545
546 addBlockToCycle(NewBlock, Cycle);
548}
549
550/// \brief Find the innermost cycle containing a given block.
551///
552/// \returns the innermost cycle containing \p Block or nullptr if
553/// it is not contained in any cycle.
554template <typename ContextT>
556 -> CycleT * {
557 verifyBlockNumberEpoch(Block->getParent());
559 return Number < BlockMap.size() ? BlockMap[Number] : nullptr;
560}
561
562/// \brief Find the innermost cycle containing both given cycles.
563///
564/// \returns the innermost cycle containing both \p A and \p B
565/// or nullptr if there is no such cycle.
566template <typename ContextT>
568 CycleT *B) const
569 -> CycleT * {
570 if (!A || !B)
571 return nullptr;
572
573 // If cycles A and B have different depth replace them with parent cycle
574 // until they have the same depth.
575 while (A->getDepth() > B->getDepth())
576 A = A->getParentCycle();
577 while (B->getDepth() > A->getDepth())
578 B = B->getParentCycle();
579
580 // Cycles A and B are at same depth but may be disjoint, replace them with
581 // parent cycles until we find cycle that contains both or we run out of
582 // parent cycles.
583 while (A != B) {
584 A = A->getParentCycle();
585 B = B->getParentCycle();
586 }
587
588 return A;
589}
590
591/// \brief Find the innermost cycle containing both given blocks.
592///
593/// \returns the innermost cycle containing both \p A and \p B
594/// or nullptr if there is no such cycle.
595template <typename ContextT>
601
602/// \brief get the depth for the cycle which containing a given block.
603///
604/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
605/// not contained in any cycle.
606template <typename ContextT>
609 if (!Cycle)
610 return 0;
611 return Cycle->getDepth();
612}
613
614/// \brief Verify the internal consistency of the cycle tree.
615///
616/// Note that this does \em not check that cycles are really cycles in the CFG,
617/// or that the right set of cycles in the CFG were found.
618template <typename ContextT>
620#ifndef NDEBUG
621 DenseSet<BlockT *> CycleHeaders;
622
623 for (CycleT *TopCycle : toplevel_cycles()) {
624 for (CycleT *Cycle : depth_first(TopCycle)) {
625 BlockT *Header = Cycle->getHeader();
626 assert(CycleHeaders.insert(Header).second);
627 if (VerifyFull)
628 Cycle->verifyCycle();
629 else
630 Cycle->verifyCycleNest();
631 // Check the block map entries for blocks contained in this cycle.
632 for (BlockT *BB : Cycle->blocks()) {
633 CycleT *CycleInBlockMap = getCycle(BB);
634 assert(CycleInBlockMap != nullptr);
635 assert(Cycle->contains(CycleInBlockMap));
636 }
637 }
638 }
639#endif
640}
641
642/// \brief Verify that the entire cycle tree well-formed.
643template <typename ContextT> void GenericCycleInfo<ContextT>::verify() const {
644 verifyCycleNest(/*VerifyFull=*/true);
645}
646
647/// \brief Print the cycle info.
648template <typename ContextT>
650 for (const auto *TLC : toplevel_cycles()) {
651 for (const CycleT *Cycle : depth_first(TLC)) {
652 for (unsigned I = 0; I < Cycle->Depth; ++I)
653 Out << " ";
654
655 Out << Cycle->print(Context) << '\n';
656 }
657 }
658}
659
660} // namespace llvm
661
662#undef DEBUG_TYPE
663
664#endif // LLVM_ADT_GENERICCYCLEIMPL_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
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.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:483
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:114
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
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.
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.
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 size() const
Definition SmallPtrSet.h:99
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 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)
Definition DenseSet.h:202
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
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.
Definition STLExtras.h:2208
CycleInfo::CycleT Cycle
Definition CycleInfo.h:26
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
auto succ_size(const MachineBasicBlock *BB)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Other
Any other memory.
Definition ModRef.h:68
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.
Definition STLExtras.h:1772
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.
Definition STLExtras.h:1947
iterator_range< df_iterator< T > > depth_first(const T &G)
std::pair< iterator, bool > insert(NodeRef N)