dominator_tree.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright (c) 2017 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_OPT_DOMINATOR_TREE_H_
  15. #define SOURCE_OPT_DOMINATOR_TREE_H_
  16. #include <algorithm>
  17. #include <cstdint>
  18. #include <map>
  19. #include <utility>
  20. #include <vector>
  21. #include "source/opt/cfg.h"
  22. #include "source/opt/tree_iterator.h"
  23. namespace spvtools {
  24. namespace opt {
  25. // This helper struct forms the nodes in the tree, with each node containing its
  26. // children. It also contains two values, for the pre and post indexes in the
  27. // tree which are used to compare two nodes.
  28. struct DominatorTreeNode {
  29. explicit DominatorTreeNode(BasicBlock* bb)
  30. : bb_(bb),
  31. parent_(nullptr),
  32. children_({}),
  33. dfs_num_pre_(-1),
  34. dfs_num_post_(-1) {}
  35. using iterator = std::vector<DominatorTreeNode*>::iterator;
  36. using const_iterator = std::vector<DominatorTreeNode*>::const_iterator;
  37. // depth first preorder iterator.
  38. using df_iterator = TreeDFIterator<DominatorTreeNode>;
  39. using const_df_iterator = TreeDFIterator<const DominatorTreeNode>;
  40. // depth first postorder iterator.
  41. using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>;
  42. using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>;
  43. iterator begin() { return children_.begin(); }
  44. iterator end() { return children_.end(); }
  45. const_iterator begin() const { return cbegin(); }
  46. const_iterator end() const { return cend(); }
  47. const_iterator cbegin() const { return children_.begin(); }
  48. const_iterator cend() const { return children_.end(); }
  49. // Depth first preorder iterator using this node as root.
  50. df_iterator df_begin() { return df_iterator(this); }
  51. df_iterator df_end() { return df_iterator(); }
  52. const_df_iterator df_begin() const { return df_cbegin(); }
  53. const_df_iterator df_end() const { return df_cend(); }
  54. const_df_iterator df_cbegin() const { return const_df_iterator(this); }
  55. const_df_iterator df_cend() const { return const_df_iterator(); }
  56. // Depth first postorder iterator using this node as root.
  57. post_iterator post_begin() { return post_iterator::begin(this); }
  58. post_iterator post_end() { return post_iterator::end(nullptr); }
  59. const_post_iterator post_begin() const { return post_cbegin(); }
  60. const_post_iterator post_end() const { return post_cend(); }
  61. const_post_iterator post_cbegin() const {
  62. return const_post_iterator::begin(this);
  63. }
  64. const_post_iterator post_cend() const {
  65. return const_post_iterator::end(nullptr);
  66. }
  67. inline uint32_t id() const { return bb_->id(); }
  68. BasicBlock* bb_;
  69. DominatorTreeNode* parent_;
  70. std::vector<DominatorTreeNode*> children_;
  71. // These indexes are used to compare two given nodes. A node is a child or
  72. // grandchild of another node if its preorder index is greater than the
  73. // first nodes preorder index AND if its postorder index is less than the
  74. // first nodes postorder index.
  75. int dfs_num_pre_;
  76. int dfs_num_post_;
  77. };
  78. // A class representing a tree of BasicBlocks in a given function, where each
  79. // node is dominated by its parent.
  80. class DominatorTree {
  81. public:
  82. // Map OpLabel ids to dominator tree nodes
  83. using DominatorTreeNodeMap = std::map<uint32_t, DominatorTreeNode>;
  84. using iterator = TreeDFIterator<DominatorTreeNode>;
  85. using const_iterator = TreeDFIterator<const DominatorTreeNode>;
  86. using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>;
  87. using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>;
  88. // List of DominatorTreeNode to define the list of roots
  89. using DominatorTreeNodeList = std::vector<DominatorTreeNode*>;
  90. using roots_iterator = DominatorTreeNodeList::iterator;
  91. using roots_const_iterator = DominatorTreeNodeList::const_iterator;
  92. DominatorTree() : postdominator_(false) {}
  93. explicit DominatorTree(bool post) : postdominator_(post) {}
  94. // Depth first iterators.
  95. // Traverse the dominator tree in a depth first pre-order.
  96. // The pseudo-block is ignored.
  97. iterator begin() { return ++iterator(GetRoot()); }
  98. iterator end() { return iterator(); }
  99. const_iterator begin() const { return cbegin(); }
  100. const_iterator end() const { return cend(); }
  101. const_iterator cbegin() const { return ++const_iterator(GetRoot()); }
  102. const_iterator cend() const { return const_iterator(); }
  103. // Traverse the dominator tree in a depth first post-order.
  104. // The pseudo-block is ignored.
  105. post_iterator post_begin() { return post_iterator::begin(GetRoot()); }
  106. post_iterator post_end() { return post_iterator::end(GetRoot()); }
  107. const_post_iterator post_begin() const { return post_cbegin(); }
  108. const_post_iterator post_end() const { return post_cend(); }
  109. const_post_iterator post_cbegin() const {
  110. return const_post_iterator::begin(GetRoot());
  111. }
  112. const_post_iterator post_cend() const {
  113. return const_post_iterator::end(GetRoot());
  114. }
  115. roots_iterator roots_begin() { return roots_.begin(); }
  116. roots_iterator roots_end() { return roots_.end(); }
  117. roots_const_iterator roots_begin() const { return roots_cbegin(); }
  118. roots_const_iterator roots_end() const { return roots_cend(); }
  119. roots_const_iterator roots_cbegin() const { return roots_.begin(); }
  120. roots_const_iterator roots_cend() const { return roots_.end(); }
  121. // Get the unique root of the tree.
  122. // It is guaranteed to work on a dominator tree.
  123. // post-dominator might have a list.
  124. DominatorTreeNode* GetRoot() {
  125. assert(roots_.size() == 1);
  126. return *roots_.begin();
  127. }
  128. const DominatorTreeNode* GetRoot() const {
  129. assert(roots_.size() == 1);
  130. return *roots_.begin();
  131. }
  132. const DominatorTreeNodeList& Roots() const { return roots_; }
  133. // Dumps the tree in the graphvis dot format into the |out_stream|.
  134. void DumpTreeAsDot(std::ostream& out_stream) const;
  135. // Build the (post-)dominator tree for the given control flow graph
  136. // |cfg| and the function |f|. |f| must exist in the |cfg|. Any
  137. // existing data in the dominator tree will be overwritten
  138. void InitializeTree(const CFG& cfg, const Function* f);
  139. // Check if the basic block |a| dominates the basic block |b|.
  140. bool Dominates(const BasicBlock* a, const BasicBlock* b) const;
  141. // Check if the basic block id |a| dominates the basic block id |b|.
  142. bool Dominates(uint32_t a, uint32_t b) const;
  143. // Check if the dominator tree node |a| dominates the dominator tree node |b|.
  144. bool Dominates(const DominatorTreeNode* a, const DominatorTreeNode* b) const;
  145. // Check if the basic block |a| strictly dominates the basic block |b|.
  146. bool StrictlyDominates(const BasicBlock* a, const BasicBlock* b) const;
  147. // Check if the basic block id |a| strictly dominates the basic block id |b|.
  148. bool StrictlyDominates(uint32_t a, uint32_t b) const;
  149. // Check if the dominator tree node |a| strictly dominates the dominator tree
  150. // node |b|.
  151. bool StrictlyDominates(const DominatorTreeNode* a,
  152. const DominatorTreeNode* b) const;
  153. // Returns the immediate dominator of basic block |a|.
  154. BasicBlock* ImmediateDominator(const BasicBlock* A) const;
  155. // Returns the immediate dominator of basic block id |a|.
  156. BasicBlock* ImmediateDominator(uint32_t a) const;
  157. // Returns true if the basic block |a| is reachable by this tree. A node would
  158. // be unreachable if it cannot be reached by traversal from the start node or
  159. // for a postdominator tree, cannot be reached from the exit nodes.
  160. inline bool ReachableFromRoots(const BasicBlock* a) const {
  161. if (!a) return false;
  162. return ReachableFromRoots(a->id());
  163. }
  164. // Returns true if the basic block id |a| is reachable by this tree.
  165. bool ReachableFromRoots(uint32_t a) const {
  166. return GetTreeNode(a) != nullptr;
  167. }
  168. // Returns true if this tree is a post dominator tree.
  169. bool IsPostDominator() const { return postdominator_; }
  170. // Clean up the tree.
  171. void ClearTree() {
  172. nodes_.clear();
  173. roots_.clear();
  174. }
  175. // Applies the std::function |func| to all nodes in the dominator tree.
  176. // Tree nodes are visited in a depth first pre-order.
  177. bool Visit(std::function<bool(DominatorTreeNode*)> func) {
  178. for (auto n : *this) {
  179. if (!func(&n)) return false;
  180. }
  181. return true;
  182. }
  183. // Applies the std::function |func| to all nodes in the dominator tree.
  184. // Tree nodes are visited in a depth first pre-order.
  185. bool Visit(std::function<bool(const DominatorTreeNode*)> func) const {
  186. for (auto n : *this) {
  187. if (!func(&n)) return false;
  188. }
  189. return true;
  190. }
  191. // Applies the std::function |func| to all nodes in the dominator tree from
  192. // |node| downwards. The boolean return from |func| is used to determine
  193. // whether or not the children should also be traversed. Tree nodes are
  194. // visited in a depth first pre-order.
  195. void VisitChildrenIf(std::function<bool(DominatorTreeNode*)> func,
  196. iterator node) {
  197. if (func(&*node)) {
  198. for (auto n : *node) {
  199. VisitChildrenIf(func, n->df_begin());
  200. }
  201. }
  202. }
  203. // Returns the DominatorTreeNode associated with the basic block |bb|.
  204. // If the |bb| is unknown to the dominator tree, it returns null.
  205. inline DominatorTreeNode* GetTreeNode(BasicBlock* bb) {
  206. return GetTreeNode(bb->id());
  207. }
  208. // Returns the DominatorTreeNode associated with the basic block |bb|.
  209. // If the |bb| is unknown to the dominator tree, it returns null.
  210. inline const DominatorTreeNode* GetTreeNode(BasicBlock* bb) const {
  211. return GetTreeNode(bb->id());
  212. }
  213. // Returns the DominatorTreeNode associated with the basic block id |id|.
  214. // If the id |id| is unknown to the dominator tree, it returns null.
  215. inline DominatorTreeNode* GetTreeNode(uint32_t id) {
  216. DominatorTreeNodeMap::iterator node_iter = nodes_.find(id);
  217. if (node_iter == nodes_.end()) {
  218. return nullptr;
  219. }
  220. return &node_iter->second;
  221. }
  222. // Returns the DominatorTreeNode associated with the basic block id |id|.
  223. // If the id |id| is unknown to the dominator tree, it returns null.
  224. inline const DominatorTreeNode* GetTreeNode(uint32_t id) const {
  225. DominatorTreeNodeMap::const_iterator node_iter = nodes_.find(id);
  226. if (node_iter == nodes_.end()) {
  227. return nullptr;
  228. }
  229. return &node_iter->second;
  230. }
  231. // Adds the basic block |bb| to the tree structure if it doesn't already
  232. // exist.
  233. DominatorTreeNode* GetOrInsertNode(BasicBlock* bb);
  234. // Recomputes the DF numbering of the tree.
  235. void ResetDFNumbering();
  236. private:
  237. // Wrapper function which gets the list of pairs of each BasicBlocks to its
  238. // immediately dominating BasicBlock and stores the result in the edges
  239. // parameter.
  240. //
  241. // The |edges| vector will contain the dominator tree as pairs of nodes.
  242. // The first node in the pair is a node in the graph. The second node in the
  243. // pair is its immediate dominator.
  244. // The root of the tree has themself as immediate dominator.
  245. void GetDominatorEdges(
  246. const Function* f, const BasicBlock* dummy_start_node,
  247. std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges);
  248. // The roots of the tree.
  249. std::vector<DominatorTreeNode*> roots_;
  250. // Pairs each basic block id to the tree node containing that basic block.
  251. DominatorTreeNodeMap nodes_;
  252. // True if this is a post dominator tree.
  253. bool postdominator_;
  254. };
  255. } // namespace opt
  256. } // namespace spvtools
  257. #endif // SOURCE_OPT_DOMINATOR_TREE_H_