dominator_tree.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. // succeding 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. CFA<BBType>::DepthFirstTraversal(bb, successors, pre, post, nop_backedge);
  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. // succeding 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. static void DepthFirstSearchPostOrder(const BBType* bb,
  71. SuccessorLambda successors,
  72. PostLambda post) {
  73. // Ignore preorder operation.
  74. auto nop_preorder = [](const BBType*) {};
  75. DepthFirstSearch(bb, successors, nop_preorder, post);
  76. }
  77. // Small type trait to get the function class type.
  78. template <typename BBType>
  79. struct GetFunctionClass {
  80. using FunctionType = Function;
  81. };
  82. // Helper class to compute predecessors and successors for each Basic Block in a
  83. // function. Through GetPredFunctor and GetSuccessorFunctor it provides an
  84. // interface to get the successor and predecessor lists for each basic
  85. // block. This is required by the DepthFirstTraversal and ComputeDominator
  86. // functions which take as parameter an std::function returning the successors
  87. // and predecessors respectively.
  88. //
  89. // When computing the post-dominator tree, all edges are inverted. So successors
  90. // returned by this class will be predecessors in the original CFG.
  91. template <typename BBType>
  92. class BasicBlockSuccessorHelper {
  93. // This should eventually become const BasicBlock.
  94. using BasicBlock = BBType;
  95. using Function = typename GetFunctionClass<BBType>::FunctionType;
  96. using BasicBlockListTy = std::vector<BasicBlock*>;
  97. using BasicBlockMapTy = std::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. std::map<uint32_t, BasicBlock*> id_to_BB_map;
  145. auto GetSuccessorBasicBlock = [&f, &id_to_BB_map](uint32_t successor_id) {
  146. BasicBlock*& Succ = id_to_BB_map[successor_id];
  147. if (!Succ) {
  148. for (BasicBlock& BBIt : f) {
  149. if (successor_id == BBIt.id()) {
  150. Succ = &BBIt;
  151. break;
  152. }
  153. }
  154. }
  155. return Succ;
  156. };
  157. if (invert_graph_) {
  158. // For the post dominator tree, we see the inverted graph.
  159. // successors_ in the inverted graph are the predecessors in the CFG.
  160. // The tree construction requires 1 entry point, so we add a placeholder
  161. // node that is connected to all function exiting basic blocks. An exiting
  162. // basic block is a block with an OpKill, OpUnreachable, OpReturn,
  163. // OpReturnValue, or OpTerminateInvocation as terminator instruction.
  164. for (BasicBlock& bb : f) {
  165. if (bb.hasSuccessor()) {
  166. BasicBlockListTy& pred_list = predecessors_[&bb];
  167. const auto& const_bb = bb;
  168. const_bb.ForEachSuccessorLabel(
  169. [this, &pred_list, &bb,
  170. &GetSuccessorBasicBlock](const uint32_t successor_id) {
  171. BasicBlock* succ = GetSuccessorBasicBlock(successor_id);
  172. // Inverted graph: our successors in the CFG
  173. // are our predecessors in the inverted graph.
  174. this->successors_[succ].push_back(&bb);
  175. pred_list.push_back(succ);
  176. });
  177. } else {
  178. successors_[placeholder_start_node].push_back(&bb);
  179. predecessors_[&bb].push_back(
  180. const_cast<BasicBlock*>(placeholder_start_node));
  181. }
  182. }
  183. } else {
  184. successors_[placeholder_start_node].push_back(f.entry().get());
  185. predecessors_[f.entry().get()].push_back(
  186. const_cast<BasicBlock*>(placeholder_start_node));
  187. for (BasicBlock& bb : f) {
  188. BasicBlockListTy& succ_list = successors_[&bb];
  189. const auto& const_bb = bb;
  190. const_bb.ForEachSuccessorLabel([&](const uint32_t successor_id) {
  191. BasicBlock* succ = GetSuccessorBasicBlock(successor_id);
  192. succ_list.push_back(succ);
  193. predecessors_[succ].push_back(&bb);
  194. });
  195. }
  196. }
  197. }
  198. } // namespace
  199. bool DominatorTree::StrictlyDominates(uint32_t a, uint32_t b) const {
  200. if (a == b) return false;
  201. return Dominates(a, b);
  202. }
  203. bool DominatorTree::StrictlyDominates(const BasicBlock* a,
  204. const BasicBlock* b) const {
  205. return DominatorTree::StrictlyDominates(a->id(), b->id());
  206. }
  207. bool DominatorTree::StrictlyDominates(const DominatorTreeNode* a,
  208. const DominatorTreeNode* b) const {
  209. if (a == b) return false;
  210. return Dominates(a, b);
  211. }
  212. bool DominatorTree::Dominates(uint32_t a, uint32_t b) const {
  213. // Check that both of the inputs are actual nodes.
  214. const DominatorTreeNode* a_node = GetTreeNode(a);
  215. const DominatorTreeNode* b_node = GetTreeNode(b);
  216. if (!a_node || !b_node) return false;
  217. return Dominates(a_node, b_node);
  218. }
  219. bool DominatorTree::Dominates(const DominatorTreeNode* a,
  220. const DominatorTreeNode* b) const {
  221. if (!a || !b) return false;
  222. // Node A dominates node B if they are the same.
  223. if (a == b) return true;
  224. return a->dfs_num_pre_ < b->dfs_num_pre_ &&
  225. a->dfs_num_post_ > b->dfs_num_post_;
  226. }
  227. bool DominatorTree::Dominates(const BasicBlock* A, const BasicBlock* B) const {
  228. return Dominates(A->id(), B->id());
  229. }
  230. BasicBlock* DominatorTree::ImmediateDominator(const BasicBlock* A) const {
  231. return ImmediateDominator(A->id());
  232. }
  233. BasicBlock* DominatorTree::ImmediateDominator(uint32_t a) const {
  234. // Check that A is a valid node in the tree.
  235. auto a_itr = nodes_.find(a);
  236. if (a_itr == nodes_.end()) return nullptr;
  237. const DominatorTreeNode* node = &a_itr->second;
  238. if (node->parent_ == nullptr) {
  239. return nullptr;
  240. }
  241. return node->parent_->bb_;
  242. }
  243. DominatorTreeNode* DominatorTree::GetOrInsertNode(BasicBlock* bb) {
  244. DominatorTreeNode* dtn = nullptr;
  245. std::map<uint32_t, DominatorTreeNode>::iterator node_iter =
  246. nodes_.find(bb->id());
  247. if (node_iter == nodes_.end()) {
  248. dtn = &nodes_.emplace(std::make_pair(bb->id(), DominatorTreeNode{bb}))
  249. .first->second;
  250. } else {
  251. dtn = &node_iter->second;
  252. }
  253. return dtn;
  254. }
  255. void DominatorTree::GetDominatorEdges(
  256. const Function* f, const BasicBlock* placeholder_start_node,
  257. std::vector<std::pair<BasicBlock*, BasicBlock*>>* edges) {
  258. // Each time the depth first traversal calls the postorder callback
  259. // std::function we push that node into the postorder vector to create our
  260. // postorder list.
  261. std::vector<const BasicBlock*> postorder;
  262. auto postorder_function = [&](const BasicBlock* b) {
  263. postorder.push_back(b);
  264. };
  265. // CFA::CalculateDominators requires std::vector<BasicBlock*>
  266. // BB are derived from F, so we need to const cast it at some point
  267. // no modification is made on F.
  268. BasicBlockSuccessorHelper<BasicBlock> helper{
  269. *const_cast<Function*>(f), placeholder_start_node, postdominator_};
  270. // The successor function tells DepthFirstTraversal how to move to successive
  271. // nodes by providing an interface to get a list of successor nodes from any
  272. // given node.
  273. auto successor_functor = helper.GetSuccessorFunctor();
  274. // The predecessor functor does the same as the successor functor
  275. // but for all nodes preceding a given node.
  276. auto predecessor_functor = helper.GetPredFunctor();
  277. // If we're building a post dominator tree we traverse the tree in reverse
  278. // using the predecessor function in place of the successor function and vice
  279. // versa.
  280. DepthFirstSearchPostOrder(placeholder_start_node, successor_functor,
  281. postorder_function);
  282. *edges = CFA<BasicBlock>::CalculateDominators(postorder, predecessor_functor);
  283. }
  284. void DominatorTree::InitializeTree(const CFG& cfg, const Function* f) {
  285. ClearTree();
  286. // Skip over empty functions.
  287. if (f->cbegin() == f->cend()) {
  288. return;
  289. }
  290. const BasicBlock* placeholder_start_node =
  291. postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();
  292. // Get the immediate dominator for each node.
  293. std::vector<std::pair<BasicBlock*, BasicBlock*>> edges;
  294. GetDominatorEdges(f, placeholder_start_node, &edges);
  295. // Transform the vector<pair> into the tree structure which we can use to
  296. // efficiently query dominance.
  297. for (auto edge : edges) {
  298. DominatorTreeNode* first = GetOrInsertNode(edge.first);
  299. if (edge.first == edge.second) {
  300. if (std::find(roots_.begin(), roots_.end(), first) == roots_.end())
  301. roots_.push_back(first);
  302. continue;
  303. }
  304. DominatorTreeNode* second = GetOrInsertNode(edge.second);
  305. first->parent_ = second;
  306. second->children_.push_back(first);
  307. }
  308. ResetDFNumbering();
  309. }
  310. void DominatorTree::ResetDFNumbering() {
  311. int index = 0;
  312. auto preFunc = [&index](const DominatorTreeNode* node) {
  313. const_cast<DominatorTreeNode*>(node)->dfs_num_pre_ = ++index;
  314. };
  315. auto postFunc = [&index](const DominatorTreeNode* node) {
  316. const_cast<DominatorTreeNode*>(node)->dfs_num_post_ = ++index;
  317. };
  318. auto getSucc = [](const DominatorTreeNode* node) { return &node->children_; };
  319. for (auto root : roots_) DepthFirstSearch(root, getSucc, preFunc, postFunc);
  320. }
  321. void DominatorTree::DumpTreeAsDot(std::ostream& out_stream) const {
  322. out_stream << "digraph {\n";
  323. Visit([&out_stream](const DominatorTreeNode* node) {
  324. // Print the node.
  325. if (node->bb_) {
  326. out_stream << node->bb_->id() << "[label=\"" << node->bb_->id()
  327. << "\"];\n";
  328. }
  329. // Print the arrow from the parent to this node. Entry nodes will not have
  330. // parents so draw them as children from the placeholder node.
  331. if (node->parent_) {
  332. out_stream << node->parent_->bb_->id() << " -> " << node->bb_->id()
  333. << ";\n";
  334. }
  335. // Return true to continue the traversal.
  336. return true;
  337. });
  338. out_stream << "}\n";
  339. }
  340. } // namespace opt
  341. } // namespace spvtools