LLVM 23.0.0git
PostOrderIterator.h
Go to the documentation of this file.
1//===- llvm/ADT/PostOrderIterator.h - PostOrder iterator --------*- 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 file builds on the ADT/GraphTraits.h file to build a generic graph
11/// post order iterator. This should work over any graph type that has a
12/// GraphTraits specialization.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_ADT_POSTORDERITERATOR_H
17#define LLVM_ADT_POSTORDERITERATOR_H
18
22#include <iterator>
23#include <optional>
24#include <type_traits>
25#include <utility>
26
27namespace llvm {
28namespace po_detail {
29
30template <typename NodeRef> class NumberSet {
32
33public:
34 void reserve(size_t Size) {
35 if (Size < Data.size())
36 Data.resize(Size, false);
37 }
38
39 std::pair<std::nullopt_t, bool> insert(NodeRef Node) {
41 if (Idx >= Data.size())
42 Data.resize(Idx + 1);
43 bool Inserted = !Data[Idx];
44 Data[Idx] = true;
45 return {std::nullopt, Inserted};
46 }
47};
48
49template <typename GraphT>
51 std::conditional_t<GraphHasNodeNumbers<GraphT>,
54
55} // namespace po_detail
56
57/// CRTP base class for post-order traversal. Storage for visited nodes must be
58/// provided by the sub-class, which must implement insertEdge(). Due to CRTP
59/// limitations, the sub-class must call init() with the start node before
60/// traversing; not calling init results in an empty iterator.
61///
62/// Sub-classes can observe the post-order traversal with finishPostorder(),
63/// which is called before the iterator moves to the next node, and also the
64/// pre-order traversal with insertEdge().
65///
66/// Unwanted graph nodes (e.g. from a previous traversal) can be skipped by
67/// returning false from insertEdge().
68///
69/// This class only supports a single traversal of the graph.
70template <typename DerivedT, typename GraphTraits>
72 using NodeRef = typename GraphTraits::NodeRef;
73 using ChildItTy = typename GraphTraits::ChildIteratorType;
74
75 struct StackEntry {
76 NodeRef Node; ///< Node.
77 ChildItTy It; ///< Iterator for next child.
78 ChildItTy End; ///< End iterator for children.
79
80 // This constructor is carefully designed so that there is no store between
81 // the calls to child_begin() and child_end(). LLVM IR successors() is a
82 // pure function called for begin and end, but the second call can't be
83 // removed if there's a potentially visible store (here: store to the
84 // member It in the VisitStack) in between.
85 StackEntry(NodeRef Node, iterator_range<ChildItTy> Children)
86 : Node(Node), It(Children.begin()), End(Children.end()) {}
87 };
89
90public:
91 class iterator {
93
94 public:
95 using iterator_category = std::input_iterator_tag;
96 using value_type = NodeRef;
97 using difference_type = std::ptrdiff_t;
99 using reference = NodeRef;
100
101 private:
102 DerivedT *POT = nullptr;
103 NodeRef V = nullptr;
104
105 public:
106 iterator() = default;
107
108 private:
109 iterator(DerivedT &POT, value_type V) : POT(&POT), V(V) {}
110
111 public:
112 bool operator==(const iterator &X) const { return V == X.V; }
113 bool operator!=(const iterator &X) const { return !(*this == X); }
114
115 reference operator*() const { return V; }
116 pointer operator->() const { return &V; }
117
118 iterator &operator++() { // Preincrement
119 V = POT->next();
120 return *this;
121 }
122
123 iterator operator++(int) { // Postincrement
124 iterator tmp = *this;
125 ++*this;
126 return tmp;
127 }
128 };
129
130protected:
132
133 DerivedT *derived() { return static_cast<DerivedT *>(this); }
134
135 /// Initialize post-order traversal at given start node.
136 void init(NodeRef Start) {
137 if (derived()->insertEdge(std::optional<NodeRef>(), Start)) {
138 VisitStack.emplace_back(Start, make_range(GraphTraits::child_begin(Start),
139 GraphTraits::child_end(Start)));
140 traverseChild();
141 }
142 }
143
144private:
145 void traverseChild() {
146 while (true) {
147 auto &Entry = VisitStack.back();
148 if (Entry.It == Entry.End)
149 break;
150 NodeRef BB = *Entry.It++;
151 // If the block is not visited...
152 if (derived()->insertEdge(std::optional<NodeRef>(Entry.Node), BB))
153 VisitStack.emplace_back(BB, make_range(GraphTraits::child_begin(BB),
154 GraphTraits::child_end(BB)));
155 }
156 }
157
158 NodeRef next() {
159 derived()->finishPostorder(VisitStack.back().Node);
160 VisitStack.pop_back();
161 if (VisitStack.empty())
162 return nullptr;
163 traverseChild();
164 return VisitStack.back().Node;
165 }
166
167public:
169 if (VisitStack.empty())
170 return iterator(); // We don't even want to see the start node.
171 return iterator(*derived(), VisitStack.back().Node);
172 }
173 iterator end() { return iterator(); }
174
175 // Methods that are intended to be overridden by sub-classes.
176
177 /// Add edge and return whether To should be visited. From is nullopt for the
178 /// root node.
179 bool insertEdge(std::optional<NodeRef> From, NodeRef To);
180
181 /// Callback just before the iterator moves to the next block.
182 void finishPostorder(NodeRef) {}
183};
184
185/// Post-order traversal of a graph. Note: the traversal state is stored in this
186/// class, not in the iterators -- the lifetime of PostOrderTraversal must
187/// exceed the lifetime of the iterators. Special care must be taken with
188/// range-based for-loops in combination with LLVM ranges:
189///
190/// // Fine:
191/// for (BasicBlock *BB : post_order(F)) { ... }
192///
193/// // Problematic! Lifetime of PostOrderTraversal ends before the loop is
194/// // entered, because make_filter_range only stores the iterators but not
195/// // the range object itself.
196/// for (BasicBlock *BB : make_filter_range(post_order(F), ...)) { ... }
197/// // Fixed:
198/// auto POT = post_order(F);
199/// for (BasicBlock *BB : make_filter_range(POT, ...)) { ... }
200///
201/// This class only supports a single traversal of the graph.
202template <typename GraphT, typename SetType = po_detail::DefaultSet<GraphT>>
204 : public PostOrderTraversalBase<PostOrderTraversal<GraphT, SetType>,
205 GraphTraits<GraphT>> {
206 using NodeRef = typename GraphTraits<GraphT>::NodeRef;
207
208 SetType Visited;
209
210public:
211 /// Default constructor for an empty traversal.
213
214 /// Post-order traversal of the graph starting at the root node using an
215 /// internal storage.
216 PostOrderTraversal(const GraphT &G) {
218 }
219
220 bool insertEdge(std::optional<NodeRef> From, NodeRef To) {
221 return Visited.insert(To).second;
222 }
223};
224
225/// Post-order traversal of the graph starting at the root node using an
226/// external storage. This can be used to keep track of visited nodes after the
227/// traversal and to skip nodes that are already contained in the set. See
228/// PostOrderTraversal for usage restrictions.
229template <typename GraphT, typename SetType>
231 : public PostOrderTraversalBase<PostOrderExtTraversal<GraphT, SetType>,
232 GraphTraits<GraphT>> {
233 using NodeRef = typename GraphTraits<GraphT>::NodeRef;
234
235 SetType &Visited;
236
237public:
238 PostOrderExtTraversal(const GraphT &G, SetType &S) : Visited(S) {
240 }
241
242 bool insertEdge(std::optional<NodeRef> From, NodeRef To) {
243 return Visited.insert(To).second;
244 }
245};
246
247// Provide global constructors that automatically figure out correct types...
248//
249/// Post-order traversal of a graph. Note: this returns a PostOrderTraversal,
250/// not an iterator range; \see PostOrderTraversal.
251template <class T> auto post_order(const T &G) {
252 return PostOrderTraversal<T>(G);
253}
254template <class T, class SetType> auto post_order_ext(const T &G, SetType &S) {
256}
257template <class T, class SetType>
258auto inverse_post_order_ext(const T &G, SetType &S) {
259 return PostOrderExtTraversal<Inverse<T>, SetType>(G, S);
260}
261
262//===--------------------------------------------------------------------===//
263// Reverse Post Order CFG iterator code
264//===--------------------------------------------------------------------===//
265//
266// This is used to visit basic blocks in a method in reverse post order. This
267// class is awkward to use because I don't know a good incremental algorithm to
268// computer RPO from a graph. Because of this, the construction of the
269// ReversePostOrderTraversal object is expensive (it must walk the entire graph
270// with a postorder iterator to build the data structures). The moral of this
271// story is: Don't create more ReversePostOrderTraversal classes than necessary.
272//
273// Because it does the traversal in its constructor, it won't invalidate when
274// BasicBlocks are removed, *but* it may contain erased blocks. Some places
275// rely on this behavior (i.e. GVN).
276//
277// This class should be used like this:
278// {
279// ReversePostOrderTraversal<Function*> RPOT(FuncPtr); // Expensive to create
280// for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
281// ...
282// }
283// for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
284// ...
285// }
286// }
287//
288
289template<class GraphT, class GT = GraphTraits<GraphT>>
291 using NodeRef = typename GT::NodeRef;
292
293 using VecTy = SmallVector<NodeRef, 8>;
294 VecTy Blocks; // Block list in normal PO order
295
296 void Initialize(const GraphT &G) {
297 llvm::copy(post_order(G), std::back_inserter(Blocks));
298 }
299
300public:
303
304 ReversePostOrderTraversal(const GraphT &G) { Initialize(G); }
305
306 // Because we want a reverse post order, use reverse iterators from the vector
307 rpo_iterator begin() { return Blocks.rbegin(); }
308 const_rpo_iterator begin() const { return Blocks.rbegin(); }
309 rpo_iterator end() { return Blocks.rend(); }
310 const_rpo_iterator end() const { return Blocks.rend(); }
311};
312
313} // end namespace llvm
314
315#endif // LLVM_ADT_POSTORDERITERATOR_H
#define X(NUM, ENUM, NAME)
Definition ELF.h:851
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
#define G(x, y, z)
Definition MD5.cpp:55
#define T
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
Post-order traversal of the graph starting at the root node using an external storage.
bool insertEdge(std::optional< NodeRef > From, NodeRef To)
PostOrderExtTraversal(const GraphT &G, SetType &S)
bool operator!=(const iterator &X) const
bool operator==(const iterator &X) const
bool insertEdge(std::optional< NodeRef > From, NodeRef To)
Add edge and return whether To should be visited.
void init(NodeRef Start)
Initialize post-order traversal at given start node.
void finishPostorder(NodeRef)
Callback just before the iterator moves to the next block.
Post-order traversal of a graph.
PostOrderTraversal()=default
Default constructor for an empty traversal.
bool insertEdge(std::optional< NodeRef > From, NodeRef To)
PostOrderTraversal(const GraphT &G)
Post-order traversal of the graph starting at the root node using an internal storage.
const_rpo_iterator end() const
const_rpo_iterator begin() const
typename VecTy::reverse_iterator rpo_iterator
typename VecTy::const_reverse_iterator const_rpo_iterator
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
std::reverse_iterator< const_iterator > const_reverse_iterator
std::reverse_iterator< iterator > 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.
std::pair< std::nullopt_t, bool > insert(NodeRef Node)
std::conditional_t< GraphHasNodeNumbers< GraphT >, NumberSet< typename GraphTraits< GraphT >::NodeRef >, SmallPtrSet< typename GraphTraits< GraphT >::NodeRef, 8 > > DefaultSet
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 inverse_post_order_ext(const T &G, SetType &S)
auto post_order_ext(const T &G, SetType &S)
auto post_order(const T &G)
Post-order traversal of a graph.
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1885
typename GraphType::UnknownGraphTypeError NodeRef
Definition GraphTraits.h:95