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 15 #ifndef SOURCE_OPT_DOMINATOR_TREE_H_ 16 #define SOURCE_OPT_DOMINATOR_TREE_H_ 17 18 #include <algorithm> 19 #include <cstdint> 20 #include <map> 21 #include <utility> 22 #include <vector> 23 24 #include "source/opt/cfg.h" 25 #include "source/opt/tree_iterator.h" 26 27 namespace spvtools { 28 namespace opt { 29 // This helper struct forms the nodes in the tree, with each node containing its 30 // children. It also contains two values, for the pre and post indexes in the 31 // tree which are used to compare two nodes. 32 struct DominatorTreeNode { DominatorTreeNodeDominatorTreeNode33 explicit DominatorTreeNode(BasicBlock* bb) 34 : bb_(bb), 35 parent_(nullptr), 36 children_({}), 37 dfs_num_pre_(-1), 38 dfs_num_post_(-1) {} 39 40 using iterator = std::vector<DominatorTreeNode*>::iterator; 41 using const_iterator = std::vector<DominatorTreeNode*>::const_iterator; 42 43 // depth first preorder iterator. 44 using df_iterator = TreeDFIterator<DominatorTreeNode>; 45 using const_df_iterator = TreeDFIterator<const DominatorTreeNode>; 46 // depth first postorder iterator. 47 using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>; 48 using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>; 49 beginDominatorTreeNode50 iterator begin() { return children_.begin(); } endDominatorTreeNode51 iterator end() { return children_.end(); } beginDominatorTreeNode52 const_iterator begin() const { return cbegin(); } endDominatorTreeNode53 const_iterator end() const { return cend(); } cbeginDominatorTreeNode54 const_iterator cbegin() const { return children_.begin(); } cendDominatorTreeNode55 const_iterator cend() const { return children_.end(); } 56 57 // Depth first preorder iterator using this node as root. df_beginDominatorTreeNode58 df_iterator df_begin() { return df_iterator(this); } df_endDominatorTreeNode59 df_iterator df_end() { return df_iterator(); } df_beginDominatorTreeNode60 const_df_iterator df_begin() const { return df_cbegin(); } df_endDominatorTreeNode61 const_df_iterator df_end() const { return df_cend(); } df_cbeginDominatorTreeNode62 const_df_iterator df_cbegin() const { return const_df_iterator(this); } df_cendDominatorTreeNode63 const_df_iterator df_cend() const { return const_df_iterator(); } 64 65 // Depth first postorder iterator using this node as root. post_beginDominatorTreeNode66 post_iterator post_begin() { return post_iterator::begin(this); } post_endDominatorTreeNode67 post_iterator post_end() { return post_iterator::end(nullptr); } post_beginDominatorTreeNode68 const_post_iterator post_begin() const { return post_cbegin(); } post_endDominatorTreeNode69 const_post_iterator post_end() const { return post_cend(); } post_cbeginDominatorTreeNode70 const_post_iterator post_cbegin() const { 71 return const_post_iterator::begin(this); 72 } post_cendDominatorTreeNode73 const_post_iterator post_cend() const { 74 return const_post_iterator::end(nullptr); 75 } 76 idDominatorTreeNode77 inline uint32_t id() const { return bb_->id(); } 78 79 BasicBlock* bb_; 80 DominatorTreeNode* parent_; 81 std::vector<DominatorTreeNode*> children_; 82 83 // These indexes are used to compare two given nodes. A node is a child or 84 // grandchild of another node if its preorder index is greater than the 85 // first nodes preorder index AND if its postorder index is less than the 86 // first nodes postorder index. 87 int dfs_num_pre_; 88 int dfs_num_post_; 89 }; 90 91 // A class representing a tree of BasicBlocks in a given function, where each 92 // node is dominated by its parent. 93 class DominatorTree { 94 public: 95 // Map OpLabel ids to dominator tree nodes 96 using DominatorTreeNodeMap = std::map<uint32_t, DominatorTreeNode>; 97 using iterator = TreeDFIterator<DominatorTreeNode>; 98 using const_iterator = TreeDFIterator<const DominatorTreeNode>; 99 using post_iterator = PostOrderTreeDFIterator<DominatorTreeNode>; 100 using const_post_iterator = PostOrderTreeDFIterator<const DominatorTreeNode>; 101 102 // List of DominatorTreeNode to define the list of roots 103 using DominatorTreeNodeList = std::vector<DominatorTreeNode*>; 104 using roots_iterator = DominatorTreeNodeList::iterator; 105 using roots_const_iterator = DominatorTreeNodeList::const_iterator; 106 DominatorTree()107 DominatorTree() : postdominator_(false) {} DominatorTree(bool post)108 explicit DominatorTree(bool post) : postdominator_(post) {} 109 110 // Depth first iterators. 111 // Traverse the dominator tree in a depth first pre-order. 112 // The pseudo-block is ignored. begin()113 iterator begin() { return ++iterator(GetRoot()); } end()114 iterator end() { return iterator(); } begin()115 const_iterator begin() const { return cbegin(); } end()116 const_iterator end() const { return cend(); } cbegin()117 const_iterator cbegin() const { return ++const_iterator(GetRoot()); } cend()118 const_iterator cend() const { return const_iterator(); } 119 120 // Traverse the dominator tree in a depth first post-order. 121 // The pseudo-block is ignored. post_begin()122 post_iterator post_begin() { return post_iterator::begin(GetRoot()); } post_end()123 post_iterator post_end() { return post_iterator::end(GetRoot()); } post_begin()124 const_post_iterator post_begin() const { return post_cbegin(); } post_end()125 const_post_iterator post_end() const { return post_cend(); } post_cbegin()126 const_post_iterator post_cbegin() const { 127 return const_post_iterator::begin(GetRoot()); 128 } post_cend()129 const_post_iterator post_cend() const { 130 return const_post_iterator::end(GetRoot()); 131 } 132 roots_begin()133 roots_iterator roots_begin() { return roots_.begin(); } roots_end()134 roots_iterator roots_end() { return roots_.end(); } roots_begin()135 roots_const_iterator roots_begin() const { return roots_cbegin(); } roots_end()136 roots_const_iterator roots_end() const { return roots_cend(); } roots_cbegin()137 roots_const_iterator roots_cbegin() const { return roots_.begin(); } roots_cend()138 roots_const_iterator roots_cend() const { return roots_.end(); } 139 140 // Get the unique root of the tree. 141 // It is guaranteed to work on a dominator tree. 142 // post-dominator might have a list. GetRoot()143 DominatorTreeNode* GetRoot() { 144 assert(roots_.size() == 1); 145 return *roots_.begin(); 146 } 147 GetRoot()148 const DominatorTreeNode* GetRoot() const { 149 assert(roots_.size() == 1); 150 return *roots_.begin(); 151 } 152 Roots()153 const DominatorTreeNodeList& Roots() const { return roots_; } 154 155 // Dumps the tree in the graphvis dot format into the |out_stream|. 156 void DumpTreeAsDot(std::ostream& out_stream) const; 157 158 // Build the (post-)dominator tree for the given control flow graph 159 // |cfg| and the function |f|. |f| must exist in the |cfg|. Any 160 // existing data in the dominator tree will be overwritten 161 void InitializeTree(const CFG& cfg, const Function* f); 162 163 // Check if the basic block |a| dominates the basic block |b|. 164 bool Dominates(const BasicBlock* a, const BasicBlock* b) const; 165 166 // Check if the basic block id |a| dominates the basic block id |b|. 167 bool Dominates(uint32_t a, uint32_t b) const; 168 169 // Check if the dominator tree node |a| dominates the dominator tree node |b|. 170 bool Dominates(const DominatorTreeNode* a, const DominatorTreeNode* b) const; 171 172 // Check if the basic block |a| strictly dominates the basic block |b|. 173 bool StrictlyDominates(const BasicBlock* a, const BasicBlock* b) const; 174 175 // Check if the basic block id |a| strictly dominates the basic block id |b|. 176 bool StrictlyDominates(uint32_t a, uint32_t b) const; 177 178 // Check if the dominator tree node |a| strictly dominates the dominator tree 179 // node |b|. 180 bool StrictlyDominates(const DominatorTreeNode* a, 181 const DominatorTreeNode* b) const; 182 183 // Returns the immediate dominator of basic block |a|. 184 BasicBlock* ImmediateDominator(const BasicBlock* A) const; 185 186 // Returns the immediate dominator of basic block id |a|. 187 BasicBlock* ImmediateDominator(uint32_t a) const; 188 189 // Returns true if the basic block |a| is reachable by this tree. A node would 190 // be unreachable if it cannot be reached by traversal from the start node or 191 // for a postdominator tree, cannot be reached from the exit nodes. ReachableFromRoots(const BasicBlock * a)192 inline bool ReachableFromRoots(const BasicBlock* a) const { 193 if (!a) return false; 194 return ReachableFromRoots(a->id()); 195 } 196 197 // Returns true if the basic block id |a| is reachable by this tree. ReachableFromRoots(uint32_t a)198 bool ReachableFromRoots(uint32_t a) const { 199 return GetTreeNode(a) != nullptr; 200 } 201 202 // Returns true if this tree is a post dominator tree. IsPostDominator()203 bool IsPostDominator() const { return postdominator_; } 204 205 // Clean up the tree. ClearTree()206 void ClearTree() { 207 nodes_.clear(); 208 roots_.clear(); 209 } 210 211 // Applies the std::function |func| to all nodes in the dominator tree. 212 // Tree nodes are visited in a depth first pre-order. Visit(std::function<bool (DominatorTreeNode *)> func)213 bool Visit(std::function<bool(DominatorTreeNode*)> func) { 214 for (auto n : *this) { 215 if (!func(&n)) return false; 216 } 217 return true; 218 } 219 220 // Applies the std::function |func| to all nodes in the dominator tree. 221 // Tree nodes are visited in a depth first pre-order. Visit(std::function<bool (const DominatorTreeNode *)> func)222 bool Visit(std::function<bool(const DominatorTreeNode*)> func) const { 223 for (auto n : *this) { 224 if (!func(&n)) return false; 225 } 226 return true; 227 } 228 229 // Applies the std::function |func| to all nodes in the dominator tree from 230 // |node| downwards. The boolean return from |func| is used to determine 231 // whether or not the children should also be traversed. Tree nodes are 232 // visited in a depth first pre-order. VisitChildrenIf(std::function<bool (DominatorTreeNode *)> func,iterator node)233 void VisitChildrenIf(std::function<bool(DominatorTreeNode*)> func, 234 iterator node) { 235 if (func(&*node)) { 236 for (auto n : *node) { 237 VisitChildrenIf(func, n->df_begin()); 238 } 239 } 240 } 241 242 // Returns the DominatorTreeNode associated with the basic block |bb|. 243 // If the |bb| is unknown to the dominator tree, it returns null. GetTreeNode(BasicBlock * bb)244 inline DominatorTreeNode* GetTreeNode(BasicBlock* bb) { 245 return GetTreeNode(bb->id()); 246 } 247 // Returns the DominatorTreeNode associated with the basic block |bb|. 248 // If the |bb| is unknown to the dominator tree, it returns null. GetTreeNode(BasicBlock * bb)249 inline const DominatorTreeNode* GetTreeNode(BasicBlock* bb) const { 250 return GetTreeNode(bb->id()); 251 } 252 253 // Returns the DominatorTreeNode associated with the basic block id |id|. 254 // If the id |id| is unknown to the dominator tree, it returns null. GetTreeNode(uint32_t id)255 inline DominatorTreeNode* GetTreeNode(uint32_t id) { 256 DominatorTreeNodeMap::iterator node_iter = nodes_.find(id); 257 if (node_iter == nodes_.end()) { 258 return nullptr; 259 } 260 return &node_iter->second; 261 } 262 // Returns the DominatorTreeNode associated with the basic block id |id|. 263 // If the id |id| is unknown to the dominator tree, it returns null. GetTreeNode(uint32_t id)264 inline const DominatorTreeNode* GetTreeNode(uint32_t id) const { 265 DominatorTreeNodeMap::const_iterator node_iter = nodes_.find(id); 266 if (node_iter == nodes_.end()) { 267 return nullptr; 268 } 269 return &node_iter->second; 270 } 271 272 // Adds the basic block |bb| to the tree structure if it doesn't already 273 // exist. 274 DominatorTreeNode* GetOrInsertNode(BasicBlock* bb); 275 276 // Recomputes the DF numbering of the tree. 277 void ResetDFNumbering(); 278 279 private: 280 // Wrapper function which gets the list of pairs of each BasicBlocks to its 281 // immediately dominating BasicBlock and stores the result in the the edges 282 // parameter. 283 // 284 // The |edges| vector will contain the dominator tree as pairs of nodes. 285 // The first node in the pair is a node in the graph. The second node in the 286 // pair is its immediate dominator. 287 // The root of the tree has themself as immediate dominator. 288 void GetDominatorEdges( 289 const Function* f, const BasicBlock* dummy_start_node, 290 std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges); 291 292 // The roots of the tree. 293 std::vector<DominatorTreeNode*> roots_; 294 295 // Pairs each basic block id to the tree node containing that basic block. 296 DominatorTreeNodeMap nodes_; 297 298 // True if this is a post dominator tree. 299 bool postdominator_; 300 }; 301 302 } // namespace opt 303 } // namespace spvtools 304 305 #endif // SOURCE_OPT_DOMINATOR_TREE_H_ 306