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