Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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 = value_type &;
  104.  
  105. private:
  106.   using NodeRef = typename GT::NodeRef;
  107.   using ChildItTy = typename GT::ChildIteratorType;
  108.  
  109.   // VisitStack - Used to maintain the ordering.  Top = current block
  110.   // First element is basic block pointer, second is the 'next child' to visit
  111.   SmallVector<std::pair<NodeRef, ChildItTy>, 8> VisitStack;
  112.  
  113.   po_iterator(NodeRef BB) {
  114.     this->insertEdge(std::optional<NodeRef>(), BB);
  115.     VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
  116.     traverseChild();
  117.   }
  118.  
  119.   po_iterator() = default; // End is when stack is empty.
  120.  
  121.   po_iterator(NodeRef BB, SetType &S)
  122.       : po_iterator_storage<SetType, ExtStorage>(S) {
  123.     if (this->insertEdge(std::optional<NodeRef>(), BB)) {
  124.       VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
  125.       traverseChild();
  126.     }
  127.   }
  128.  
  129.   po_iterator(SetType &S)
  130.       : po_iterator_storage<SetType, ExtStorage>(S) {
  131.   } // End is when stack is empty.
  132.  
  133.   void traverseChild() {
  134.     while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) {
  135.       NodeRef BB = *VisitStack.back().second++;
  136.       if (this->insertEdge(std::optional<NodeRef>(VisitStack.back().first),
  137.                            BB)) {
  138.         // If the block is not visited...
  139.         VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
  140.       }
  141.     }
  142.   }
  143.  
  144. public:
  145.   // Provide static "constructors"...
  146.   static po_iterator begin(const GraphT &G) {
  147.     return po_iterator(GT::getEntryNode(G));
  148.   }
  149.   static po_iterator end(const GraphT &G) { return po_iterator(); }
  150.  
  151.   static po_iterator begin(const GraphT &G, SetType &S) {
  152.     return po_iterator(GT::getEntryNode(G), S);
  153.   }
  154.   static po_iterator end(const GraphT &G, SetType &S) { return po_iterator(S); }
  155.  
  156.   bool operator==(const po_iterator &x) const {
  157.     return VisitStack == x.VisitStack;
  158.   }
  159.   bool operator!=(const po_iterator &x) const { return !(*this == x); }
  160.  
  161.   const NodeRef &operator*() const { return VisitStack.back().first; }
  162.  
  163.   // This is a nonstandard operator-> that dereferences the pointer an extra
  164.   // time... so that you can actually call methods ON the BasicBlock, because
  165.   // the contained type is a pointer.  This allows BBIt->getTerminator() f.e.
  166.   //
  167.   NodeRef operator->() const { return **this; }
  168.  
  169.   po_iterator &operator++() { // Preincrement
  170.     this->finishPostorder(VisitStack.back().first);
  171.     VisitStack.pop_back();
  172.     if (!VisitStack.empty())
  173.       traverseChild();
  174.     return *this;
  175.   }
  176.  
  177.   po_iterator operator++(int) { // Postincrement
  178.     po_iterator tmp = *this;
  179.     ++*this;
  180.     return tmp;
  181.   }
  182. };
  183.  
  184. // Provide global constructors that automatically figure out correct types...
  185. //
  186. template <class T>
  187. po_iterator<T> po_begin(const T &G) { return po_iterator<T>::begin(G); }
  188. template <class T>
  189. po_iterator<T> po_end  (const T &G) { return po_iterator<T>::end(G); }
  190.  
  191. template <class T> iterator_range<po_iterator<T>> post_order(const T &G) {
  192.   return make_range(po_begin(G), po_end(G));
  193. }
  194.  
  195. // Provide global definitions of external postorder iterators...
  196. template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
  197. struct po_ext_iterator : public po_iterator<T, SetType, true> {
  198.   po_ext_iterator(const po_iterator<T, SetType, true> &V) :
  199.   po_iterator<T, SetType, true>(V) {}
  200. };
  201.  
  202. template<class T, class SetType>
  203. po_ext_iterator<T, SetType> po_ext_begin(T G, SetType &S) {
  204.   return po_ext_iterator<T, SetType>::begin(G, S);
  205. }
  206.  
  207. template<class T, class SetType>
  208. po_ext_iterator<T, SetType> po_ext_end(T G, SetType &S) {
  209.   return po_ext_iterator<T, SetType>::end(G, S);
  210. }
  211.  
  212. template <class T, class SetType>
  213. iterator_range<po_ext_iterator<T, SetType>> post_order_ext(const T &G, SetType &S) {
  214.   return make_range(po_ext_begin(G, S), po_ext_end(G, S));
  215. }
  216.  
  217. // Provide global definitions of inverse post order iterators...
  218. template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>,
  219.           bool External = false>
  220. struct ipo_iterator : public po_iterator<Inverse<T>, SetType, External> {
  221.   ipo_iterator(const po_iterator<Inverse<T>, SetType, External> &V) :
  222.      po_iterator<Inverse<T>, SetType, External> (V) {}
  223. };
  224.  
  225. template <class T>
  226. ipo_iterator<T> ipo_begin(const T &G) {
  227.   return ipo_iterator<T>::begin(G);
  228. }
  229.  
  230. template <class T>
  231. ipo_iterator<T> ipo_end(const T &G){
  232.   return ipo_iterator<T>::end(G);
  233. }
  234.  
  235. template <class T>
  236. iterator_range<ipo_iterator<T>> inverse_post_order(const T &G) {
  237.   return make_range(ipo_begin(G), ipo_end(G));
  238. }
  239.  
  240. // Provide global definitions of external inverse postorder iterators...
  241. template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
  242. struct ipo_ext_iterator : public ipo_iterator<T, SetType, true> {
  243.   ipo_ext_iterator(const ipo_iterator<T, SetType, true> &V) :
  244.     ipo_iterator<T, SetType, true>(V) {}
  245.   ipo_ext_iterator(const po_iterator<Inverse<T>, SetType, true> &V) :
  246.     ipo_iterator<T, SetType, true>(V) {}
  247. };
  248.  
  249. template <class T, class SetType>
  250. ipo_ext_iterator<T, SetType> ipo_ext_begin(const T &G, SetType &S) {
  251.   return ipo_ext_iterator<T, SetType>::begin(G, S);
  252. }
  253.  
  254. template <class T, class SetType>
  255. ipo_ext_iterator<T, SetType> ipo_ext_end(const T &G, SetType &S) {
  256.   return ipo_ext_iterator<T, SetType>::end(G, S);
  257. }
  258.  
  259. template <class T, class SetType>
  260. iterator_range<ipo_ext_iterator<T, SetType>>
  261. inverse_post_order_ext(const T &G, SetType &S) {
  262.   return make_range(ipo_ext_begin(G, S), ipo_ext_end(G, S));
  263. }
  264.  
  265. //===--------------------------------------------------------------------===//
  266. // Reverse Post Order CFG iterator code
  267. //===--------------------------------------------------------------------===//
  268. //
  269. // This is used to visit basic blocks in a method in reverse post order.  This
  270. // class is awkward to use because I don't know a good incremental algorithm to
  271. // computer RPO from a graph.  Because of this, the construction of the
  272. // ReversePostOrderTraversal object is expensive (it must walk the entire graph
  273. // with a postorder iterator to build the data structures).  The moral of this
  274. // story is: Don't create more ReversePostOrderTraversal classes than necessary.
  275. //
  276. // Because it does the traversal in its constructor, it won't invalidate when
  277. // BasicBlocks are removed, *but* it may contain erased blocks. Some places
  278. // rely on this behavior (i.e. GVN).
  279. //
  280. // This class should be used like this:
  281. // {
  282. //   ReversePostOrderTraversal<Function*> RPOT(FuncPtr); // Expensive to create
  283. //   for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
  284. //      ...
  285. //   }
  286. //   for (rpo_iterator I = RPOT.begin(); I != RPOT.end(); ++I) {
  287. //      ...
  288. //   }
  289. // }
  290. //
  291.  
  292. template<class GraphT, class GT = GraphTraits<GraphT>>
  293. class ReversePostOrderTraversal {
  294.   using NodeRef = typename GT::NodeRef;
  295.  
  296.   std::vector<NodeRef> Blocks; // Block list in normal PO order
  297.  
  298.   void Initialize(const GraphT &G) {
  299.     std::copy(po_begin(G), po_end(G), std::back_inserter(Blocks));
  300.   }
  301.  
  302. public:
  303.   using rpo_iterator = typename std::vector<NodeRef>::reverse_iterator;
  304.   using const_rpo_iterator = typename std::vector<NodeRef>::const_reverse_iterator;
  305.  
  306.   ReversePostOrderTraversal(const GraphT &G) { Initialize(G); }
  307.  
  308.   // Because we want a reverse post order, use reverse iterators from the vector
  309.   rpo_iterator begin() { return Blocks.rbegin(); }
  310.   const_rpo_iterator begin() const { return Blocks.crbegin(); }
  311.   rpo_iterator end() { return Blocks.rend(); }
  312.   const_rpo_iterator end() const { return Blocks.crend(); }
  313. };
  314.  
  315. } // end namespace llvm
  316.  
  317. #endif // LLVM_ADT_POSTORDERITERATOR_H
  318.