dominator_tree.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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. #include <iostream>
  15. #include <memory>
  16. #include <set>
  17. #include "source/cfa.h"
  18. #include "source/opt/dominator_tree.h"
  19. #include "source/opt/ir_context.h"
  20. // Calculates the dominator or postdominator tree for a given function.
  21. // 1 - Compute the successors and predecessors for each BasicBlock. We add a
  22. // placeholder node for the start node or for postdominators the exit. This node
  23. // will point to all entry or all exit nodes.
  24. // 2 - Using the CFA::DepthFirstTraversal get a depth first postordered list of
  25. // all BasicBlocks. Using the successors (or for postdominator, predecessors)
  26. // calculated in step 1 to traverse the tree.
  27. // 3 - Pass the list calculated in step 2 to the CFA::CalculateDominators using
  28. // the predecessors list (or for postdominator, successors). This will give us a
  29. // vector of BB pairs. Each BB and its immediate dominator.
  30. // 4 - Using the list from 3 use those edges to build a tree of
  31. // DominatorTreeNodes. Each node containing a link to the parent dominator and
  32. // children which are dominated.
  33. // 5 - Using the tree from 4, perform a depth first traversal to calculate the
  34. // preorder and postorder index of each node. We use these indexes to compare
  35. // nodes against each other for domination checks.
  36. namespace spvtools {
  37. namespace opt {
  38. namespace {
  39. // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
  40. // depth first search on generic BasicBlock types. Will call post and pre order
  41. // user defined functions during traversal
  42. //
  43. // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
  44. // SuccessorLambda - Lamdba matching the signature of 'const
  45. // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
  46. // succeeding BasicBlock A.
  47. // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
  48. // called on each node traversed AFTER their children.
  49. // PreLambda - Lamdba matching the signature of 'void (const BBType*)' will be
  50. // called on each node traversed BEFORE their children.
  51. template <typename BBType, typename SuccessorLambda, typename PreLambda,
  52. typename PostLambda>
  53. static void DepthFirstSearch(const BBType* bb, SuccessorLambda successors,
  54. PreLambda pre, PostLambda post) {
  55. // Ignore backedge operation.
  56. auto nop_backedge = [](const BBType*, const BBType*) {};
  57. auto no_terminal_blocks = [](const BBType*) { return false; };
  58. CFA<BBType>::DepthFirstTraversal(bb, successors, pre, post, nop_backedge,
  59. no_terminal_blocks);
  60. }
  61. // Wrapper around CFA::DepthFirstTraversal to provide an interface to perform
  62. // depth first search on generic BasicBlock types. This overload is for only
  63. // performing user defined post order.
  64. //
  65. // BBType - BasicBlock type. Will either be BasicBlock or DominatorTreeNode
  66. // SuccessorLambda - Lamdba matching the signature of 'const
  67. // std::vector<BBType>*(const BBType *A)'. Will return a vector of the nodes
  68. // succeeding BasicBlock A.
  69. // PostLambda - Lamdba matching the signature of 'void (const BBType*)' will be
  70. // called on each node traversed after their children.
  71. template <typename BBType, typename SuccessorLambda, typename PostLambda>
  72. static void DepthFirstSearchPostOrder(const BBType* bb,
  73. SuccessorLambda successors,
  74. PostLambda post) {
  75. // Ignore preorder operation.
  76. auto nop_preorder = [](const BBType*) {};
  77. DepthFirstSearch(bb, successors, nop_preorder, post);
  78. }
  79. // Small type trait to get the function class type.
  80. template <typename BBType>
  81. struct GetFunctionClass {
  82. using FunctionType = Function;
  83. };
  84. // Helper class to compute predecessors and successors for each Basic Block in a
  85. // function. Through GetPredFunctor and GetSuccessorFunctor it provides an
  86. // interface to get the successor and predecessor lists for each basic
  87. // block. This is required by the DepthFirstTraversal and ComputeDominator
  88. // functions which take as parameter an std::function returning the successors
  89. // and predecessors respectively.
  90. //
  91. // When computing the post-dominator tree, all edges are inverted. So successors
  92. // returned by this class will be predecessors in the original CFG.
  93. template <typename BBType>
  94. class BasicBlockSuccessorHelper {
  95. // This should eventually become const BasicBlock.
  96. using BasicBlock = BBType;
  97. using Function = typename GetFunctionClass<BBType>::FunctionType;
  98. using BasicBlockListTy = std::vector<BasicBlock*>;
  99. using BasicBlockMapTy = std::map<const BasicBlock*, BasicBlockListTy>;
  100. public:
  101. // For compliance with the dominance tree computation, entry nodes are
  102. // connected to a single placeholder node.
  103. BasicBlockSuccessorHelper(Function& func,
  104. const BasicBlock* placeholder_start_node,
  105. bool post);
  106. // CFA::CalculateDominators requires std::vector<BasicBlock*>.
  107. using GetBlocksFunction =
  108. std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
  109. // Returns the list of predecessor functions.
  110. GetBlocksFunction GetPredFunctor() {
  111. return [this](const BasicBlock* bb) {
  112. BasicBlockListTy* v = &this->predecessors_[bb];
  113. return v;
  114. };
  115. }
  116. // Returns a vector of the list of successor nodes from a given node.
  117. GetBlocksFunction GetSuccessorFunctor() {
  118. return [this](const BasicBlock* bb) {
  119. BasicBlockListTy* v = &this->successors_[bb];
  120. return v;
  121. };
  122. }
  123. private:
  124. bool invert_graph_;
  125. BasicBlockMapTy successors_;
  126. BasicBlockMapTy predecessors_;
  127. // Build the successors and predecessors map for each basic blocks |f|.
  128. // If |invert_graph_| is true, all edges are reversed (successors becomes
  129. // predecessors and vice versa).
  130. // For convenience, the start of the graph is |placeholder_start_node|.
  131. // The dominator tree construction requires a unique entry node, which cannot
  132. // be guaranteed for the postdominator graph. The |placeholder_start_node| BB
  133. // is here to gather all entry nodes.
  134. void CreateSuccessorMap(Function& f,
  135. const BasicBlock* placeholder_start_node);
  136. };
  137. template <typename BBType>
  138. BasicBlockSuccessorHelper<BBType>::BasicBlockSuccessorHelper(
  139. Function& func, const BasicBlock* placeholder_start_node, bool invert)
  140. : invert_graph_(invert) {
  141. CreateSuccessorMap(func, placeholder_start_node);
  142. }
  143. template <typename BBType>
  144. void BasicBlockSuccessorHelper<BBType>::CreateSuccessorMap(
  145. Function& f, const BasicBlock* placeholder_start_node) {
  146. std::map<uint32_t, BasicBlock*> id_to_BB_map;
  147. auto GetSuccessorBasicBlock = [&f, &id_to_BB_map](uint32_t successor_id) {
  148. BasicBlock*& Succ = id_to_BB_map[successor_id];
  149. if (!Succ) {
  150. for (BasicBlock& BBIt : f) {
  151. if (successor_id == BBIt.id()) {
  152. Succ = &BBIt;
  153. break;
  154. }
  155. }
  156. }
  157. return Succ;
  158. };
  159. if (invert_graph_) {
  160. // For the post dominator tree, we see the inverted graph.
  161. // successors_ in the inverted graph are the predecessors in the CFG.
  162. // The tree construction requires 1 entry point, so we add a placeholder
  163. // node that is connected to all function exiting basic blocks. An exiting
  164. // basic block is a block with an OpKill, OpUnreachable, OpReturn,
  165. // OpReturnValue, or OpTerminateInvocation as terminator instruction.
  166. for (BasicBlock& bb : f) {
  167. if (bb.hasSuccessor()) {
  168. BasicBlockListTy& pred_list = predecessors_[&bb];
  169. const auto& const_bb = bb;
  170. const_bb.ForEachSuccessorLabel(
  171. [this, &pred_list, &bb,
  172. &GetSuccessorBasicBlock](const uint32_t successor_id) {
  173. BasicBlock* succ = GetSuccessorBasicBlock(successor_id);
  174. // Inverted graph: our successors in the CFG
  175. // are our predecessors in the inverted graph.
  176. this->successors_[succ].push_back(&bb);
  177. pred_list.push_back(succ);
  178. });
  179. } else {
  180. successors_[placeholder_start_node].push_back(&bb);
  181. predecessors_[&bb].push_back(
  182. const_cast<BasicBlock*>(placeholder_start_node));
  183. }
  184. }
  185. } else {
  186. successors_[placeholder_start_node].push_back(f.entry().get());
  187. predecessors_[f.entry().get()].push_back(
  188. const_cast<BasicBlock*>(placeholder_start_node));
  189. for (BasicBlock& bb : f) {
  190. BasicBlockListTy& succ_list = successors_[&bb];
  191. const auto& const_bb = bb;
  192. const_bb.ForEachSuccessorLabel([&](const uint32_t successor_id) {
  193. BasicBlock* succ = GetSuccessorBasicBlock(successor_id);
  194. succ_list.push_back(succ);
  195. predecessors_[succ].push_back(&bb);
  196. });
  197. }
  198. }
  199. }
  200. } // namespace
  201. bool DominatorTree::StrictlyDominates(uint32_t a, uint32_t b) const {
  202. if (a == b) return false;
  203. return Dominates(a, b);
  204. }
  205. bool DominatorTree::StrictlyDominates(const BasicBlock* a,
  206. const BasicBlock* b) const {
  207. return DominatorTree::StrictlyDominates(a->id(), b->id());
  208. }
  209. bool DominatorTree::StrictlyDominates(const DominatorTreeNode* a,
  210. const DominatorTreeNode* b) const {
  211. if (a == b) return false;
  212. return Dominates(a, b);
  213. }
  214. bool DominatorTree::Dominates(uint32_t a, uint32_t b) const {
  215. // Check that both of the inputs are actual nodes.
  216. const DominatorTreeNode* a_node = GetTreeNode(a);
  217. const DominatorTreeNode* b_node = GetTreeNode(b);
  218. if (!a_node || !b_node) return false;
  219. return Dominates(a_node, b_node);
  220. }
  221. bool DominatorTree::Dominates(const DominatorTreeNode* a,
  222. const DominatorTreeNode* b) const {
  223. if (!a || !b) return false;
  224. // Node A dominates node B if they are the same.
  225. if (a == b) return true;
  226. return a->dfs_num_pre_ < b->dfs_num_pre_ &&
  227. a->dfs_num_post_ > b->dfs_num_post_;
  228. }
  229. bool DominatorTree::Dominates(const BasicBlock* A, const BasicBlock* B) const {
  230. return Dominates(A->id(), B->id());
  231. }
  232. BasicBlock* DominatorTree::ImmediateDominator(const BasicBlock* A) const {
  233. return ImmediateDominator(A->id());
  234. }
  235. BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
  236. // Check that A is a valid node in the tree.
  237. auto a_itr = nodes_.find(a);
  238. if (a_itr == nodes_.end()) return nullptr;
  239. const DominatorTreeNode* node = &a_itr->second;
  240. if (node->parent_ == nullptr) {
  241. return nullptr;
  242. }
  243. return node->parent_->bb_;
  244. }
  245. DominatorTreeNode* DominatorTree::GetOrInsertNode(BasicBlock* bb) {
  246. DominatorTreeNode* dtn = nullptr;
  247. std::map<uint32_t, DominatorTreeNode>::iterator node_iter =
  248. nodes_.find(bb->id());
  249. if (node_iter == nodes_.end()) {
  250. dtn = &nodes_.emplace(std::make_pair(bb->id(), DominatorTreeNode{bb}))
  251. .first->second;
  252. } else {
  253. dtn = &node_iter->second;
  254. }
  255. return dtn;
  256. }
  257. void DominatorTree::GetDominatorEdges(
  258. const Function* f, const BasicBlock* placeholder_start_node,
  259. std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges) {
  260. // Each time the depth first traversal calls the postorder callback
  261. // std::function we push that node into the postorder vector to create our
  262. // postorder list.
  263. std::vector<const BasicBlock*> postorder;
  264. auto postorder_function = [&](const BasicBlock* b) {
  265. postorder.push_back(b);
  266. };
  267. // CFA::CalculateDominators requires std::vector<BasicBlock*>
  268. // BB are derived from F, so we need to const cast it at some point
  269. // no modification is made on F.
  270. BasicBlockSuccessorHelper<BasicBlock> helper{
  271. *const_cast<Function*>(f), placeholder_start_node, postdominator_};
  272. // The successor function tells DepthFirstTraversal how to move to successive
  273. // nodes by providing an interface to get a list of successor nodes from any
  274. // given node.
  275. auto successor_functor = helper.GetSuccessorFunctor();
  276. // The predecessor functor does the same as the successor functor
  277. // but for all nodes preceding a given node.
  278. auto predecessor_functor = helper.GetPredFunctor();
  279. // If we're building a post dominator tree we traverse the tree in reverse
  280. // using the predecessor function in place of the successor function and vice
  281. // versa.
  282. DepthFirstSearchPostOrder(placeholder_start_node, successor_functor,
  283. postorder_function);
  284. *edges = CFA<BasicBlock>::CalculateDominators(postorder, predecessor_functor);
  285. }
  286. void DominatorTree::InitializeTree(const CFG& cfg, const Function* f) {
  287. ClearTree();
  288. // Skip over empty functions.
  289. if (f->cbegin() == f->cend()) {
  290. return;
  291. }
  292. const BasicBlock* placeholder_start_node =
  293. postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();
  294. // Get the immediate dominator for each node.
  295. std::vector<std::pair<BasicBlock*, BasicBlock*>> edges;
  296. GetDominatorEdges(f, placeholder_start_node, &edges);
  297. // Transform the vector<pair> into the tree structure which we can use to
  298. // efficiently query dominance.
  299. for (auto edge : edges) {
  300. DominatorTreeNode* first = GetOrInsertNode(edge.first);
  301. if (edge.first == edge.second) {
  302. if (std::find(roots_.begin(), roots_.end(), first) == roots_.end())
  303. roots_.push_back(first);
  304. continue;
  305. }
  306. DominatorTreeNode* second = GetOrInsertNode(edge.second);
  307. first->parent_ = second;
  308. second->children_.push_back(first);
  309. }
  310. ResetDFNumbering();
  311. }
  312. void DominatorTree::ResetDFNumbering() {
  313. int index = 0;
  314. auto preFunc = [&index](const DominatorTreeNode* node) {
  315. const_cast<DominatorTreeNode*>(node)->dfs_num_pre_ = ++index;
  316. };
  317. auto postFunc = [&index](const DominatorTreeNode* node) {
  318. const_cast<DominatorTreeNode*>(node)->dfs_num_post_ = ++index;
  319. };
  320. auto getSucc = [](const DominatorTreeNode* node) { return &node->children_; };
  321. for (auto root : roots_) DepthFirstSearch(root, getSucc, preFunc, postFunc);
  322. }
  323. void DominatorTree::DumpTreeAsDot(std::ostream& out_stream) const {
  324. out_stream << "digraph {\n";
  325. Visit([&out_stream](const DominatorTreeNode* node) {
  326. // Print the node.
  327. if (node->bb_) {
  328. out_stream << node->bb_->id() << "[label=\"" << node->bb_->id()
  329. << "\"];\n";
  330. }
  331. // Print the arrow from the parent to this node. Entry nodes will not have
  332. // parents so draw them as children from the placeholder node.
  333. if (node->parent_) {
  334. out_stream << node->parent_->bb_->id() << " -> " << node->bb_->id()
  335. << ";\n";
  336. }
  337. // Return true to continue the traversal.
  338. return true;
  339. });
  340. out_stream << "}\n";
  341. }
  342. } // namespace opt
  343. } // namespace spvtools