function.h 12 KB

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