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