basic_block.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Copyright (c) 2016 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. // This file defines the language constructs for representing a SPIR-V
  15. // module in memory.
  16. #ifndef SOURCE_OPT_BASIC_BLOCK_H_
  17. #define SOURCE_OPT_BASIC_BLOCK_H_
  18. #include <functional>
  19. #include <iterator>
  20. #include <memory>
  21. #include <ostream>
  22. #include <string>
  23. #include <utility>
  24. #include <vector>
  25. #include "source/opt/instruction.h"
  26. #include "source/opt/instruction_list.h"
  27. #include "source/opt/iterator.h"
  28. namespace spvtools {
  29. namespace opt {
  30. class Function;
  31. class IRContext;
  32. // A SPIR-V basic block.
  33. class BasicBlock {
  34. public:
  35. using iterator = InstructionList::iterator;
  36. using const_iterator = InstructionList::const_iterator;
  37. using reverse_iterator = std::reverse_iterator<InstructionList::iterator>;
  38. using const_reverse_iterator =
  39. std::reverse_iterator<InstructionList::const_iterator>;
  40. // Creates a basic block with the given starting |label|.
  41. inline explicit BasicBlock(std::unique_ptr<Instruction> label);
  42. explicit BasicBlock(const BasicBlock& bb) = delete;
  43. // Creates a clone of the basic block in the given |context|
  44. //
  45. // The parent function will default to null and needs to be explicitly set by
  46. // the user.
  47. //
  48. // If the inst-to-block map in |context| is valid, then the new instructions
  49. // will be inserted into the map.
  50. BasicBlock* Clone(IRContext*) const;
  51. // Sets the enclosing function for this basic block.
  52. void SetParent(Function* function) { function_ = function; }
  53. // Return the enclosing function
  54. inline Function* GetParent() const { return function_; }
  55. // Appends an instruction to this basic block.
  56. inline void AddInstruction(std::unique_ptr<Instruction> i);
  57. // Appends all of block's instructions (except label) to this block
  58. inline void AddInstructions(BasicBlock* bp);
  59. // The pointer to the label starting this basic block.
  60. std::unique_ptr<Instruction>& GetLabel() { return label_; }
  61. // The label starting this basic block.
  62. Instruction* GetLabelInst() { return label_.get(); }
  63. const Instruction* GetLabelInst() const { return label_.get(); }
  64. // Returns the merge instruction in this basic block, if it exists.
  65. // Otherwise return null. May be used whenever tail() can be used.
  66. const Instruction* GetMergeInst() const;
  67. Instruction* GetMergeInst();
  68. // Returns the OpLoopMerge instruction in this basic block, if it exists.
  69. // Otherwise return null. May be used whenever tail() can be used.
  70. const Instruction* GetLoopMergeInst() const;
  71. Instruction* GetLoopMergeInst();
  72. // Returns the id of the label at the top of this block
  73. inline uint32_t id() const { return label_->result_id(); }
  74. iterator begin() { return insts_.begin(); }
  75. iterator end() { return insts_.end(); }
  76. const_iterator begin() const { return insts_.cbegin(); }
  77. const_iterator end() const { return insts_.cend(); }
  78. const_iterator cbegin() const { return insts_.cbegin(); }
  79. const_iterator cend() const { return insts_.cend(); }
  80. reverse_iterator rbegin() { return reverse_iterator(end()); }
  81. reverse_iterator rend() { return reverse_iterator(begin()); }
  82. const_reverse_iterator rbegin() const {
  83. return const_reverse_iterator(cend());
  84. }
  85. const_reverse_iterator rend() const {
  86. return const_reverse_iterator(cbegin());
  87. }
  88. const_reverse_iterator crbegin() const {
  89. return const_reverse_iterator(cend());
  90. }
  91. const_reverse_iterator crend() const {
  92. return const_reverse_iterator(cbegin());
  93. }
  94. // Returns an iterator pointing to the last instruction. This may only
  95. // be used if this block has an instruction other than the OpLabel
  96. // that defines it.
  97. iterator tail() {
  98. assert(!insts_.empty());
  99. return --end();
  100. }
  101. // Returns a const iterator, but othewrise similar to tail().
  102. const_iterator ctail() const {
  103. assert(!insts_.empty());
  104. return --insts_.cend();
  105. }
  106. // Returns true if the basic block has at least one successor.
  107. inline bool hasSuccessor() const { return ctail()->IsBranch(); }
  108. // Runs the given function |f| on each instruction in this basic block, and
  109. // optionally on the debug line instructions that might precede them.
  110. inline void ForEachInst(const std::function<void(Instruction*)>& f,
  111. bool run_on_debug_line_insts = false);
  112. inline void ForEachInst(const std::function<void(const Instruction*)>& f,
  113. bool run_on_debug_line_insts = false) const;
  114. // Runs the given function |f| on each instruction in this basic block, and
  115. // optionally on the debug line instructions that might precede them. If |f|
  116. // returns false, iteration is terminated and this function returns false.
  117. inline bool WhileEachInst(const std::function<bool(Instruction*)>& f,
  118. bool run_on_debug_line_insts = false);
  119. inline bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
  120. bool run_on_debug_line_insts = false) const;
  121. // Runs the given function |f| on each Phi instruction in this basic block,
  122. // and optionally on the debug line instructions that might precede them.
  123. inline void ForEachPhiInst(const std::function<void(Instruction*)>& f,
  124. bool run_on_debug_line_insts = false);
  125. // Runs the given function |f| on each Phi instruction in this basic block,
  126. // and optionally on the debug line instructions that might precede them. If
  127. // |f| returns false, iteration is terminated and this function return false.
  128. inline bool WhileEachPhiInst(const std::function<bool(Instruction*)>& f,
  129. bool run_on_debug_line_insts = false);
  130. // Runs the given function |f| on each label id of each successor block
  131. void ForEachSuccessorLabel(
  132. const std::function<void(const uint32_t)>& f) const;
  133. // Runs the given function |f| on each label id of each successor block. If
  134. // |f| returns false, iteration is terminated and this function returns false.
  135. bool WhileEachSuccessorLabel(
  136. const std::function<bool(const uint32_t)>& f) const;
  137. // Runs the given function |f| on each label id of each successor block.
  138. // Modifying the pointed value will change the branch taken by the basic
  139. // block. It is the caller responsibility to update or invalidate the CFG.
  140. void ForEachSuccessorLabel(const std::function<void(uint32_t*)>& f);
  141. // Returns true if |block| is a direct successor of |this|.
  142. bool IsSuccessor(const BasicBlock* block) const;
  143. // Runs the given function |f| on the merge and continue label, if any
  144. void ForMergeAndContinueLabel(const std::function<void(const uint32_t)>& f);
  145. // Returns true if this basic block has any Phi instructions.
  146. bool HasPhiInstructions() {
  147. return !WhileEachPhiInst([](Instruction*) { return false; });
  148. }
  149. // Return true if this block is a loop header block.
  150. bool IsLoopHeader() const { return GetLoopMergeInst() != nullptr; }
  151. // Returns the ID of the merge block declared by a merge instruction in this
  152. // block, if any. If none, returns zero.
  153. uint32_t MergeBlockIdIfAny() const;
  154. // Returns MergeBlockIdIfAny() and asserts that it is non-zero.
  155. uint32_t MergeBlockId() const;
  156. // Returns the ID of the continue block declared by a merge instruction in
  157. // this block, if any. If none, returns zero.
  158. uint32_t ContinueBlockIdIfAny() const;
  159. // Returns ContinueBlockIdIfAny() and asserts that it is non-zero.
  160. uint32_t ContinueBlockId() const;
  161. // Returns the terminator instruction. Assumes the terminator exists.
  162. Instruction* terminator() { return &*tail(); }
  163. const Instruction* terminator() const { return &*ctail(); }
  164. // Returns true if this basic block exits this function and returns to its
  165. // caller.
  166. bool IsReturn() const { return ctail()->IsReturn(); }
  167. // Returns true if this basic block exits this function or aborts execution.
  168. bool IsReturnOrAbort() const { return ctail()->IsReturnOrAbort(); }
  169. // Kill all instructions in this block. Whether or not to kill the label is
  170. // indicated by |killLabel|.
  171. void KillAllInsts(bool killLabel);
  172. // Splits this basic block into two. Returns a new basic block with label
  173. // |label_id| containing the instructions from |iter| onwards. Instructions
  174. // prior to |iter| remain in this basic block. The new block will be added
  175. // to the function immediately after the original block.
  176. BasicBlock* SplitBasicBlock(IRContext* context, uint32_t label_id,
  177. iterator iter);
  178. // Pretty-prints this basic block into a std::string by printing every
  179. // instruction in it.
  180. //
  181. // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
  182. // is always added to |options|.
  183. std::string PrettyPrint(uint32_t options = 0u) const;
  184. // Dump this basic block on stderr. Useful when running interactive
  185. // debuggers.
  186. void Dump() const;
  187. private:
  188. // The enclosing function.
  189. Function* function_;
  190. // The label starting this basic block.
  191. std::unique_ptr<Instruction> label_;
  192. // Instructions inside this basic block, but not the OpLabel.
  193. InstructionList insts_;
  194. };
  195. // Pretty-prints |block| to |str|. Returns |str|.
  196. std::ostream& operator<<(std::ostream& str, const BasicBlock& block);
  197. inline BasicBlock::BasicBlock(std::unique_ptr<Instruction> label)
  198. : function_(nullptr), label_(std::move(label)) {}
  199. inline void BasicBlock::AddInstruction(std::unique_ptr<Instruction> i) {
  200. insts_.push_back(std::move(i));
  201. }
  202. inline void BasicBlock::AddInstructions(BasicBlock* bp) {
  203. auto bEnd = end();
  204. (void)bEnd.MoveBefore(&bp->insts_);
  205. }
  206. inline bool BasicBlock::WhileEachInst(
  207. const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) {
  208. if (label_) {
  209. if (!label_->WhileEachInst(f, run_on_debug_line_insts)) return false;
  210. }
  211. if (insts_.empty()) {
  212. return true;
  213. }
  214. Instruction* inst = &insts_.front();
  215. while (inst != nullptr) {
  216. Instruction* next_instruction = inst->NextNode();
  217. if (!inst->WhileEachInst(f, run_on_debug_line_insts)) return false;
  218. inst = next_instruction;
  219. }
  220. return true;
  221. }
  222. inline bool BasicBlock::WhileEachInst(
  223. const std::function<bool(const Instruction*)>& f,
  224. bool run_on_debug_line_insts) const {
  225. if (label_) {
  226. if (!static_cast<const Instruction*>(label_.get())
  227. ->WhileEachInst(f, run_on_debug_line_insts))
  228. return false;
  229. }
  230. for (const auto& inst : insts_) {
  231. if (!static_cast<const Instruction*>(&inst)->WhileEachInst(
  232. f, run_on_debug_line_insts))
  233. return false;
  234. }
  235. return true;
  236. }
  237. inline void BasicBlock::ForEachInst(const std::function<void(Instruction*)>& f,
  238. bool run_on_debug_line_insts) {
  239. WhileEachInst(
  240. [&f](Instruction* inst) {
  241. f(inst);
  242. return true;
  243. },
  244. run_on_debug_line_insts);
  245. }
  246. inline void BasicBlock::ForEachInst(
  247. const std::function<void(const Instruction*)>& f,
  248. bool run_on_debug_line_insts) const {
  249. WhileEachInst(
  250. [&f](const Instruction* inst) {
  251. f(inst);
  252. return true;
  253. },
  254. run_on_debug_line_insts);
  255. }
  256. inline bool BasicBlock::WhileEachPhiInst(
  257. const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) {
  258. if (insts_.empty()) {
  259. return true;
  260. }
  261. Instruction* inst = &insts_.front();
  262. while (inst != nullptr) {
  263. Instruction* next_instruction = inst->NextNode();
  264. if (inst->opcode() != spv::Op::OpPhi) break;
  265. if (!inst->WhileEachInst(f, run_on_debug_line_insts)) return false;
  266. inst = next_instruction;
  267. }
  268. return true;
  269. }
  270. inline void BasicBlock::ForEachPhiInst(
  271. const std::function<void(Instruction*)>& f, bool run_on_debug_line_insts) {
  272. WhileEachPhiInst(
  273. [&f](Instruction* inst) {
  274. f(inst);
  275. return true;
  276. },
  277. run_on_debug_line_insts);
  278. }
  279. } // namespace opt
  280. } // namespace spvtools
  281. #endif // SOURCE_OPT_BASIC_BLOCK_H_