validation_state.h 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  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. /// Registers that the entry point declares its local size
  191. void RegisterEntryPointLocalSize(uint32_t entry_point,
  192. const Instruction* inst) {
  193. entry_point_to_local_size_or_id_[entry_point] = inst;
  194. }
  195. /// Registers that the entry point maximum number of primitives
  196. /// mesh shader will ever emit
  197. void RegisterEntryPointOutputPrimitivesEXT(uint32_t entry_point,
  198. const Instruction* inst) {
  199. entry_point_to_output_primitives_[entry_point] = inst;
  200. }
  201. /// Returns the maximum number of primitives mesh shader can emit
  202. uint32_t GetOutputPrimitivesEXT(uint32_t entry_point) {
  203. auto entry = entry_point_to_output_primitives_.find(entry_point);
  204. if (entry != entry_point_to_output_primitives_.end()) {
  205. auto inst = entry->second;
  206. return inst->GetOperandAs<uint32_t>(2);
  207. }
  208. return 0;
  209. }
  210. /// Returns whether the entry point declares its local size
  211. bool EntryPointHasLocalSizeOrId(uint32_t entry_point) const {
  212. return entry_point_to_local_size_or_id_.find(entry_point) !=
  213. entry_point_to_local_size_or_id_.end();
  214. }
  215. /// Returns the id of the local size
  216. const Instruction* EntryPointLocalSizeOrId(uint32_t entry_point) const {
  217. return entry_point_to_local_size_or_id_.find(entry_point)->second;
  218. }
  219. /// Returns the interface descriptions of a given entry point.
  220. const std::vector<EntryPointDescription>& entry_point_descriptions(
  221. uint32_t entry_point) {
  222. return entry_point_descriptions_.at(entry_point);
  223. }
  224. /// Returns Execution Models for the given Entry Point.
  225. /// Returns nullptr if none found (would trigger assertion).
  226. const std::set<spv::ExecutionModel>* GetExecutionModels(
  227. uint32_t entry_point) const {
  228. const auto it = entry_point_to_execution_models_.find(entry_point);
  229. if (it == entry_point_to_execution_models_.end()) {
  230. assert(0);
  231. return nullptr;
  232. }
  233. return &it->second;
  234. }
  235. /// Returns Execution Modes for the given Entry Point.
  236. /// Returns nullptr if none found.
  237. const std::set<spv::ExecutionMode>* GetExecutionModes(
  238. uint32_t entry_point) const {
  239. const auto it = entry_point_to_execution_modes_.find(entry_point);
  240. if (it == entry_point_to_execution_modes_.end()) {
  241. return nullptr;
  242. }
  243. return &it->second;
  244. }
  245. /// Traverses call tree and computes function_to_entry_points_.
  246. /// Note: called after fully parsing the binary.
  247. void ComputeFunctionToEntryPointMapping();
  248. /// Traverse call tree and computes recursive_entry_points_.
  249. /// Note: called after fully parsing the binary and calling
  250. /// ComputeFunctionToEntryPointMapping.
  251. void ComputeRecursiveEntryPoints();
  252. /// Returns all the entry points that can call |func|.
  253. const std::vector<uint32_t>& FunctionEntryPoints(uint32_t func) const;
  254. /// Returns all the entry points that statically use |id|.
  255. ///
  256. /// Note: requires ComputeFunctionToEntryPointMapping to have been called.
  257. std::set<uint32_t> EntryPointReferences(uint32_t id) const;
  258. /// Inserts an <id> to the set of functions that are target of OpFunctionCall.
  259. void AddFunctionCallTarget(const uint32_t id) {
  260. function_call_targets_.insert(id);
  261. current_function().AddFunctionCallTarget(id);
  262. }
  263. /// Returns whether or not a function<id> is the target of OpFunctionCall.
  264. bool IsFunctionCallTarget(const uint32_t id) {
  265. return (function_call_targets_.find(id) != function_call_targets_.end());
  266. }
  267. bool IsFunctionCallDefined(const uint32_t id) {
  268. return (id_to_function_.find(id) != id_to_function_.end());
  269. }
  270. /// Registers the capability and its dependent capabilities
  271. void RegisterCapability(spv::Capability cap);
  272. /// Registers the extension.
  273. void RegisterExtension(Extension ext);
  274. /// Registers the function in the module. Subsequent instructions will be
  275. /// called against this function
  276. spv_result_t RegisterFunction(uint32_t id, uint32_t ret_type_id,
  277. spv::FunctionControlMask function_control,
  278. uint32_t function_type_id);
  279. /// Register a function end instruction
  280. spv_result_t RegisterFunctionEnd();
  281. /// Returns true if the capability is enabled in the module.
  282. bool HasCapability(spv::Capability cap) const {
  283. return module_capabilities_.contains(cap);
  284. }
  285. /// Returns a reference to the set of capabilities in the module.
  286. /// This is provided for debuggability.
  287. const CapabilitySet& module_capabilities() const {
  288. return module_capabilities_;
  289. }
  290. /// Returns true if the extension is enabled in the module.
  291. bool HasExtension(Extension ext) const {
  292. return module_extensions_.contains(ext);
  293. }
  294. /// Returns true if any of the capabilities is enabled, or if |capabilities|
  295. /// is an empty set.
  296. bool HasAnyOfCapabilities(const CapabilitySet& capabilities) const;
  297. /// Returns true if any of the extensions is enabled, or if |extensions|
  298. /// is an empty set.
  299. bool HasAnyOfExtensions(const ExtensionSet& extensions) const;
  300. /// Sets the addressing model of this module (logical/physical).
  301. void set_addressing_model(spv::AddressingModel am);
  302. /// Returns true if the OpMemoryModel was found.
  303. bool has_memory_model_specified() const {
  304. return addressing_model_ != spv::AddressingModel::Max &&
  305. memory_model_ != spv::MemoryModel::Max;
  306. }
  307. /// Returns the addressing model of this module, or Logical if uninitialized.
  308. spv::AddressingModel addressing_model() const;
  309. /// Returns the addressing model of this module, or Logical if uninitialized.
  310. uint32_t pointer_size_and_alignment() const {
  311. return pointer_size_and_alignment_;
  312. }
  313. /// Sets the memory model of this module.
  314. void set_memory_model(spv::MemoryModel mm);
  315. /// Returns the memory model of this module, or Simple if uninitialized.
  316. spv::MemoryModel memory_model() const;
  317. /// Sets the bit width for sampler/image type variables. If not set, they are
  318. /// considered opaque
  319. void set_samplerimage_variable_address_mode(uint32_t bit_width);
  320. /// Get the addressing mode currently set. If 0, it means addressing mode is
  321. /// invalid Sampler/Image type variables must be considered opaque This mode
  322. /// is only valid after the instruction has been read
  323. uint32_t samplerimage_variable_address_mode() const;
  324. /// Returns true if the OpSamplerImageAddressingModeNV was found.
  325. bool has_samplerimage_variable_address_mode_specified() const {
  326. return sampler_image_addressing_mode_ != 0;
  327. }
  328. const AssemblyGrammar& grammar() const { return grammar_; }
  329. /// Inserts the instruction into the list of ordered instructions in the file.
  330. Instruction* AddOrderedInstruction(const spv_parsed_instruction_t* inst);
  331. /// Registers the instruction. This will add the instruction to the list of
  332. /// definitions and register sampled image consumers.
  333. void RegisterInstruction(Instruction* inst);
  334. /// Registers the debug instruction information.
  335. void RegisterDebugInstruction(const Instruction* inst);
  336. /// Registers the decoration for the given <id>
  337. void RegisterDecorationForId(uint32_t id, const Decoration& dec) {
  338. auto& dec_list = id_decorations_[id];
  339. dec_list.insert(dec);
  340. }
  341. /// Registers the list of decorations for the given <id>
  342. template <class InputIt>
  343. void RegisterDecorationsForId(uint32_t id, InputIt begin, InputIt end) {
  344. std::set<Decoration>& cur_decs = id_decorations_[id];
  345. cur_decs.insert(begin, end);
  346. }
  347. /// Registers the list of decorations for the given member of the given
  348. /// structure.
  349. template <class InputIt>
  350. void RegisterDecorationsForStructMember(uint32_t struct_id,
  351. uint32_t member_index, InputIt begin,
  352. InputIt end) {
  353. std::set<Decoration>& cur_decs = id_decorations_[struct_id];
  354. for (InputIt iter = begin; iter != end; ++iter) {
  355. Decoration dec = *iter;
  356. dec.set_struct_member_index(member_index);
  357. cur_decs.insert(dec);
  358. }
  359. }
  360. /// Returns all the decorations for the given <id>. If no decorations exist
  361. /// for the <id>, it registers an empty set for it in the map and
  362. /// returns the empty set.
  363. std::set<Decoration>& id_decorations(uint32_t id) {
  364. return id_decorations_[id];
  365. }
  366. /// Returns the range of decorations for the given field of the given <id>.
  367. struct FieldDecorationsIter {
  368. std::set<Decoration>::const_iterator begin;
  369. std::set<Decoration>::const_iterator end;
  370. };
  371. FieldDecorationsIter id_member_decorations(uint32_t id,
  372. uint32_t member_index) {
  373. const auto& decorations = id_decorations_[id];
  374. // The decorations are sorted by member_index, so this look up will give the
  375. // exact range of decorations for this member index.
  376. Decoration min_decoration((spv::Decoration)0, {}, member_index);
  377. Decoration max_decoration(spv::Decoration::Max, {}, member_index);
  378. FieldDecorationsIter result;
  379. result.begin = decorations.lower_bound(min_decoration);
  380. result.end = decorations.upper_bound(max_decoration);
  381. return result;
  382. }
  383. // Returns const pointer to the internal decoration container.
  384. const std::map<uint32_t, std::set<Decoration>>& id_decorations() const {
  385. return id_decorations_;
  386. }
  387. /// Returns true if the given id <id> has the given decoration <dec>,
  388. /// otherwise returns false.
  389. bool HasDecoration(uint32_t id, spv::Decoration dec) {
  390. const auto& decorations = id_decorations_.find(id);
  391. if (decorations == id_decorations_.end()) return false;
  392. return std::any_of(
  393. decorations->second.begin(), decorations->second.end(),
  394. [dec](const Decoration& d) { return dec == d.dec_type(); });
  395. }
  396. /// Finds id's def, if it exists. If found, returns the definition otherwise
  397. /// nullptr
  398. const Instruction* FindDef(uint32_t id) const;
  399. /// Finds id's def, if it exists. If found, returns the definition otherwise
  400. /// nullptr
  401. Instruction* FindDef(uint32_t id);
  402. /// Returns the instructions in the order they appear in the binary
  403. const std::vector<Instruction>& ordered_instructions() const {
  404. return ordered_instructions_;
  405. }
  406. /// Returns a map of instructions mapped by their result id
  407. const std::unordered_map<uint32_t, Instruction*>& all_definitions() const {
  408. return all_definitions_;
  409. }
  410. /// Returns a vector containing the instructions that consume the given
  411. /// SampledImage id.
  412. std::vector<Instruction*> getSampledImageConsumers(uint32_t id) const;
  413. /// Records cons_id as a consumer of sampled_image_id.
  414. void RegisterSampledImageConsumer(uint32_t sampled_image_id,
  415. Instruction* consumer);
  416. // Record a cons_id as a consumer of texture_id
  417. // if texture 'texture_id' has a QCOM image processing decoration
  418. // and consumer is a load or a sampled image instruction
  419. void RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id,
  420. const Instruction* consumer0,
  421. const Instruction* consumer1);
  422. // Record a function's storage class consumer instruction
  423. void RegisterStorageClassConsumer(spv::StorageClass storage_class,
  424. Instruction* consumer);
  425. /// Returns the set of Global Variables.
  426. std::unordered_set<uint32_t>& global_vars() { return global_vars_; }
  427. /// Returns the set of Local Variables.
  428. std::unordered_set<uint32_t>& local_vars() { return local_vars_; }
  429. /// Returns the number of Global Variables.
  430. size_t num_global_vars() { return global_vars_.size(); }
  431. /// Returns the number of Local Variables.
  432. size_t num_local_vars() { return local_vars_.size(); }
  433. /// Inserts a new <id> to the set of Global Variables.
  434. void registerGlobalVariable(const uint32_t id) { global_vars_.insert(id); }
  435. /// Inserts a new <id> to the set of Local Variables.
  436. void registerLocalVariable(const uint32_t id) { local_vars_.insert(id); }
  437. // Returns true if using relaxed block layout, equivalent to
  438. // VK_KHR_relaxed_block_layout.
  439. bool IsRelaxedBlockLayout() const {
  440. return features_.env_relaxed_block_layout || options()->relax_block_layout;
  441. }
  442. // Returns true if allowing localsizeid, either because the environment always
  443. // allows it, or because it is enabled from the command-line.
  444. bool IsLocalSizeIdAllowed() const {
  445. return features_.env_allow_localsizeid || options()->allow_localsizeid;
  446. }
  447. /// Sets the struct nesting depth for a given struct ID
  448. void set_struct_nesting_depth(uint32_t id, uint32_t depth) {
  449. struct_nesting_depth_[id] = depth;
  450. }
  451. /// Returns the nesting depth of a given structure ID
  452. uint32_t struct_nesting_depth(uint32_t id) {
  453. return struct_nesting_depth_[id];
  454. }
  455. /// Records the has a nested block/bufferblock decorated struct for a given
  456. /// struct ID
  457. void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) {
  458. struct_has_nested_blockorbufferblock_struct_[id] = has;
  459. }
  460. /// For a given struct ID returns true if it has a nested block/bufferblock
  461. /// decorated struct
  462. bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) {
  463. return struct_has_nested_blockorbufferblock_struct_[id];
  464. }
  465. /// Records that the structure type has a member decorated with a built-in.
  466. void RegisterStructTypeWithBuiltInMember(uint32_t id) {
  467. builtin_structs_.insert(id);
  468. }
  469. /// Returns true if the struct type with the given Id has a BuiltIn member.
  470. bool IsStructTypeWithBuiltInMember(uint32_t id) const {
  471. return (builtin_structs_.find(id) != builtin_structs_.end());
  472. }
  473. // Returns the state of optional features.
  474. const Feature& features() const { return features_; }
  475. /// Adds the instruction data to unique_type_declarations_.
  476. /// Returns false if an identical type declaration already exists.
  477. bool RegisterUniqueTypeDeclaration(const Instruction* inst);
  478. // Returns type_id of the scalar component of |id|.
  479. // |id| can be either
  480. // - scalar, vector or matrix type
  481. // - object of either scalar, vector or matrix type
  482. uint32_t GetComponentType(uint32_t id) const;
  483. // Returns
  484. // - 1 for scalar types or objects
  485. // - vector size for vector types or objects
  486. // - num columns for matrix types or objects
  487. // Should not be called with any other arguments (will return zero and invoke
  488. // assertion).
  489. uint32_t GetDimension(uint32_t id) const;
  490. // Returns bit width of scalar or component.
  491. // |id| can be
  492. // - scalar, vector or matrix type
  493. // - object of either scalar, vector or matrix type
  494. // Will invoke assertion and return 0 if |id| is none of the above.
  495. uint32_t GetBitWidth(uint32_t id) const;
  496. // Provides detailed information on matrix type.
  497. // Returns false iff |id| is not matrix type.
  498. bool GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows, uint32_t* num_cols,
  499. uint32_t* column_type, uint32_t* component_type) const;
  500. // Collects struct member types into |member_types|.
  501. // Returns false iff not struct type or has no members.
  502. // Deletes prior contents of |member_types|.
  503. bool GetStructMemberTypes(uint32_t struct_type_id,
  504. std::vector<uint32_t>* member_types) const;
  505. // Returns true iff |id| is a type corresponding to the name of the function.
  506. // Only works for types not for objects.
  507. bool IsVoidType(uint32_t id) const;
  508. bool IsFloatScalarType(uint32_t id) const;
  509. bool IsFloatArrayType(uint32_t id) const;
  510. bool IsFloatVectorType(uint32_t id) const;
  511. bool IsFloat16Vector2Or4Type(uint32_t id) const;
  512. bool IsFloatScalarOrVectorType(uint32_t id) const;
  513. bool IsFloatMatrixType(uint32_t id) const;
  514. bool IsIntScalarType(uint32_t id) const;
  515. bool IsIntArrayType(uint32_t id) const;
  516. bool IsIntVectorType(uint32_t id) const;
  517. bool IsIntScalarOrVectorType(uint32_t id) const;
  518. bool IsUnsignedIntScalarType(uint32_t id) const;
  519. bool IsUnsignedIntVectorType(uint32_t id) const;
  520. bool IsUnsignedIntScalarOrVectorType(uint32_t id) const;
  521. bool IsSignedIntScalarType(uint32_t id) const;
  522. bool IsSignedIntVectorType(uint32_t id) const;
  523. bool IsBoolScalarType(uint32_t id) const;
  524. bool IsBoolVectorType(uint32_t id) const;
  525. bool IsBoolScalarOrVectorType(uint32_t id) const;
  526. bool IsPointerType(uint32_t id) const;
  527. bool IsAccelerationStructureType(uint32_t id) const;
  528. bool IsCooperativeMatrixType(uint32_t id) const;
  529. bool IsCooperativeMatrixNVType(uint32_t id) const;
  530. bool IsCooperativeMatrixKHRType(uint32_t id) const;
  531. bool IsCooperativeMatrixAType(uint32_t id) const;
  532. bool IsCooperativeMatrixBType(uint32_t id) const;
  533. bool IsCooperativeMatrixAccType(uint32_t id) const;
  534. bool IsFloatCooperativeMatrixType(uint32_t id) const;
  535. bool IsIntCooperativeMatrixType(uint32_t id) const;
  536. bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const;
  537. bool IsUnsigned64BitHandle(uint32_t id) const;
  538. bool IsCooperativeVectorNVType(uint32_t id) const;
  539. bool IsFloatCooperativeVectorNVType(uint32_t id) const;
  540. bool IsIntCooperativeVectorNVType(uint32_t id) const;
  541. bool IsUnsignedIntCooperativeVectorNVType(uint32_t id) const;
  542. // Returns true if |id| is a type id that contains |type| (or integer or
  543. // floating point type) of |width| bits.
  544. bool ContainsSizedIntOrFloatType(uint32_t id, spv::Op type,
  545. uint32_t width) const;
  546. // Returns true if |id| is a type id that contains a 8- or 16-bit int or
  547. // 16-bit float that is not generally enabled for use.
  548. bool ContainsLimitedUseIntOrFloatType(uint32_t id) const;
  549. // Returns true if |id| is a type that contains a runtime-sized array.
  550. // Does not consider a pointers as contains the array.
  551. bool ContainsRuntimeArray(uint32_t id) const;
  552. // Generic type traversal.
  553. // Only traverse pointers and functions if |traverse_all_types| is true.
  554. // Recursively tests |f| against the type hierarchy headed by |id|.
  555. bool ContainsType(uint32_t id,
  556. const std::function<bool(const Instruction*)>& f,
  557. bool traverse_all_types = true) const;
  558. // Returns true if |id| is type id that contains an untyped pointer.
  559. bool ContainsUntypedPointer(uint32_t id) const;
  560. // Returns type_id if id has type or zero otherwise.
  561. uint32_t GetTypeId(uint32_t id) const;
  562. // Returns opcode of the instruction which issued the id or OpNop if the
  563. // instruction is not registered.
  564. spv::Op GetIdOpcode(uint32_t id) const;
  565. // Returns type_id for given id operand if it has a type or zero otherwise.
  566. // |operand_index| is expected to be pointing towards an operand which is an
  567. // id.
  568. uint32_t GetOperandTypeId(const Instruction* inst,
  569. size_t operand_index) const;
  570. // Provides information on pointer type. Returns false iff not pointer type.
  571. bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
  572. spv::StorageClass* storage_class) const;
  573. // Is the ID the type of a pointer to a uniform block: Block-decorated struct
  574. // in uniform storage class? The result is only valid after internal method
  575. // CheckDecorationsOfBuffers has been called.
  576. bool IsPointerToUniformBlock(uint32_t type_id) const {
  577. return pointer_to_uniform_block_.find(type_id) !=
  578. pointer_to_uniform_block_.cend();
  579. }
  580. // Save the ID of a pointer to uniform block.
  581. void RegisterPointerToUniformBlock(uint32_t type_id) {
  582. pointer_to_uniform_block_.insert(type_id);
  583. }
  584. // Is the ID the type of a struct used as a uniform block?
  585. // The result is only valid after internal method CheckDecorationsOfBuffers
  586. // has been called.
  587. bool IsStructForUniformBlock(uint32_t type_id) const {
  588. return struct_for_uniform_block_.find(type_id) !=
  589. struct_for_uniform_block_.cend();
  590. }
  591. // Save the ID of a struct of a uniform block.
  592. void RegisterStructForUniformBlock(uint32_t type_id) {
  593. struct_for_uniform_block_.insert(type_id);
  594. }
  595. // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated
  596. // struct in uniform storage class, or Block-decorated struct in StorageBuffer
  597. // storage class? The result is only valid after internal method
  598. // CheckDecorationsOfBuffers has been called.
  599. bool IsPointerToStorageBuffer(uint32_t type_id) const {
  600. return pointer_to_storage_buffer_.find(type_id) !=
  601. pointer_to_storage_buffer_.cend();
  602. }
  603. // Save the ID of a pointer to a storage buffer.
  604. void RegisterPointerToStorageBuffer(uint32_t type_id) {
  605. pointer_to_storage_buffer_.insert(type_id);
  606. }
  607. // Is the ID the type of a struct for storage buffer?
  608. // The result is only valid after internal method CheckDecorationsOfBuffers
  609. // has been called.
  610. bool IsStructForStorageBuffer(uint32_t type_id) const {
  611. return struct_for_storage_buffer_.find(type_id) !=
  612. struct_for_storage_buffer_.cend();
  613. }
  614. // Save the ID of a struct of a storage buffer.
  615. void RegisterStructForStorageBuffer(uint32_t type_id) {
  616. struct_for_storage_buffer_.insert(type_id);
  617. }
  618. // Is the ID the type of a pointer to a storage image? That is, the pointee
  619. // type is an image type which is known to not use a sampler.
  620. bool IsPointerToStorageImage(uint32_t type_id) const {
  621. return pointer_to_storage_image_.find(type_id) !=
  622. pointer_to_storage_image_.cend();
  623. }
  624. // Save the ID of a pointer to a storage image.
  625. void RegisterPointerToStorageImage(uint32_t type_id) {
  626. pointer_to_storage_image_.insert(type_id);
  627. }
  628. // Tries to evaluate a any scalar integer OpConstant as uint64.
  629. // OpConstantNull is defined as zero for scalar int (will return true)
  630. // OpSpecConstant* return false since their values cannot be relied upon
  631. // during validation.
  632. bool EvalConstantValUint64(uint32_t id, uint64_t* val) const;
  633. // Same as EvalConstantValUint64 but returns a signed int
  634. bool EvalConstantValInt64(uint32_t id, int64_t* val) const;
  635. // Tries to evaluate a 32-bit signed or unsigned scalar integer constant.
  636. // Returns tuple <is_int32, is_const_int32, value>.
  637. // OpSpecConstant* return |is_const_int32| as false since their values cannot
  638. // be relied upon during validation.
  639. std::tuple<bool, bool, uint32_t> EvalInt32IfConst(uint32_t id) const;
  640. // Returns the disassembly string for the given instruction.
  641. std::string Disassemble(const Instruction& inst) const;
  642. // Returns the disassembly string for the given instruction.
  643. std::string Disassemble(const uint32_t* words, uint16_t num_words) const;
  644. // Returns the string name for |decoration|.
  645. std::string SpvDecorationString(uint32_t decoration) {
  646. spv_operand_desc desc = nullptr;
  647. if (grammar_.lookupOperand(SPV_OPERAND_TYPE_DECORATION, decoration,
  648. &desc) != SPV_SUCCESS) {
  649. return std::string("Unknown");
  650. }
  651. return std::string(desc->name);
  652. }
  653. std::string SpvDecorationString(spv::Decoration decoration) {
  654. return SpvDecorationString(uint32_t(decoration));
  655. }
  656. // Returns whether type result_type_id and type m2 are cooperative matrices
  657. // with the same "shape" (matching scope, rows, cols). If any are
  658. // specialization constants, we assume they can match because we can't prove
  659. // they don't.
  660. spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst,
  661. uint32_t result_type_id,
  662. uint32_t m2, bool is_conversion,
  663. bool swap_row_col = false);
  664. spv_result_t CooperativeVectorDimensionsMatch(const Instruction* inst,
  665. uint32_t v1, uint32_t v2);
  666. // Returns true if |lhs| and |rhs| logically match and, if the decorations of
  667. // |rhs| are a subset of |lhs|.
  668. //
  669. // 1. Must both be either OpTypeArray or OpTypeStruct
  670. // 2. If OpTypeArray, then
  671. // * Length must be the same
  672. // * Element type must match or logically match
  673. // 3. If OpTypeStruct, then
  674. // * Both have same number of elements
  675. // * Element N for both structs must match or logically match
  676. //
  677. // If |check_decorations| is false, then the decorations are not checked.
  678. bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs,
  679. bool check_decorations);
  680. // Traces |inst| to find a single base pointer. Returns the base pointer.
  681. // Will trace through the following instructions:
  682. // * OpAccessChain
  683. // * OpInBoundsAccessChain
  684. // * OpPtrAccessChain
  685. // * OpInBoundsPtrAccessChain
  686. // * OpCopyObject
  687. const Instruction* TracePointer(const Instruction* inst) const;
  688. // Validates the storage class for the target environment.
  689. bool IsValidStorageClass(spv::StorageClass storage_class) const;
  690. // Takes a Vulkan Valid Usage ID (VUID) as |id| and optional |reference| and
  691. // will return a non-empty string only if ID is known and targeting Vulkan.
  692. // VUIDs are found in the Vulkan-Docs repo in the form "[[VUID-ref-ref-id]]"
  693. // where "id" is always an 5 char long number (with zeros padding) and matches
  694. // to |id|. |reference| is used if there is a "common validity" and the VUID
  695. // shares the same |id| value.
  696. //
  697. // More details about Vulkan validation can be found in Vulkan Guide:
  698. // https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/validation_overview.md
  699. std::string VkErrorID(uint32_t id, const char* reference = nullptr) const;
  700. // Testing method to allow setting the current layout section.
  701. void SetCurrentLayoutSectionForTesting(ModuleLayoutSection section) {
  702. current_layout_section_ = section;
  703. }
  704. // Check if instruction 'id' is a consumer of a texture decorated
  705. // with a QCOM image processing decoration
  706. bool IsQCOMImageProcessingTextureConsumer(uint32_t id) {
  707. return qcom_image_processing_consumers_.find(id) !=
  708. qcom_image_processing_consumers_.end();
  709. }
  710. private:
  711. ValidationState_t(const ValidationState_t&);
  712. const spv_const_context context_;
  713. /// Stores the Validator command line options. Must be a valid options object.
  714. const spv_const_validator_options options_;
  715. /// The SPIR-V binary module we're validating.
  716. const uint32_t* words_;
  717. const size_t num_words_;
  718. /// The generator of the SPIR-V.
  719. uint32_t generator_ = 0;
  720. /// The version of the SPIR-V.
  721. uint32_t version_ = 0;
  722. /// The total number of instructions in the binary.
  723. size_t total_instructions_ = 0;
  724. /// The total number of functions in the binary.
  725. size_t total_functions_ = 0;
  726. /// IDs which have been forward declared but have not been defined
  727. std::unordered_set<uint32_t> unresolved_forward_ids_;
  728. /// IDs that have been declared as forward pointers.
  729. std::unordered_set<uint32_t> forward_pointer_ids_;
  730. /// Stores a vector of instructions that use the result of a given
  731. /// OpSampledImage instruction.
  732. std::unordered_map<uint32_t, std::vector<Instruction*>>
  733. sampled_image_consumers_;
  734. /// Stores load instructions that load textures used
  735. // in QCOM image processing functions
  736. std::unordered_set<uint32_t> qcom_image_processing_consumers_;
  737. /// A map of operand IDs and their names defined by the OpName instruction
  738. std::unordered_map<uint32_t, std::string> operand_names_;
  739. /// The section of the code being processed
  740. ModuleLayoutSection current_layout_section_;
  741. /// A list of functions in the module.
  742. /// Pointers to objects in this container are guaranteed to be stable and
  743. /// valid until the end of lifetime of the validation state.
  744. std::vector<Function> module_functions_;
  745. /// Capabilities declared in the module
  746. CapabilitySet module_capabilities_;
  747. /// Extensions declared in the module
  748. ExtensionSet module_extensions_;
  749. /// List of all instructions in the order they appear in the binary
  750. std::vector<Instruction> ordered_instructions_;
  751. /// Instructions that can be referenced by Ids
  752. std::unordered_map<uint32_t, Instruction*> all_definitions_;
  753. /// IDs that are entry points, ie, arguments to OpEntryPoint.
  754. std::vector<uint32_t> entry_points_;
  755. /// Maps an entry point id to its descriptions.
  756. std::unordered_map<uint32_t, std::vector<EntryPointDescription>>
  757. entry_point_descriptions_;
  758. /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call
  759. /// graph that recurses.
  760. std::set<uint32_t> recursive_entry_points_;
  761. /// Functions IDs that are target of OpFunctionCall.
  762. std::unordered_set<uint32_t> function_call_targets_;
  763. /// ID Bound from the Header
  764. uint32_t id_bound_;
  765. /// Set of Global Variable IDs (Storage Class other than 'Function')
  766. std::unordered_set<uint32_t> global_vars_;
  767. /// Set of Local Variable IDs ('Function' Storage Class)
  768. std::unordered_set<uint32_t> local_vars_;
  769. /// Set of struct types that have members with a BuiltIn decoration.
  770. std::unordered_set<uint32_t> builtin_structs_;
  771. /// Structure Nesting Depth
  772. std::unordered_map<uint32_t, uint32_t> struct_nesting_depth_;
  773. /// Structure has nested blockorbufferblock struct
  774. std::unordered_map<uint32_t, bool>
  775. struct_has_nested_blockorbufferblock_struct_;
  776. /// Stores the list of decorations for a given <id>
  777. std::map<uint32_t, std::set<Decoration>> id_decorations_;
  778. /// Stores type declarations which need to be unique (i.e. non-aggregates),
  779. /// in the form [opcode, operand words], result_id is not stored.
  780. /// Using ordered set to avoid the need for a vector hash function.
  781. /// The size of this container is expected not to exceed double-digits.
  782. std::set<std::vector<uint32_t>> unique_type_declarations_;
  783. AssemblyGrammar grammar_;
  784. spv::AddressingModel addressing_model_;
  785. spv::MemoryModel memory_model_;
  786. // pointer size derived from addressing model. Assumes all storage classes
  787. // have the same pointer size (for physical pointer types).
  788. uint32_t pointer_size_and_alignment_;
  789. /// bit width of sampler/image type variables. Valid values are 32 and 64
  790. uint32_t sampler_image_addressing_mode_;
  791. /// NOTE: See correspoding getter functions
  792. bool in_function_;
  793. /// The state of optional features. These are determined by capabilities
  794. /// declared by the module and the environment.
  795. Feature features_;
  796. /// Maps function ids to function stat objects.
  797. std::unordered_map<uint32_t, Function*> id_to_function_;
  798. /// Mapping entry point -> execution models. It is presumed that the same
  799. /// function could theoretically be used as 'main' by multiple OpEntryPoint
  800. /// instructions.
  801. std::unordered_map<uint32_t, std::set<spv::ExecutionModel>>
  802. entry_point_to_execution_models_;
  803. /// Mapping entry point -> execution modes.
  804. std::unordered_map<uint32_t, std::set<spv::ExecutionMode>>
  805. entry_point_to_execution_modes_;
  806. // Mapping entry point -> local size execution mode instruction
  807. std::unordered_map<uint32_t, const Instruction*>
  808. entry_point_to_local_size_or_id_;
  809. // Mapping entry point -> OutputPrimitivesEXT execution mode instruction
  810. std::unordered_map<uint32_t, const Instruction*>
  811. entry_point_to_output_primitives_;
  812. /// Mapping function -> array of entry points inside this
  813. /// module which can (indirectly) call the function.
  814. std::unordered_map<uint32_t, std::vector<uint32_t>> function_to_entry_points_;
  815. const std::vector<uint32_t> empty_ids_;
  816. // The IDs of types of pointers to Block-decorated structs in Uniform storage
  817. // class. This is populated at the start of ValidateDecorations.
  818. std::unordered_set<uint32_t> pointer_to_uniform_block_;
  819. // The IDs of struct types for uniform blocks.
  820. // This is populated at the start of ValidateDecorations.
  821. std::unordered_set<uint32_t> struct_for_uniform_block_;
  822. // The IDs of types of pointers to BufferBlock-decorated structs in Uniform
  823. // storage class, or Block-decorated structs in StorageBuffer storage class.
  824. // This is populated at the start of ValidateDecorations.
  825. std::unordered_set<uint32_t> pointer_to_storage_buffer_;
  826. // The IDs of struct types for storage buffers.
  827. // This is populated at the start of ValidateDecorations.
  828. std::unordered_set<uint32_t> struct_for_storage_buffer_;
  829. // The IDs of types of pointers to storage images. This is populated in the
  830. // TypePass.
  831. std::unordered_set<uint32_t> pointer_to_storage_image_;
  832. /// Maps ids to friendly names.
  833. std::unique_ptr<spvtools::FriendlyNameMapper> friendly_mapper_;
  834. spvtools::NameMapper name_mapper_;
  835. /// Variables used to reduce the number of diagnostic messages.
  836. uint32_t num_of_warnings_;
  837. uint32_t max_num_of_warnings_;
  838. };
  839. } // namespace val
  840. } // namespace spvtools
  841. #endif // SOURCE_VAL_VALIDATION_STATE_H_