function.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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 <unordered_set>
  21. #include <utility>
  22. #include <vector>
  23. #include "source/opt/basic_block.h"
  24. #include "source/opt/instruction.h"
  25. #include "source/opt/iterator.h"
  26. namespace spvtools {
  27. namespace opt {
  28. class CFG;
  29. class IRContext;
  30. class Module;
  31. // A SPIR-V function.
  32. class Function {
  33. public:
  34. using iterator = UptrVectorIterator<BasicBlock>;
  35. using const_iterator = UptrVectorIterator<BasicBlock, true>;
  36. // Creates a function instance declared by the given OpFunction instruction
  37. // |def_inst|.
  38. inline explicit Function(std::unique_ptr<Instruction> def_inst);
  39. explicit Function(const Function& f) = delete;
  40. // Creates a clone of the instruction in the given |context|
  41. //
  42. // The parent module will default to null and needs to be explicitly set by
  43. // the user.
  44. Function* Clone(IRContext*) const;
  45. // The OpFunction instruction that begins the definition of this function.
  46. Instruction& DefInst() { return *def_inst_; }
  47. const Instruction& DefInst() const { return *def_inst_; }
  48. // Appends a parameter to this function.
  49. inline void AddParameter(std::unique_ptr<Instruction> p);
  50. // Appends a debug instruction in function header to this function.
  51. inline void AddDebugInstructionInHeader(std::unique_ptr<Instruction> p);
  52. // Appends a basic block to this function.
  53. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b);
  54. // Appends a basic block to this function at the position |ip|.
  55. inline void AddBasicBlock(std::unique_ptr<BasicBlock> b, iterator ip);
  56. template <typename T>
  57. inline void AddBasicBlocks(T begin, T end, iterator ip);
  58. // Move basic block with |id| to the position after |ip|. Both have to be
  59. // contained in this function.
  60. inline void MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip);
  61. // Delete all basic blocks that contain no instructions.
  62. inline void RemoveEmptyBlocks();
  63. // Removes a parameter from the function with result id equal to |id|.
  64. // Does nothing if the function doesn't have such a parameter.
  65. inline void RemoveParameter(uint32_t id);
  66. // Saves the given function end instruction.
  67. inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst);
  68. // Add a non-semantic instruction that succeeds this function in the module.
  69. // These instructions are maintained in the order they are added.
  70. inline void AddNonSemanticInstruction(
  71. std::unique_ptr<Instruction> non_semantic);
  72. // Returns the given function end instruction.
  73. inline Instruction* EndInst() { return end_inst_.get(); }
  74. inline const Instruction* EndInst() const { return end_inst_.get(); }
  75. // Returns function's id
  76. inline uint32_t result_id() const { return def_inst_->result_id(); }
  77. // Returns function's return type id
  78. inline uint32_t type_id() const { return def_inst_->type_id(); }
  79. // Returns the function's control mask
  80. inline uint32_t control_mask() const { return def_inst_->GetSingleWordInOperand(0); }
  81. // Returns the entry basic block for this function.
  82. const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); }
  83. // Returns the last basic block in this function.
  84. BasicBlock* tail() { return blocks_.back().get(); }
  85. const BasicBlock* tail() const { return blocks_.back().get(); }
  86. iterator begin() { return iterator(&blocks_, blocks_.begin()); }
  87. iterator end() { return iterator(&blocks_, blocks_.end()); }
  88. const_iterator begin() const { return cbegin(); }
  89. const_iterator end() const { return cend(); }
  90. const_iterator cbegin() const {
  91. return const_iterator(&blocks_, blocks_.cbegin());
  92. }
  93. const_iterator cend() const {
  94. return const_iterator(&blocks_, blocks_.cend());
  95. }
  96. // Returns an iterator to the basic block |id|.
  97. iterator FindBlock(uint32_t bb_id) {
  98. return std::find_if(begin(), end(), [bb_id](const BasicBlock& it_bb) {
  99. return bb_id == it_bb.id();
  100. });
  101. }
  102. // Runs the given function |f| on instructions in this function, in order,
  103. // and optionally on debug line instructions that might precede them and
  104. // non-semantic instructions that succceed the function.
  105. void ForEachInst(const std::function<void(Instruction*)>& f,
  106. bool run_on_debug_line_insts = false,
  107. bool run_on_non_semantic_insts = false);
  108. void ForEachInst(const std::function<void(const Instruction*)>& f,
  109. bool run_on_debug_line_insts = false,
  110. bool run_on_non_semantic_insts = false) const;
  111. // Runs the given function |f| on instructions in this function, in order,
  112. // and optionally on debug line instructions that might precede them and
  113. // non-semantic instructions that succeed the function. If |f| returns
  114. // false, iteration is terminated and this function returns false.
  115. bool WhileEachInst(const std::function<bool(Instruction*)>& f,
  116. bool run_on_debug_line_insts = false,
  117. bool run_on_non_semantic_insts = false);
  118. bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
  119. bool run_on_debug_line_insts = false,
  120. bool run_on_non_semantic_insts = false) const;
  121. // Runs the given function |f| on each parameter instruction in this function,
  122. // in order, and optionally on debug line instructions that might precede
  123. // them.
  124. void ForEachParam(const std::function<void(const Instruction*)>& f,
  125. bool run_on_debug_line_insts = false) const;
  126. void ForEachParam(const std::function<void(Instruction*)>& f,
  127. bool run_on_debug_line_insts = false);
  128. // Runs the given function |f| on each debug instruction in this function's
  129. // header in order.
  130. void ForEachDebugInstructionsInHeader(
  131. const std::function<void(Instruction*)>& f);
  132. BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block,
  133. BasicBlock* position);
  134. BasicBlock* InsertBasicBlockBefore(std::unique_ptr<BasicBlock>&& new_block,
  135. BasicBlock* position);
  136. // Returns true if the function has a return block other than the exit block.
  137. bool HasEarlyReturn() const;
  138. // Returns true if the function calls itself either directly or indirectly.
  139. bool IsRecursive() const;
  140. // Pretty-prints all the basic blocks in this function into a std::string.
  141. //
  142. // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
  143. // is always added to |options|.
  144. std::string PrettyPrint(uint32_t options = 0u) const;
  145. // Dump this function on stderr. Useful when running interactive
  146. // debuggers.
  147. void Dump() const;
  148. // Returns true is a function declaration and not a function definition.
  149. bool IsDeclaration() { return begin() == end(); }
  150. // Reorders the basic blocks in the function to match the structured order.
  151. void ReorderBasicBlocksInStructuredOrder();
  152. private:
  153. // Reorders the basic blocks in the function to match the order given by the
  154. // range |{begin,end}|. The range must contain every basic block in the
  155. // function, and no extras.
  156. template <class It>
  157. void ReorderBasicBlocks(It begin, It end);
  158. template <class It>
  159. bool ContainsAllBlocksInTheFunction(It begin, It end);
  160. // The OpFunction instruction that begins the definition of this function.
  161. std::unique_ptr<Instruction> def_inst_;
  162. // All parameters to this function.
  163. std::vector<std::unique_ptr<Instruction>> params_;
  164. // All debug instructions in this function's header.
  165. InstructionList debug_insts_in_header_;
  166. // All basic blocks inside this function in specification order
  167. std::vector<std::unique_ptr<BasicBlock>> blocks_;
  168. // The OpFunctionEnd instruction.
  169. std::unique_ptr<Instruction> end_inst_;
  170. // Non-semantic instructions succeeded by this function.
  171. std::vector<std::unique_ptr<Instruction>> non_semantic_;
  172. };
  173. // Pretty-prints |func| to |str|. Returns |str|.
  174. std::ostream& operator<<(std::ostream& str, const Function& func);
  175. inline Function::Function(std::unique_ptr<Instruction> def_inst)
  176. : def_inst_(std::move(def_inst)), end_inst_() {}
  177. inline void Function::AddParameter(std::unique_ptr<Instruction> p) {
  178. params_.emplace_back(std::move(p));
  179. }
  180. inline void Function::AddDebugInstructionInHeader(
  181. std::unique_ptr<Instruction> p) {
  182. debug_insts_in_header_.push_back(std::move(p));
  183. }
  184. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) {
  185. AddBasicBlock(std::move(b), end());
  186. }
  187. inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b,
  188. iterator ip) {
  189. b->SetParent(this);
  190. ip.InsertBefore(std::move(b));
  191. }
  192. template <typename T>
  193. inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) {
  194. blocks_.insert(ip.Get(), std::make_move_iterator(src_begin),
  195. std::make_move_iterator(src_end));
  196. }
  197. inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) {
  198. std::unique_ptr<BasicBlock> block_to_move = std::move(*FindBlock(id).Get());
  199. blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
  200. assert(block_to_move->GetParent() == ip->GetParent() &&
  201. "Both blocks have to be in the same function.");
  202. InsertBasicBlockAfter(std::move(block_to_move), ip);
  203. }
  204. inline void Function::RemoveEmptyBlocks() {
  205. auto first_empty =
  206. std::remove_if(std::begin(blocks_), std::end(blocks_),
  207. [](const std::unique_ptr<BasicBlock>& bb) -> bool {
  208. return bb->GetLabelInst()->opcode() == spv::Op::OpNop;
  209. });
  210. blocks_.erase(first_empty, std::end(blocks_));
  211. }
  212. inline void Function::RemoveParameter(uint32_t id) {
  213. params_.erase(std::remove_if(params_.begin(), params_.end(),
  214. [id](const std::unique_ptr<Instruction>& param) {
  215. return param->result_id() == id;
  216. }),
  217. params_.end());
  218. }
  219. inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
  220. end_inst_ = std::move(end_inst);
  221. }
  222. inline void Function::AddNonSemanticInstruction(
  223. std::unique_ptr<Instruction> non_semantic) {
  224. non_semantic_.emplace_back(std::move(non_semantic));
  225. }
  226. template <class It>
  227. void Function::ReorderBasicBlocks(It begin, It end) {
  228. // Asserts to make sure every node in the function is in new_order.
  229. assert(ContainsAllBlocksInTheFunction(begin, end));
  230. // We have a pointer to all the elements in order, so we can release all
  231. // pointers in |block_|, and then create the new unique pointers from |{begin,
  232. // end}|.
  233. std::for_each(blocks_.begin(), blocks_.end(),
  234. [](std::unique_ptr<BasicBlock>& bb) { bb.release(); });
  235. std::transform(begin, end, blocks_.begin(), [](BasicBlock* bb) {
  236. return std::unique_ptr<BasicBlock>(bb);
  237. });
  238. }
  239. template <class It>
  240. bool Function::ContainsAllBlocksInTheFunction(It begin, It end) {
  241. std::unordered_multiset<BasicBlock*> range(begin, end);
  242. if (range.size() != blocks_.size()) {
  243. return false;
  244. }
  245. for (auto& bb : blocks_) {
  246. if (range.count(bb.get()) == 0) return false;
  247. }
  248. return true;
  249. }
  250. } // namespace opt
  251. } // namespace spvtools
  252. #endif // SOURCE_OPT_FUNCTION_H_