validation_state.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  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. kLayoutSamplerImageAddressMode, /// < Section 2.4 #5
  47. kLayoutEntryPoint, /// < Section 2.4 #6
  48. kLayoutExecutionMode, /// < Section 2.4 #7
  49. kLayoutDebug1, /// < Section 2.4 #8 > 1
  50. kLayoutDebug2, /// < Section 2.4 #8 > 2
  51. kLayoutDebug3, /// < Section 2.4 #8 > 3
  52. kLayoutAnnotations, /// < Section 2.4 #9
  53. kLayoutTypes, /// < Section 2.4 #10
  54. kLayoutFunctionDeclarations, /// < Section 2.4 #11
  55. kLayoutFunctionDefinitions /// < Section 2.4 #12
  56. };
  57. /// This class manages the state of the SPIR-V validation as it is being parsed.
  58. class ValidationState_t {
  59. public:
  60. // Features that can optionally be turned on by a capability or environment.
  61. struct Feature {
  62. bool declare_int16_type = false; // Allow OpTypeInt with 16 bit width?
  63. bool declare_float16_type = false; // Allow OpTypeFloat with 16 bit width?
  64. bool free_fp_rounding_mode = false; // Allow the FPRoundingMode decoration
  65. // and its values to be used without
  66. // requiring any capability
  67. // Allow functionalities enabled by VariablePointers or
  68. // VariablePointersStorageBuffer capability.
  69. bool variable_pointers = false;
  70. // Permit group oerations Reduce, InclusiveScan, ExclusiveScan
  71. bool group_ops_reduce_and_scans = false;
  72. // Allow OpTypeInt with 8 bit width?
  73. bool declare_int8_type = false;
  74. // Target environment uses relaxed block layout.
  75. // This is true for Vulkan 1.1 or later.
  76. bool env_relaxed_block_layout = false;
  77. // Allow an OpTypeInt with 8 bit width to be used in more than just int
  78. // conversion opcodes
  79. bool use_int8_type = false;
  80. // SPIR-V 1.4 allows us to select between any two composite values
  81. // of the same type.
  82. bool select_between_composites = false;
  83. // SPIR-V 1.4 allows two memory access operands for OpCopyMemory and
  84. // OpCopyMemorySized.
  85. bool copy_memory_permits_two_memory_accesses = false;
  86. // SPIR-V 1.4 allows UConvert as a spec constant op in any environment.
  87. // The Kernel capability already enables it, separately from this flag.
  88. bool uconvert_spec_constant_op = false;
  89. // SPIR-V 1.4 allows Function and Private variables to be NonWritable
  90. bool nonwritable_var_in_function_or_private = false;
  91. // Whether LocalSizeId execution mode is allowed by the environment.
  92. bool env_allow_localsizeid = false;
  93. };
  94. ValidationState_t(const spv_const_context context,
  95. const spv_const_validator_options opt,
  96. const uint32_t* words, const size_t num_words,
  97. const uint32_t max_warnings);
  98. /// Returns the context
  99. spv_const_context context() const { return context_; }
  100. /// Returns the command line options
  101. spv_const_validator_options options() const { return options_; }
  102. /// Sets the ID of the generator for this module.
  103. void setGenerator(uint32_t gen) { generator_ = gen; }
  104. /// Returns the ID of the generator for this module.
  105. uint32_t generator() const { return generator_; }
  106. /// Sets the SPIR-V version of this module.
  107. void setVersion(uint32_t ver) { version_ = ver; }
  108. /// Gets the SPIR-V version of this module.
  109. uint32_t version() const { return version_; }
  110. /// Forward declares the id in the module
  111. spv_result_t ForwardDeclareId(uint32_t id);
  112. /// Removes a forward declared ID if it has been defined
  113. spv_result_t RemoveIfForwardDeclared(uint32_t id);
  114. /// Registers an ID as a forward pointer
  115. spv_result_t RegisterForwardPointer(uint32_t id);
  116. /// Returns whether or not an ID is a forward pointer
  117. bool IsForwardPointer(uint32_t id) const;
  118. /// Assigns a name to an ID
  119. void AssignNameToId(uint32_t id, std::string name);
  120. /// Returns a string representation of the ID in the format <id>[Name] where
  121. /// the <id> is the numeric valid of the id and the Name is a name assigned by
  122. /// the OpName instruction
  123. std::string getIdName(uint32_t id) const;
  124. /// Accessor function for ID bound.
  125. uint32_t getIdBound() const;
  126. /// Mutator function for ID bound.
  127. void setIdBound(uint32_t bound);
  128. /// Returns the number of ID which have been forward referenced but not
  129. /// defined
  130. size_t unresolved_forward_id_count() const;
  131. /// Returns a vector of unresolved forward ids.
  132. std::vector<uint32_t> UnresolvedForwardIds() const;
  133. /// Returns true if the id has been defined
  134. bool IsDefinedId(uint32_t id) const;
  135. /// Increments the total number of instructions in the file.
  136. void increment_total_instructions() { total_instructions_++; }
  137. /// Increments the total number of functions in the file.
  138. void increment_total_functions() { total_functions_++; }
  139. /// Allocates internal storage. Note, calling this will invalidate any
  140. /// pointers to |ordered_instructions_| or |module_functions_| and, hence,
  141. /// should only be called at the beginning of validation.
  142. void preallocateStorage();
  143. /// Returns the current layout section which is being processed
  144. ModuleLayoutSection current_layout_section() const;
  145. /// Increments the module_layout_order_section_
  146. void ProgressToNextLayoutSectionOrder();
  147. /// Determines if the op instruction is in a previous layout section
  148. bool IsOpcodeInPreviousLayoutSection(spv::Op op);
  149. /// Determines if the op instruction is part of the current section
  150. bool IsOpcodeInCurrentLayoutSection(spv::Op op);
  151. DiagnosticStream diag(spv_result_t error_code, const Instruction* inst);
  152. /// Returns the function states
  153. std::vector<Function>& functions();
  154. /// Returns the function states
  155. Function& current_function();
  156. const Function& current_function() const;
  157. /// Returns function state with the given id, or nullptr if no such function.
  158. const Function* function(uint32_t id) const;
  159. Function* function(uint32_t id);
  160. /// Returns true if the called after a function instruction but before the
  161. /// function end instruction
  162. bool in_function_body() const;
  163. /// Returns true if called after a label instruction but before a branch
  164. /// instruction
  165. bool in_block() const;
  166. struct EntryPointDescription {
  167. std::string name;
  168. std::vector<uint32_t> interfaces;
  169. };
  170. /// Registers |id| as an entry point with |execution_model| and |interfaces|.
  171. void RegisterEntryPoint(const uint32_t id,
  172. spv::ExecutionModel execution_model,
  173. EntryPointDescription&& desc) {
  174. entry_points_.push_back(id);
  175. entry_point_to_execution_models_[id].insert(execution_model);
  176. entry_point_descriptions_[id].emplace_back(desc);
  177. }
  178. /// Returns a list of entry point function ids
  179. const std::vector<uint32_t>& entry_points() const { return entry_points_; }
  180. /// Returns the set of entry points that root call graphs that contain
  181. /// recursion.
  182. const std::set<uint32_t>& recursive_entry_points() const {
  183. return recursive_entry_points_;
  184. }
  185. /// Registers execution mode for the given entry point.
  186. void RegisterExecutionModeForEntryPoint(uint32_t entry_point,
  187. spv::ExecutionMode execution_mode) {
  188. entry_point_to_execution_modes_[entry_point].insert(execution_mode);
  189. }
  190. /// Returns the interface descriptions of a given entry point.
  191. const std::vector<EntryPointDescription>& entry_point_descriptions(
  192. uint32_t entry_point) {
  193. return entry_point_descriptions_.at(entry_point);
  194. }
  195. /// Returns Execution Models for the given Entry Point.
  196. /// Returns nullptr if none found (would trigger assertion).
  197. const std::set<spv::ExecutionModel>* GetExecutionModels(
  198. uint32_t entry_point) const {
  199. const auto it = entry_point_to_execution_models_.find(entry_point);
  200. if (it == entry_point_to_execution_models_.end()) {
  201. assert(0);
  202. return nullptr;
  203. }
  204. return &it->second;
  205. }
  206. /// Returns Execution Modes for the given Entry Point.
  207. /// Returns nullptr if none found.
  208. const std::set<spv::ExecutionMode>* GetExecutionModes(
  209. uint32_t entry_point) const {
  210. const auto it = entry_point_to_execution_modes_.find(entry_point);
  211. if (it == entry_point_to_execution_modes_.end()) {
  212. return nullptr;
  213. }
  214. return &it->second;
  215. }
  216. /// Traverses call tree and computes function_to_entry_points_.
  217. /// Note: called after fully parsing the binary.
  218. void ComputeFunctionToEntryPointMapping();
  219. /// Traverse call tree and computes recursive_entry_points_.
  220. /// Note: called after fully parsing the binary and calling
  221. /// ComputeFunctionToEntryPointMapping.
  222. void ComputeRecursiveEntryPoints();
  223. /// Returns all the entry points that can call |func|.
  224. const std::vector<uint32_t>& FunctionEntryPoints(uint32_t func) const;
  225. /// Returns all the entry points that statically use |id|.
  226. ///
  227. /// Note: requires ComputeFunctionToEntryPointMapping to have been called.
  228. std::set<uint32_t> EntryPointReferences(uint32_t id) const;
  229. /// Inserts an <id> to the set of functions that are target of OpFunctionCall.
  230. void AddFunctionCallTarget(const uint32_t id) {
  231. function_call_targets_.insert(id);
  232. current_function().AddFunctionCallTarget(id);
  233. }
  234. /// Returns whether or not a function<id> is the target of OpFunctionCall.
  235. bool IsFunctionCallTarget(const uint32_t id) {
  236. return (function_call_targets_.find(id) != function_call_targets_.end());
  237. }
  238. bool IsFunctionCallDefined(const uint32_t id) {
  239. return (id_to_function_.find(id) != id_to_function_.end());
  240. }
  241. /// Registers the capability and its dependent capabilities
  242. void RegisterCapability(spv::Capability cap);
  243. /// Registers the extension.
  244. void RegisterExtension(Extension ext);
  245. /// Registers the function in the module. Subsequent instructions will be
  246. /// called against this function
  247. spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
  248. spv::FunctionControlMask function_control,
  249. uint32_t function_type_id);
  250. /// Register a function end instruction
  251. spv_result_t RegisterFunctionEnd();
  252. /// Returns true if the capability is enabled in the module.
  253. bool HasCapability(spv::Capability cap) const {
  254. return module_capabilities_.Contains(cap);
  255. }
  256. /// Returns a reference to the set of capabilities in the module.
  257. /// This is provided for debuggability.
  258. const CapabilitySet& module_capabilities() const {
  259. return module_capabilities_;
  260. }
  261. /// Returns true if the extension is enabled in the module.
  262. bool HasExtension(Extension ext) const {
  263. return module_extensions_.Contains(ext);
  264. }
  265. /// Returns true if any of the capabilities is enabled, or if |capabilities|
  266. /// is an empty set.
  267. bool HasAnyOfCapabilities(const CapabilitySet& capabilities) const;
  268. /// Returns true if any of the extensions is enabled, or if |extensions|
  269. /// is an empty set.
  270. bool HasAnyOfExtensions(const ExtensionSet& extensions) const;
  271. /// Sets the addressing model of this module (logical/physical).
  272. void set_addressing_model(spv::AddressingModel am);
  273. /// Returns true if the OpMemoryModel was found.
  274. bool has_memory_model_specified() const {
  275. return addressing_model_ != spv::AddressingModel::Max &&
  276. memory_model_ != spv::MemoryModel::Max;
  277. }
  278. /// Returns the addressing model of this module, or Logical if uninitialized.
  279. spv::AddressingModel addressing_model() const;
  280. /// Returns the addressing model of this module, or Logical if uninitialized.
  281. uint32_t pointer_size_and_alignment() const {
  282. return pointer_size_and_alignment_;
  283. }
  284. /// Sets the memory model of this module.
  285. void set_memory_model(spv::MemoryModel mm);
  286. /// Returns the memory model of this module, or Simple if uninitialized.
  287. spv::MemoryModel memory_model() const;
  288. /// Sets the bit width for sampler/image type variables. If not set, they are
  289. /// considered opaque
  290. void set_samplerimage_variable_address_mode(uint32_t bit_width);
  291. /// Get the addressing mode currently set. If 0, it means addressing mode is
  292. /// invalid Sampler/Image type variables must be considered opaque This mode
  293. /// is only valid after the instruction has been read
  294. uint32_t samplerimage_variable_address_mode() const;
  295. /// Returns true if the OpSamplerImageAddressingModeNV was found.
  296. bool has_samplerimage_variable_address_mode_specified() const {
  297. return sampler_image_addressing_mode_ != 0;
  298. }
  299. const AssemblyGrammar& grammar() const { return grammar_; }
  300. /// Inserts the instruction into the list of ordered instructions in the file.
  301. Instruction* AddOrderedInstruction(const spv_parsed_instruction_t* inst);
  302. /// Registers the instruction. This will add the instruction to the list of
  303. /// definitions and register sampled image consumers.
  304. void RegisterInstruction(Instruction* inst);
  305. /// Registers the debug instruction information.
  306. void RegisterDebugInstruction(const Instruction* inst);
  307. /// Registers the decoration for the given <id>
  308. void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
  309. auto& dec_list = id_decorations_[id];
  310. dec_list.insert(dec);
  311. }
  312. /// Registers the list of decorations for the given <id>
  313. template <class InputIt>
  314. void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) {
  315. std::set<Decoration>& cur_decs = id_decorations_[id];
  316. cur_decs.insert(begin, end);
  317. }
  318. /// Registers the list of decorations for the given member of the given
  319. /// structure.
  320. template <class InputIt>
  321. void RegisterDecorationsForStructMember(uint32_t struct_id,
  322. uint32_t member_index, InputIt begin,
  323. InputIt end) {
  324. std::set<Decoration>& cur_decs = id_decorations_[struct_id];
  325. for (InputIt iter = begin; iter != end; ++iter) {
  326. Decoration dec = *iter;
  327. dec.set_struct_member_index(member_index);
  328. cur_decs.insert(dec);
  329. }
  330. }
  331. /// Returns all the decorations for the given <id>. If no decorations exist
  332. /// for the <id>, it registers an empty set for it in the map and
  333. /// returns the empty set.
  334. std::set<Decoration>& id_decorations(uint32_t id) {
  335. return id_decorations_[id];
  336. }
  337. /// Returns the range of decorations for the given field of the given <id>.
  338. struct FieldDecorationsIter {
  339. std::set<Decoration>::const_iterator begin;
  340. std::set<Decoration>::const_iterator end;
  341. };
  342. FieldDecorationsIter id_member_decorations(uint32_t id,
  343. uint32_t member_index) {
  344. const auto& decorations = id_decorations_[id];
  345. // The decorations are sorted by member_index, so this look up will give the
  346. // exact range of decorations for this member index.
  347. Decoration min_decoration((spv::Decoration)0, {}, member_index);
  348. Decoration max_decoration(spv::Decoration::Max, {}, member_index);
  349. FieldDecorationsIter result;
  350. result.begin = decorations.lower_bound(min_decoration);
  351. result.end = decorations.upper_bound(max_decoration);
  352. return result;
  353. }
  354. // Returns const pointer to the internal decoration container.
  355. const std::map<uint32_t, std::set<Decoration>>& id_decorations() const {
  356. return id_decorations_;
  357. }
  358. /// Returns true if the given id <id> has the given decoration <dec>,
  359. /// otherwise returns false.
  360. bool HasDecoration(uint32_t id, spv::Decoration dec) {
  361. const auto& decorations = id_decorations_.find(id);
  362. if (decorations == id_decorations_.end()) return false;
  363. return std::any_of(
  364. decorations->second.begin(), decorations->second.end(),
  365. [dec](const Decoration& d) { return dec == d.dec_type(); });
  366. }
  367. /// Finds id's def, if it exists. If found, returns the definition otherwise
  368. /// nullptr
  369. const Instruction* FindDef(uint32_t id) const;
  370. /// Finds id's def, if it exists. If found, returns the definition otherwise
  371. /// nullptr
  372. Instruction* FindDef(uint32_t id);
  373. /// Returns the instructions in the order they appear in the binary
  374. const std::vector<Instruction>& ordered_instructions() const {
  375. return ordered_instructions_;
  376. }
  377. /// Returns a map of instructions mapped by their result id
  378. const std::unordered_map<uint32_t, Instruction*>& all_definitions() const {
  379. return all_definitions_;
  380. }
  381. /// Returns a vector containing the instructions that consume the given
  382. /// SampledImage id.
  383. std::vector<Instruction*> getSampledImageConsumers(uint32_t id) const;
  384. /// Records cons_id as a consumer of sampled_image_id.
  385. void RegisterSampledImageConsumer(uint32_t sampled_image_id,
  386. Instruction* consumer);
  387. // Record a function's storage class consumer instruction
  388. void RegisterStorageClassConsumer(spv::StorageClass storage_class,
  389. Instruction* consumer);
  390. /// Returns the set of Global Variables.
  391. std::unordered_set<uint32_t>& global_vars() { return global_vars_; }
  392. /// Returns the set of Local Variables.
  393. std::unordered_set<uint32_t>& local_vars() { return local_vars_; }
  394. /// Returns the number of Global Variables.
  395. size_t num_global_vars() { return global_vars_.size(); }
  396. /// Returns the number of Local Variables.
  397. size_t num_local_vars() { return local_vars_.size(); }
  398. /// Inserts a new <id> to the set of Global Variables.
  399. void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); }
  400. /// Inserts a new <id> to the set of Local Variables.
  401. void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); }
  402. // Returns true if using relaxed block layout, equivalent to
  403. // VK_KHR_relaxed_block_layout.
  404. bool IsRelaxedBlockLayout() const {
  405. return features_.env_relaxed_block_layout || options()->relax_block_layout;
  406. }
  407. // Returns true if allowing localsizeid, either because the environment always
  408. // allows it, or because it is enabled from the command-line.
  409. bool IsLocalSizeIdAllowed() const {
  410. return features_.env_allow_localsizeid || options()->allow_localsizeid;
  411. }
  412. /// Sets the struct nesting depth for a given struct ID
  413. void set_struct_nesting_depth(uint32_t id, uint32_t depth) {
  414. struct_nesting_depth_[id] = depth;
  415. }
  416. /// Returns the nesting depth of a given structure ID
  417. uint32_t struct_nesting_depth(uint32_t id) {
  418. return struct_nesting_depth_[id];
  419. }
  420. /// Records the has a nested block/bufferblock decorated struct for a given
  421. /// struct ID
  422. void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) {
  423. struct_has_nested_blockorbufferblock_struct_[id] = has;
  424. }
  425. /// For a given struct ID returns true if it has a nested block/bufferblock
  426. /// decorated struct
  427. bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) {
  428. return struct_has_nested_blockorbufferblock_struct_[id];
  429. }
  430. /// Records that the structure type has a member decorated with a built-in.
  431. void RegisterStructTypeWithBuiltInMember(uint32_t id) {
  432. builtin_structs_.insert(id);
  433. }
  434. /// Returns true if the struct type with the given Id has a BuiltIn member.
  435. bool IsStructTypeWithBuiltInMember(uint32_t id) const {
  436. return (builtin_structs_.find(id) != builtin_structs_.end());
  437. }
  438. // Returns the state of optional features.
  439. const Feature& features() const { return features_; }
  440. /// Adds the instruction data to unique_type_declarations_.
  441. /// Returns false if an identical type declaration already exists.
  442. bool RegisterUniqueTypeDeclaration(const Instruction* inst);
  443. // Returns type_id of the scalar component of |id|.
  444. // |id| can be either
  445. // - scalar, vector or matrix type
  446. // - object of either scalar, vector or matrix type
  447. uint32_t GetComponentType(uint32_t id) const;
  448. // Returns
  449. // - 1 for scalar types or objects
  450. // - vector size for vector types or objects
  451. // - num columns for matrix types or objects
  452. // Should not be called with any other arguments (will return zero and invoke
  453. // assertion).
  454. uint32_t GetDimension(uint32_t id) const;
  455. // Returns bit width of scalar or component.
  456. // |id| can be
  457. // - scalar, vector or matrix type
  458. // - object of either scalar, vector or matrix type
  459. // Will invoke assertion and return 0 if |id| is none of the above.
  460. uint32_t GetBitWidth(uint32_t id) const;
  461. // Provides detailed information on matrix type.
  462. // Returns false iff |id| is not matrix type.
  463. bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols,
  464. uint32_t* column_type, uint32_t* component_type) const;
  465. // Collects struct member types into |member_types|.
  466. // Returns false iff not struct type or has no members.
  467. // Deletes prior contents of |member_types|.
  468. bool GetStructMemberTypes(uint32_t struct_type_id,
  469. std::vector<uint32_t>* member_types) const;
  470. // Returns true iff |id| is a type corresponding to the name of the function.
  471. // Only works for types not for objects.
  472. bool IsVoidType(uint32_t id) const;
  473. bool IsFloatScalarType(uint32_t id) const;
  474. bool IsFloatVectorType(uint32_t id) const;
  475. bool IsFloatScalarOrVectorType(uint32_t id) const;
  476. bool IsFloatMatrixType(uint32_t id) const;
  477. bool IsIntScalarType(uint32_t id) const;
  478. bool IsIntVectorType(uint32_t id) const;
  479. bool IsIntScalarOrVectorType(uint32_t id) const;
  480. bool IsUnsignedIntScalarType(uint32_t id) const;
  481. bool IsUnsignedIntVectorType(uint32_t id) const;
  482. bool IsSignedIntScalarType(uint32_t id) const;
  483. bool IsSignedIntVectorType(uint32_t id) const;
  484. bool IsBoolScalarType(uint32_t id) const;
  485. bool IsBoolVectorType(uint32_t id) const;
  486. bool IsBoolScalarOrVectorType(uint32_t id) const;
  487. bool IsPointerType(uint32_t id) const;
  488. bool IsAccelerationStructureType(uint32_t id) const;
  489. bool IsCooperativeMatrixType(uint32_t id) const;
  490. bool IsFloatCooperativeMatrixType(uint32_t id) const;
  491. bool IsIntCooperativeMatrixType(uint32_t id) const;
  492. bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const;
  493. bool IsUnsigned64BitHandle(uint32_t id) const;
  494. // Returns true if |id| is a type id that contains |type| (or integer or
  495. // floating point type) of |width| bits.
  496. bool ContainsSizedIntOrFloatType(uint32_t id, spv::Op type,
  497. uint32_t width) const;
  498. // Returns true if |id| is a type id that contains a 8- or 16-bit int or
  499. // 16-bit float that is not generally enabled for use.
  500. bool ContainsLimitedUseIntOrFloatType(uint32_t id) const;
  501. // Returns true if |id| is a type that contains a runtime-sized array.
  502. // Does not consider a pointers as contains the array.
  503. bool ContainsRuntimeArray(uint32_t id) const;
  504. // Generic type traversal.
  505. // Only traverse pointers and functions if |traverse_all_types| is true.
  506. // Recursively tests |f| against the type hierarchy headed by |id|.
  507. bool ContainsType(uint32_t id,
  508. const std::function<bool(const Instruction*)>& f,
  509. bool traverse_all_types = true) const;
  510. // Gets value from OpConstant and OpSpecConstant as uint64.
  511. // Returns false on failure (no instruction, wrong instruction, not int).
  512. bool GetConstantValUint64(uint32_t id, uint64_t* val) const;
  513. // Returns type_id if id has type or zero otherwise.
  514. uint32_t GetTypeId(uint32_t id) const;
  515. // Returns opcode of the instruction which issued the id or OpNop if the
  516. // instruction is not registered.
  517. spv::Op GetIdOpcode(uint32_t id) const;
  518. // Returns type_id for given id operand if it has a type or zero otherwise.
  519. // |operand_index| is expected to be pointing towards an operand which is an
  520. // id.
  521. uint32_t GetOperandTypeId(const Instruction* inst,
  522. size_t operand_index) const;
  523. // Provides information on pointer type. Returns false iff not pointer type.
  524. bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
  525. spv::StorageClass* storage_class) const;
  526. // Is the ID the type of a pointer to a uniform block: Block-decorated struct
  527. // in uniform storage class? The result is only valid after internal method
  528. // CheckDecorationsOfBuffers has been called.
  529. bool IsPointerToUniformBlock(uint32_t type_id) const {
  530. return pointer_to_uniform_block_.find(type_id) !=
  531. pointer_to_uniform_block_.cend();
  532. }
  533. // Save the ID of a pointer to uniform block.
  534. void RegisterPointerToUniformBlock(uint32_t type_id) {
  535. pointer_to_uniform_block_.insert(type_id);
  536. }
  537. // Is the ID the type of a struct used as a uniform block?
  538. // The result is only valid after internal method CheckDecorationsOfBuffers
  539. // has been called.
  540. bool IsStructForUniformBlock(uint32_t type_id) const {
  541. return struct_for_uniform_block_.find(type_id) !=
  542. struct_for_uniform_block_.cend();
  543. }
  544. // Save the ID of a struct of a uniform block.
  545. void RegisterStructForUniformBlock(uint32_t type_id) {
  546. struct_for_uniform_block_.insert(type_id);
  547. }
  548. // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated
  549. // struct in uniform storage class, or Block-decorated struct in StorageBuffer
  550. // storage class? The result is only valid after internal method
  551. // CheckDecorationsOfBuffers has been called.
  552. bool IsPointerToStorageBuffer(uint32_t type_id) const {
  553. return pointer_to_storage_buffer_.find(type_id) !=
  554. pointer_to_storage_buffer_.cend();
  555. }
  556. // Save the ID of a pointer to a storage buffer.
  557. void RegisterPointerToStorageBuffer(uint32_t type_id) {
  558. pointer_to_storage_buffer_.insert(type_id);
  559. }
  560. // Is the ID the type of a struct for storage buffer?
  561. // The result is only valid after internal method CheckDecorationsOfBuffers
  562. // has been called.
  563. bool IsStructForStorageBuffer(uint32_t type_id) const {
  564. return struct_for_storage_buffer_.find(type_id) !=
  565. struct_for_storage_buffer_.cend();
  566. }
  567. // Save the ID of a struct of a storage buffer.
  568. void RegisterStructForStorageBuffer(uint32_t type_id) {
  569. struct_for_storage_buffer_.insert(type_id);
  570. }
  571. // Is the ID the type of a pointer to a storage image? That is, the pointee
  572. // type is an image type which is known to not use a sampler.
  573. bool IsPointerToStorageImage(uint32_t type_id) const {
  574. return pointer_to_storage_image_.find(type_id) !=
  575. pointer_to_storage_image_.cend();
  576. }
  577. // Save the ID of a pointer to a storage image.
  578. void RegisterPointerToStorageImage(uint32_t type_id) {
  579. pointer_to_storage_image_.insert(type_id);
  580. }
  581. // Tries to evaluate a 32-bit signed or unsigned scalar integer constant.
  582. // Returns tuple <is_int32, is_const_int32, value>.
  583. // OpSpecConstant* return |is_const_int32| as false since their values cannot
  584. // be relied upon during validation.
  585. std::tuple<bool, bool, uint32_t> EvalInt32IfConst(uint32_t id) const;
  586. // Returns the disassembly string for the given instruction.
  587. std::string Disassemble(const Instruction& inst) const;
  588. // Returns the disassembly string for the given instruction.
  589. std::string Disassemble(const uint32_t* words, uint16_t num_words) const;
  590. // Returns the string name for |decoration|.
  591. std::string SpvDecorationString(uint32_t decoration) {
  592. spv_operand_desc desc = nullptr;
  593. if (grammar_.lookupOperand(SPV_OPERAND_TYPE_DECORATION, decoration,
  594. &desc) != SPV_SUCCESS) {
  595. return std::string("Unknown");
  596. }
  597. return std::string(desc->name);
  598. }
  599. std::string SpvDecorationString(spv::Decoration decoration) {
  600. return SpvDecorationString(uint32_t(decoration));
  601. }
  602. // Returns whether type m1 and type m2 are cooperative matrices with
  603. // the same "shape" (matching scope, rows, cols). If any are specialization
  604. // constants, we assume they can match because we can't prove they don't.
  605. spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst,
  606. uint32_t m1, uint32_t m2);
  607. // Returns true if |lhs| and |rhs| logically match and, if the decorations of
  608. // |rhs| are a subset of |lhs|.
  609. //
  610. // 1. Must both be either OpTypeArray or OpTypeStruct
  611. // 2. If OpTypeArray, then
  612. // * Length must be the same
  613. // * Element type must match or logically match
  614. // 3. If OpTypeStruct, then
  615. // * Both have same number of elements
  616. // * Element N for both structs must match or logically match
  617. //
  618. // If |check_decorations| is false, then the decorations are not checked.
  619. bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs,
  620. bool check_decorations);
  621. // Traces |inst| to find a single base pointer. Returns the base pointer.
  622. // Will trace through the following instructions:
  623. // * OpAccessChain
  624. // * OpInBoundsAccessChain
  625. // * OpPtrAccessChain
  626. // * OpInBoundsPtrAccessChain
  627. // * OpCopyObject
  628. const Instruction* TracePointer(const Instruction* inst) const;
  629. // Validates the storage class for the target environment.
  630. bool IsValidStorageClass(spv::StorageClass storage_class) const;
  631. // Takes a Vulkan Valid Usage ID (VUID) as |id| and optional |reference| and
  632. // will return a non-empty string only if ID is known and targeting Vulkan.
  633. // VUIDs are found in the Vulkan-Docs repo in the form "[[VUID-ref-ref-id]]"
  634. // where "id" is always an 5 char long number (with zeros padding) and matches
  635. // to |id|. |reference| is used if there is a "common validity" and the VUID
  636. // shares the same |id| value.
  637. //
  638. // More details about Vulkan validation can be found in Vulkan Guide:
  639. // https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/validation_overview.md
  640. std::string VkErrorID(uint32_t id, const char* reference = nullptr) const;
  641. // Testing method to allow setting the current layout section.
  642. void SetCurrentLayoutSectionForTesting(ModuleLayoutSection section) {
  643. current_layout_section_ = section;
  644. }
  645. private:
  646. ValidationState_t(const ValidationState_t&);
  647. const spv_const_context context_;
  648. /// Stores the Validator command line options. Must be a valid options object.
  649. const spv_const_validator_options options_;
  650. /// The SPIR-V binary module we're validating.
  651. const uint32_t* words_;
  652. const size_t num_words_;
  653. /// The generator of the SPIR-V.
  654. uint32_t generator_ = 0;
  655. /// The version of the SPIR-V.
  656. uint32_t version_ = 0;
  657. /// The total number of instructions in the binary.
  658. size_t total_instructions_ = 0;
  659. /// The total number of functions in the binary.
  660. size_t total_functions_ = 0;
  661. /// IDs which have been forward declared but have not been defined
  662. std::unordered_set<uint32_t> unresolved_forward_ids_;
  663. /// IDs that have been declared as forward pointers.
  664. std::unordered_set<uint32_t> forward_pointer_ids_;
  665. /// Stores a vector of instructions that use the result of a given
  666. /// OpSampledImage instruction.
  667. std::unordered_map<uint32_t, std::vector<Instruction*>>
  668. sampled_image_consumers_;
  669. /// A map of operand IDs and their names defined by the OpName instruction
  670. std::unordered_map<uint32_t, std::string> operand_names_;
  671. /// The section of the code being processed
  672. ModuleLayoutSection current_layout_section_;
  673. /// A list of functions in the module.
  674. /// Pointers to objects in this container are guaranteed to be stable and
  675. /// valid until the end of lifetime of the validation state.
  676. std::vector<Function> module_functions_;
  677. /// Capabilities declared in the module
  678. CapabilitySet module_capabilities_;
  679. /// Extensions declared in the module
  680. ExtensionSet module_extensions_;
  681. /// List of all instructions in the order they appear in the binary
  682. std::vector<Instruction> ordered_instructions_;
  683. /// Instructions that can be referenced by Ids
  684. std::unordered_map<uint32_t, Instruction*> all_definitions_;
  685. /// IDs that are entry points, ie, arguments to OpEntryPoint.
  686. std::vector<uint32_t> entry_points_;
  687. /// Maps an entry point id to its descriptions.
  688. std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
  689. entry_point_descriptions_;
  690. /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call
  691. /// graph that recurses.
  692. std::set<uint32_t> recursive_entry_points_;
  693. /// Functions IDs that are target of OpFunctionCall.
  694. std::unordered_set<uint32_t> function_call_targets_;
  695. /// ID Bound from the Header
  696. uint32_t id_bound_;
  697. /// Set of Global Variable IDs (Storage Class other than 'Function')
  698. std::unordered_set<uint32_t> global_vars_;
  699. /// Set of Local Variable IDs ('Function' Storage Class)
  700. std::unordered_set<uint32_t> local_vars_;
  701. /// Set of struct types that have members with a BuiltIn decoration.
  702. std::unordered_set<uint32_t> builtin_structs_;
  703. /// Structure Nesting Depth
  704. std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_;
  705. /// Structure has nested blockorbufferblock struct
  706. std::unordered_map<uint32_t, bool>
  707. struct_has_nested_blockorbufferblock_struct_;
  708. /// Stores the list of decorations for a given <id>
  709. std::map<uint32_t, std::set<Decoration>> id_decorations_;
  710. /// Stores type declarations which need to be unique (i.e. non-aggregates),
  711. /// in the form [opcode, operand words], result_id is not stored.
  712. /// Using ordered set to avoid the need for a vector hash function.
  713. /// The size of this container is expected not to exceed double-digits.
  714. std::set<std::vector<uint32_t>> unique_type_declarations_;
  715. AssemblyGrammar grammar_;
  716. spv::AddressingModel addressing_model_;
  717. spv::MemoryModel memory_model_;
  718. // pointer size derived from addressing model. Assumes all storage classes
  719. // have the same pointer size (for physical pointer types).
  720. uint32_t pointer_size_and_alignment_;
  721. /// bit width of sampler/image type variables. Valid values are 32 and 64
  722. uint32_t sampler_image_addressing_mode_;
  723. /// NOTE: See correspoding getter functions
  724. bool in_function_;
  725. /// The state of optional features. These are determined by capabilities
  726. /// declared by the module and the environment.
  727. Feature features_;
  728. /// Maps function ids to function stat objects.
  729. std::unordered_map<uint32_t, Function*> id_to_function_;
  730. /// Mapping entry point -> execution models. It is presumed that the same
  731. /// function could theoretically be used as 'main' by multiple OpEntryPoint
  732. /// instructions.
  733. std::unordered_map<uint32_t, std::set<spv::ExecutionModel>>
  734. entry_point_to_execution_models_;
  735. /// Mapping entry point -> execution modes.
  736. std::unordered_map<uint32_t, std::set<spv::ExecutionMode>>
  737. entry_point_to_execution_modes_;
  738. /// Mapping function -> array of entry points inside this
  739. /// module which can (indirectly) call the function.
  740. std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_;
  741. const std::vector<uint32_t> empty_ids_;
  742. // The IDs of types of pointers to Block-decorated structs in Uniform storage
  743. // class. This is populated at the start of ValidateDecorations.
  744. std::unordered_set<uint32_t> pointer_to_uniform_block_;
  745. // The IDs of struct types for uniform blocks.
  746. // This is populated at the start of ValidateDecorations.
  747. std::unordered_set<uint32_t> struct_for_uniform_block_;
  748. // The IDs of types of pointers to BufferBlock-decorated structs in Uniform
  749. // storage class, or Block-decorated structs in StorageBuffer storage class.
  750. // This is populated at the start of ValidateDecorations.
  751. std::unordered_set<uint32_t> pointer_to_storage_buffer_;
  752. // The IDs of struct types for storage buffers.
  753. // This is populated at the start of ValidateDecorations.
  754. std::unordered_set<uint32_t> struct_for_storage_buffer_;
  755. // The IDs of types of pointers to storage images. This is populated in the
  756. // TypePass.
  757. std::unordered_set<uint32_t> pointer_to_storage_image_;
  758. /// Maps ids to friendly names.
  759. std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper_;
  760. spvtools::NameMapper name_mapper_;
  761. /// Variables used to reduce the number of diagnostic messages.
  762. uint32_t num_of_warnings_;
  763. uint32_t max_num_of_warnings_;
  764. };
  765. } // namespace val
  766. } // namespace spvtools
  767. #endif // SOURCE_VAL_VALIDATION_STATE_H_