LLVM 23.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.rst 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/DenseSet.h"
34#include "llvm/ADT/SetVector.h"
36#include "llvm/Support/Debug.h"
38
39namespace llvm {
40
41template <typename ContextT> class GenericCycleInfo;
42template <typename ContextT> class GenericCycleInfoCompute;
43
44/// A possibly irreducible generalization of a \ref Loop.
45template <typename ContextT> class GenericCycle {
46public:
47 using BlockT = typename ContextT::BlockT;
48 using FunctionT = typename ContextT::FunctionT;
49 template <typename> friend class GenericCycleInfo;
50 template <typename> friend class GenericCycleInfoCompute;
51
52private:
53 /// The parent cycle. Is null for the root "cycle". Top-level cycles point
54 /// at the root.
55 GenericCycle *ParentCycle = nullptr;
56
57 /// The top-level cycle this cycle is part of. Points to itself if this is
58 /// a top-level cycle.
59 GenericCycle *TopLevelCycle;
60
61 /// The entry block(s) of the cycle. The header is the only entry if
62 /// this is a loop. Is empty for the root "cycle", to avoid
63 /// unnecessary memory use.
65
66 /// Child cycles, if any.
67 std::vector<std::unique_ptr<GenericCycle>> Children;
68
69 /// Basic blocks that are contained in the cycle, including entry blocks,
70 /// and including blocks that are part of a child cycle.
73 BlockSetVectorT Blocks;
74
75 /// Depth of the cycle in the tree. The root "cycle" is at depth 0.
76 ///
77 /// \note Depths are not necessarily contiguous. However, child loops always
78 /// have strictly greater depth than their parents, and sibling loops
79 /// always have the same depth.
80 unsigned Depth = 0;
81
82 /// Cache for the results of GetExitBlocks
83 mutable SmallVector<BlockT *, 4> ExitBlocksCache;
84
85 void clear() {
86 Entries.clear();
87 Children.clear();
88 Blocks.clear();
89 Depth = 0;
90 ParentCycle = nullptr;
91 clearCache();
92 }
93
94 void appendEntry(BlockT *Block) {
95 Entries.push_back(Block);
96 clearCache();
97 }
98
99 void appendBlock(BlockT *Block) {
100 Blocks.insert(Block);
101 clearCache();
102 }
103
104 GenericCycle(const GenericCycle &) = delete;
105 GenericCycle &operator=(const GenericCycle &) = delete;
106 GenericCycle(GenericCycle &&Rhs) = delete;
107 GenericCycle &operator=(GenericCycle &&Rhs) = delete;
108
109public:
110 GenericCycle() : TopLevelCycle(this) {}
111
112 /// \brief Whether the cycle is a natural loop.
113 bool isReducible() const { return Entries.size() == 1; }
114
115 BlockT *getHeader() const { return Entries[0]; }
116
118 return Entries;
119 }
120
121 /// Clear the cache of the cycle.
122 /// This should be run in all non-const function in GenericCycle
123 /// and GenericCycleInfo.
124 void clearCache() const { ExitBlocksCache.clear(); }
125
126 /// \brief Return whether \p Block is an entry block of the cycle.
127 bool isEntry(const BlockT *Block) const {
128 return is_contained(Entries, Block);
129 }
130
131 /// \brief Replace all entries with \p Block as single entry.
134 Entries.clear();
135 Entries.push_back(Block);
136 clearCache();
137 }
138
139 /// \brief Return whether \p Block is contained in the cycle.
140 bool contains(const BlockT *Block) const { return Blocks.contains(Block); }
141
142 /// \brief Returns true iff this cycle contains \p C.
143 ///
144 /// Note: Non-strict containment check, i.e. returns true if C is the
145 /// same cycle.
146 bool contains(const GenericCycle *C) const;
147
148 const GenericCycle *getParentCycle() const { return ParentCycle; }
149 GenericCycle *getParentCycle() { return ParentCycle; }
150 unsigned getDepth() const { return Depth; }
151
152 /// Return all of the successor blocks of this cycle.
153 ///
154 /// These are the blocks _outside of the current cycle_ which are
155 /// branched to.
156 void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
157
158 /// Return all blocks of this cycle that have successor outside of this cycle.
159 /// These blocks have cycle exit branch.
160 void getExitingBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
161
162 /// Return the preheader block for this cycle. Pre-header is well-defined for
163 /// reducible cycle in docs/LoopTerminology.rst as: the only one entering
164 /// block and its only edge is to the entry block. Return null for irreducible
165 /// cycles.
166 BlockT *getCyclePreheader() const;
167
168 /// If the cycle has exactly one entry with exactly one predecessor, return
169 /// it, otherwise return nullptr.
171
172 void verifyCycle() const;
173 void verifyCycleNest() const;
174
175 /// Iteration over child cycles.
176 //@{
178 typename std::vector<std::unique_ptr<GenericCycle>>::const_iterator;
180 : iterator_adaptor_base<const_child_iterator, const_child_iterator_base> {
181 using Base =
183
186
188 GenericCycle *operator*() const { return Base::I->get(); }
189 };
190
192 return const_child_iterator{Children.begin()};
193 }
195 return const_child_iterator{Children.end()};
196 }
197 size_t getNumChildren() const { return Children.size(); }
199 return llvm::make_range(const_child_iterator{Children.begin()},
200 const_child_iterator{Children.end()});
201 }
202 //@}
203
204 /// Iteration over blocks in the cycle (including entry blocks).
205 //@{
207
209 return const_block_iterator{Blocks.begin()};
210 }
212 return const_block_iterator{Blocks.end()};
213 }
214 size_t getNumBlocks() const { return Blocks.size(); }
218 //@}
219
220 /// Iteration over entry blocks.
221 //@{
224 const_entry_iterator entry_begin() const { return Entries.begin(); }
225 const_entry_iterator entry_end() const { return Entries.end(); }
226 size_t getNumEntries() const { return Entries.size(); }
232 const_reverse_entry_iterator entry_rbegin() const { return Entries.rbegin(); }
233 const_reverse_entry_iterator entry_rend() const { return Entries.rend(); }
234 //@}
235
236 Printable printEntries(const ContextT &Ctx) const {
237 return Printable([this, &Ctx](raw_ostream &Out) {
238 ListSeparator LS(" ");
239 for (auto *Entry : Entries)
240 Out << LS << Ctx.print(Entry);
241 });
242 }
243
244 Printable print(const ContextT &Ctx) const {
245 return Printable([this, &Ctx](raw_ostream &Out) {
246 Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
247
248 for (auto *Block : Blocks) {
249 if (isEntry(Block))
250 continue;
251
252 Out << ' ' << Ctx.print(Block);
253 }
254 });
255 }
256};
257
258/// \brief Cycle information for a function.
259template <typename ContextT> class GenericCycleInfo {
260public:
261 using BlockT = typename ContextT::BlockT;
263 using FunctionT = typename ContextT::FunctionT;
264 template <typename> friend class GenericCycle;
265 template <typename> friend class GenericCycleInfoCompute;
266
267private:
268 ContextT Context;
269 unsigned BlockNumberEpoch;
270
271 /// Map basic block numbers to their inner-most containing cycle.
272 SmallVector<CycleT *> BlockMap;
273
274 /// Top-level cycles discovered by any DFS.
275 ///
276 /// Note: The implementation treats the nullptr as the parent of
277 /// every top-level cycle. See \ref contains for an example.
278 std::vector<std::unique_ptr<CycleT>> TopLevelCycles;
279
280 /// Move \p Child to \p NewParent by manipulating Children vectors.
281 ///
282 /// Note: This is an incomplete operation that does not update the depth of
283 /// the subtree.
284 void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
285
286 void verifyBlockNumberEpoch(const FunctionT *Fn) const;
287 void addToBlockMap(BlockT *Block, CycleT *Cycle);
288
289public:
290 GenericCycleInfo() = default;
293
294 void clear();
295 void compute(FunctionT &F);
296 void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New);
297
298 const FunctionT *getFunction() const { return Context.getFunction(); }
299 const ContextT &getSSAContext() const { return Context; }
300
301 CycleT *getCycle(const BlockT *Block) const;
304 unsigned getCycleDepth(const BlockT *Block) const;
306
307 /// Assumes that \p Cycle is the innermost cycle containing \p Block.
308 /// \p Block will be appended to \p Cycle and all of its parent cycles.
309 /// \p Block will be added to BlockMap with \p Cycle and
310 /// BlockMapTopLevel with \p Cycle's top level parent cycle.
312
313 /// Methods for debug and self-test.
314 //@{
315 void verifyCycleNest(bool VerifyFull = false) const;
316 void verify() const;
317 void print(raw_ostream &Out) const;
318 void dump() const { print(dbgs()); }
319 Printable print(const CycleT *Cycle) { return Cycle->print(Context); }
320 //@}
321
322 /// Iteration over top-level cycles.
323 //@{
325 typename std::vector<std::unique_ptr<CycleT>>::const_iterator;
327 : iterator_adaptor_base<const_toplevel_iterator,
328 const_toplevel_iterator_base> {
331
335
337 CycleT *operator*() const { return Base::I->get(); }
338 };
339
341 return const_toplevel_iterator{TopLevelCycles.begin()};
342 }
344 return const_toplevel_iterator{TopLevelCycles.end()};
345 }
346
348 return llvm::make_range(const_toplevel_iterator{TopLevelCycles.begin()},
349 const_toplevel_iterator{TopLevelCycles.end()});
350 }
351 //@}
352};
353
354/// \brief GraphTraits for iterating over a sub-tree of the CycleT tree.
355template <typename CycleRefT, typename ChildIteratorT> struct CycleGraphTraits {
356 using NodeRef = CycleRefT;
357
358 using nodes_iterator = ChildIteratorT;
360
361 static NodeRef getEntryNode(NodeRef Graph) { return Graph; }
362
364 return Ref->child_begin();
365 }
366 static ChildIteratorType child_end(NodeRef Ref) { return Ref->child_end(); }
367
368 // Not implemented:
369 // static nodes_iterator nodes_begin(GraphType *G)
370 // static nodes_iterator nodes_end (GraphType *G)
371 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
372
373 // typedef EdgeRef - Type of Edge token in the graph, which should
374 // be cheap to copy.
375 // typedef ChildEdgeIteratorType - Type used to iterate over children edges in
376 // graph, dereference to a EdgeRef.
377
378 // static ChildEdgeIteratorType child_edge_begin(NodeRef)
379 // static ChildEdgeIteratorType child_edge_end(NodeRef)
380 // Return iterators that point to the beginning and ending of the
381 // edge list for the given callgraph node.
382 //
383 // static NodeRef edge_dest(EdgeRef)
384 // Return the destination node of an edge.
385 // static unsigned size (GraphType *G)
386 // Return total number of nodes in the graph
387};
388
389template <typename BlockT>
393template <typename BlockT>
397
398} // namespace llvm
399
400#endif // LLVM_ADT_GENERICCYCLEINFO_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
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 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
This file implements a set that has insertion order iteration characteristics.
This file contains some functions that are useful when dealing with strings.
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
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.
void addBlockToCycle(BlockT *Block, CycleT *Cycle)
Assumes that Cycle is the innermost cycle containing Block.
typename std::vector< std::unique_ptr< CycleT > >::const_iterator const_toplevel_iterator_base
Iteration over top-level cycles.
iterator_range< const_toplevel_iterator > toplevel_cycles() const
CycleT * getTopLevelParentCycle(const BlockT *Block) const
friend class GenericCycleInfoCompute
const_toplevel_iterator toplevel_end() const
const FunctionT * getFunction() const
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.
GenericCycleInfo & operator=(GenericCycleInfo &&)=default
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)
const ContextT & getSSAContext() const
GenericCycleInfo(GenericCycleInfo &&)=default
Printable print(const CycleT *Cycle)
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
const_toplevel_iterator toplevel_begin() const
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
A possibly irreducible generalization of a Loop.
void clearCache() const
Clear the cache of the cycle.
BlockT * getHeader() const
bool isReducible() const
Whether the cycle is a natural loop.
typename ContextT::FunctionT FunctionT
const_entry_iterator entry_end() const
friend class GenericCycleInfoCompute
void getExitingBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all blocks of this cycle that have successor outside of this cycle.
const_entry_iterator entry_begin() const
void verifyCycle() const
Verify that this is actually a well-formed cycle in the CFG.
const_child_iterator child_begin() const
iterator_range< const_entry_iterator > entries() const
void verifyCycleNest() const
Verify the parent-child relations of this cycle.
typename SmallVectorImpl< BlockT * >::const_reverse_iterator const_reverse_entry_iterator
Printable print(const ContextT &Ctx) const
iterator_range< const_block_iterator > blocks() const
const SmallVectorImpl< BlockT * > & getEntries() const
BlockT * getCyclePreheader() const
Return the preheader block for this cycle.
typename BlockSetVectorT::const_iterator const_block_iterator
Iteration over blocks in the cycle (including entry blocks).
bool isEntry(const BlockT *Block) const
Return whether Block is an entry block of the cycle.
const_reverse_entry_iterator entry_rend() const
const_block_iterator block_begin() const
const_reverse_entry_iterator entry_rbegin() const
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.
Printable printEntries(const ContextT &Ctx) const
size_t getNumEntries() const
const_child_iterator child_end() const
size_t getNumChildren() const
typename SmallVectorImpl< BlockT * >::const_iterator const_entry_iterator
Iteration over entry blocks.
typename ContextT::BlockT BlockT
const GenericCycle * getParentCycle() const
void setSingleEntry(BlockT *Block)
Replace all entries with Block as single entry.
GenericCycle * getParentCycle()
friend class GenericCycleInfo
unsigned getDepth() const
const_block_iterator block_end() const
typename std::vector< std::unique_ptr< GenericCycle > >::const_iterator const_child_iterator_base
Iteration over child cycles.
size_t getNumBlocks() const
iterator_range< const_child_iterator > children() 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 vector that has set insertion semantics.
Definition SetVector.h:57
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
typename SuperClass::const_iterator const_iterator
void push_back(const T &Elt)
std::reverse_iterator< const_iterator > const_reverse_iterator
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
Definition Types.h:26
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
CycleInfo::CycleT Cycle
Definition CycleInfo.h:26
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
GraphTraits for iterating over a sub-tree of the CycleT tree.
static ChildIteratorType child_begin(NodeRef Ref)
nodes_iterator ChildIteratorType
ChildIteratorT nodes_iterator
static NodeRef getEntryNode(NodeRef Graph)
static ChildIteratorType child_end(NodeRef Ref)
iterator_adaptor_base< const_toplevel_iterator, const_toplevel_iterator_base > Base
const const_toplevel_iterator_base & wrapped()
const_toplevel_iterator(const_toplevel_iterator_base I)
const_child_iterator(const_child_iterator_base I)
const const_child_iterator_base & wrapped()
iterator_adaptor_base< const_child_iterator, const_child_iterator_base > Base