cfg.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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_CFG_H_
  15. #define SOURCE_OPT_CFG_H_
  16. #include <algorithm>
  17. #include <list>
  18. #include <unordered_map>
  19. #include <unordered_set>
  20. #include <vector>
  21. #include "source/opt/basic_block.h"
  22. namespace spvtools {
  23. namespace opt {
  24. class CFG {
  25. public:
  26. explicit CFG(Module* module);
  27. // Return the list of predecessors for basic block with label |blkid|.
  28. // TODO(dnovillo): Move this to BasicBlock.
  29. const std::vector<uint32_t>& preds(uint32_t blk_id) const {
  30. assert(label2preds_.count(blk_id));
  31. return label2preds_.at(blk_id);
  32. }
  33. // Return a pointer to the basic block instance corresponding to the label
  34. // |blk_id|.
  35. BasicBlock* block(uint32_t blk_id) const { return id2block_.at(blk_id); }
  36. // Return the pseudo entry and exit blocks.
  37. const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
  38. BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
  39. const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
  40. BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
  41. // Return true if |block_ptr| is the pseudo-entry block.
  42. bool IsPseudoEntryBlock(BasicBlock* block_ptr) const {
  43. return block_ptr == &pseudo_entry_block_;
  44. }
  45. // Return true if |block_ptr| is the pseudo-exit block.
  46. bool IsPseudoExitBlock(BasicBlock* block_ptr) const {
  47. return block_ptr == &pseudo_exit_block_;
  48. }
  49. // Compute structured block order into |order| for |func| starting at |root|.
  50. // This order has the property that dominators come before all blocks they
  51. // dominate, merge blocks come after all blocks that are in the control
  52. // constructs of their header, and continue blocks come after all of the
  53. // blocks in the body of their loop.
  54. void ComputeStructuredOrder(Function* func, BasicBlock* root,
  55. std::list<BasicBlock*>* order);
  56. // Compute structured block order into |order| for |func| starting at |root|
  57. // and ending at |end|. This order has the property that dominators come
  58. // before all blocks they dominate, merge blocks come after all blocks that
  59. // are in the control constructs of their header, and continue blocks come
  60. // after all the blocks in the body of their loop.
  61. void ComputeStructuredOrder(Function* func, BasicBlock* root, BasicBlock* end,
  62. std::list<BasicBlock*>* order);
  63. // Applies |f| to all blocks that can be reach from |bb| in post order.
  64. void ForEachBlockInPostOrder(BasicBlock* bb,
  65. const std::function<void(BasicBlock*)>& f);
  66. // Applies |f| to all blocks that can be reach from |bb| in reverse post
  67. // order.
  68. void ForEachBlockInReversePostOrder(
  69. BasicBlock* bb, const std::function<void(BasicBlock*)>& f);
  70. // Applies |f| to all blocks that can be reach from |bb| in reverse post
  71. // order. Return false if |f| return false on any basic block, and stops
  72. // processing.
  73. bool WhileEachBlockInReversePostOrder(
  74. BasicBlock* bb, const std::function<bool(BasicBlock*)>& f);
  75. // Registers |blk| as a basic block in the cfg, this also updates the
  76. // predecessor lists of each successor of |blk|. |blk| must have a terminator
  77. // instruction at the end of the block.
  78. void RegisterBlock(BasicBlock* blk) {
  79. assert(blk->begin() != blk->end() &&
  80. "Basic blocks must have a terminator before registering.");
  81. assert(blk->tail()->IsBlockTerminator() &&
  82. "Basic blocks must have a terminator before registering.");
  83. uint32_t blk_id = blk->id();
  84. id2block_[blk_id] = blk;
  85. AddEdges(blk);
  86. }
  87. // Removes from the CFG any mapping for the basic block id |blk_id|.
  88. void ForgetBlock(const BasicBlock* blk) {
  89. id2block_.erase(blk->id());
  90. label2preds_.erase(blk->id());
  91. RemoveSuccessorEdges(blk);
  92. }
  93. void RemoveEdge(uint32_t pred_blk_id, uint32_t succ_blk_id) {
  94. auto pred_it = label2preds_.find(succ_blk_id);
  95. if (pred_it == label2preds_.end()) return;
  96. auto& preds_list = pred_it->second;
  97. auto it = std::find(preds_list.begin(), preds_list.end(), pred_blk_id);
  98. if (it != preds_list.end()) preds_list.erase(it);
  99. }
  100. // Registers |blk| to all of its successors.
  101. void AddEdges(BasicBlock* blk);
  102. // Registers the basic block id |pred_blk_id| as being a predecessor of the
  103. // basic block id |succ_blk_id|.
  104. void AddEdge(uint32_t pred_blk_id, uint32_t succ_blk_id) {
  105. label2preds_[succ_blk_id].push_back(pred_blk_id);
  106. }
  107. // Removes any edges that no longer exist from the predecessor mapping for
  108. // the basic block id |blk_id|.
  109. void RemoveNonExistingEdges(uint32_t blk_id);
  110. // Remove all edges that leave |bb|.
  111. void RemoveSuccessorEdges(const BasicBlock* bb) {
  112. bb->ForEachSuccessorLabel(
  113. [bb, this](uint32_t succ_id) { RemoveEdge(bb->id(), succ_id); });
  114. }
  115. // Divides |block| into two basic blocks. The first block will have the same
  116. // id as |block| and will become a preheader for the loop. The other block
  117. // is a new block that will be the new loop header.
  118. //
  119. // Returns a pointer to the new loop header. Returns |nullptr| if the new
  120. // loop pointer could not be created.
  121. BasicBlock* SplitLoopHeader(BasicBlock* bb);
  122. private:
  123. // Compute structured successors for function |func|. A block's structured
  124. // successors are the blocks it branches to together with its declared merge
  125. // block and continue block if it has them. When order matters, the merge
  126. // block and continue block always appear first. This assures correct depth
  127. // first search in the presence of early returns and kills. If the successor
  128. // vector contain duplicates of the merge or continue blocks, they are safely
  129. // ignored by DFS.
  130. void ComputeStructuredSuccessors(Function* func);
  131. // Computes the post-order traversal of the cfg starting at |bb| skipping
  132. // nodes in |seen|. The order of the traversal is appended to |order|, and
  133. // all nodes in the traversal are added to |seen|.
  134. void ComputePostOrderTraversal(BasicBlock* bb,
  135. std::vector<BasicBlock*>* order,
  136. std::unordered_set<BasicBlock*>* seen);
  137. // Module for this CFG.
  138. Module* module_;
  139. // Map from block to its structured successor blocks. See
  140. // ComputeStructuredSuccessors() for definition.
  141. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  142. block2structured_succs_;
  143. // Extra block whose successors are all blocks with no predecessors
  144. // in function.
  145. BasicBlock pseudo_entry_block_;
  146. // Augmented CFG Exit Block.
  147. BasicBlock pseudo_exit_block_;
  148. // Map from block's label id to its predecessor blocks ids
  149. std::unordered_map<uint32_t, std::vector<uint32_t>> label2preds_;
  150. // Map from block's label id to block.
  151. std::unordered_map<uint32_t, BasicBlock*> id2block_;
  152. };
  153. } // namespace opt
  154. } // namespace spvtools
  155. #endif // SOURCE_OPT_CFG_H_