basic_block.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 instruciton 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.
  134. // Modifying the pointed value will change the branch taken by the basic
  135. // block. It is the caller responsibility to update or invalidate the CFG.
  136. void ForEachSuccessorLabel(const std::function<void(uint32_t*)>& f);
  137. // Returns true if |block| is a direct successor of |this|.
  138. bool IsSuccessor(const BasicBlock* block) const;
  139. // Runs the given function |f| on the merge and continue label, if any
  140. void ForMergeAndContinueLabel(const std::function<void(const uint32_t)>& f);
  141. // Returns true if this basic block has any Phi instructions.
  142. bool HasPhiInstructions() {
  143. return !WhileEachPhiInst([](Instruction*) { return false; });
  144. }
  145. // Return true if this block is a loop header block.
  146. bool IsLoopHeader() const { return GetLoopMergeInst() != nullptr; }
  147. // Returns the ID of the merge block declared by a merge instruction in this
  148. // block, if any. If none, returns zero.
  149. uint32_t MergeBlockIdIfAny() const;
  150. // Returns MergeBlockIdIfAny() and asserts that it is non-zero.
  151. uint32_t MergeBlockId() const;
  152. // Returns the ID of the continue block declared by a merge instruction in
  153. // this block, if any. If none, returns zero.
  154. uint32_t ContinueBlockIdIfAny() const;
  155. // Returns ContinueBlockIdIfAny() and asserts that it is non-zero.
  156. uint32_t ContinueBlockId() const;
  157. // Returns the terminator instruction. Assumes the terminator exists.
  158. Instruction* terminator() { return &*tail(); }
  159. const Instruction* terminator() const { return &*ctail(); }
  160. // Returns true if this basic block exits this function and returns to its
  161. // caller.
  162. bool IsReturn() const { return ctail()->IsReturn(); }
  163. // Returns true if this basic block exits this function or aborts execution.
  164. bool IsReturnOrAbort() const { return ctail()->IsReturnOrAbort(); }
  165. // Kill all instructions in this block. Whether or not to kill the label is
  166. // indicated by |killLabel|.
  167. void KillAllInsts(bool killLabel);
  168. // Splits this basic block into two. Returns a new basic block with label
  169. // |labelId| containing the instructions from |iter| onwards. Instructions
  170. // prior to |iter| remain in this basic block. The new block will be added
  171. // to the function immediately after the original block.
  172. BasicBlock* SplitBasicBlock(IRContext* context, uint32_t label_id,
  173. iterator iter);
  174. // Pretty-prints this basic block into a std::string by printing every
  175. // instruction in it.
  176. //
  177. // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
  178. // is always added to |options|.
  179. std::string PrettyPrint(uint32_t options = 0u) const;
  180. // Dump this basic block on stderr. Useful when running interactive
  181. // debuggers.
  182. void Dump() const;
  183. private:
  184. // The enclosing function.
  185. Function* function_;
  186. // The label starting this basic block.
  187. std::unique_ptr<Instruction> label_;
  188. // Instructions inside this basic block, but not the OpLabel.
  189. InstructionList insts_;
  190. };
  191. // Pretty-prints |block| to |str|. Returns |str|.
  192. std::ostream& operator<<(std::ostream& str, const BasicBlock& block);
  193. inline BasicBlock::BasicBlock(std::unique_ptr<Instruction> label)
  194. : function_(nullptr), label_(std::move(label)) {}
  195. inline void BasicBlock::AddInstruction(std::unique_ptr<Instruction> i) {
  196. insts_.push_back(std::move(i));
  197. }
  198. inline void BasicBlock::AddInstructions(BasicBlock* bp) {
  199. auto bEnd = end();
  200. (void)bEnd.MoveBefore(&bp->insts_);
  201. }
  202. inline bool BasicBlock::WhileEachInst(
  203. const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) {
  204. if (label_) {
  205. if (!label_->WhileEachInst(f, run_on_debug_line_insts)) return false;
  206. }
  207. if (insts_.empty()) {
  208. return true;
  209. }
  210. Instruction* inst = &insts_.front();
  211. while (inst != nullptr) {
  212. Instruction* next_instruction = inst->NextNode();
  213. if (!inst->WhileEachInst(f, run_on_debug_line_insts)) return false;
  214. inst = next_instruction;
  215. }
  216. return true;
  217. }
  218. inline bool BasicBlock::WhileEachInst(
  219. const std::function<bool(const Instruction*)>& f,
  220. bool run_on_debug_line_insts) const {
  221. if (label_) {
  222. if (!static_cast<const Instruction*>(label_.get())
  223. ->WhileEachInst(f, run_on_debug_line_insts))
  224. return false;
  225. }
  226. for (const auto& inst : insts_) {
  227. if (!static_cast<const Instruction*>(&inst)->WhileEachInst(
  228. f, run_on_debug_line_insts))
  229. return false;
  230. }
  231. return true;
  232. }
  233. inline void BasicBlock::ForEachInst(const std::function<void(Instruction*)>& f,
  234. bool run_on_debug_line_insts) {
  235. WhileEachInst(
  236. [&f](Instruction* inst) {
  237. f(inst);
  238. return true;
  239. },
  240. run_on_debug_line_insts);
  241. }
  242. inline void BasicBlock::ForEachInst(
  243. const std::function<void(const Instruction*)>& f,
  244. bool run_on_debug_line_insts) const {
  245. WhileEachInst(
  246. [&f](const Instruction* inst) {
  247. f(inst);
  248. return true;
  249. },
  250. run_on_debug_line_insts);
  251. }
  252. inline bool BasicBlock::WhileEachPhiInst(
  253. const std::function<bool(Instruction*)>& f, bool run_on_debug_line_insts) {
  254. if (insts_.empty()) {
  255. return true;
  256. }
  257. Instruction* inst = &insts_.front();
  258. while (inst != nullptr) {
  259. Instruction* next_instruction = inst->NextNode();
  260. if (inst->opcode() != SpvOpPhi) break;
  261. if (!inst->WhileEachInst(f, run_on_debug_line_insts)) return false;
  262. inst = next_instruction;
  263. }
  264. return true;
  265. }
  266. inline void BasicBlock::ForEachPhiInst(
  267. const std::function<void(Instruction*)>& f, bool run_on_debug_line_insts) {
  268. WhileEachPhiInst(
  269. [&f](Instruction* inst) {
  270. f(inst);
  271. return true;
  272. },
  273. run_on_debug_line_insts);
  274. }
  275. } // namespace opt
  276. } // namespace spvtools
  277. #endif // SOURCE_OPT_BASIC_BLOCK_H_