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"
39#include "llvm/ADT/iterator.h"
40#include "llvm/Support/Debug.h"
42#include <memory>
43#include <type_traits>
44
45namespace llvm {
46
47template <typename ContextT> class GenericCycleInfo;
48template <typename ContextT> class GenericCycleInfoCompute;
49
50/// Opaque handle to a cycle within a GenericCycleInfo that wraps the cycle's
51/// preorder index. Handles remain valid as long as the cycle forest is not
52/// recomputed; addBlockToCycle() adds a block but never adds, removes, or
53/// reorders cycles, so it leaves every handle valid.
54class CycleRef {
55 static constexpr unsigned InvalidIndex = ~0u;
56 unsigned Index = InvalidIndex;
57
58 explicit CycleRef(unsigned Index) : Index(Index) {}
59 template <typename ContextT> friend class GenericCycleInfo;
60 template <typename ContextT> friend class GenericCycleInfoCompute;
61 friend struct DenseMapInfo<CycleRef>;
62
63public:
64 CycleRef() = default;
65 bool isValid() const { return Index != InvalidIndex; }
66 explicit operator bool() const { return isValid(); }
67 bool operator==(CycleRef O) const { return Index == O.Index; }
68 bool operator!=(CycleRef O) const { return Index != O.Index; }
69};
70
71template <> struct DenseMapInfo<CycleRef> {
72 static unsigned getHashValue(CycleRef C) {
74 }
75 static bool isEqual(CycleRef A, CycleRef B) { return A.Index == B.Index; }
76};
77
78/// \brief Cycle information for a function.
79template <typename ContextT> class GenericCycleInfo {
80public:
81 using BlockT = typename ContextT::BlockT;
82 using FunctionT = typename ContextT::FunctionT;
83 template <typename> friend class GenericCycleInfoCompute;
84
85private:
86 /// Internal, data-only storage for a cycle. Consumers name a cycle by a
87 /// CycleRef handle and query it through GenericCycleInfo.
88 class Cycle {
89 public:
90 /// The parent cycle; invalid for a top-level cycle.
91 CycleRef Parent;
92
93 /// This cycle's blocks (its own and its nested cycles') occupy the
94 /// half-open range [IdxBegin, IdxEnd) of BlockLayout, nested like an Euler
95 /// tour of the cycle tree, so containment is an interval test (see
96 /// contains()).
97 unsigned IdxBegin = 0, IdxEnd = 0;
98
99 /// Depth of the cycle in the tree: top-level cycles are at depth 1 and each
100 /// nested cycle is one deeper (getCycleDepth() returns 0 for blocks outside
101 /// any cycle). Sibling cycles share a depth.
102 unsigned Depth = 0;
103
104 /// Number of cycles nested inside this one: the subtree occupies
105 /// [this, this + 1 + NumDescendants) of Cycles.
106 unsigned NumDescendants = 0;
107
108 /// The entry blocks (header first) are BlockLayout[EntryBegin,
109 /// EntryBegin+EntrySize). A reducible cycle has a single entry at IdxBegin.
110 /// An irreducible one appends its list past the Euler tour.
111 unsigned EntryBegin = 0, EntrySize = 0;
112
113 /// Whether this cycle has a parent, i.e. is not top-level.
114 bool hasParent() const { return Parent.isValid(); }
115 };
116 static_assert(std::is_trivially_destructible_v<Cycle>);
117 using CycleT = Cycle;
118
119 ContextT Context;
120 unsigned BlockNumberEpoch;
121
122 /// Map each basic block number to its inner-most containing cycle, or an
123 /// invalid handle if none.
124 SmallVector<CycleRef> BlockMap;
125
126 /// Euler tour of the cycle forest: every cycle's blocks form a contiguous
127 /// slice [IdxBegin, IdxEnd), nested inside its parent's. Entry lists for
128 /// irreducible cycles are appended past the tour (see EntryBegin).
129 SmallVector<BlockT *, 8> BlockLayout;
130
131 /// All cycles in forest preorder: every cycle is immediately followed by
132 /// its descendants, and skipping a top-level cycle's subtree lands on the
133 /// next top-level cycle.
134 std::unique_ptr<CycleT[]> Cycles;
135 unsigned NumCycles = 0;
136
137 /// getExitBlocks caches, indexed by the cycle's preorder index. Empty until
138 /// the first query, then sized to NumCycles.
139 mutable SmallVector<SmallVector<BlockT *, 0>, 0> ExitBlocksCaches;
140
141 /// The preorder index of \p C, i.e. its offset in the Cycles array.
142 unsigned getCycleIndex(const CycleT &C) const { return &C - Cycles.get(); }
143
144 /// Resolve a handle to its stored cycle. The assert catches deref of an
145 /// invalid handle and (partially) of a handle from another CycleInfo.
146 CycleT &deref(CycleRef C) {
147 assert(C.Index < NumCycles);
148 return Cycles[C.Index];
149 }
150 const CycleT &deref(CycleRef C) const {
151 assert(C.Index < NumCycles);
152 return Cycles[C.Index];
153 }
154 /// The handle for a stored cycle.
155 CycleRef ref(const CycleT &C) const { return CycleRef(getCycleIndex(C)); }
156
157 void verifyBlockNumberEpoch(const FunctionT *Fn) const {
158 assert(BlockNumberEpoch ==
159 GraphTraits<const FunctionT *>::getNumberEpoch(Fn) &&
160 "CycleInfo used with outdated block number epoch");
161 }
162 void addToBlockMap(BlockT *Block, CycleRef C);
163
164public:
165 /// Iteration over child cycles, yielding handles. The first child (if any)
166 /// immediately follows this cycle in the preorder array, and each next
167 /// sibling follows the previous child's subtree.
169 : iterator_facade_base<const_child_iterator, std::forward_iterator_tag,
170 CycleRef, std::ptrdiff_t, CycleRef, CycleRef> {
171 const GenericCycleInfo *CI = nullptr;
172 unsigned Index = 0;
173
177
178 CycleRef operator*() const { return CycleRef(Index); }
180 Index += 1 + CI->Cycles[Index].NumDescendants;
181 return *this;
182 }
184 return Index == Other.Index;
185 }
186 };
187
188 GenericCycleInfo() = default;
191
192 void clear();
193 void compute(FunctionT &F);
194 void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New);
195
196 const FunctionT *getFunction() const { return Context.getFunction(); }
197 const ContextT &getSSAContext() const { return Context; }
198
199 /// All cycles in forest preorder.
200 auto cycles() const {
201 return map_range(seq(0u, NumCycles),
202 [](unsigned I) { return CycleRef(I); });
203 }
204
205 /// \brief Find the innermost cycle containing \p Block.
206 ///
207 /// \returns the innermost cycle containing \p Block or an invalid handle if
208 /// it is not contained in any cycle.
210 verifyBlockNumberEpoch(Block->getParent());
212 // A block added after compute() that no cycle contains (e.g. a critical
213 // edge MachineSink split outside every cycle) has a number beyond BlockMap.
214 if (Number >= BlockMap.size())
215 return CycleRef();
216 return BlockMap[Number];
217 }
218
220 return BlockLayout[deref(C).EntryBegin];
221 }
222 bool isReducible(CycleRef C) const { return deref(C).EntrySize == 1; }
223 CycleRef getParentCycle(CycleRef C) const { return deref(C).Parent; }
224 unsigned getDepth(CycleRef C) const { return deref(C).Depth; }
225 size_t getNumBlocks(CycleRef C) const {
226 const CycleT &Cyc = deref(C);
227 return Cyc.IdxEnd - Cyc.IdxBegin;
228 }
229
231 const CycleT &Cyc = deref(C);
232 return ArrayRef(BlockLayout).slice(Cyc.EntryBegin, Cyc.EntrySize);
233 }
234 bool isEntry(CycleRef C, const BlockT *Block) const {
235 return is_contained(getEntries(C), Block);
236 }
237 // Append a one-element entry list past the Euler tour; storing Block at
238 // IdxBegin instead would disturb the block order.
240 CycleT &Cyc = deref(C);
241 Cyc.EntryBegin = BlockLayout.size();
242 BlockLayout.push_back(Block);
243 Cyc.EntrySize = 1;
244 }
245 /// Returns true iff \p Outer contains \p Inner. O(1). Non-strict.
246 bool contains(CycleRef Outer, CycleRef Inner) const {
247 const CycleT &O = deref(Outer);
248 const CycleT &I = deref(Inner);
249 return O.IdxBegin <= I.IdxBegin && I.IdxEnd <= O.IdxEnd;
250 }
252 unsigned First = C.Index + 1;
253 return llvm::make_range(
255 const_child_iterator(*this, First + deref(C).NumDescendants));
256 }
257 Printable printEntries(CycleRef C, const ContextT &Ctx) const {
258 return Printable([this, C, &Ctx](raw_ostream &Out) {
259 ListSeparator LS(" ");
260 for (auto *Entry : getEntries(C))
261 Out << LS << Ctx.print(Entry);
262 });
263 }
264
265 /// \brief Return whether \p Block is contained in \p C. O(1).
266 bool contains(CycleRef C, const BlockT *Block) const {
267 CycleRef Inner = getCycle(Block);
268 return Inner.isValid() && contains(C, Inner);
269 }
270
271 /// \brief Return the blocks of \p C, including those of nested cycles.
273 const CycleT &Cyc = deref(C);
274 return ArrayRef<BlockT *>(BlockLayout.begin() + Cyc.IdxBegin,
275 BlockLayout.begin() + Cyc.IdxEnd);
276 }
277
280
281 /// \brief Return the depth of the innermost cycle containing \p Block, or 0
282 /// if it is not contained in any cycle.
283 unsigned getCycleDepth(const BlockT *Block) const {
285 return C.isValid() ? getDepth(C) : 0;
286 }
287
290 if (!C)
291 return C;
292 while (CycleRef P = getParentCycle(C))
293 C = P;
294 return C;
295 }
296
297 /// Return all of the successor blocks of \p C: the blocks outside of \p C
298 /// which are branched to from within it.
299 void getExitBlocks(CycleRef C, SmallVectorImpl<BlockT *> &TmpStorage) const;
300
301 /// Return all blocks of \p C that have a successor outside of \p C.
303 SmallVectorImpl<BlockT *> &TmpStorage) const;
304
305 /// Return the preheader block for \p C. Pre-header is well-defined for
306 /// reducible cycle in docs/LoopTerminology.md as: the only one entering
307 /// block and its only edge is to the entry block. Return null for
308 /// irreducible cycles.
310
311 /// If \p C has exactly one entry with exactly one predecessor, return it,
312 /// otherwise return nullptr.
314
315 /// Verify that \p C is actually a well-formed cycle in the CFG.
316 void verifyCycle(CycleRef C) const;
317
318 /// Verify the parent-child relations of \p C.
319 ///
320 /// Note that this does \em not check that \p C is really a cycle in the CFG.
321 void verifyCycleNest(CycleRef C) const;
322
323 /// Assumes that \p C is the innermost cycle containing \p Block.
324 /// \p Block will be appended to \p C and all of its parent cycles.
325 /// \p Block will be added to BlockMap with \p C.
327
328 /// Methods for debug and self-test.
329 //@{
330 void verifyCycleNest(bool VerifyFull = false) const;
331 void verify() const;
332 void print(raw_ostream &Out) const;
333 void dump() const { print(dbgs()); }
334 Printable print(CycleRef C) const;
335 //@}
336
337 /// Iteration over top-level cycles.
338 //@{
340
345 return const_toplevel_iterator(*this, NumCycles);
346 }
347
351 //@}
352};
353
354} // namespace llvm
355
356#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 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
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
const_toplevel_iterator toplevel_end() const
void verifyCycleNest(CycleRef C) const
Verify the parent-child relations of C.
const FunctionT * getFunction() const
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
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:365
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:1947
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