function.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // Copyright (c) 2015-2016 The Khronos Group 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_VAL_FUNCTION_H_
  15. #define SOURCE_VAL_FUNCTION_H_
  16. #include <functional>
  17. #include <list>
  18. #include <map>
  19. #include <set>
  20. #include <string>
  21. #include <unordered_map>
  22. #include <unordered_set>
  23. #include <utility>
  24. #include <vector>
  25. #include "source/latest_version_spirv_header.h"
  26. #include "source/val/basic_block.h"
  27. #include "source/val/construct.h"
  28. #include "spirv-tools/libspirv.h"
  29. namespace spvtools {
  30. namespace val {
  31. struct bb_constr_type_pair_hash {
  32. std::size_t operator()(
  33. const std::pair<const BasicBlock*, ConstructType>& p) const {
  34. auto h1 = std::hash<const BasicBlock*>{}(p.first);
  35. auto h2 = std::hash<std::underlying_type<ConstructType>::type>{}(
  36. static_cast<std::underlying_type<ConstructType>::type>(p.second));
  37. return (h1 ^ h2);
  38. }
  39. };
  40. enum class FunctionDecl {
  41. kFunctionDeclUnknown, /// < Unknown function declaration
  42. kFunctionDeclDeclaration, /// < Function declaration
  43. kFunctionDeclDefinition /// < Function definition
  44. };
  45. /// This class manages all function declaration and definitions in a module. It
  46. /// handles the state and id information while parsing a function in the SPIR-V
  47. /// binary.
  48. class Function {
  49. public:
  50. Function(uint32_t id, uint32_t result_type_id,
  51. SpvFunctionControlMask function_control, uint32_t function_type_id);
  52. /// Registers a function parameter in the current function
  53. /// @return Returns SPV_SUCCESS if the call was successful
  54. spv_result_t RegisterFunctionParameter(uint32_t id, uint32_t type_id);
  55. /// Sets the declaration type of the current function
  56. /// @return Returns SPV_SUCCESS if the call was successful
  57. spv_result_t RegisterSetFunctionDeclType(FunctionDecl type);
  58. /// Registers a block in the current function. Subsequent block instructions
  59. /// will target this block
  60. /// @param id The ID of the label of the block
  61. /// @return Returns SPV_SUCCESS if the call was successful
  62. spv_result_t RegisterBlock(uint32_t id, bool is_definition = true);
  63. /// Registers a variable in the current block
  64. ///
  65. /// @param[in] type_id The type ID of the varaible
  66. /// @param[in] id The ID of the varaible
  67. /// @param[in] storage The storage of the variable
  68. /// @param[in] init_id The initializer ID of the variable
  69. ///
  70. /// @return Returns SPV_SUCCESS if the call was successful
  71. spv_result_t RegisterBlockVariable(uint32_t type_id, uint32_t id,
  72. SpvStorageClass storage, uint32_t init_id);
  73. /// Registers a loop merge construct in the function
  74. ///
  75. /// @param[in] merge_id The merge block ID of the loop
  76. /// @param[in] continue_id The continue block ID of the loop
  77. ///
  78. /// @return Returns SPV_SUCCESS if the call was successful
  79. spv_result_t RegisterLoopMerge(uint32_t merge_id, uint32_t continue_id);
  80. /// Registers a selection merge construct in the function
  81. /// @return Returns SPV_SUCCESS if the call was successful
  82. spv_result_t RegisterSelectionMerge(uint32_t merge_id);
  83. /// Registers the end of the block
  84. ///
  85. /// @param[in] successors_list A list of ids to the block's successors
  86. /// @param[in] branch_instruction the branch instruction that ended the block
  87. void RegisterBlockEnd(std::vector<uint32_t> successors_list,
  88. SpvOp branch_instruction);
  89. /// Registers the end of the function. This is idempotent.
  90. void RegisterFunctionEnd();
  91. /// Returns true if the \p id block is the first block of this function
  92. bool IsFirstBlock(uint32_t id) const;
  93. /// Returns true if the \p merge_block_id is a BlockType of \p type
  94. bool IsBlockType(uint32_t merge_block_id, BlockType type) const;
  95. /// Returns a pair consisting of the BasicBlock with \p id and a bool
  96. /// which is true if the block has been defined, and false if it is
  97. /// declared but not defined. This function will return nullptr if the
  98. /// \p id was not declared and not defined at the current point in the binary
  99. std::pair<const BasicBlock*, bool> GetBlock(uint32_t id) const;
  100. std::pair<BasicBlock*, bool> GetBlock(uint32_t id);
  101. /// Returns the first block of the current function
  102. const BasicBlock* first_block() const;
  103. /// Returns the first block of the current function
  104. BasicBlock* first_block();
  105. /// Returns a vector of all the blocks in the function
  106. const std::vector<BasicBlock*>& ordered_blocks() const;
  107. /// Returns a vector of all the blocks in the function
  108. std::vector<BasicBlock*>& ordered_blocks();
  109. /// Returns a list of all the cfg constructs in the function
  110. const std::list<Construct>& constructs() const;
  111. /// Returns a list of all the cfg constructs in the function
  112. std::list<Construct>& constructs();
  113. /// Returns the number of blocks in the current function being parsed
  114. size_t block_count() const;
  115. /// Returns the id of the function
  116. uint32_t id() const { return id_; }
  117. /// Returns return type id of the function
  118. uint32_t GetResultTypeId() const { return result_type_id_; }
  119. /// Returns the number of blocks in the current function being parsed
  120. size_t undefined_block_count() const;
  121. const std::unordered_set<uint32_t>& undefined_blocks() const {
  122. return undefined_blocks_;
  123. }
  124. /// Returns the block that is currently being parsed in the binary
  125. BasicBlock* current_block();
  126. /// Returns the block that is currently being parsed in the binary
  127. const BasicBlock* current_block() const;
  128. // For dominance calculations, we want to analyze all the
  129. // blocks in the function, even in degenerate control flow cases
  130. // including unreachable blocks. We therefore make an "augmented CFG"
  131. // which is the same as the ordinary CFG but adds:
  132. // - A pseudo-entry node.
  133. // - A pseudo-exit node.
  134. // - A minimal set of edges so that a forward traversal from the
  135. // pseudo-entry node will visit all nodes.
  136. // - A minimal set of edges so that a backward traversal from the
  137. // pseudo-exit node will visit all nodes.
  138. // In particular, the pseudo-entry node is the unique source of the
  139. // augmented CFG, and the psueo-exit node is the unique sink of the
  140. // augmented CFG.
  141. /// Returns the pseudo exit block
  142. BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
  143. /// Returns the pseudo exit block
  144. const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
  145. /// Returns the pseudo exit block
  146. BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
  147. /// Returns the pseudo exit block
  148. const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
  149. using GetBlocksFunction =
  150. std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
  151. /// Returns the block successors function for the augmented CFG.
  152. GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
  153. /// Like AugmentedCFGSuccessorsFunction, but also includes a forward edge from
  154. /// a loop header block to its continue target, if they are different blocks.
  155. GetBlocksFunction
  156. AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
  157. /// Returns the block predecessors function for the augmented CFG.
  158. GetBlocksFunction AugmentedCFGPredecessorsFunction() const;
  159. /// Returns the control flow nesting depth of the given basic block.
  160. /// This function only works when you have structured control flow.
  161. /// This function should only be called after the control flow constructs have
  162. /// been identified and dominators have been computed.
  163. int GetBlockDepth(BasicBlock* bb);
  164. /// Prints a GraphViz digraph of the CFG of the current funciton
  165. void PrintDotGraph() const;
  166. /// Prints a directed graph of the CFG of the current funciton
  167. void PrintBlocks() const;
  168. /// Registers execution model limitation such as "Feature X is only available
  169. /// with Execution Model Y".
  170. void RegisterExecutionModelLimitation(SpvExecutionModel model,
  171. const std::string& message);
  172. /// Registers execution model limitation with an |is_compatible| functor.
  173. void RegisterExecutionModelLimitation(
  174. std::function<bool(SpvExecutionModel, std::string*)> is_compatible) {
  175. execution_model_limitations_.push_back(is_compatible);
  176. }
  177. /// Returns true if the given execution model passes the limitations stored in
  178. /// execution_model_limitations_. Returns false otherwise and fills optional
  179. /// |reason| parameter.
  180. bool IsCompatibleWithExecutionModel(SpvExecutionModel model,
  181. std::string* reason = nullptr) const;
  182. // Inserts id to the set of functions called from this function.
  183. void AddFunctionCallTarget(uint32_t call_target_id) {
  184. function_call_targets_.insert(call_target_id);
  185. }
  186. // Returns a set with ids of all functions called from this function.
  187. const std::set<uint32_t> function_call_targets() const {
  188. return function_call_targets_;
  189. }
  190. // Returns the block containing the OpSelectionMerge or OpLoopMerge that
  191. // references |merge_block|.
  192. // Values of |merge_block_header_| inserted by CFGPass, so do not call before
  193. // the first iteration of ordered instructions in
  194. // ValidateBinaryUsingContextAndValidationState has completed.
  195. BasicBlock* GetMergeHeader(BasicBlock* merge_block) {
  196. return merge_block_header_[merge_block];
  197. }
  198. // Returns vector of the blocks containing a OpLoopMerge that references
  199. // |continue_target|.
  200. // Values of |continue_target_headers_| inserted by CFGPass, so do not call
  201. // before the first iteration of ordered instructions in
  202. // ValidateBinaryUsingContextAndValidationState has completed.
  203. std::vector<BasicBlock*> GetContinueHeaders(BasicBlock* continue_target) {
  204. if (continue_target_headers_.find(continue_target) ==
  205. continue_target_headers_.end()) {
  206. return {};
  207. }
  208. return continue_target_headers_[continue_target];
  209. }
  210. private:
  211. // Computes the representation of the augmented CFG.
  212. // Populates augmented_successors_map_ and augmented_predecessors_map_.
  213. void ComputeAugmentedCFG();
  214. // Adds a copy of the given Construct, and tracks it by its entry block.
  215. // Returns a reference to the stored construct.
  216. Construct& AddConstruct(const Construct& new_construct);
  217. // Returns a reference to the construct corresponding to the given entry
  218. // block.
  219. Construct& FindConstructForEntryBlock(const BasicBlock* entry_block,
  220. ConstructType t);
  221. /// The result id of the OpLabel that defined this block
  222. uint32_t id_;
  223. /// The type of the function
  224. uint32_t function_type_id_;
  225. /// The type of the return value
  226. uint32_t result_type_id_;
  227. /// The control fo the funciton
  228. SpvFunctionControlMask function_control_;
  229. /// The type of declaration of each function
  230. FunctionDecl declaration_type_;
  231. // Have we finished parsing this function?
  232. bool end_has_been_registered_;
  233. /// The blocks in the function mapped by block ID
  234. std::unordered_map<uint32_t, BasicBlock> blocks_;
  235. /// A list of blocks in the order they appeared in the binary
  236. std::vector<BasicBlock*> ordered_blocks_;
  237. /// Blocks which are forward referenced by blocks but not defined
  238. std::unordered_set<uint32_t> undefined_blocks_;
  239. /// The block that is currently being parsed
  240. BasicBlock* current_block_;
  241. /// A pseudo entry node used in dominance analysis.
  242. /// After the function end has been registered, the successor list of the
  243. /// pseudo entry node is the minimal set of nodes such that all nodes in the
  244. /// CFG can be reached by following successor lists. That is, the successors
  245. /// will be:
  246. /// - Any basic block without predecessors. This includes the entry
  247. /// block to the function.
  248. /// - A single node from each otherwise unreachable cycle in the CFG, if
  249. /// such cycles exist.
  250. /// The pseudo entry node does not appear in the predecessor or successor
  251. /// list of any ordinary block.
  252. /// It has no predecessors.
  253. /// It has Id 0.
  254. BasicBlock pseudo_entry_block_;
  255. /// A pseudo exit block used in dominance analysis.
  256. /// After the function end has been registered, the predecessor list of the
  257. /// pseudo exit node is the minimal set of nodes such that all nodes in the
  258. /// CFG can be reached by following predecessor lists. That is, the
  259. /// predecessors will be:
  260. /// - Any basic block without successors. This includes any basic block
  261. /// ending with an OpReturn, OpReturnValue or similar instructions.
  262. /// - A single node from each otherwise unreachable cycle in the CFG, if
  263. /// such cycles exist.
  264. /// The pseudo exit node does not appear in the predecessor or successor
  265. /// list of any ordinary block.
  266. /// It has no successors.
  267. BasicBlock pseudo_exit_block_;
  268. // Maps a block to its successors in the augmented CFG, if that set is
  269. // different from its successors in the ordinary CFG.
  270. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  271. augmented_successors_map_;
  272. // Maps a block to its predecessors in the augmented CFG, if that set is
  273. // different from its predecessors in the ordinary CFG.
  274. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  275. augmented_predecessors_map_;
  276. // Maps a structured loop header to its CFG successors and also its
  277. // continue target if that continue target is not the loop header
  278. // itself. This might have duplicates.
  279. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  280. loop_header_successors_plus_continue_target_map_;
  281. /// The constructs that are available in this function
  282. std::list<Construct> cfg_constructs_;
  283. /// The variable IDs of the functions
  284. std::vector<uint32_t> variable_ids_;
  285. /// The function parameter ids of the functions
  286. std::vector<uint32_t> parameter_ids_;
  287. /// Maps a construct's entry block to the construct(s).
  288. /// Since a basic block may be the entry block of different types of
  289. /// constructs, the type of the construct should also be specified in order to
  290. /// get the unique construct.
  291. std::unordered_map<std::pair<const BasicBlock*, ConstructType>, Construct*,
  292. bb_constr_type_pair_hash>
  293. entry_block_to_construct_;
  294. /// This map provides the header block for a given merge block.
  295. std::unordered_map<BasicBlock*, BasicBlock*> merge_block_header_;
  296. /// This map provides the header blocks for a given continue target.
  297. std::unordered_map<BasicBlock*, std::vector<BasicBlock*>>
  298. continue_target_headers_;
  299. /// Stores the control flow nesting depth of a given basic block
  300. std::unordered_map<BasicBlock*, int> block_depth_;
  301. /// Stores execution model limitations imposed by instructions used within the
  302. /// function. The functor stored in the list return true if execution model
  303. /// is compatible, false otherwise. If the functor returns false, it can also
  304. /// optionally fill the string parameter with the reason for incompatibility.
  305. std::list<std::function<bool(SpvExecutionModel, std::string*)>>
  306. execution_model_limitations_;
  307. /// Stores ids of all functions called from this function.
  308. std::set<uint32_t> function_call_targets_;
  309. };
  310. } // namespace val
  311. } // namespace spvtools
  312. #endif // SOURCE_VAL_FUNCTION_H_