function.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 basic block to this function.
  50. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b);
  51. // Appends a basic block to this function at the position |ip|.
  52. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b, iterator ip);
  53. template <typename T>
  54. inline void AddBasicBlocks(T begin, T end, iterator ip);
  55. // Move basic block with |id| to the position after |ip|. Both have to be
  56. // contained in this function.
  57. inline void MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip);
  58. // Delete all basic blocks that contain no instructions.
  59. inline void RemoveEmptyBlocks();
  60. // Saves the given function end instruction.
  61. inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst);
  62. // Returns the given function end instruction.
  63. inline Instruction* EndInst() { return end_inst_.get(); }
  64. inline const Instruction* EndInst() const { return end_inst_.get(); }
  65. // Returns function's id
  66. inline uint32_t result_id() const { return def_inst_->result_id(); }
  67. // Returns function's return type id
  68. inline uint32_t type_id() const { return def_inst_->type_id(); }
  69. // Returns the entry basic block for this function.
  70. const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); }
  71. iterator begin() { return iterator(&blocks_, blocks_.begin()); }
  72. iterator end() { return iterator(&blocks_, blocks_.end()); }
  73. const_iterator begin() const { return cbegin(); }
  74. const_iterator end() const { return cend(); }
  75. const_iterator cbegin() const {
  76. return const_iterator(&blocks_, blocks_.cbegin());
  77. }
  78. const_iterator cend() const {
  79. return const_iterator(&blocks_, blocks_.cend());
  80. }
  81. // Returns an iterator to the basic block |id|.
  82. iterator FindBlock(uint32_t bb_id) {
  83. return std::find_if(begin(), end(), [bb_id](const BasicBlock& it_bb) {
  84. return bb_id == it_bb.id();
  85. });
  86. }
  87. // Runs the given function |f| on instructions in this function, in order,
  88. // and optionally on debug line instructions that might precede them.
  89. void ForEachInst(const std::function<void(Instruction*)>& f,
  90. bool run_on_debug_line_insts = false);
  91. void ForEachInst(const std::function<void(const Instruction*)>& f,
  92. bool run_on_debug_line_insts = false) const;
  93. // Runs the given function |f| on instructions in this function, in order,
  94. // and optionally on debug line instructions that might precede them.
  95. // If |f| returns false, iteration is terminated and this function returns
  96. // false.
  97. bool WhileEachInst(const std::function<bool(Instruction*)>& f,
  98. bool run_on_debug_line_insts = false);
  99. bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
  100. bool run_on_debug_line_insts = false) const;
  101. // Runs the given function |f| on each parameter instruction in this function,
  102. // in order, and optionally on debug line instructions that might precede
  103. // them.
  104. void ForEachParam(const std::function<void(const Instruction*)>& f,
  105. bool run_on_debug_line_insts = false) const;
  106. void ForEachParam(const std::function<void(Instruction*)>& f,
  107. bool run_on_debug_line_insts = false);
  108. BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block,
  109. BasicBlock* position);
  110. BasicBlock* InsertBasicBlockBefore(std::unique_ptr<BasicBlock>&& new_block,
  111. BasicBlock* position);
  112. // Return true if the function calls itself either directly or indirectly.
  113. bool IsRecursive() const;
  114. // Pretty-prints all the basic blocks in this function into a std::string.
  115. //
  116. // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
  117. // is always added to |options|.
  118. std::string PrettyPrint(uint32_t options = 0u) const;
  119. // Dump this function on stderr. Useful when running interactive
  120. // debuggers.
  121. void Dump() const;
  122. private:
  123. // The OpFunction instruction that begins the definition of this function.
  124. std::unique_ptr<Instruction> def_inst_;
  125. // All parameters to this function.
  126. std::vector<std::unique_ptr<Instruction>> params_;
  127. // All basic blocks inside this function in specification order
  128. std::vector<std::unique_ptr<BasicBlock>> blocks_;
  129. // The OpFunctionEnd instruction.
  130. std::unique_ptr<Instruction> end_inst_;
  131. };
  132. // Pretty-prints |func| to |str|. Returns |str|.
  133. std::ostream& operator<<(std::ostream& str, const Function& func);
  134. inline Function::Function(std::unique_ptr<Instruction> def_inst)
  135. : def_inst_(std::move(def_inst)), end_inst_() {}
  136. inline void Function::AddParameter(std::unique_ptr<Instruction> p) {
  137. params_.emplace_back(std::move(p));
  138. }
  139. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) {
  140. AddBasicBlock(std::move(b), end());
  141. }
  142. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b,
  143. iterator ip) {
  144. ip.InsertBefore(std::move(b));
  145. }
  146. template <typename T>
  147. inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) {
  148. blocks_.insert(ip.Get(), std::make_move_iterator(src_begin),
  149. std::make_move_iterator(src_end));
  150. }
  151. inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) {
  152. auto block_to_move = std::move(*FindBlock(id).Get());
  153. assert(block_to_move->GetParent() == ip->GetParent() &&
  154. "Both blocks have to be in the same function.");
  155. InsertBasicBlockAfter(std::move(block_to_move), ip);
  156. blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
  157. }
  158. inline void Function::RemoveEmptyBlocks() {
  159. auto first_empty =
  160. std::remove_if(std::begin(blocks_), std::end(blocks_),
  161. [](const std::unique_ptr<BasicBlock>& bb) -> bool {
  162. return bb->GetLabelInst()->opcode() == SpvOpNop;
  163. });
  164. blocks_.erase(first_empty, std::end(blocks_));
  165. }
  166. inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
  167. end_inst_ = std::move(end_inst);
  168. }
  169. } // namespace opt
  170. } // namespace spvtools
  171. #endif // SOURCE_OPT_FUNCTION_H_