validation_state.h 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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_VALIDATION_STATE_H_
  15. #define SOURCE_VAL_VALIDATION_STATE_H_
  16. #include <algorithm>
  17. #include <map>
  18. #include <set>
  19. #include <string>
  20. #include <tuple>
  21. #include <unordered_map>
  22. #include <unordered_set>
  23. #include <vector>
  24. #include "source/assembly_grammar.h"
  25. #include "source/diagnostic.h"
  26. #include "source/disassemble.h"
  27. #include "source/enum_set.h"
  28. #include "source/latest_version_spirv_header.h"
  29. #include "source/name_mapper.h"
  30. #include "source/spirv_definition.h"
  31. #include "source/spirv_validator_options.h"
  32. #include "source/val/decoration.h"
  33. #include "source/val/function.h"
  34. #include "source/val/instruction.h"
  35. #include "spirv-tools/libspirv.h"
  36. namespace spvtools {
  37. namespace val {
  38. /// This enum represents the sections of a SPIRV module. See section 2.4
  39. /// of the SPIRV spec for additional details of the order. The enumerant values
  40. /// are in the same order as the vector returned by GetModuleOrder
  41. enum ModuleLayoutSection {
  42. kLayoutCapabilities, /// < Section 2.4 #1
  43. kLayoutExtensions, /// < Section 2.4 #2
  44. kLayoutExtInstImport, /// < Section 2.4 #3
  45. kLayoutMemoryModel, /// < Section 2.4 #4
  46. kLayoutEntryPoint, /// < Section 2.4 #5
  47. kLayoutExecutionMode, /// < Section 2.4 #6
  48. kLayoutDebug1, /// < Section 2.4 #7 > 1
  49. kLayoutDebug2, /// < Section 2.4 #7 > 2
  50. kLayoutDebug3, /// < Section 2.4 #7 > 3
  51. kLayoutAnnotations, /// < Section 2.4 #8
  52. kLayoutTypes, /// < Section 2.4 #9
  53. kLayoutFunctionDeclarations, /// < Section 2.4 #10
  54. kLayoutFunctionDefinitions /// < Section 2.4 #11
  55. };
  56. /// This class manages the state of the SPIR-V validation as it is being parsed.
  57. class ValidationState_t {
  58. public:
  59. // Features that can optionally be turned on by a capability or environment.
  60. struct Feature {
  61. bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
  62. bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
  63. bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration
  64. // and its vaules to be used without
  65. // requiring any capability
  66. // Allow functionalities enabled by VariablePointers capability.
  67. bool variable_pointers = false;
  68. // Allow functionalities enabled by VariablePointersStorageBuffer
  69. // capability.
  70. bool variable_pointers_storage_buffer = false;
  71. // Permit group oerations Reduce, InclusiveScan, ExclusiveScan
  72. bool group_ops_reduce_and_scans = false;
  73. // Disallows the use of OpUndef
  74. bool bans_op_undef = false;
  75. // Allow OpTypeInt with 8 bit width?
  76. bool declare_int8_type = false;
  77. // Target environment uses relaxed block layout.
  78. // This is true for Vulkan 1.1 or later.
  79. bool env_relaxed_block_layout = false;
  80. // Allow an OpTypeInt with 8 bit width to be used in more than just int
  81. // conversion opcodes
  82. bool use_int8_type = false;
  83. // Use scalar block layout. See VK_EXT_scalar_block_layout:
  84. // Defines scalar alignment:
  85. // - scalar alignment equals the scalar size in bytes
  86. // - array alignment is same as its element alignment
  87. // - array alignment is max alignment of any of its members
  88. // - vector alignment is same as component alignment
  89. // - matrix alignment is same as component alignment
  90. // For struct in Uniform, StorageBuffer, PushConstant:
  91. // - Offset of a member is multiple of scalar alignment of that member
  92. // - ArrayStride and MatrixStride are multiples of scalar alignment
  93. // Members need not be listed in offset order
  94. bool scalar_block_layout = false;
  95. // Permit UConvert as an OpSpecConstantOp operation.
  96. // The Kernel capability already enables it, separately from this flag.
  97. bool uconvert_spec_constant_op = false;
  98. };
  99. ValidationState_t(const spv_const_context context,
  100. const spv_const_validator_options opt,
  101. const uint32_t* words, const size_t num_words,
  102. const uint32_t max_warnings);
  103. /// Returns the context
  104. spv_const_context context() const { return context_; }
  105. /// Returns the command line options
  106. spv_const_validator_options options() const { return options_; }
  107. /// Sets the ID of the generator for this module.
  108. void setGenerator(uint32_t gen) { generator_ = gen; }
  109. /// Returns the ID of the generator for this module.
  110. uint32_t generator() const { return generator_; }
  111. /// Sets the SPIR-V version of this module.
  112. void setVersion(uint32_t ver) { version_ = ver; }
  113. /// Gets the SPIR-V version of this module.
  114. uint32_t version() const { return version_; }
  115. /// Forward declares the id in the module
  116. spv_result_t ForwardDeclareId(uint32_t id);
  117. /// Removes a forward declared ID if it has been defined
  118. spv_result_t RemoveIfForwardDeclared(uint32_t id);
  119. /// Registers an ID as a forward pointer
  120. spv_result_t RegisterForwardPointer(uint32_t id);
  121. /// Returns whether or not an ID is a forward pointer
  122. bool IsForwardPointer(uint32_t id) const;
  123. /// Assigns a name to an ID
  124. void AssignNameToId(uint32_t id, std::string name);
  125. /// Returns a string representation of the ID in the format <id>[Name] where
  126. /// the <id> is the numeric valid of the id and the Name is a name assigned by
  127. /// the OpName instruction
  128. std::string getIdName(uint32_t id) const;
  129. /// Accessor function for ID bound.
  130. uint32_t getIdBound() const;
  131. /// Mutator function for ID bound.
  132. void setIdBound(uint32_t bound);
  133. /// Returns the number of ID which have been forward referenced but not
  134. /// defined
  135. size_t unresolved_forward_id_count() const;
  136. /// Returns a vector of unresolved forward ids.
  137. std::vector<uint32_t> UnresolvedForwardIds() const;
  138. /// Returns true if the id has been defined
  139. bool IsDefinedId(uint32_t id) const;
  140. /// Increments the total number of instructions in the file.
  141. void increment_total_instructions() { total_instructions_++; }
  142. /// Increments the total number of functions in the file.
  143. void increment_total_functions() { total_functions_++; }
  144. /// Allocates internal storage. Note, calling this will invalidate any
  145. /// pointers to |ordered_instructions_| or |module_functions_| and, hence,
  146. /// should only be called at the beginning of validation.
  147. void preallocateStorage();
  148. /// Returns the current layout section which is being processed
  149. ModuleLayoutSection current_layout_section() const;
  150. /// Increments the module_layout_order_section_
  151. void ProgressToNextLayoutSectionOrder();
  152. /// Determines if the op instruction is part of the current section
  153. bool IsOpcodeInCurrentLayoutSection(SpvOp op);
  154. DiagnosticStream diag(spv_result_t error_code, const Instruction* inst);
  155. /// Returns the function states
  156. std::vector<Function>& functions();
  157. /// Returns the function states
  158. Function& current_function();
  159. const Function& current_function() const;
  160. /// Returns function state with the given id, or nullptr if no such function.
  161. const Function* function(uint32_t id) const;
  162. Function* function(uint32_t id);
  163. /// Returns true if the called after a function instruction but before the
  164. /// function end instruction
  165. bool in_function_body() const;
  166. /// Returns true if called after a label instruction but before a branch
  167. /// instruction
  168. bool in_block() const;
  169. struct EntryPointDescription {
  170. std::string name;
  171. std::vector<uint32_t> interfaces;
  172. };
  173. /// Registers |id| as an entry point with |execution_model| and |interfaces|.
  174. void RegisterEntryPoint(const uint32_t id, SpvExecutionModel execution_model,
  175. EntryPointDescription&& desc) {
  176. entry_points_.push_back(id);
  177. entry_point_to_execution_models_[id].insert(execution_model);
  178. entry_point_descriptions_[id].emplace_back(desc);
  179. }
  180. /// Returns a list of entry point function ids
  181. const std::vector<uint32_t>& entry_points() const { return entry_points_; }
  182. /// Returns the set of entry points that root call graphs that contain
  183. /// recursion.
  184. const std::set<uint32_t>& recursive_entry_points() const {
  185. return recursive_entry_points_;
  186. }
  187. /// Registers execution mode for the given entry point.
  188. void RegisterExecutionModeForEntryPoint(uint32_t entry_point,
  189. SpvExecutionMode execution_mode) {
  190. entry_point_to_execution_modes_[entry_point].insert(execution_mode);
  191. }
  192. /// Returns the interface descriptions of a given entry point.
  193. const std::vector<EntryPointDescription>& entry_point_descriptions(
  194. uint32_t entry_point) {
  195. return entry_point_descriptions_.at(entry_point);
  196. }
  197. /// Returns Execution Models for the given Entry Point.
  198. /// Returns nullptr if none found (would trigger assertion).
  199. const std::set<SpvExecutionModel>* GetExecutionModels(
  200. uint32_t entry_point) const {
  201. const auto it = entry_point_to_execution_models_.find(entry_point);
  202. if (it == entry_point_to_execution_models_.end()) {
  203. assert(0);
  204. return nullptr;
  205. }
  206. return &it->second;
  207. }
  208. /// Returns Execution Modes for the given Entry Point.
  209. /// Returns nullptr if none found.
  210. const std::set<SpvExecutionMode>* GetExecutionModes(
  211. uint32_t entry_point) const {
  212. const auto it = entry_point_to_execution_modes_.find(entry_point);
  213. if (it == entry_point_to_execution_modes_.end()) {
  214. return nullptr;
  215. }
  216. return &it->second;
  217. }
  218. /// Traverses call tree and computes function_to_entry_points_.
  219. /// Note: called after fully parsing the binary.
  220. void ComputeFunctionToEntryPointMapping();
  221. /// Traverse call tree and computes recursive_entry_points_.
  222. /// Note: called after fully parsing the binary and calling
  223. /// ComputeFunctionToEntryPointMapping.
  224. void ComputeRecursiveEntryPoints();
  225. /// Returns all the entry points that can call |func|.
  226. const std::vector<uint32_t>& FunctionEntryPoints(uint32_t func) const;
  227. /// Returns all the entry points that statically use |id|.
  228. ///
  229. /// Note: requires ComputeFunctionToEntryPointMapping to have been called.
  230. std::set<uint32_t> EntryPointReferences(uint32_t id) const;
  231. /// Inserts an <id> to the set of functions that are target of OpFunctionCall.
  232. void AddFunctionCallTarget(const uint32_t id) {
  233. function_call_targets_.insert(id);
  234. current_function().AddFunctionCallTarget(id);
  235. }
  236. /// Returns whether or not a function<id> is the target of OpFunctionCall.
  237. bool IsFunctionCallTarget(const uint32_t id) {
  238. return (function_call_targets_.find(id) != function_call_targets_.end());
  239. }
  240. bool IsFunctionCallDefined(const uint32_t id) {
  241. return (id_to_function_.find(id) != id_to_function_.end());
  242. }
  243. /// Registers the capability and its dependent capabilities
  244. void RegisterCapability(SpvCapability cap);
  245. /// Registers the extension.
  246. void RegisterExtension(Extension ext);
  247. /// Registers the function in the module. Subsequent instructions will be
  248. /// called against this function
  249. spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
  250. SpvFunctionControlMask function_control,
  251. uint32_t function_type_id);
  252. /// Register a function end instruction
  253. spv_result_t RegisterFunctionEnd();
  254. /// Returns true if the capability is enabled in the module.
  255. bool HasCapability(SpvCapability cap) const {
  256. return module_capabilities_.Contains(cap);
  257. }
  258. /// Returns true if the extension is enabled in the module.
  259. bool HasExtension(Extension ext) const {
  260. return module_extensions_.Contains(ext);
  261. }
  262. /// Returns true if any of the capabilities is enabled, or if |capabilities|
  263. /// is an empty set.
  264. bool HasAnyOfCapabilities(const CapabilitySet& capabilities) const;
  265. /// Returns true if any of the extensions is enabled, or if |extensions|
  266. /// is an empty set.
  267. bool HasAnyOfExtensions(const ExtensionSet& extensions) const;
  268. /// Sets the addressing model of this module (logical/physical).
  269. void set_addressing_model(SpvAddressingModel am);
  270. /// Returns true if the OpMemoryModel was found.
  271. bool has_memory_model_specified() const {
  272. return addressing_model_ != SpvAddressingModelMax &&
  273. memory_model_ != SpvMemoryModelMax;
  274. }
  275. /// Returns the addressing model of this module, or Logical if uninitialized.
  276. SpvAddressingModel addressing_model() const;
  277. /// Returns the addressing model of this module, or Logical if uninitialized.
  278. uint32_t pointer_size_and_alignment() const {
  279. return pointer_size_and_alignment_;
  280. }
  281. /// Sets the memory model of this module.
  282. void set_memory_model(SpvMemoryModel mm);
  283. /// Returns the memory model of this module, or Simple if uninitialized.
  284. SpvMemoryModel memory_model() const;
  285. const AssemblyGrammar& grammar() const { return grammar_; }
  286. /// Inserts the instruction into the list of ordered instructions in the file.
  287. Instruction* AddOrderedInstruction(const spv_parsed_instruction_t* inst);
  288. /// Registers the instruction. This will add the instruction to the list of
  289. /// definitions and register sampled image consumers.
  290. void RegisterInstruction(Instruction* inst);
  291. /// Registers the debug instruction information.
  292. void RegisterDebugInstruction(const Instruction* inst);
  293. /// Registers the decoration for the given <id>
  294. void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
  295. id_decorations_[id].push_back(dec);
  296. }
  297. /// Registers the list of decorations for the given <id>
  298. template <class InputIt>
  299. void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) {
  300. std::vector<Decoration>& cur_decs = id_decorations_[id];
  301. cur_decs.insert(cur_decs.end(), begin, end);
  302. }
  303. /// Registers the list of decorations for the given member of the given
  304. /// structure.
  305. template <class InputIt>
  306. void RegisterDecorationsForStructMember(uint32_t struct_id,
  307. uint32_t member_index, InputIt begin,
  308. InputIt end) {
  309. RegisterDecorationsForId(struct_id, begin, end);
  310. for (auto& decoration : id_decorations_[struct_id]) {
  311. decoration.set_struct_member_index(member_index);
  312. }
  313. }
  314. /// Returns all the decorations for the given <id>. If no decorations exist
  315. /// for the <id>, it registers an empty vector for it in the map and
  316. /// returns the empty vector.
  317. std::vector<Decoration>& id_decorations(uint32_t id) {
  318. return id_decorations_[id];
  319. }
  320. // Returns const pointer to the internal decoration container.
  321. const std::map<uint32_t, std::vector<Decoration>>& id_decorations() const {
  322. return id_decorations_;
  323. }
  324. /// Returns true if the given id <id> has the given decoration <dec>,
  325. /// otherwise returns false.
  326. bool HasDecoration(uint32_t id, SpvDecoration dec) {
  327. const auto& decorations = id_decorations_.find(id);
  328. if (decorations == id_decorations_.end()) return false;
  329. return std::any_of(
  330. decorations->second.begin(), decorations->second.end(),
  331. [dec](const Decoration& d) { return dec == d.dec_type(); });
  332. }
  333. /// Finds id's def, if it exists. If found, returns the definition otherwise
  334. /// nullptr
  335. const Instruction* FindDef(uint32_t id) const;
  336. /// Finds id's def, if it exists. If found, returns the definition otherwise
  337. /// nullptr
  338. Instruction* FindDef(uint32_t id);
  339. /// Returns the instructions in the order they appear in the binary
  340. const std::vector<Instruction>& ordered_instructions() const {
  341. return ordered_instructions_;
  342. }
  343. /// Returns a map of instructions mapped by their result id
  344. const std::unordered_map<uint32_t, Instruction*>& all_definitions() const {
  345. return all_definitions_;
  346. }
  347. /// Returns a vector containing the Ids of instructions that consume the given
  348. /// SampledImage id.
  349. std::vector<uint32_t> getSampledImageConsumers(uint32_t id) const;
  350. /// Records cons_id as a consumer of sampled_image_id.
  351. void RegisterSampledImageConsumer(uint32_t sampled_image_id,
  352. uint32_t cons_id);
  353. /// Returns the set of Global Variables.
  354. std::unordered_set<uint32_t>& global_vars() { return global_vars_; }
  355. /// Returns the set of Local Variables.
  356. std::unordered_set<uint32_t>& local_vars() { return local_vars_; }
  357. /// Returns the number of Global Variables.
  358. size_t num_global_vars() { return global_vars_.size(); }
  359. /// Returns the number of Local Variables.
  360. size_t num_local_vars() { return local_vars_.size(); }
  361. /// Inserts a new <id> to the set of Global Variables.
  362. void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); }
  363. /// Inserts a new <id> to the set of Local Variables.
  364. void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); }
  365. // Returns true if using relaxed block layout, equivalent to
  366. // VK_KHR_relaxed_block_layout.
  367. bool IsRelaxedBlockLayout() const {
  368. return features_.env_relaxed_block_layout || options()->relax_block_layout;
  369. }
  370. /// Sets the struct nesting depth for a given struct ID
  371. void set_struct_nesting_depth(uint32_t id, uint32_t depth) {
  372. struct_nesting_depth_[id] = depth;
  373. }
  374. /// Returns the nesting depth of a given structure ID
  375. uint32_t struct_nesting_depth(uint32_t id) {
  376. return struct_nesting_depth_[id];
  377. }
  378. /// Records the has a nested block/bufferblock decorated struct for a given
  379. /// struct ID
  380. void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) {
  381. struct_has_nested_blockorbufferblock_struct_[id] = has;
  382. }
  383. /// For a given struct ID returns true if it has a nested block/bufferblock
  384. /// decorated struct
  385. bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) {
  386. return struct_has_nested_blockorbufferblock_struct_[id];
  387. }
  388. /// Records that the structure type has a member decorated with a built-in.
  389. void RegisterStructTypeWithBuiltInMember(uint32_t id) {
  390. builtin_structs_.insert(id);
  391. }
  392. /// Returns true if the struct type with the given Id has a BuiltIn member.
  393. bool IsStructTypeWithBuiltInMember(uint32_t id) const {
  394. return (builtin_structs_.find(id) != builtin_structs_.end());
  395. }
  396. // Returns the state of optional features.
  397. const Feature& features() const { return features_; }
  398. /// Adds the instruction data to unique_type_declarations_.
  399. /// Returns false if an identical type declaration already exists.
  400. bool RegisterUniqueTypeDeclaration(const Instruction* inst);
  401. // Returns type_id of the scalar component of |id|.
  402. // |id| can be either
  403. // - scalar, vector or matrix type
  404. // - object of either scalar, vector or matrix type
  405. uint32_t GetComponentType(uint32_t id) const;
  406. // Returns
  407. // - 1 for scalar types or objects
  408. // - vector size for vector types or objects
  409. // - num columns for matrix types or objects
  410. // Should not be called with any other arguments (will return zero and invoke
  411. // assertion).
  412. uint32_t GetDimension(uint32_t id) const;
  413. // Returns bit width of scalar or component.
  414. // |id| can be
  415. // - scalar, vector or matrix type
  416. // - object of either scalar, vector or matrix type
  417. // Will invoke assertion and return 0 if |id| is none of the above.
  418. uint32_t GetBitWidth(uint32_t id) const;
  419. // Provides detailed information on matrix type.
  420. // Returns false iff |id| is not matrix type.
  421. bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols,
  422. uint32_t* column_type, uint32_t* component_type) const;
  423. // Collects struct member types into |member_types|.
  424. // Returns false iff not struct type or has no members.
  425. // Deletes prior contents of |member_types|.
  426. bool GetStructMemberTypes(uint32_t struct_type_id,
  427. std::vector<uint32_t>* member_types) const;
  428. // Returns true iff |id| is a type corresponding to the name of the function.
  429. // Only works for types not for objects.
  430. bool IsFloatScalarType(uint32_t id) const;
  431. bool IsFloatVectorType(uint32_t id) const;
  432. bool IsFloatScalarOrVectorType(uint32_t id) const;
  433. bool IsFloatMatrixType(uint32_t id) const;
  434. bool IsIntScalarType(uint32_t id) const;
  435. bool IsIntVectorType(uint32_t id) const;
  436. bool IsIntScalarOrVectorType(uint32_t id) const;
  437. bool IsUnsignedIntScalarType(uint32_t id) const;
  438. bool IsUnsignedIntVectorType(uint32_t id) const;
  439. bool IsSignedIntScalarType(uint32_t id) const;
  440. bool IsSignedIntVectorType(uint32_t id) const;
  441. bool IsBoolScalarType(uint32_t id) const;
  442. bool IsBoolVectorType(uint32_t id) const;
  443. bool IsBoolScalarOrVectorType(uint32_t id) const;
  444. bool IsPointerType(uint32_t id) const;
  445. bool IsCooperativeMatrixType(uint32_t id) const;
  446. bool IsFloatCooperativeMatrixType(uint32_t id) const;
  447. bool IsIntCooperativeMatrixType(uint32_t id) const;
  448. bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const;
  449. // Gets value from OpConstant and OpSpecConstant as uint64.
  450. // Returns false on failure (no instruction, wrong instruction, not int).
  451. bool GetConstantValUint64(uint32_t id, uint64_t* val) const;
  452. // Returns type_id if id has type or zero otherwise.
  453. uint32_t GetTypeId(uint32_t id) const;
  454. // Returns opcode of the instruction which issued the id or OpNop if the
  455. // instruction is not registered.
  456. SpvOp GetIdOpcode(uint32_t id) const;
  457. // Returns type_id for given id operand if it has a type or zero otherwise.
  458. // |operand_index| is expected to be pointing towards an operand which is an
  459. // id.
  460. uint32_t GetOperandTypeId(const Instruction* inst,
  461. size_t operand_index) const;
  462. // Provides information on pointer type. Returns false iff not pointer type.
  463. bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
  464. uint32_t* storage_class) const;
  465. // Is the ID the type of a pointer to a uniform block: Block-decorated struct
  466. // in uniform storage class? The result is only valid after internal method
  467. // CheckDecorationsOfBuffers has been called.
  468. bool IsPointerToUniformBlock(uint32_t type_id) const {
  469. return pointer_to_uniform_block_.find(type_id) !=
  470. pointer_to_uniform_block_.cend();
  471. }
  472. // Save the ID of a pointer to uniform block.
  473. void RegisterPointerToUniformBlock(uint32_t type_id) {
  474. pointer_to_uniform_block_.insert(type_id);
  475. }
  476. // Is the ID the type of a struct used as a uniform block?
  477. // The result is only valid after internal method CheckDecorationsOfBuffers
  478. // has been called.
  479. bool IsStructForUniformBlock(uint32_t type_id) const {
  480. return struct_for_uniform_block_.find(type_id) !=
  481. struct_for_uniform_block_.cend();
  482. }
  483. // Save the ID of a struct of a uniform block.
  484. void RegisterStructForUniformBlock(uint32_t type_id) {
  485. struct_for_uniform_block_.insert(type_id);
  486. }
  487. // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated
  488. // struct in uniform storage class, or Block-decorated struct in StorageBuffer
  489. // storage class? The result is only valid after internal method
  490. // CheckDecorationsOfBuffers has been called.
  491. bool IsPointerToStorageBuffer(uint32_t type_id) const {
  492. return pointer_to_storage_buffer_.find(type_id) !=
  493. pointer_to_storage_buffer_.cend();
  494. }
  495. // Save the ID of a pointer to a storage buffer.
  496. void RegisterPointerToStorageBuffer(uint32_t type_id) {
  497. pointer_to_storage_buffer_.insert(type_id);
  498. }
  499. // Is the ID the type of a struct for storage buffer?
  500. // The result is only valid after internal method CheckDecorationsOfBuffers
  501. // has been called.
  502. bool IsStructForStorageBuffer(uint32_t type_id) const {
  503. return struct_for_storage_buffer_.find(type_id) !=
  504. struct_for_storage_buffer_.cend();
  505. }
  506. // Save the ID of a struct of a storage buffer.
  507. void RegisterStructForStorageBuffer(uint32_t type_id) {
  508. struct_for_storage_buffer_.insert(type_id);
  509. }
  510. // Is the ID the type of a pointer to a storage image? That is, the pointee
  511. // type is an image type which is known to not use a sampler.
  512. bool IsPointerToStorageImage(uint32_t type_id) const {
  513. return pointer_to_storage_image_.find(type_id) !=
  514. pointer_to_storage_image_.cend();
  515. }
  516. // Save the ID of a pointer to a storage image.
  517. void RegisterPointerToStorageImage(uint32_t type_id) {
  518. pointer_to_storage_image_.insert(type_id);
  519. }
  520. // Tries to evaluate a 32-bit signed or unsigned scalar integer constant.
  521. // Returns tuple <is_int32, is_const_int32, value>.
  522. // OpSpecConstant* return |is_const_int32| as false since their values cannot
  523. // be relied upon during validation.
  524. std::tuple<bool, bool, uint32_t> EvalInt32IfConst(uint32_t id) const;
  525. // Returns the disassembly string for the given instruction.
  526. std::string Disassemble(const Instruction& inst) const;
  527. // Returns the disassembly string for the given instruction.
  528. std::string Disassemble(const uint32_t* words, uint16_t num_words) const;
  529. // Returns whether type m1 and type m2 are cooperative matrices with
  530. // the same "shape" (matching scope, rows, cols). If any are specialization
  531. // constants, we assume they can match because we can't prove they don't.
  532. spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst,
  533. uint32_t m1, uint32_t m2);
  534. private:
  535. ValidationState_t(const ValidationState_t&);
  536. const spv_const_context context_;
  537. /// Stores the Validator command line options. Must be a valid options object.
  538. const spv_const_validator_options options_;
  539. /// The SPIR-V binary module we're validating.
  540. const uint32_t* words_;
  541. const size_t num_words_;
  542. /// The generator of the SPIR-V.
  543. uint32_t generator_ = 0;
  544. /// The version of the SPIR-V.
  545. uint32_t version_ = 0;
  546. /// The total number of instructions in the binary.
  547. size_t total_instructions_ = 0;
  548. /// The total number of functions in the binary.
  549. size_t total_functions_ = 0;
  550. /// IDs which have been forward declared but have not been defined
  551. std::unordered_set<uint32_t> unresolved_forward_ids_;
  552. /// IDs that have been declared as forward pointers.
  553. std::unordered_set<uint32_t> forward_pointer_ids_;
  554. /// Stores a vector of instructions that use the result of a given
  555. /// OpSampledImage instruction.
  556. std::unordered_map<uint32_t, std::vector<uint32_t>> sampled_image_consumers_;
  557. /// A map of operand IDs and their names defined by the OpName instruction
  558. std::unordered_map<uint32_t, std::string> operand_names_;
  559. /// The section of the code being processed
  560. ModuleLayoutSection current_layout_section_;
  561. /// A list of functions in the module.
  562. /// Pointers to objects in this container are guaranteed to be stable and
  563. /// valid until the end of lifetime of the validation state.
  564. std::vector<Function> module_functions_;
  565. /// Capabilities declared in the module
  566. CapabilitySet module_capabilities_;
  567. /// Extensions declared in the module
  568. ExtensionSet module_extensions_;
  569. /// List of all instructions in the order they appear in the binary
  570. std::vector<Instruction> ordered_instructions_;
  571. /// Instructions that can be referenced by Ids
  572. std::unordered_map<uint32_t, Instruction*> all_definitions_;
  573. /// IDs that are entry points, ie, arguments to OpEntryPoint.
  574. std::vector<uint32_t> entry_points_;
  575. /// Maps an entry point id to its desciptions.
  576. std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
  577. entry_point_descriptions_;
  578. /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call
  579. /// graph that recurses.
  580. std::set<uint32_t> recursive_entry_points_;
  581. /// Functions IDs that are target of OpFunctionCall.
  582. std::unordered_set<uint32_t> function_call_targets_;
  583. /// ID Bound from the Header
  584. uint32_t id_bound_;
  585. /// Set of Global Variable IDs (Storage Class other than 'Function')
  586. std::unordered_set<uint32_t> global_vars_;
  587. /// Set of Local Variable IDs ('Function' Storage Class)
  588. std::unordered_set<uint32_t> local_vars_;
  589. /// Set of struct types that have members with a BuiltIn decoration.
  590. std::unordered_set<uint32_t> builtin_structs_;
  591. /// Structure Nesting Depth
  592. std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_;
  593. /// Structure has nested blockorbufferblock struct
  594. std::unordered_map<uint32_t, bool>
  595. struct_has_nested_blockorbufferblock_struct_;
  596. /// Stores the list of decorations for a given <id>
  597. std::map<uint32_t, std::vector<Decoration>> id_decorations_;
  598. /// Stores type declarations which need to be unique (i.e. non-aggregates),
  599. /// in the form [opcode, operand words], result_id is not stored.
  600. /// Using ordered set to avoid the need for a vector hash function.
  601. /// The size of this container is expected not to exceed double-digits.
  602. std::set<std::vector<uint32_t>> unique_type_declarations_;
  603. AssemblyGrammar grammar_;
  604. SpvAddressingModel addressing_model_;
  605. SpvMemoryModel memory_model_;
  606. // pointer size derived from addressing model. Assumes all storage classes
  607. // have the same pointer size (for physical pointer types).
  608. uint32_t pointer_size_and_alignment_;
  609. /// NOTE: See correspoding getter functions
  610. bool in_function_;
  611. /// The state of optional features. These are determined by capabilities
  612. /// declared by the module and the environment.
  613. Feature features_;
  614. /// Maps function ids to function stat objects.
  615. std::unordered_map<uint32_t, Function*> id_to_function_;
  616. /// Mapping entry point -> execution models. It is presumed that the same
  617. /// function could theoretically be used as 'main' by multiple OpEntryPoint
  618. /// instructions.
  619. std::unordered_map<uint32_t, std::set<SpvExecutionModel>>
  620. entry_point_to_execution_models_;
  621. /// Mapping entry point -> execution modes.
  622. std::unordered_map<uint32_t, std::set<SpvExecutionMode>>
  623. entry_point_to_execution_modes_;
  624. /// Mapping function -> array of entry points inside this
  625. /// module which can (indirectly) call the function.
  626. std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_;
  627. const std::vector<uint32_t> empty_ids_;
  628. // The IDs of types of pointers to Block-decorated structs in Uniform storage
  629. // class. This is populated at the start of ValidateDecorations.
  630. std::unordered_set<uint32_t> pointer_to_uniform_block_;
  631. // The IDs of struct types for uniform blocks.
  632. // This is populated at the start of ValidateDecorations.
  633. std::unordered_set<uint32_t> struct_for_uniform_block_;
  634. // The IDs of types of pointers to BufferBlock-decorated structs in Uniform
  635. // storage class, or Block-decorated structs in StorageBuffer storage class.
  636. // This is populated at the start of ValidateDecorations.
  637. std::unordered_set<uint32_t> pointer_to_storage_buffer_;
  638. // The IDs of struct types for storage buffers.
  639. // This is populated at the start of ValidateDecorations.
  640. std::unordered_set<uint32_t> struct_for_storage_buffer_;
  641. // The IDs of types of pointers to storage images. This is populated in the
  642. // TypePass.
  643. std::unordered_set<uint32_t> pointer_to_storage_image_;
  644. /// Maps ids to friendly names.
  645. std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper_;
  646. spvtools::NameMapper name_mapper_;
  647. /// Variables used to reduce the number of diagnostic messages.
  648. uint32_t num_of_warnings_;
  649. uint32_t max_num_of_warnings_;
  650. };
  651. } // namespace val
  652. } // namespace spvtools
  653. #endif // SOURCE_VAL_VALIDATION_STATE_H_