function.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. #ifndef SOURCE_OPT_FUNCTION_H_
  15. #define SOURCE_OPT_FUNCTION_H_
  16. #include <algorithm>
  17. #include <functional>
  18. #include <memory>
  19. #include <string>
  20. #include <utility>
  21. #include <vector>
  22. #include "source/opt/basic_block.h"
  23. #include "source/opt/instruction.h"
  24. #include "source/opt/iterator.h"
  25. namespace spvtools {
  26. namespace opt {
  27. class CFG;
  28. class IRContext;
  29. class Module;
  30. // A SPIR-V function.
  31. class Function {
  32. public:
  33. using iterator = UptrVectorIterator<BasicBlock>;
  34. using const_iterator = UptrVectorIterator<BasicBlock, true>;
  35. // Creates a function instance declared by the given OpFunction instruction
  36. // |def_inst|.
  37. inline explicit Function(std::unique_ptr<Instruction> def_inst);
  38. explicit Function(const Function& f) = delete;
  39. // Creates a clone of the instruction in the given |context|
  40. //
  41. // The parent module will default to null and needs to be explicitly set by
  42. // the user.
  43. Function* Clone(IRContext*) const;
  44. // The OpFunction instruction that begins the definition of this function.
  45. Instruction& DefInst() { return *def_inst_; }
  46. const Instruction& DefInst() const { return *def_inst_; }
  47. // Appends a parameter to this function.
  48. inline void AddParameter(std::unique_ptr<Instruction> p);
  49. // Appends a debug instruction in function header to this function.
  50. inline void AddDebugInstructionInHeader(std::unique_ptr<Instruction> p);
  51. // Appends a basic block to this function.
  52. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b);
  53. // Appends a basic block to this function at the position |ip|.
  54. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b, iterator ip);
  55. template <typename T>
  56. inline void AddBasicBlocks(T begin, T end, iterator ip);
  57. // Move basic block with |id| to the position after |ip|. Both have to be
  58. // contained in this function.
  59. inline void MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip);
  60. // Delete all basic blocks that contain no instructions.
  61. inline void RemoveEmptyBlocks();
  62. // Removes a parameter from the function with result id equal to |id|.
  63. // Does nothing if the function doesn't have such a parameter.
  64. inline void RemoveParameter(uint32_t id);
  65. // Saves the given function end instruction.
  66. inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst);
  67. // Returns the given function end instruction.
  68. inline Instruction* EndInst() { return end_inst_.get(); }
  69. inline const Instruction* EndInst() const { return end_inst_.get(); }
  70. // Returns function's id
  71. inline uint32_t result_id() const { return def_inst_->result_id(); }
  72. // Returns function's return type id
  73. inline uint32_t type_id() const { return def_inst_->type_id(); }
  74. // Returns the entry basic block for this function.
  75. const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); }
  76. // Returns the last basic block in this function.
  77. BasicBlock* tail() { return blocks_.back().get(); }
  78. const BasicBlock* tail() const { return blocks_.back().get(); }
  79. iterator begin() { return iterator(&blocks_, blocks_.begin()); }
  80. iterator end() { return iterator(&blocks_, blocks_.end()); }
  81. const_iterator begin() const { return cbegin(); }
  82. const_iterator end() const { return cend(); }
  83. const_iterator cbegin() const {
  84. return const_iterator(&blocks_, blocks_.cbegin());
  85. }
  86. const_iterator cend() const {
  87. return const_iterator(&blocks_, blocks_.cend());
  88. }
  89. // Returns an iterator to the basic block |id|.
  90. iterator FindBlock(uint32_t bb_id) {
  91. return std::find_if(begin(), end(), [bb_id](const BasicBlock& it_bb) {
  92. return bb_id == it_bb.id();
  93. });
  94. }
  95. // Runs the given function |f| on instructions in this function, in order,
  96. // and optionally on debug line instructions that might precede them.
  97. void ForEachInst(const std::function<void(Instruction*)>& f,
  98. bool run_on_debug_line_insts = false);
  99. void ForEachInst(const std::function<void(const Instruction*)>& f,
  100. bool run_on_debug_line_insts = false) const;
  101. // Runs the given function |f| on instructions in this function, in order,
  102. // and optionally on debug line instructions that might precede them.
  103. // If |f| returns false, iteration is terminated and this function returns
  104. // false.
  105. bool WhileEachInst(const std::function<bool(Instruction*)>& f,
  106. bool run_on_debug_line_insts = false);
  107. bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
  108. bool run_on_debug_line_insts = false) const;
  109. // Runs the given function |f| on each parameter instruction in this function,
  110. // in order, and optionally on debug line instructions that might precede
  111. // them.
  112. void ForEachParam(const std::function<void(const Instruction*)>& f,
  113. bool run_on_debug_line_insts = false) const;
  114. void ForEachParam(const std::function<void(Instruction*)>& f,
  115. bool run_on_debug_line_insts = false);
  116. // Runs the given function |f| on each debug instruction in this function's
  117. // header in order.
  118. void ForEachDebugInstructionsInHeader(
  119. const std::function<void(Instruction*)>& f);
  120. BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block,
  121. BasicBlock* position);
  122. BasicBlock* InsertBasicBlockBefore(std::unique_ptr<BasicBlock>&& new_block,
  123. BasicBlock* position);
  124. // Return true if the function calls itself either directly or indirectly.
  125. bool IsRecursive() const;
  126. // Pretty-prints all the basic blocks in this function into a std::string.
  127. //
  128. // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
  129. // is always added to |options|.
  130. std::string PrettyPrint(uint32_t options = 0u) const;
  131. // Dump this function on stderr. Useful when running interactive
  132. // debuggers.
  133. void Dump() const;
  134. private:
  135. // The OpFunction instruction that begins the definition of this function.
  136. std::unique_ptr<Instruction> def_inst_;
  137. // All parameters to this function.
  138. std::vector<std::unique_ptr<Instruction>> params_;
  139. // All debug instructions in this function's header.
  140. InstructionList debug_insts_in_header_;
  141. // All basic blocks inside this function in specification order
  142. std::vector<std::unique_ptr<BasicBlock>> blocks_;
  143. // The OpFunctionEnd instruction.
  144. std::unique_ptr<Instruction> end_inst_;
  145. };
  146. // Pretty-prints |func| to |str|. Returns |str|.
  147. std::ostream& operator<<(std::ostream& str, const Function& func);
  148. inline Function::Function(std::unique_ptr<Instruction> def_inst)
  149. : def_inst_(std::move(def_inst)), end_inst_() {}
  150. inline void Function::AddParameter(std::unique_ptr<Instruction> p) {
  151. params_.emplace_back(std::move(p));
  152. }
  153. inline void Function::AddDebugInstructionInHeader(
  154. std::unique_ptr<Instruction> p) {
  155. debug_insts_in_header_.push_back(std::move(p));
  156. }
  157. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) {
  158. AddBasicBlock(std::move(b), end());
  159. }
  160. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b,
  161. iterator ip) {
  162. ip.InsertBefore(std::move(b));
  163. }
  164. template <typename T>
  165. inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) {
  166. blocks_.insert(ip.Get(), std::make_move_iterator(src_begin),
  167. std::make_move_iterator(src_end));
  168. }
  169. inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) {
  170. std::unique_ptr<BasicBlock> block_to_move = std::move(*FindBlock(id).Get());
  171. blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
  172. assert(block_to_move->GetParent() == ip->GetParent() &&
  173. "Both blocks have to be in the same function.");
  174. InsertBasicBlockAfter(std::move(block_to_move), ip);
  175. }
  176. inline void Function::RemoveEmptyBlocks() {
  177. auto first_empty =
  178. std::remove_if(std::begin(blocks_), std::end(blocks_),
  179. [](const std::unique_ptr<BasicBlock>& bb) -> bool {
  180. return bb->GetLabelInst()->opcode() == SpvOpNop;
  181. });
  182. blocks_.erase(first_empty, std::end(blocks_));
  183. }
  184. inline void Function::RemoveParameter(uint32_t id) {
  185. params_.erase(std::remove_if(params_.begin(), params_.end(),
  186. [id](const std::unique_ptr<Instruction>& param) {
  187. return param->result_id() == id;
  188. }),
  189. params_.end());
  190. }
  191. inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
  192. end_inst_ = std::move(end_inst);
  193. }
  194. } // namespace opt
  195. } // namespace spvtools
  196. #endif // SOURCE_OPT_FUNCTION_H_