dominator_tree.cpp 14 KB

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