basic_block.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Copyright (c) 2015-2016 The Khronos Group 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_VAL_BASIC_BLOCK_H_
  15. #define SOURCE_VAL_BASIC_BLOCK_H_
  16. #include <bitset>
  17. #include <cstdint>
  18. #include <functional>
  19. #include <memory>
  20. #include <vector>
  21. #include "source/latest_version_spirv_header.h"
  22. namespace spvtools {
  23. namespace val {
  24. enum BlockType : uint32_t {
  25. kBlockTypeUndefined,
  26. kBlockTypeSelection,
  27. kBlockTypeLoop,
  28. kBlockTypeMerge,
  29. kBlockTypeBreak,
  30. kBlockTypeContinue,
  31. kBlockTypeReturn,
  32. kBlockTypeCOUNT ///< Total number of block types. (must be the last element)
  33. };
  34. class Instruction;
  35. // This class represents a basic block in a SPIR-V module
  36. class BasicBlock {
  37. public:
  38. /// Constructor for a BasicBlock
  39. ///
  40. /// @param[in] id The ID of the basic block
  41. explicit BasicBlock(uint32_t id);
  42. /// Returns the id of the BasicBlock
  43. uint32_t id() const { return id_; }
  44. /// Returns the predecessors of the BasicBlock
  45. const std::vector<BasicBlock*>* predecessors() const {
  46. return &predecessors_;
  47. }
  48. /// Returns the predecessors of the BasicBlock
  49. std::vector<BasicBlock*>* predecessors() { return &predecessors_; }
  50. /// Returns the successors of the BasicBlock
  51. const std::vector<BasicBlock*>* successors() const { return &successors_; }
  52. /// Returns the successors of the BasicBlock
  53. std::vector<BasicBlock*>* successors() { return &successors_; }
  54. /// Returns the structural successors of the BasicBlock
  55. std::vector<BasicBlock*>* structural_predecessors() {
  56. return &structural_predecessors_;
  57. }
  58. /// Returns the structural predecessors of the BasicBlock
  59. const std::vector<BasicBlock*>* structural_predecessors() const {
  60. return &structural_predecessors_;
  61. }
  62. /// Returns the structural successors of the BasicBlock
  63. std::vector<BasicBlock*>* structural_successors() {
  64. return &structural_successors_;
  65. }
  66. /// Returns the structural predecessors of the BasicBlock
  67. const std::vector<BasicBlock*>* structural_successors() const {
  68. return &structural_successors_;
  69. }
  70. /// Returns true if the block is reachable in the CFG.
  71. bool reachable() const { return reachable_; }
  72. /// Returns true if the block is structurally reachable in the CFG.
  73. bool structurally_reachable() const { return structurally_reachable_; }
  74. /// Returns true if BasicBlock is of the given type
  75. bool is_type(BlockType type) const {
  76. if (type == kBlockTypeUndefined) return type_.none();
  77. return type_.test(type);
  78. }
  79. /// Sets the reachability of the basic block in the CFG
  80. void set_reachable(bool reachability) { reachable_ = reachability; }
  81. /// Sets the structural reachability of the basic block in the CFG
  82. void set_structurally_reachable(bool reachability) {
  83. structurally_reachable_ = reachability;
  84. }
  85. /// Sets the type of the BasicBlock
  86. void set_type(BlockType type) {
  87. if (type == kBlockTypeUndefined)
  88. type_.reset();
  89. else
  90. type_.set(type);
  91. }
  92. /// Sets the immediate dominator of this basic block
  93. ///
  94. /// @param[in] dom_block The dominator block
  95. void SetImmediateDominator(BasicBlock* dom_block);
  96. /// Sets the immediate dominator of this basic block
  97. ///
  98. /// @param[in] dom_block The dominator block
  99. void SetImmediateStructuralDominator(BasicBlock* dom_block);
  100. /// Sets the immediate post dominator of this basic block
  101. ///
  102. /// @param[in] pdom_block The post dominator block
  103. void SetImmediateStructuralPostDominator(BasicBlock* pdom_block);
  104. /// Returns the immediate dominator of this basic block
  105. BasicBlock* immediate_dominator();
  106. /// Returns the immediate dominator of this basic block
  107. const BasicBlock* immediate_dominator() const;
  108. /// Returns the immediate dominator of this basic block
  109. BasicBlock* immediate_structural_dominator();
  110. /// Returns the immediate dominator of this basic block
  111. const BasicBlock* immediate_structural_dominator() const;
  112. /// Returns the immediate post dominator of this basic block
  113. BasicBlock* immediate_structural_post_dominator();
  114. /// Returns the immediate post dominator of this basic block
  115. const BasicBlock* immediate_structural_post_dominator() const;
  116. /// Returns the label instruction for the block, or nullptr if not set.
  117. const Instruction* label() const { return label_; }
  118. //// Registers the label instruction for the block.
  119. void set_label(const Instruction* t) { label_ = t; }
  120. /// Registers the terminator instruction for the block.
  121. void set_terminator(const Instruction* t) { terminator_ = t; }
  122. /// Returns the terminator instruction for the block.
  123. const Instruction* terminator() const { return terminator_; }
  124. /// Adds @p next BasicBlocks as successors of this BasicBlock
  125. void RegisterSuccessors(
  126. const std::vector<BasicBlock*>& next = std::vector<BasicBlock*>());
  127. /// Returns true if the id of the BasicBlock matches
  128. bool operator==(const BasicBlock& other) const { return other.id_ == id_; }
  129. /// Returns true if the id of the BasicBlock matches
  130. bool operator==(const uint32_t& other_id) const { return other_id == id_; }
  131. /// Returns true if this block dominates the other block.
  132. /// Assumes dominators have been computed.
  133. bool dominates(const BasicBlock& other) const;
  134. /// Returns true if this block structurally dominates the other block.
  135. /// Assumes structural dominators have been computed.
  136. bool structurally_dominates(const BasicBlock& other) const;
  137. /// Returns true if this block structurally postdominates the other block.
  138. /// Assumes structural dominators have been computed.
  139. bool structurally_postdominates(const BasicBlock& other) const;
  140. void RegisterStructuralSuccessor(BasicBlock* block) {
  141. block->structural_predecessors_.push_back(this);
  142. structural_successors_.push_back(block);
  143. }
  144. /// @brief A BasicBlock dominator iterator class
  145. ///
  146. /// This iterator will iterate over the (post)dominators of the block
  147. class DominatorIterator {
  148. public:
  149. using iterator_category = std::forward_iterator_tag;
  150. using value_type = BasicBlock*;
  151. using pointer = value_type*;
  152. using reference = value_type&;
  153. using difference_type = std::ptrdiff_t;
  154. /// @brief Constructs the end of dominator iterator
  155. ///
  156. /// This will create an iterator which will represent the element
  157. /// before the root node of the dominator tree
  158. DominatorIterator();
  159. /// @brief Constructs an iterator for the given block which points to
  160. /// @p block
  161. ///
  162. /// @param block The block which is referenced by the iterator
  163. /// @param dominator_func This function will be called to get the immediate
  164. /// (post)dominator of the current block
  165. DominatorIterator(
  166. const BasicBlock* block,
  167. std::function<const BasicBlock*(const BasicBlock*)> dominator_func);
  168. /// @brief Advances the iterator
  169. DominatorIterator& operator++();
  170. /// @brief Returns the current element
  171. const BasicBlock*& operator*();
  172. friend bool operator==(const DominatorIterator& lhs,
  173. const DominatorIterator& rhs);
  174. private:
  175. const BasicBlock* current_;
  176. std::function<const BasicBlock*(const BasicBlock*)> dom_func_;
  177. };
  178. /// Returns a dominator iterator which points to the current block
  179. const DominatorIterator dom_begin() const;
  180. /// Returns a dominator iterator which points to the current block
  181. DominatorIterator dom_begin();
  182. /// Returns a dominator iterator which points to one element past the first
  183. /// block
  184. const DominatorIterator dom_end() const;
  185. /// Returns a dominator iterator which points to one element past the first
  186. /// block
  187. DominatorIterator dom_end();
  188. /// Returns a dominator iterator which points to the current block
  189. const DominatorIterator structural_dom_begin() const;
  190. /// Returns a dominator iterator which points to the current block
  191. DominatorIterator structural_dom_begin();
  192. /// Returns a dominator iterator which points to one element past the first
  193. /// block
  194. const DominatorIterator structural_dom_end() const;
  195. /// Returns a dominator iterator which points to one element past the first
  196. /// block
  197. DominatorIterator structural_dom_end();
  198. /// Returns a post dominator iterator which points to the current block
  199. const DominatorIterator structural_pdom_begin() const;
  200. /// Returns a post dominator iterator which points to the current block
  201. DominatorIterator structural_pdom_begin();
  202. /// Returns a post dominator iterator which points to one element past the
  203. /// last block
  204. const DominatorIterator structural_pdom_end() const;
  205. /// Returns a post dominator iterator which points to one element past the
  206. /// last block
  207. DominatorIterator structural_pdom_end();
  208. private:
  209. /// Id of the BasicBlock
  210. const uint32_t id_;
  211. /// Pointer to the immediate dominator of the BasicBlock
  212. BasicBlock* immediate_dominator_;
  213. /// Pointer to the immediate structural dominator of the BasicBlock
  214. BasicBlock* immediate_structural_dominator_;
  215. /// Pointer to the immediate structural post dominator of the BasicBlock
  216. BasicBlock* immediate_structural_post_dominator_;
  217. /// The set of predecessors of the BasicBlock
  218. std::vector<BasicBlock*> predecessors_;
  219. /// The set of successors of the BasicBlock
  220. std::vector<BasicBlock*> successors_;
  221. /// The type of the block
  222. std::bitset<kBlockTypeCOUNT> type_;
  223. /// True if the block is reachable in the CFG
  224. bool reachable_;
  225. /// True if the block is structurally reachable in the CFG
  226. bool structurally_reachable_;
  227. /// label of this block, if any.
  228. const Instruction* label_;
  229. /// Terminator of this block.
  230. const Instruction* terminator_;
  231. std::vector<BasicBlock*> structural_predecessors_;
  232. std::vector<BasicBlock*> structural_successors_;
  233. };
  234. /// @brief Returns true if the iterators point to the same element or if both
  235. /// iterators point to the @p dom_end block
  236. bool operator==(const BasicBlock::DominatorIterator& lhs,
  237. const BasicBlock::DominatorIterator& rhs);
  238. /// @brief Returns true if the iterators point to different elements and they
  239. /// do not both point to the @p dom_end block
  240. bool operator!=(const BasicBlock::DominatorIterator& lhs,
  241. const BasicBlock::DominatorIterator& rhs);
  242. } // namespace val
  243. } // namespace spvtools
  244. #endif // SOURCE_VAL_BASIC_BLOCK_H_