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 
19 #include "llvm/ADT/GraphTraits.h"
20 #include "llvm/ADT/SmallPtrSet.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/iterator_range.h"
23 #include <iterator>
24 #include <optional>
25 #include <set>
26 #include <utility>
27 #include <vector>
28 
29 namespace llvm {
30 
31 // The po_iterator_storage template provides access to the set of already
32 // visited nodes during the po_iterator's depth-first traversal.
33 //
34 // The default implementation simply contains a set of visited nodes, while
35 // the External=true version uses a reference to an external set.
36 //
37 // It is possible to prune the depth-first traversal in several ways:
38 //
39 // - When providing an external set that already contains some graph nodes,
40 //   those nodes won't be visited again. This is useful for restarting a
41 //   post-order traversal on a graph with nodes that aren't dominated by a
42 //   single node.
43 //
44 // - By providing a custom SetType class, unwanted graph nodes can be excluded
45 //   by having the insert() function return false. This could for example
46 //   confine a CFG traversal to blocks in a specific loop.
47 //
48 // - Finally, by specializing the po_iterator_storage template itself, graph
49 //   edges can be pruned by returning false in the insertEdge() function. This
50 //   could be used to remove loop back-edges from the CFG seen by po_iterator.
51 //
52 // A specialized po_iterator_storage class can observe both the pre-order and
53 // the post-order. The insertEdge() function is called in a pre-order, while
54 // the finishPostorder() function is called just before the po_iterator moves
55 // on to the next node.
56 
57 /// Default po_iterator_storage implementation with an internal set object.
58 template<class SetType, bool External>
59 class po_iterator_storage {
60   SetType Visited;
61 
62 public:
63   // Return true if edge destination should be visited.
64   template <typename NodeRef>
65   bool insertEdge(std::optional<NodeRef> From, NodeRef To) {
66     return Visited.insert(To).second;
67   }
68 
69   // Called after all children of BB have been visited.
70   template <typename NodeRef> void finishPostorder(NodeRef BB) {}
71 };
72 
73 /// Specialization of po_iterator_storage that references an external set.
74 template<class SetType>
75 class po_iterator_storage<SetType, true> {
76   SetType &Visited;
77 
78 public:
79   po_iterator_storage(SetType &VSet) : Visited(VSet) {}
80   po_iterator_storage(const po_iterator_storage &S) : Visited(S.Visited) {}
81 
82   // Return true if edge destination should be visited, called with From = 0 for
83   // the root node.
84   // Graph edges can be pruned by specializing this function.
85   template <class NodeRef>
86   bool insertEdge(std::optional<NodeRef> From, NodeRef To) {
87     return Visited.insert(To).second;
88   }
89 
90   // Called after all children of BB have been visited.
91   template <class NodeRef> void finishPostorder(NodeRef BB) {}
92 };
93 
94 template <class GraphT,
95           class SetType = SmallPtrSet<typename GraphTraits<GraphT>::NodeRef, 8>,
96           bool ExtStorage = false, class GT = GraphTraits<GraphT>>
97 class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
98 public:
99   using iterator_category = std::forward_iterator_tag;
100   using value_type = typename GT::NodeRef;
101   using difference_type = std::ptrdiff_t;
102   using pointer = value_type *;
103   using reference = const value_type &;
104 
105 private:
106   using NodeRef = typename GT::NodeRef;
107   using ChildItTy = typename GT::ChildIteratorType;
108 
109   /// Used to maintain the ordering.
110   /// First element is basic block pointer, second is iterator for the next
111   /// child to visit, third is the end iterator.
112   SmallVector<std::tuple<NodeRef, ChildItTy, ChildItTy>, 8> VisitStack;
113 
114   po_iterator(NodeRef BB) {
115     this->insertEdge(std::optional<NodeRef>(), BB);
116     VisitStack.emplace_back(BB, GT::child_begin(BB), GT::child_end(BB));
117     traverseChild();
118   }
119 
120   po_iterator() = default; // End is when stack is empty.
121 
122   po_iterator(NodeRef BB, SetType &S)
123       : po_iterator_storage<SetType, ExtStorage>(S) {
124     if (this->insertEdge(std::optional<NodeRef>(), BB)) {
125       VisitStack.emplace_back(BB, GT::child_begin(BB), GT::child_end(BB));
126       traverseChild();
127     }
128   }
129 
130   po_iterator(SetType &S)
131       : po_iterator_storage<SetType, ExtStorage>(S) {
132   } // End is when stack is empty.
133 
134   void traverseChild() {
135     while (true) {
136       auto &Entry = VisitStack.back();
137       if (std::get<1>(Entry) == std::get<2>(Entry))
138         break;
139       NodeRef BB = *std::get<1>(Entry)++;
140       if (this->insertEdge(std::optional<NodeRef>(std::get<0>(Entry)), BB)) {
141         // If the block is not visited...
142         VisitStack.emplace_back(BB, GT::child_begin(BB), GT::child_end(BB));
143       }
144     }
145   }
146 
147 public:
148   // Provide static "constructors"...
149   static po_iterator begin(const GraphT &G) {
150     return po_iterator(GT::getEntryNode(G));
151   }
152   static po_iterator end(const GraphT &G) { return po_iterator(); }
153 
154   static po_iterator begin(const GraphT &G, SetType &S) {
155     return po_iterator(GT::getEntryNode(G), S);
156   }
157   static po_iterator end(const GraphT &G, SetType &S) { return po_iterator(S); }
158 
159   bool operator==(const po_iterator &x) const {
160     return VisitStack == x.VisitStack;
161   }
162   bool operator!=(const po_iterator &x) const { return !(*this == x); }
163 
164   reference operator*() const { return std::get<0>(VisitStack.back()); }
165 
166   // This is a nonstandard operator-> that dereferences the pointer an extra
167   // time... so that you can actually call methods ON the BasicBlock, because
168   // the contained type is a pointer.  This allows BBIt->getTerminator() f.e.
169   //
170   NodeRef operator->() const { return **this; }
171 
172   po_iterator &operator++() { // Preincrement
173     this->finishPostorder(std::get<0>(VisitStack.back()));
174     VisitStack.pop_back();
175     if (!VisitStack.empty())
176       traverseChild();
177     return *this;
178   }
179 
180   po_iterator operator++(int) { // Postincrement
181     po_iterator tmp = *this;
182     ++*this;
183     return tmp;
184   }
185 };
186 
187 // Provide global constructors that automatically figure out correct types...
188 //
189 template <class T>
190 po_iterator<T> po_begin(const T &G) { return po_iterator<T>::begin(G); }
191 template <class T>
192 po_iterator<T> po_end  (const T &G) { return po_iterator<T>::end(G); }
193 
194 template <class T> iterator_range<po_iterator<T>> post_order(const T &G) {
195   return make_range(po_begin(G), po_end(G));
196 }
197 
198 // Provide global definitions of external postorder iterators...
199 template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
200 struct po_ext_iterator : public po_iterator<T, SetType, true> {
201   po_ext_iterator(const po_iterator<T, SetType, true> &V) :
202   po_iterator<T, SetType, true>(V) {}
203 };
204 
205 template<class T, class SetType>
206 po_ext_iterator<T, SetType> po_ext_begin(T G, SetType &S) {
207   return po_ext_iterator<T, SetType>::begin(G, S);
208 }
209 
210 template<class T, class SetType>
211 po_ext_iterator<T, SetType> po_ext_end(T G, SetType &S) {
212   return po_ext_iterator<T, SetType>::end(G, S);
213 }
214 
215 template <class T, class SetType>
216 iterator_range<po_ext_iterator<T, SetType>> post_order_ext(const T &G, SetType &S) {
217   return make_range(po_ext_begin(G, S), po_ext_end(G, S));
218 }
219 
220 // Provide global definitions of inverse post order iterators...
221 template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>,
222           bool External = false>
223 struct ipo_iterator : public po_iterator<Inverse<T>, SetType, External> {
224   ipo_iterator(const po_iterator<Inverse<T>, SetType, External> &V) :
225      po_iterator<Inverse<T>, SetType, External> (V) {}
226 };
227 
228 template <class T>
229 ipo_iterator<T> ipo_begin(const T &G) {
230   return ipo_iterator<T>::begin(G);
231 }
232 
233 template <class T>
234 ipo_iterator<T> ipo_end(const T &G){
235   return ipo_iterator<T>::end(G);
236 }
237 
238 template <class T>
239 iterator_range<ipo_iterator<T>> inverse_post_order(const T &G) {
240   return make_range(ipo_begin(G), ipo_end(G));
241 }
242 
243 // Provide global definitions of external inverse postorder iterators...
244 template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
245 struct ipo_ext_iterator : public ipo_iterator<T, SetType, true> {
246   ipo_ext_iterator(const ipo_iterator<T, SetType, true> &V) :
247     ipo_iterator<T, SetType, true>(V) {}
248   ipo_ext_iterator(const po_iterator<Inverse<T>, SetType, true> &V) :
249     ipo_iterator<T, SetType, true>(V) {}
250 };
251 
252 template <class T, class SetType>
253 ipo_ext_iterator<T, SetType> ipo_ext_begin(const T &G, SetType &S) {
254   return ipo_ext_iterator<T, SetType>::begin(G, S);
255 }
256 
257 template <class T, class SetType>
258 ipo_ext_iterator<T, SetType> ipo_ext_end(const T &G, SetType &S) {
259   return ipo_ext_iterator<T, SetType>::end(G, S);
260 }
261 
262 template <class T, class SetType>
263 iterator_range<ipo_ext_iterator<T, SetType>>
264 inverse_post_order_ext(const T &G, SetType &S) {
265   return make_range(ipo_ext_begin(G, S), ipo_ext_end(G, S));
266 }
267 
268 //===--------------------------------------------------------------------===//
269 // Reverse Post Order CFG iterator code
270 //===--------------------------------------------------------------------===//
271 //
272 // This is used to visit basic blocks in a method in reverse post order.  This
273 // class is awkward to use because I don't know a good incremental algorithm to
274 // computer RPO from a graph.  Because of this, the construction of the
275 // ReversePostOrderTraversal object is expensive (it must walk the entire graph
276 // with a postorder iterator to build the data structures).  The moral of this
277 // story is: Don't create more ReversePostOrderTraversal classes than necessary.
278 //
279 // Because it does the traversal in its constructor, it won't invalidate when
280 // BasicBlocks are removed, *but* it may contain erased blocks. Some places
281 // rely on this behavior (i.e. GVN).
282 //
283 // This class should be used like this:
284 // {
285 //   ReversePostOrderTraversal<Function*> RPOT(FuncPtr); // Expensive to create
286 //   for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
287 //      ...
288 //   }
289 //   for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
290 //      ...
291 //   }
292 // }
293 //
294 
295 template<class GraphT, class GT = GraphTraits<GraphT>>
296 class ReversePostOrderTraversal {
297   using NodeRef = typename GT::NodeRef;
298 
299   using VecTy = SmallVector<NodeRef, 8>;
300   VecTy Blocks; // Block list in normal PO order
301 
302   void Initialize(const GraphT &G) {
303     std::copy(po_begin(G), po_end(G), std::back_inserter(Blocks));
304   }
305 
306 public:
307   using rpo_iterator = typename VecTy::reverse_iterator;
308   using const_rpo_iterator = typename VecTy::const_reverse_iterator;
309 
310   ReversePostOrderTraversal(const GraphT &G) { Initialize(G); }
311 
312   // Because we want a reverse post order, use reverse iterators from the vector
313   rpo_iterator begin() { return Blocks.rbegin(); }
314   const_rpo_iterator begin() const { return Blocks.rbegin(); }
315   rpo_iterator end() { return Blocks.rend(); }
316   const_rpo_iterator end() const { return Blocks.rend(); }
317 };
318 
319 } // end namespace llvm
320 
321 #endif // LLVM_ADT_POSTORDERITERATOR_H
322