function.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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. void RegisterBlockEnd(std::vector<uint32_t> successors_list);
  87. /// Registers the end of the function. This is idempotent.
  88. void RegisterFunctionEnd();
  89. /// Returns true if the \p id block is the first block of this function
  90. bool IsFirstBlock(uint32_t id) const;
  91. /// Returns true if the \p merge_block_id is a BlockType of \p type
  92. bool IsBlockType(uint32_t merge_block_id, BlockType type) const;
  93. /// Returns a pair consisting of the BasicBlock with \p id and a bool
  94. /// which is true if the block has been defined, and false if it is
  95. /// declared but not defined. This function will return nullptr if the
  96. /// \p id was not declared and not defined at the current point in the binary
  97. std::pair<const BasicBlock*, bool> GetBlock(uint32_t id) const;
  98. std::pair<BasicBlock*, bool> GetBlock(uint32_t id);
  99. /// Returns the first block of the current function
  100. const BasicBlock* first_block() const;
  101. /// Returns the first block of the current function
  102. BasicBlock* first_block();
  103. /// Returns a vector of all the blocks in the function
  104. const std::vector<BasicBlock*>& ordered_blocks() const;
  105. /// Returns a vector of all the blocks in the function
  106. std::vector<BasicBlock*>& ordered_blocks();
  107. /// Returns a list of all the cfg constructs in the function
  108. const std::list<Construct>& constructs() const;
  109. /// Returns a list of all the cfg constructs in the function
  110. std::list<Construct>& constructs();
  111. /// Returns the number of blocks in the current function being parsed
  112. size_t block_count() const;
  113. /// Returns the id of the function
  114. uint32_t id() const { return id_; }
  115. /// Returns return type id of the function
  116. uint32_t GetResultTypeId() const { return result_type_id_; }
  117. /// Returns the number of blocks in the current function being parsed
  118. size_t undefined_block_count() const;
  119. const std::unordered_set<uint32_t>& undefined_blocks() const {
  120. return undefined_blocks_;
  121. }
  122. /// Returns the block that is currently being parsed in the binary
  123. BasicBlock* current_block();
  124. /// Returns the block that is currently being parsed in the binary
  125. const BasicBlock* current_block() const;
  126. // For dominance calculations, we want to analyze all the
  127. // blocks in the function, even in degenerate control flow cases
  128. // including unreachable blocks. We therefore make an "augmented CFG"
  129. // which is the same as the ordinary CFG but adds:
  130. // - A pseudo-entry node.
  131. // - A pseudo-exit node.
  132. // - A minimal set of edges so that a forward traversal from the
  133. // pseudo-entry node will visit all nodes.
  134. // - A minimal set of edges so that a backward traversal from the
  135. // pseudo-exit node will visit all nodes.
  136. // In particular, the pseudo-entry node is the unique source of the
  137. // augmented CFG, and the psueo-exit node is the unique sink of the
  138. // augmented CFG.
  139. /// Returns the pseudo exit block
  140. BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
  141. /// Returns the pseudo exit block
  142. const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
  143. /// Returns the pseudo exit block
  144. BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
  145. /// Returns the pseudo exit block
  146. const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
  147. using GetBlocksFunction =
  148. std::function<const std::vector<BasicBlock*>*(const BasicBlock*)>;
  149. /// Returns the block successors function for the augmented CFG.
  150. GetBlocksFunction AugmentedCFGSuccessorsFunction() const;
  151. /// Like AugmentedCFGSuccessorsFunction, but also includes a forward edge from
  152. /// a loop header block to its continue target, if they are different blocks.
  153. GetBlocksFunction
  154. AugmentedCFGSuccessorsFunctionIncludingHeaderToContinueEdge() const;
  155. /// Returns the block predecessors function for the augmented CFG.
  156. GetBlocksFunction AugmentedCFGPredecessorsFunction() const;
  157. /// Returns the control flow nesting depth of the given basic block.
  158. /// This function only works when you have structured control flow.
  159. /// This function should only be called after the control flow constructs have
  160. /// been identified and dominators have been computed.
  161. int GetBlockDepth(BasicBlock* bb);
  162. /// Prints a GraphViz digraph of the CFG of the current funciton
  163. void PrintDotGraph() const;
  164. /// Prints a directed graph of the CFG of the current funciton
  165. void PrintBlocks() const;
  166. /// Registers execution model limitation such as "Feature X is only available
  167. /// with Execution Model Y".
  168. void RegisterExecutionModelLimitation(SpvExecutionModel model,
  169. const std::string& message);
  170. /// Registers execution model limitation with an |is_compatible| functor.
  171. void RegisterExecutionModelLimitation(
  172. std::function<bool(SpvExecutionModel, std::string*)> is_compatible) {
  173. execution_model_limitations_.push_back(is_compatible);
  174. }
  175. /// Registers limitation with an |is_compatible| functor.
  176. void RegisterLimitation(std::function<bool(const ValidationState_t& _,
  177. const Function*, std::string*)>
  178. is_compatible) {
  179. limitations_.push_back(is_compatible);
  180. }
  181. bool CheckLimitations(const ValidationState_t& _, const Function* entry_point,
  182. std::string* reason) const;
  183. /// Returns true if the given execution model passes the limitations stored in
  184. /// execution_model_limitations_. Returns false otherwise and fills optional
  185. /// |reason| parameter.
  186. bool IsCompatibleWithExecutionModel(SpvExecutionModel model,
  187. std::string* reason = nullptr) const;
  188. // Inserts id to the set of functions called from this function.
  189. void AddFunctionCallTarget(uint32_t call_target_id) {
  190. function_call_targets_.insert(call_target_id);
  191. }
  192. // Returns a set with ids of all functions called from this function.
  193. const std::set<uint32_t> function_call_targets() const {
  194. return function_call_targets_;
  195. }
  196. // Returns the block containing the OpSelectionMerge or OpLoopMerge that
  197. // references |merge_block|.
  198. // Values of |merge_block_header_| inserted by CFGPass, so do not call before
  199. // the first iteration of ordered instructions in
  200. // ValidateBinaryUsingContextAndValidationState has completed.
  201. BasicBlock* GetMergeHeader(BasicBlock* merge_block) {
  202. return merge_block_header_[merge_block];
  203. }
  204. // Returns vector of the blocks containing a OpLoopMerge that references
  205. // |continue_target|.
  206. // Values of |continue_target_headers_| inserted by CFGPass, so do not call
  207. // before the first iteration of ordered instructions in
  208. // ValidateBinaryUsingContextAndValidationState has completed.
  209. std::vector<BasicBlock*> GetContinueHeaders(BasicBlock* continue_target) {
  210. if (continue_target_headers_.find(continue_target) ==
  211. continue_target_headers_.end()) {
  212. return {};
  213. }
  214. return continue_target_headers_[continue_target];
  215. }
  216. private:
  217. // Computes the representation of the augmented CFG.
  218. // Populates augmented_successors_map_ and augmented_predecessors_map_.
  219. void ComputeAugmentedCFG();
  220. // Adds a copy of the given Construct, and tracks it by its entry block.
  221. // Returns a reference to the stored construct.
  222. Construct& AddConstruct(const Construct& new_construct);
  223. // Returns a reference to the construct corresponding to the given entry
  224. // block.
  225. Construct& FindConstructForEntryBlock(const BasicBlock* entry_block,
  226. ConstructType t);
  227. /// The result id of the OpLabel that defined this block
  228. uint32_t id_;
  229. /// The type of the function
  230. uint32_t function_type_id_;
  231. /// The type of the return value
  232. uint32_t result_type_id_;
  233. /// The control fo the funciton
  234. SpvFunctionControlMask function_control_;
  235. /// The type of declaration of each function
  236. FunctionDecl declaration_type_;
  237. // Have we finished parsing this function?
  238. bool end_has_been_registered_;
  239. /// The blocks in the function mapped by block ID
  240. std::unordered_map<uint32_t, BasicBlock> blocks_;
  241. /// A list of blocks in the order they appeared in the binary
  242. std::vector<BasicBlock*> ordered_blocks_;
  243. /// Blocks which are forward referenced by blocks but not defined
  244. std::unordered_set<uint32_t> undefined_blocks_;
  245. /// The block that is currently being parsed
  246. BasicBlock* current_block_;
  247. /// A pseudo entry node used in dominance analysis.
  248. /// After the function end has been registered, the successor list of the
  249. /// pseudo entry node is the minimal set of nodes such that all nodes in the
  250. /// CFG can be reached by following successor lists. That is, the successors
  251. /// will be:
  252. /// - Any basic block without predecessors. This includes the entry
  253. /// block to the function.
  254. /// - A single node from each otherwise unreachable cycle in the CFG, if
  255. /// such cycles exist.
  256. /// The pseudo entry node does not appear in the predecessor or successor
  257. /// list of any ordinary block.
  258. /// It has no predecessors.
  259. /// It has Id 0.
  260. BasicBlock pseudo_entry_block_;
  261. /// A pseudo exit block used in dominance analysis.
  262. /// After the function end has been registered, the predecessor list of the
  263. /// pseudo exit node is the minimal set of nodes such that all nodes in the
  264. /// CFG can be reached by following predecessor lists. That is, the
  265. /// predecessors will be:
  266. /// - Any basic block without successors. This includes any basic block
  267. /// ending with an OpReturn, OpReturnValue or similar instructions.
  268. /// - A single node from each otherwise unreachable cycle in the CFG, if
  269. /// such cycles exist.
  270. /// The pseudo exit node does not appear in the predecessor or successor
  271. /// list of any ordinary block.
  272. /// It has no successors.
  273. BasicBlock pseudo_exit_block_;
  274. // Maps a block to its successors in the augmented CFG, if that set is
  275. // different from its successors in the ordinary CFG.
  276. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  277. augmented_successors_map_;
  278. // Maps a block to its predecessors in the augmented CFG, if that set is
  279. // different from its predecessors in the ordinary CFG.
  280. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  281. augmented_predecessors_map_;
  282. // Maps a structured loop header to its CFG successors and also its
  283. // continue target if that continue target is not the loop header
  284. // itself. This might have duplicates.
  285. std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
  286. loop_header_successors_plus_continue_target_map_;
  287. /// The constructs that are available in this function
  288. std::list<Construct> cfg_constructs_;
  289. /// The variable IDs of the functions
  290. std::vector<uint32_t> variable_ids_;
  291. /// The function parameter ids of the functions
  292. std::vector<uint32_t> parameter_ids_;
  293. /// Maps a construct's entry block to the construct(s).
  294. /// Since a basic block may be the entry block of different types of
  295. /// constructs, the type of the construct should also be specified in order to
  296. /// get the unique construct.
  297. std::unordered_map<std::pair<const BasicBlock*, ConstructType>, Construct*,
  298. bb_constr_type_pair_hash>
  299. entry_block_to_construct_;
  300. /// This map provides the header block for a given merge block.
  301. std::unordered_map<BasicBlock*, BasicBlock*> merge_block_header_;
  302. /// This map provides the header blocks for a given continue target.
  303. std::unordered_map<BasicBlock*, std::vector<BasicBlock*>>
  304. continue_target_headers_;
  305. /// Stores the control flow nesting depth of a given basic block
  306. std::unordered_map<BasicBlock*, int> block_depth_;
  307. /// Stores execution model limitations imposed by instructions used within the
  308. /// function. The functor stored in the list return true if execution model
  309. /// is compatible, false otherwise. If the functor returns false, it can also
  310. /// optionally fill the string parameter with the reason for incompatibility.
  311. std::list<std::function<bool(SpvExecutionModel, std::string*)>>
  312. execution_model_limitations_;
  313. /// Stores limitations imposed by instructions used within the function.
  314. /// Similar to execution_model_limitations_;
  315. std::list<std::function<bool(const ValidationState_t& _, const Function*,
  316. std::string*)>>
  317. limitations_;
  318. /// Stores ids of all functions called from this function.
  319. std::set<uint32_t> function_call_targets_;
  320. };
  321. } // namespace val
  322. } // namespace spvtools
  323. #endif // SOURCE_VAL_FUNCTION_H_