LLVM 24.0.0git
GenericCycleInfo.h
Go to the documentation of this file.
1//===- GenericCycleInfo.h - Info for Cycles in any IR ------*- 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/// \brief Find all cycles in a control-flow graph, including irreducible loops.
11///
12/// See docs/CycleTerminology.md for a formal definition of cycles.
13///
14/// Briefly:
15/// - A cycle is a generalization of a loop which can represent
16/// irreducible control flow.
17/// - Cycles identified in a program are implementation defined,
18/// depending on the DFS traversal chosen.
19/// - Cycles are well-nested, and form a forest with a parent-child
20/// relationship.
21/// - In any choice of DFS, every natural loop L is represented by a
22/// unique cycle C which is a superset of L.
23/// - In the absence of irreducible control flow, the cycles are
24/// exactly the natural loops in the program.
25///
26//===----------------------------------------------------------------------===//
27
28#ifndef LLVM_ADT_GENERICCYCLEINFO_H
29#define LLVM_ADT_GENERICCYCLEINFO_H
30
31#include "llvm/ADT/ArrayRef.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/Sequence.h"
37#include "llvm/ADT/SetVector.h"
40#include "llvm/ADT/iterator.h"
41#include "llvm/Support/Debug.h"
43#include <memory>
44#include <type_traits>
45
46namespace llvm {
47
48template <typename ContextT> class GenericCycleInfo;
49template <typename ContextT> class GenericCycleInfoCompute;
50
51/// Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's
52/// preorder index. Handles remain valid as long as the cycle forest is not
53/// recomputed; addBlockToCycle() adds a block but never adds, removes, or
54/// reorders cycles, so it leaves every handle valid.
55class CycleRef {
56 static constexpr unsigned InvalidIndex = ~0u;
57 unsigned Index = InvalidIndex;
58
59 explicit CycleRef(unsigned Index) : Index(Index) {}
60 template <typename ContextT> friend class GenericCycleInfo;
61 template <typename ContextT> friend class GenericCycleInfoCompute;
62 friend struct DenseMapInfo<CycleRef>;
63
64public:
65 CycleRef() = default;
66 bool isValid() const { return Index != InvalidIndex; }
67 explicit operator bool() const { return isValid(); }
68 bool operator==(CycleRef O) const { return Index == O.Index; }
69 bool operator!=(CycleRef O) const { return Index != O.Index; }
70};
71
72template <> struct DenseMapInfo<CycleRef> {
73 static unsigned getHashValue(CycleRef C) {
75 }
76 static bool isEqual(CycleRef A, CycleRef B) { return A.Index == B.Index; }
77};
78
79/// \brief Cycle information for a function.
80template <typename ContextT> class GenericCycleInfo {
81public:
82 using BlockT = typename ContextT::BlockT;
83 using FunctionT = typename ContextT::FunctionT;
84 template <typename> friend class GenericCycleInfoCompute;
85
86private:
87 /// Internal, data-only storage for a cycle. Consumers name a cycle by a
88 /// CycleRef handle and query it through GenericCycleInfo.
89 class Cycle {
90 public:
91 /// The parent cycle; invalid for a top-level cycle.
92 CycleRef Parent;
93
94 /// This cycle's blocks (its own and its nested cycles') occupy the
95 /// half-open range [IdxBegin, IdxEnd) of BlockLayout, nested like an Euler
96 /// tour of the cycle tree, so containment is an interval test (see
97 /// contains()).
98 unsigned IdxBegin = 0, IdxEnd = 0;
99
100 /// Depth of the cycle in the tree: top-level cycles are at depth 1 and each
101 /// nested cycle is one deeper (getCycleDepth() returns 0 for blocks outside
102 /// any cycle). Sibling cycles share a depth.
103 unsigned Depth = 0;
104
105 /// Number of cycles nested inside this one: the subtree occupies
106 /// [this, this + 1 + NumDescendants) of Cycles.
107 unsigned NumDescendants = 0;
108
109 /// The entry blocks (header first) are BlockLayout[EntryBegin,
110 /// EntryBegin+EntrySize). A reducible cycle has a single entry at IdxBegin.
111 /// An irreducible one appends its list past the Euler tour.
112 unsigned EntryBegin = 0, EntrySize = 0;
113
114 /// Whether this cycle has a parent, i.e. is not top-level.
115 bool hasParent() const { return Parent.isValid(); }
116 };
117 static_assert(std::is_trivially_destructible_v<Cycle>);
118 using CycleT = Cycle;
119
120 ContextT Context;
121 unsigned BlockNumberEpoch;
122
123 /// Map each basic block number to its inner-most containing cycle, or an
124 /// invalid handle if none.
125 SmallVector<CycleRef> BlockMap;
126
127 /// Euler tour of the cycle forest: every cycle's blocks form a contiguous
128 /// slice [IdxBegin, IdxEnd), nested inside its parent's. Entry lists for
129 /// irreducible cycles are appended past the tour (see EntryBegin).
130 SmallVector<BlockT *, 8> BlockLayout;
131
132 /// All cycles in forest preorder: every cycle is immediately followed by
133 /// its descendants, and skipping a top-level cycle's subtree lands on the
134 /// next top-level cycle.
135 std::unique_ptr<CycleT[]> Cycles;
136 unsigned NumCycles = 0;
137
138 /// getExitBlocks caches, indexed by the cycle's preorder index. Empty until
139 /// the first query, then sized to NumCycles.
140 mutable SmallVector<SmallVector<BlockT *, 0>, 0> ExitBlocksCaches;
141
142 /// The preorder index of \p C, i.e. its offset in the Cycles array.
143 unsigned getCycleIndex(const CycleT &C) const { return &C - Cycles.get(); }
144
145 /// Resolve a handle to its stored cycle. The assert catches deref of an
146 /// invalid handle and (partially) of a handle from another CycleInfo.
147 CycleT &deref(CycleRef C) {
148 assert(C.Index < NumCycles);
149 return Cycles[C.Index];
150 }
151 const CycleT &deref(CycleRef C) const {
152 assert(C.Index < NumCycles);
153 return Cycles[C.Index];
154 }
155 /// The handle for a stored cycle.
156 CycleRef ref(const CycleT &C) const { return CycleRef(getCycleIndex(C)); }
157
158 void verifyBlockNumberEpoch(const FunctionT *Fn) const {
159 assert(BlockNumberEpoch ==
160 GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
161 "CycleInfo used with outdated block number epoch");
162 }
163 void addToBlockMap(BlockT *Block, CycleRef C);
164
165public:
166 /// Iteration over child cycles, yielding handles. The first child (if any)
167 /// immediately follows this cycle in the preorder array, and each next
168 /// sibling follows the previous child's subtree.
170 : iterator_facade_base<const_child_iterator, std::forward_iterator_tag,
171 CycleRef, std::ptrdiff_t, CycleRef, CycleRef> {
172 const GenericCycleInfo *CI = nullptr;
173 unsigned Index = 0;
174
178
179 CycleRef operator*() const { return CycleRef(Index); }
181 Index += 1 + CI->Cycles[Index].NumDescendants;
182 return *this;
183 }
185 return Index == Other.Index;
186 }
187 };
188
189 GenericCycleInfo() = default;
192
193 void clear();
194 void compute(FunctionT &F);
195 void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New);
196
197 const FunctionT *getFunction() const { return Context.getFunction(); }
198 const ContextT &getSSAContext() const { return Context; }
199
200 /// All cycles in forest preorder.
201 auto cycles() const {
202 return map_range(seq(0u, NumCycles),
203 [](unsigned I) { return CycleRef(I); });
204 }
205
206 /// \brief Find the innermost cycle containing \p Block.
207 ///
208 /// \returns the innermost cycle containing \p Block or an invalid handle if
209 /// it is not contained in any cycle.
211 verifyBlockNumberEpoch(Block->getParent());
213 // A block added after compute() that no cycle contains (e.g. a critical
214 // edge MachineSink split outside every cycle) has a number beyond BlockMap.
215 if (Number >= BlockMap.size())
216 return CycleRef();
217 return BlockMap[Number];
218 }
219
221 return BlockLayout[deref(C).EntryBegin];
222 }
223 bool isReducible(CycleRef C) const { return deref(C).EntrySize == 1; }
224 CycleRef getParentCycle(CycleRef C) const { return deref(C).Parent; }
225 unsigned getDepth(CycleRef C) const { return deref(C).Depth; }
226 size_t getNumBlocks(CycleRef C) const {
227 const CycleT &Cyc = deref(C);
228 return Cyc.IdxEnd - Cyc.IdxBegin;
229 }
230
232 const CycleT &Cyc = deref(C);
233 return ArrayRef<BlockT *>(BlockLayout).slice(Cyc.EntryBegin, Cyc.EntrySize);
234 }
235 bool isEntry(CycleRef C, const BlockT *Block) const {
236 return is_contained(getEntries(C), Block);
237 }
238 // Append a one-element entry list past the Euler tour; storing Block at
239 // IdxBegin instead would disturb the block order.
241 CycleT &Cyc = deref(C);
242 Cyc.EntryBegin = BlockLayout.size();
243 BlockLayout.push_back(Block);
244 Cyc.EntrySize = 1;
245 }
246 /// Returns true iff \p Outer contains \p Inner. O(1). Non-strict.
247 bool contains(CycleRef Outer, CycleRef Inner) const {
248 const CycleT &O = deref(Outer);
249 const CycleT &I = deref(Inner);
250 return O.IdxBegin <= I.IdxBegin && I.IdxEnd <= O.IdxEnd;
251 }
253 unsigned First = C.Index + 1;
254 return llvm::make_range(
256 const_child_iterator(*this, First + deref(C).NumDescendants));
257 }
258 Printable printEntries(CycleRef C, const ContextT &Ctx) const {
259 return Printable([this, C, &Ctx](raw_ostream &Out) {
260 ListSeparator LS(" ");
261 for (auto *Entry : getEntries(C))
262 Out << LS << Ctx.print(Entry);
263 });
264 }
265
266 /// \brief Return whether \p Block is contained in \p C. O(1).
267 bool contains(CycleRef C, const BlockT *Block) const {
268 CycleRef Inner = getCycle(Block);
269 return Inner.isValid() && contains(C, Inner);
270 }
271
272 /// \brief Return the blocks of \p C, including those of nested cycles.
274 const CycleT &Cyc = deref(C);
275 return ArrayRef<BlockT *>(BlockLayout.begin() + Cyc.IdxBegin,
276 BlockLayout.begin() + Cyc.IdxEnd);
277 }
278
281
282 /// \brief Return the depth of the innermost cycle containing \p Block, or 0
283 /// if it is not contained in any cycle.
284 unsigned getCycleDepth(const BlockT *Block) const {
286 return C.isValid() ? getDepth(C) : 0;
287 }
288
291 if (!C)
292 return C;
293 while (CycleRef P = getParentCycle(C))
294 C = P;
295 return C;
296 }
297
298 /// Return all of the successor blocks of \p C: the blocks outside of \p C
299 /// which are branched to from within it.
300 void getExitBlocks(CycleRef C, SmallVectorImpl<BlockT *> &TmpStorage) const;
301
302 /// Return all blocks of \p C that have a successor outside of \p C.
304 SmallVectorImpl<BlockT *> &TmpStorage) const;
305
306 /// Return the preheader block for \p C. Pre-header is well-defined for
307 /// reducible cycle in docs/LoopTerminology.md as: the only one entering
308 /// block and its only edge is to the entry block. Return null for
309 /// irreducible cycles.
311
312 /// If \p C has exactly one entry with exactly one predecessor, return it,
313 /// otherwise return nullptr.
315
316 /// Verify that \p C is actually a well-formed cycle in the CFG.
317 ///
318 /// \p Reachable caches the blocks reachable from the function entry. It is
319 /// computed on first use if empty, so that verifying many cycles walks the
320 /// whole function at most once. It must not be reused after the CFG changes.
321 void verifyCycle(CycleRef C, SmallPtrSetImpl<BlockT *> &Reachable) const;
322
323 /// Verify the parent-child relations of \p C.
324 ///
325 /// Note that this does \em not check that \p C is really a cycle in the CFG.
326 void verifyCycleNest(CycleRef C) const;
327
328 /// Assumes that \p C is the innermost cycle containing \p Block.
329 /// \p Block will be appended to \p C and all of its parent cycles.
330 /// \p Block will be added to BlockMap with \p C.
332
333 /// Methods for debug and self-test.
334 //@{
335 void verifyCycleNest(bool VerifyFull = false) const;
336 void verify() const;
337 void print(raw_ostream &Out) const;
338 void dump() const { print(dbgs()); }
339 Printable print(CycleRef C) const;
340 //@}
341
342 /// Iteration over top-level cycles.
343 //@{
345
350 return const_toplevel_iterator(*this, NumCycles);
351 }
352
356 //@}
357};
358
359} // namespace llvm
360
361#endif // LLVM_ADT_GENERICCYCLEINFO_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines DenseMapInfo traits for DenseMap.
This file defines the little GenericSSAContext<X> template class that can be used to implement IR ana...
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
This file contains some templates that are useful if you are working with the STL at all.
Provides some synthesis utilities to produce sequences of values.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file contains some functions that are useful when dealing with strings.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's preorder index.
CycleRef()=default
friend class GenericCycleInfoCompute
bool operator!=(CycleRef O) const
bool operator==(CycleRef O) const
bool isValid() const
friend class GenericCycleInfo
Helper class for computing cycle information.
Cycle information for a function.
typename ContextT::FunctionT FunctionT
void verify() const
Verify that the entire cycle tree well-formed.
auto cycles() const
All cycles in forest preorder.
void getExitingBlocks(CycleRef C, SmallVectorImpl< BlockT * > &TmpStorage) const
Return all blocks of C that have a successor outside of C.
iterator_range< const_toplevel_iterator > toplevel_cycles() const
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
const_toplevel_iterator toplevel_end() const
void verifyCycleNest(CycleRef C) const
Verify the parent-child relations of C.
const FunctionT * getFunction() const
void verifyCycle(CycleRef C, SmallPtrSetImpl< BlockT * > &Reachable) const
Verify that C is actually a well-formed cycle in the CFG.
const_child_iterator const_toplevel_iterator
Iteration over top-level cycles.
void print(raw_ostream &Out) const
Print the cycle info.
ArrayRef< BlockT * > getEntries(CycleRef C) const
GenericCycleInfo & operator=(GenericCycleInfo &&)=default
CycleRef getTopLevelParentCycle(const BlockT *Block) const
void setSingleEntry(CycleRef C, BlockT *Block)
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)
const ContextT & getSSAContext() const
bool contains(CycleRef Outer, CycleRef Inner) const
Returns true iff Outer contains Inner. O(1). Non-strict.
GenericCycleInfo(GenericCycleInfo &&)=default
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
unsigned getCycleDepth(const BlockT *Block) const
Return the depth of the innermost cycle containing Block, or 0 if it is not contained in any cycle.
BlockT * getHeader(CycleRef C) const
bool contains(CycleRef C, const BlockT *Block) const
Return whether Block is contained in C. O(1).
typename ContextT::BlockT BlockT
const_toplevel_iterator toplevel_begin() const
CycleRef getCycle(const BlockT *Block) const
Find the innermost cycle containing Block.
iterator_range< const_child_iterator > children(CycleRef C) const
A helper class to return the specified delimiter string after the first invocation of operator String...
Simple wrapper around std::function<void(raw_ostream&)>.
Definition Printable.h:38
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
Definition iterator.h:80
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:366
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
static unsigned getHashValue(CycleRef C)
static bool isEqual(CycleRef A, CycleRef B)
An information struct used to provide DenseMap with the various necessary components for a given valu...
Iteration over child cycles, yielding handles.
const_child_iterator(const GenericCycleInfo &CI, unsigned Index)
bool operator==(const const_child_iterator &Other) const