function.h 16 KB

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