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