xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/val/validation_state.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 #include "source/val/validation_state.h"
16 
17 #include <cassert>
18 #include <stack>
19 #include <utility>
20 
21 #include "source/opcode.h"
22 #include "source/spirv_constant.h"
23 #include "source/spirv_target_env.h"
24 #include "source/util/make_unique.h"
25 #include "source/val/basic_block.h"
26 #include "source/val/construct.h"
27 #include "source/val/function.h"
28 #include "spirv-tools/libspirv.h"
29 
30 namespace spvtools {
31 namespace val {
32 namespace {
33 
InstructionLayoutSection(ModuleLayoutSection current_section,spv::Op op)34 ModuleLayoutSection InstructionLayoutSection(
35     ModuleLayoutSection current_section, spv::Op op) {
36   // See Section 2.4
37   if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op))
38     return kLayoutTypes;
39 
40   switch (op) {
41     case spv::Op::OpCapability:
42       return kLayoutCapabilities;
43     case spv::Op::OpExtension:
44       return kLayoutExtensions;
45     case spv::Op::OpExtInstImport:
46       return kLayoutExtInstImport;
47     case spv::Op::OpMemoryModel:
48       return kLayoutMemoryModel;
49     case spv::Op::OpEntryPoint:
50       return kLayoutEntryPoint;
51     case spv::Op::OpExecutionMode:
52     case spv::Op::OpExecutionModeId:
53       return kLayoutExecutionMode;
54     case spv::Op::OpSourceContinued:
55     case spv::Op::OpSource:
56     case spv::Op::OpSourceExtension:
57     case spv::Op::OpString:
58       return kLayoutDebug1;
59     case spv::Op::OpName:
60     case spv::Op::OpMemberName:
61       return kLayoutDebug2;
62     case spv::Op::OpModuleProcessed:
63       return kLayoutDebug3;
64     case spv::Op::OpDecorate:
65     case spv::Op::OpMemberDecorate:
66     case spv::Op::OpGroupDecorate:
67     case spv::Op::OpGroupMemberDecorate:
68     case spv::Op::OpDecorationGroup:
69     case spv::Op::OpDecorateId:
70     case spv::Op::OpDecorateStringGOOGLE:
71     case spv::Op::OpMemberDecorateStringGOOGLE:
72       return kLayoutAnnotations;
73     case spv::Op::OpTypeForwardPointer:
74       return kLayoutTypes;
75     case spv::Op::OpVariable:
76     case spv::Op::OpUntypedVariableKHR:
77       if (current_section == kLayoutTypes) return kLayoutTypes;
78       return kLayoutFunctionDefinitions;
79     case spv::Op::OpExtInst:
80     case spv::Op::OpExtInstWithForwardRefsKHR:
81       // spv::Op::OpExtInst is only allowed in types section for certain
82       // extended instruction sets. This will be checked separately.
83       if (current_section == kLayoutTypes) return kLayoutTypes;
84       return kLayoutFunctionDefinitions;
85     case spv::Op::OpLine:
86     case spv::Op::OpNoLine:
87     case spv::Op::OpUndef:
88       if (current_section == kLayoutTypes) return kLayoutTypes;
89       return kLayoutFunctionDefinitions;
90     case spv::Op::OpFunction:
91     case spv::Op::OpFunctionParameter:
92     case spv::Op::OpFunctionEnd:
93       if (current_section == kLayoutFunctionDeclarations)
94         return kLayoutFunctionDeclarations;
95       return kLayoutFunctionDefinitions;
96     case spv::Op::OpSamplerImageAddressingModeNV:
97       return kLayoutSamplerImageAddressMode;
98     default:
99       break;
100   }
101   return kLayoutFunctionDefinitions;
102 }
103 
IsInstructionInLayoutSection(ModuleLayoutSection layout,spv::Op op)104 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, spv::Op op) {
105   return layout == InstructionLayoutSection(layout, op);
106 }
107 
108 // Counts the number of instructions and functions in the file.
CountInstructions(void * user_data,const spv_parsed_instruction_t * inst)109 spv_result_t CountInstructions(void* user_data,
110                                const spv_parsed_instruction_t* inst) {
111   ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
112   if (spv::Op(inst->opcode) == spv::Op::OpFunction) {
113     _.increment_total_functions();
114   }
115   _.increment_total_instructions();
116 
117   return SPV_SUCCESS;
118 }
119 
setHeader(void * user_data,spv_endianness_t,uint32_t,uint32_t version,uint32_t generator,uint32_t id_bound,uint32_t)120 spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t,
121                        uint32_t version, uint32_t generator, uint32_t id_bound,
122                        uint32_t) {
123   ValidationState_t& vstate =
124       *(reinterpret_cast<ValidationState_t*>(user_data));
125   vstate.setIdBound(id_bound);
126   vstate.setGenerator(generator);
127   vstate.setVersion(version);
128 
129   return SPV_SUCCESS;
130 }
131 
132 // Add features based on SPIR-V core version number.
UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature * features,uint32_t version)133 void UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature* features,
134                                        uint32_t version) {
135   assert(features);
136   if (version >= SPV_SPIRV_VERSION_WORD(1, 4)) {
137     features->select_between_composites = true;
138     features->copy_memory_permits_two_memory_accesses = true;
139     features->uconvert_spec_constant_op = true;
140     features->nonwritable_var_in_function_or_private = true;
141   }
142 }
143 
144 }  // namespace
145 
ValidationState_t(const spv_const_context ctx,const spv_const_validator_options opt,const uint32_t * words,const size_t num_words,const uint32_t max_warnings)146 ValidationState_t::ValidationState_t(const spv_const_context ctx,
147                                      const spv_const_validator_options opt,
148                                      const uint32_t* words,
149                                      const size_t num_words,
150                                      const uint32_t max_warnings)
151     : context_(ctx),
152       options_(opt),
153       words_(words),
154       num_words_(num_words),
155       unresolved_forward_ids_{},
156       operand_names_{},
157       current_layout_section_(kLayoutCapabilities),
158       module_functions_(),
159       module_capabilities_(),
160       module_extensions_(),
161       ordered_instructions_(),
162       all_definitions_(),
163       global_vars_(),
164       local_vars_(),
165       struct_nesting_depth_(),
166       struct_has_nested_blockorbufferblock_struct_(),
167       grammar_(ctx),
168       addressing_model_(spv::AddressingModel::Max),
169       memory_model_(spv::MemoryModel::Max),
170       pointer_size_and_alignment_(0),
171       sampler_image_addressing_mode_(0),
172       in_function_(false),
173       num_of_warnings_(0),
174       max_num_of_warnings_(max_warnings) {
175   assert(opt && "Validator options may not be Null.");
176 
177   const auto env = context_->target_env;
178 
179   if (spvIsVulkanEnv(env)) {
180     // Vulkan 1.1 includes VK_KHR_relaxed_block_layout in core.
181     if (env != SPV_ENV_VULKAN_1_0) {
182       features_.env_relaxed_block_layout = true;
183     }
184   }
185 
186   // LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4.
187   switch (env) {
188     case SPV_ENV_VULKAN_1_0:
189     case SPV_ENV_VULKAN_1_1:
190     case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
191     case SPV_ENV_VULKAN_1_2:
192       features_.env_allow_localsizeid = false;
193       break;
194     default:
195       features_.env_allow_localsizeid = true;
196       break;
197   }
198 
199   // Only attempt to count if we have words, otherwise let the other validation
200   // fail and generate an error.
201   if (num_words > 0) {
202     // Count the number of instructions in the binary.
203     // This parse should not produce any error messages. Hijack the context and
204     // replace the message consumer so that we do not pollute any state in input
205     // consumer.
206     spv_context_t hijacked_context = *ctx;
207     hijacked_context.consumer = [](spv_message_level_t, const char*,
__anona6e2c77c0202(spv_message_level_t, const char*, const spv_position_t&, const char*) 208                                    const spv_position_t&, const char*) {};
209     spvBinaryParse(&hijacked_context, this, words, num_words, setHeader,
210                    CountInstructions,
211                    /* diagnostic = */ nullptr);
212     preallocateStorage();
213   }
214   UpdateFeaturesBasedOnSpirvVersion(&features_, version_);
215 
216   name_mapper_ = spvtools::GetTrivialNameMapper();
217   if (options_->use_friendly_names) {
218     friendly_mapper_ = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
219         context_, words_, num_words_);
220     name_mapper_ = friendly_mapper_->GetNameMapper();
221   }
222 }
223 
preallocateStorage()224 void ValidationState_t::preallocateStorage() {
225   ordered_instructions_.reserve(total_instructions_);
226   module_functions_.reserve(total_functions_);
227 }
228 
ForwardDeclareId(uint32_t id)229 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
230   unresolved_forward_ids_.insert(id);
231   return SPV_SUCCESS;
232 }
233 
RemoveIfForwardDeclared(uint32_t id)234 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
235   unresolved_forward_ids_.erase(id);
236   return SPV_SUCCESS;
237 }
238 
RegisterForwardPointer(uint32_t id)239 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
240   forward_pointer_ids_.insert(id);
241   return SPV_SUCCESS;
242 }
243 
IsForwardPointer(uint32_t id) const244 bool ValidationState_t::IsForwardPointer(uint32_t id) const {
245   return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
246 }
247 
AssignNameToId(uint32_t id,std::string name)248 void ValidationState_t::AssignNameToId(uint32_t id, std::string name) {
249   operand_names_[id] = name;
250 }
251 
getIdName(uint32_t id) const252 std::string ValidationState_t::getIdName(uint32_t id) const {
253   const std::string id_name = name_mapper_(id);
254 
255   std::stringstream out;
256   out << "'" << id << "[%" << id_name << "]'";
257   return out.str();
258 }
259 
unresolved_forward_id_count() const260 size_t ValidationState_t::unresolved_forward_id_count() const {
261   return unresolved_forward_ids_.size();
262 }
263 
UnresolvedForwardIds() const264 std::vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
265   std::vector<uint32_t> out(std::begin(unresolved_forward_ids_),
266                             std::end(unresolved_forward_ids_));
267   return out;
268 }
269 
IsDefinedId(uint32_t id) const270 bool ValidationState_t::IsDefinedId(uint32_t id) const {
271   return all_definitions_.find(id) != std::end(all_definitions_);
272 }
273 
FindDef(uint32_t id) const274 const Instruction* ValidationState_t::FindDef(uint32_t id) const {
275   auto it = all_definitions_.find(id);
276   if (it == all_definitions_.end()) return nullptr;
277   return it->second;
278 }
279 
FindDef(uint32_t id)280 Instruction* ValidationState_t::FindDef(uint32_t id) {
281   auto it = all_definitions_.find(id);
282   if (it == all_definitions_.end()) return nullptr;
283   return it->second;
284 }
285 
current_layout_section() const286 ModuleLayoutSection ValidationState_t::current_layout_section() const {
287   return current_layout_section_;
288 }
289 
ProgressToNextLayoutSectionOrder()290 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
291   // Guard against going past the last element(kLayoutFunctionDefinitions)
292   if (current_layout_section_ <= kLayoutFunctionDefinitions) {
293     current_layout_section_ =
294         static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
295   }
296 }
297 
IsOpcodeInPreviousLayoutSection(spv::Op op)298 bool ValidationState_t::IsOpcodeInPreviousLayoutSection(spv::Op op) {
299   ModuleLayoutSection section =
300       InstructionLayoutSection(current_layout_section_, op);
301   return section < current_layout_section_;
302 }
303 
IsOpcodeInCurrentLayoutSection(spv::Op op)304 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(spv::Op op) {
305   return IsInstructionInLayoutSection(current_layout_section_, op);
306 }
307 
diag(spv_result_t error_code,const Instruction * inst)308 DiagnosticStream ValidationState_t::diag(spv_result_t error_code,
309                                          const Instruction* inst) {
310   if (error_code == SPV_WARNING) {
311     if (num_of_warnings_ == max_num_of_warnings_) {
312       DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code)
313           << "Other warnings have been suppressed.\n";
314     }
315     if (num_of_warnings_ >= max_num_of_warnings_) {
316       return DiagnosticStream({0, 0, 0}, nullptr, "", error_code);
317     }
318     ++num_of_warnings_;
319   }
320 
321   std::string disassembly;
322   if (inst) disassembly = Disassemble(*inst);
323 
324   return DiagnosticStream({0, 0, inst ? inst->LineNum() : 0},
325                           context_->consumer, disassembly, error_code);
326 }
327 
functions()328 std::vector<Function>& ValidationState_t::functions() {
329   return module_functions_;
330 }
331 
current_function()332 Function& ValidationState_t::current_function() {
333   assert(in_function_body());
334   return module_functions_.back();
335 }
336 
current_function() const337 const Function& ValidationState_t::current_function() const {
338   assert(in_function_body());
339   return module_functions_.back();
340 }
341 
function(uint32_t id) const342 const Function* ValidationState_t::function(uint32_t id) const {
343   const auto it = id_to_function_.find(id);
344   if (it == id_to_function_.end()) return nullptr;
345   return it->second;
346 }
347 
function(uint32_t id)348 Function* ValidationState_t::function(uint32_t id) {
349   auto it = id_to_function_.find(id);
350   if (it == id_to_function_.end()) return nullptr;
351   return it->second;
352 }
353 
in_function_body() const354 bool ValidationState_t::in_function_body() const { return in_function_; }
355 
in_block() const356 bool ValidationState_t::in_block() const {
357   return module_functions_.empty() == false &&
358          module_functions_.back().current_block() != nullptr;
359 }
360 
RegisterCapability(spv::Capability cap)361 void ValidationState_t::RegisterCapability(spv::Capability cap) {
362   // Avoid redundant work.  Otherwise the recursion could induce work
363   // quadrdatic in the capability dependency depth. (Ok, not much, but
364   // it's something.)
365   if (module_capabilities_.contains(cap)) return;
366 
367   module_capabilities_.insert(cap);
368   spv_operand_desc desc;
369   if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
370                                             uint32_t(cap), &desc)) {
371     for (auto capability :
372          CapabilitySet(desc->numCapabilities, desc->capabilities)) {
373       RegisterCapability(capability);
374     }
375   }
376 
377   switch (cap) {
378     case spv::Capability::Kernel:
379       features_.group_ops_reduce_and_scans = true;
380       break;
381     case spv::Capability::Int8:
382       features_.use_int8_type = true;
383       features_.declare_int8_type = true;
384       break;
385     case spv::Capability::StorageBuffer8BitAccess:
386     case spv::Capability::UniformAndStorageBuffer8BitAccess:
387     case spv::Capability::StoragePushConstant8:
388     case spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR:
389       features_.declare_int8_type = true;
390       break;
391     case spv::Capability::Int16:
392       features_.declare_int16_type = true;
393       break;
394     case spv::Capability::Float16:
395     case spv::Capability::Float16Buffer:
396       features_.declare_float16_type = true;
397       break;
398     case spv::Capability::StorageUniformBufferBlock16:
399     case spv::Capability::StorageUniform16:
400     case spv::Capability::StoragePushConstant16:
401     case spv::Capability::StorageInputOutput16:
402     case spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR:
403       features_.declare_int16_type = true;
404       features_.declare_float16_type = true;
405       features_.free_fp_rounding_mode = true;
406       break;
407     case spv::Capability::VariablePointers:
408     case spv::Capability::VariablePointersStorageBuffer:
409       features_.variable_pointers = true;
410       break;
411     default:
412       // TODO(dneto): For now don't validate SPV_NV_ray_tracing, which uses
413       // capability spv::Capability::RayTracingNV.
414       // spv::Capability::RayTracingProvisionalKHR would need the same
415       // treatment. One of the differences going from SPV_KHR_ray_tracing from
416       // provisional to final spec was the provisional spec uses Locations
417       // for variables in certain storage classes, just like the
418       // SPV_NV_ray_tracing extension.  So it mimics the NVIDIA extension.
419       // The final SPV_KHR_ray_tracing uses a different capability token
420       // number, so it doesn't fall into this case.
421       break;
422   }
423 }
424 
RegisterExtension(Extension ext)425 void ValidationState_t::RegisterExtension(Extension ext) {
426   if (module_extensions_.contains(ext)) return;
427 
428   module_extensions_.insert(ext);
429 
430   switch (ext) {
431     case kSPV_AMD_gpu_shader_half_float:
432     case kSPV_AMD_gpu_shader_half_float_fetch:
433       // SPV_AMD_gpu_shader_half_float enables float16 type.
434       // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
435       features_.declare_float16_type = true;
436       break;
437     case kSPV_AMD_gpu_shader_int16:
438       // This is not yet in the extension, but it's recommended for it.
439       // See https://github.com/KhronosGroup/glslang/issues/848
440       features_.uconvert_spec_constant_op = true;
441       break;
442     case kSPV_AMD_shader_ballot:
443       // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
444       // enables the use of group operations Reduce, InclusiveScan,
445       // and ExclusiveScan.  Enable it manually.
446       // https://github.com/KhronosGroup/SPIRV-Tools/issues/991
447       features_.group_ops_reduce_and_scans = true;
448       break;
449     default:
450       break;
451   }
452 }
453 
HasAnyOfCapabilities(const CapabilitySet & capabilities) const454 bool ValidationState_t::HasAnyOfCapabilities(
455     const CapabilitySet& capabilities) const {
456   return module_capabilities_.HasAnyOf(capabilities);
457 }
458 
HasAnyOfExtensions(const ExtensionSet & extensions) const459 bool ValidationState_t::HasAnyOfExtensions(
460     const ExtensionSet& extensions) const {
461   return module_extensions_.HasAnyOf(extensions);
462 }
463 
set_addressing_model(spv::AddressingModel am)464 void ValidationState_t::set_addressing_model(spv::AddressingModel am) {
465   addressing_model_ = am;
466   switch (am) {
467     case spv::AddressingModel::Physical32:
468       pointer_size_and_alignment_ = 4;
469       break;
470     default:
471     // fall through
472     case spv::AddressingModel::Physical64:
473     case spv::AddressingModel::PhysicalStorageBuffer64:
474       pointer_size_and_alignment_ = 8;
475       break;
476   }
477 }
478 
addressing_model() const479 spv::AddressingModel ValidationState_t::addressing_model() const {
480   return addressing_model_;
481 }
482 
set_memory_model(spv::MemoryModel mm)483 void ValidationState_t::set_memory_model(spv::MemoryModel mm) {
484   memory_model_ = mm;
485 }
486 
memory_model() const487 spv::MemoryModel ValidationState_t::memory_model() const {
488   return memory_model_;
489 }
490 
set_samplerimage_variable_address_mode(uint32_t bit_width)491 void ValidationState_t::set_samplerimage_variable_address_mode(
492     uint32_t bit_width) {
493   sampler_image_addressing_mode_ = bit_width;
494 }
495 
samplerimage_variable_address_mode() const496 uint32_t ValidationState_t::samplerimage_variable_address_mode() const {
497   return sampler_image_addressing_mode_;
498 }
499 
RegisterFunction(uint32_t id,uint32_t ret_type_id,spv::FunctionControlMask function_control,uint32_t function_type_id)500 spv_result_t ValidationState_t::RegisterFunction(
501     uint32_t id, uint32_t ret_type_id,
502     spv::FunctionControlMask function_control, uint32_t function_type_id) {
503   assert(in_function_body() == false &&
504          "RegisterFunction can only be called when parsing the binary outside "
505          "of another function");
506   in_function_ = true;
507   module_functions_.emplace_back(id, ret_type_id, function_control,
508                                  function_type_id);
509   id_to_function_.emplace(id, &current_function());
510 
511   // TODO(umar): validate function type and type_id
512 
513   return SPV_SUCCESS;
514 }
515 
RegisterFunctionEnd()516 spv_result_t ValidationState_t::RegisterFunctionEnd() {
517   assert(in_function_body() == true &&
518          "RegisterFunctionEnd can only be called when parsing the binary "
519          "inside of another function");
520   assert(in_block() == false &&
521          "RegisterFunctionParameter can only be called when parsing the binary "
522          "outside of a block");
523   current_function().RegisterFunctionEnd();
524   in_function_ = false;
525   return SPV_SUCCESS;
526 }
527 
AddOrderedInstruction(const spv_parsed_instruction_t * inst)528 Instruction* ValidationState_t::AddOrderedInstruction(
529     const spv_parsed_instruction_t* inst) {
530   ordered_instructions_.emplace_back(inst);
531   ordered_instructions_.back().SetLineNum(ordered_instructions_.size());
532   return &ordered_instructions_.back();
533 }
534 
535 // Improves diagnostic messages by collecting names of IDs
RegisterDebugInstruction(const Instruction * inst)536 void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
537   switch (inst->opcode()) {
538     case spv::Op::OpName: {
539       const auto target = inst->GetOperandAs<uint32_t>(0);
540       const std::string str = inst->GetOperandAs<std::string>(1);
541       AssignNameToId(target, str);
542       break;
543     }
544     case spv::Op::OpMemberName: {
545       const auto target = inst->GetOperandAs<uint32_t>(0);
546       const std::string str = inst->GetOperandAs<std::string>(2);
547       AssignNameToId(target, str);
548       break;
549     }
550     case spv::Op::OpSourceContinued:
551     case spv::Op::OpSource:
552     case spv::Op::OpSourceExtension:
553     case spv::Op::OpString:
554     case spv::Op::OpLine:
555     case spv::Op::OpNoLine:
556     default:
557       break;
558   }
559 }
560 
RegisterInstruction(Instruction * inst)561 void ValidationState_t::RegisterInstruction(Instruction* inst) {
562   if (inst->id()) all_definitions_.insert(std::make_pair(inst->id(), inst));
563 
564   // Some validation checks are easier by getting all the consumers
565   for (size_t i = 0; i < inst->operands().size(); ++i) {
566     const spv_parsed_operand_t& operand = inst->operand(i);
567     if ((SPV_OPERAND_TYPE_ID == operand.type) ||
568         (SPV_OPERAND_TYPE_TYPE_ID == operand.type)) {
569       const uint32_t operand_word = inst->word(operand.offset);
570       Instruction* operand_inst = FindDef(operand_word);
571       if (!operand_inst) {
572         continue;
573       }
574 
575       // If the instruction is using an OpTypeSampledImage as an operand, it
576       // should be recorded. The validator will ensure that all usages of an
577       // OpTypeSampledImage and its definition are in the same basic block.
578       if ((SPV_OPERAND_TYPE_ID == operand.type) &&
579           (spv::Op::OpSampledImage == operand_inst->opcode())) {
580         RegisterSampledImageConsumer(operand_word, inst);
581       }
582 
583       // In order to track storage classes (not Function) used per execution
584       // model we can't use RegisterExecutionModelLimitation on instructions
585       // like OpTypePointer which are going to be in the pre-function section.
586       // Instead just need to register storage class usage for consumers in a
587       // function block.
588       if (inst->function()) {
589         if (operand_inst->opcode() == spv::Op::OpTypePointer) {
590           RegisterStorageClassConsumer(
591               operand_inst->GetOperandAs<spv::StorageClass>(1), inst);
592         } else if (operand_inst->opcode() == spv::Op::OpVariable) {
593           RegisterStorageClassConsumer(
594               operand_inst->GetOperandAs<spv::StorageClass>(2), inst);
595         }
596       }
597     }
598   }
599 }
600 
getSampledImageConsumers(uint32_t sampled_image_id) const601 std::vector<Instruction*> ValidationState_t::getSampledImageConsumers(
602     uint32_t sampled_image_id) const {
603   std::vector<Instruction*> result;
604   auto iter = sampled_image_consumers_.find(sampled_image_id);
605   if (iter != sampled_image_consumers_.end()) {
606     result = iter->second;
607   }
608   return result;
609 }
610 
RegisterSampledImageConsumer(uint32_t sampled_image_id,Instruction * consumer)611 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
612                                                      Instruction* consumer) {
613   sampled_image_consumers_[sampled_image_id].push_back(consumer);
614 }
615 
RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id,const Instruction * consumer0,const Instruction * consumer1)616 void ValidationState_t::RegisterQCOMImageProcessingTextureConsumer(
617     uint32_t texture_id, const Instruction* consumer0,
618     const Instruction* consumer1) {
619   if (HasDecoration(texture_id, spv::Decoration::WeightTextureQCOM) ||
620       HasDecoration(texture_id, spv::Decoration::BlockMatchTextureQCOM) ||
621       HasDecoration(texture_id, spv::Decoration::BlockMatchSamplerQCOM)) {
622     qcom_image_processing_consumers_.insert(consumer0->id());
623     if (consumer1) {
624       qcom_image_processing_consumers_.insert(consumer1->id());
625     }
626   }
627 }
628 
RegisterStorageClassConsumer(spv::StorageClass storage_class,Instruction * consumer)629 void ValidationState_t::RegisterStorageClassConsumer(
630     spv::StorageClass storage_class, Instruction* consumer) {
631   if (spvIsVulkanEnv(context()->target_env)) {
632     if (storage_class == spv::StorageClass::Output) {
633       std::string errorVUID = VkErrorID(4644);
634       function(consumer->function()->id())
635           ->RegisterExecutionModelLimitation([errorVUID](
636                                                  spv::ExecutionModel model,
637                                                  std::string* message) {
638             if (model == spv::ExecutionModel::GLCompute ||
639                 model == spv::ExecutionModel::RayGenerationKHR ||
640                 model == spv::ExecutionModel::IntersectionKHR ||
641                 model == spv::ExecutionModel::AnyHitKHR ||
642                 model == spv::ExecutionModel::ClosestHitKHR ||
643                 model == spv::ExecutionModel::MissKHR ||
644                 model == spv::ExecutionModel::CallableKHR) {
645               if (message) {
646                 *message =
647                     errorVUID +
648                     "in Vulkan environment, Output Storage Class must not be "
649                     "used in GLCompute, RayGenerationKHR, IntersectionKHR, "
650                     "AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
651                     "execution models";
652               }
653               return false;
654             }
655             return true;
656           });
657     }
658 
659     if (storage_class == spv::StorageClass::Workgroup) {
660       std::string errorVUID = VkErrorID(4645);
661       function(consumer->function()->id())
662           ->RegisterExecutionModelLimitation([errorVUID](
663                                                  spv::ExecutionModel model,
664                                                  std::string* message) {
665             if (model != spv::ExecutionModel::GLCompute &&
666                 model != spv::ExecutionModel::TaskNV &&
667                 model != spv::ExecutionModel::MeshNV &&
668                 model != spv::ExecutionModel::TaskEXT &&
669                 model != spv::ExecutionModel::MeshEXT) {
670               if (message) {
671                 *message =
672                     errorVUID +
673                     "in Vulkan environment, Workgroup Storage Class is limited "
674                     "to MeshNV, TaskNV, and GLCompute execution model";
675               }
676               return false;
677             }
678             return true;
679           });
680     }
681   }
682 
683   if (storage_class == spv::StorageClass::CallableDataKHR) {
684     std::string errorVUID = VkErrorID(4704);
685     function(consumer->function()->id())
686         ->RegisterExecutionModelLimitation(
687             [errorVUID](spv::ExecutionModel model, std::string* message) {
688               if (model != spv::ExecutionModel::RayGenerationKHR &&
689                   model != spv::ExecutionModel::ClosestHitKHR &&
690                   model != spv::ExecutionModel::CallableKHR &&
691                   model != spv::ExecutionModel::MissKHR) {
692                 if (message) {
693                   *message =
694                       errorVUID +
695                       "CallableDataKHR Storage Class is limited to "
696                       "RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
697                       "MissKHR execution model";
698                 }
699                 return false;
700               }
701               return true;
702             });
703   } else if (storage_class == spv::StorageClass::IncomingCallableDataKHR) {
704     std::string errorVUID = VkErrorID(4705);
705     function(consumer->function()->id())
706         ->RegisterExecutionModelLimitation(
707             [errorVUID](spv::ExecutionModel model, std::string* message) {
708               if (model != spv::ExecutionModel::CallableKHR) {
709                 if (message) {
710                   *message =
711                       errorVUID +
712                       "IncomingCallableDataKHR Storage Class is limited to "
713                       "CallableKHR execution model";
714                 }
715                 return false;
716               }
717               return true;
718             });
719   } else if (storage_class == spv::StorageClass::RayPayloadKHR) {
720     std::string errorVUID = VkErrorID(4698);
721     function(consumer->function()->id())
722         ->RegisterExecutionModelLimitation([errorVUID](
723                                                spv::ExecutionModel model,
724                                                std::string* message) {
725           if (model != spv::ExecutionModel::RayGenerationKHR &&
726               model != spv::ExecutionModel::ClosestHitKHR &&
727               model != spv::ExecutionModel::MissKHR) {
728             if (message) {
729               *message =
730                   errorVUID +
731                   "RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
732                   "ClosestHitKHR, and MissKHR execution model";
733             }
734             return false;
735           }
736           return true;
737         });
738   } else if (storage_class == spv::StorageClass::HitAttributeKHR) {
739     std::string errorVUID = VkErrorID(4701);
740     function(consumer->function()->id())
741         ->RegisterExecutionModelLimitation(
742             [errorVUID](spv::ExecutionModel model, std::string* message) {
743               if (model != spv::ExecutionModel::IntersectionKHR &&
744                   model != spv::ExecutionModel::AnyHitKHR &&
745                   model != spv::ExecutionModel::ClosestHitKHR) {
746                 if (message) {
747                   *message = errorVUID +
748                              "HitAttributeKHR Storage Class is limited to "
749                              "IntersectionKHR, AnyHitKHR, sand ClosestHitKHR "
750                              "execution model";
751                 }
752                 return false;
753               }
754               return true;
755             });
756   } else if (storage_class == spv::StorageClass::IncomingRayPayloadKHR) {
757     std::string errorVUID = VkErrorID(4699);
758     function(consumer->function()->id())
759         ->RegisterExecutionModelLimitation(
760             [errorVUID](spv::ExecutionModel model, std::string* message) {
761               if (model != spv::ExecutionModel::AnyHitKHR &&
762                   model != spv::ExecutionModel::ClosestHitKHR &&
763                   model != spv::ExecutionModel::MissKHR) {
764                 if (message) {
765                   *message =
766                       errorVUID +
767                       "IncomingRayPayloadKHR Storage Class is limited to "
768                       "AnyHitKHR, ClosestHitKHR, and MissKHR execution model";
769                 }
770                 return false;
771               }
772               return true;
773             });
774   } else if (storage_class == spv::StorageClass::ShaderRecordBufferKHR) {
775     std::string errorVUID = VkErrorID(7119);
776     function(consumer->function()->id())
777         ->RegisterExecutionModelLimitation(
778             [errorVUID](spv::ExecutionModel model, std::string* message) {
779               if (model != spv::ExecutionModel::RayGenerationKHR &&
780                   model != spv::ExecutionModel::IntersectionKHR &&
781                   model != spv::ExecutionModel::AnyHitKHR &&
782                   model != spv::ExecutionModel::ClosestHitKHR &&
783                   model != spv::ExecutionModel::CallableKHR &&
784                   model != spv::ExecutionModel::MissKHR) {
785                 if (message) {
786                   *message =
787                       errorVUID +
788                       "ShaderRecordBufferKHR Storage Class is limited to "
789                       "RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
790                       "ClosestHitKHR, CallableKHR, and MissKHR execution model";
791                 }
792                 return false;
793               }
794               return true;
795             });
796   } else if (storage_class == spv::StorageClass::TaskPayloadWorkgroupEXT) {
797     function(consumer->function()->id())
798         ->RegisterExecutionModelLimitation(
799             [](spv::ExecutionModel model, std::string* message) {
800               if (model != spv::ExecutionModel::TaskEXT &&
801                   model != spv::ExecutionModel::MeshEXT) {
802                 if (message) {
803                   *message =
804                       "TaskPayloadWorkgroupEXT Storage Class is limited to "
805                       "TaskEXT and MeshKHR execution model";
806                 }
807                 return false;
808               }
809               return true;
810             });
811   } else if (storage_class == spv::StorageClass::HitObjectAttributeNV) {
812     function(consumer->function()->id())
813         ->RegisterExecutionModelLimitation([](spv::ExecutionModel model,
814                                               std::string* message) {
815           if (model != spv::ExecutionModel::RayGenerationKHR &&
816               model != spv::ExecutionModel::ClosestHitKHR &&
817               model != spv::ExecutionModel::MissKHR) {
818             if (message) {
819               *message =
820                   "HitObjectAttributeNV Storage Class is limited to "
821                   "RayGenerationKHR, ClosestHitKHR or MissKHR execution model";
822             }
823             return false;
824           }
825           return true;
826         });
827   }
828 }
829 
getIdBound() const830 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
831 
setIdBound(const uint32_t bound)832 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
833 
RegisterUniqueTypeDeclaration(const Instruction * inst)834 bool ValidationState_t::RegisterUniqueTypeDeclaration(const Instruction* inst) {
835   std::vector<uint32_t> key;
836   key.push_back(static_cast<uint32_t>(inst->opcode()));
837   for (size_t index = 0; index < inst->operands().size(); ++index) {
838     const spv_parsed_operand_t& operand = inst->operand(index);
839 
840     if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
841 
842     const int words_begin = operand.offset;
843     const int words_end = words_begin + operand.num_words;
844     assert(words_end <= static_cast<int>(inst->words().size()));
845 
846     key.insert(key.end(), inst->words().begin() + words_begin,
847                inst->words().begin() + words_end);
848   }
849 
850   return unique_type_declarations_.insert(std::move(key)).second;
851 }
852 
GetTypeId(uint32_t id) const853 uint32_t ValidationState_t::GetTypeId(uint32_t id) const {
854   const Instruction* inst = FindDef(id);
855   return inst ? inst->type_id() : 0;
856 }
857 
GetIdOpcode(uint32_t id) const858 spv::Op ValidationState_t::GetIdOpcode(uint32_t id) const {
859   const Instruction* inst = FindDef(id);
860   return inst ? inst->opcode() : spv::Op::OpNop;
861 }
862 
GetComponentType(uint32_t id) const863 uint32_t ValidationState_t::GetComponentType(uint32_t id) const {
864   const Instruction* inst = FindDef(id);
865   assert(inst);
866 
867   switch (inst->opcode()) {
868     case spv::Op::OpTypeFloat:
869     case spv::Op::OpTypeInt:
870     case spv::Op::OpTypeBool:
871       return id;
872 
873     case spv::Op::OpTypeArray:
874       return inst->word(2);
875 
876     case spv::Op::OpTypeVector:
877       return inst->word(2);
878 
879     case spv::Op::OpTypeMatrix:
880       return GetComponentType(inst->word(2));
881 
882     case spv::Op::OpTypeCooperativeMatrixNV:
883     case spv::Op::OpTypeCooperativeMatrixKHR:
884       return inst->word(2);
885 
886     default:
887       break;
888   }
889 
890   if (inst->type_id()) return GetComponentType(inst->type_id());
891 
892   assert(0);
893   return 0;
894 }
895 
GetDimension(uint32_t id) const896 uint32_t ValidationState_t::GetDimension(uint32_t id) const {
897   const Instruction* inst = FindDef(id);
898   assert(inst);
899 
900   switch (inst->opcode()) {
901     case spv::Op::OpTypeFloat:
902     case spv::Op::OpTypeInt:
903     case spv::Op::OpTypeBool:
904       return 1;
905 
906     case spv::Op::OpTypeVector:
907     case spv::Op::OpTypeMatrix:
908       return inst->word(3);
909 
910     case spv::Op::OpTypeCooperativeMatrixNV:
911     case spv::Op::OpTypeCooperativeMatrixKHR:
912       // Actual dimension isn't known, return 0
913       return 0;
914 
915     default:
916       break;
917   }
918 
919   if (inst->type_id()) return GetDimension(inst->type_id());
920 
921   assert(0);
922   return 0;
923 }
924 
GetBitWidth(uint32_t id) const925 uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
926   const uint32_t component_type_id = GetComponentType(id);
927   const Instruction* inst = FindDef(component_type_id);
928   assert(inst);
929 
930   if (inst->opcode() == spv::Op::OpTypeFloat ||
931       inst->opcode() == spv::Op::OpTypeInt)
932     return inst->word(2);
933 
934   if (inst->opcode() == spv::Op::OpTypeBool) return 1;
935 
936   assert(0);
937   return 0;
938 }
939 
IsVoidType(uint32_t id) const940 bool ValidationState_t::IsVoidType(uint32_t id) const {
941   const Instruction* inst = FindDef(id);
942   return inst && inst->opcode() == spv::Op::OpTypeVoid;
943 }
944 
IsFloatScalarType(uint32_t id) const945 bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
946   const Instruction* inst = FindDef(id);
947   return inst && inst->opcode() == spv::Op::OpTypeFloat;
948 }
949 
IsFloatVectorType(uint32_t id) const950 bool ValidationState_t::IsFloatVectorType(uint32_t id) const {
951   const Instruction* inst = FindDef(id);
952   if (!inst) {
953     return false;
954   }
955 
956   if (inst->opcode() == spv::Op::OpTypeVector) {
957     return IsFloatScalarType(GetComponentType(id));
958   }
959 
960   return false;
961 }
962 
IsFloat16Vector2Or4Type(uint32_t id) const963 bool ValidationState_t::IsFloat16Vector2Or4Type(uint32_t id) const {
964   const Instruction* inst = FindDef(id);
965   assert(inst);
966 
967   if (inst->opcode() == spv::Op::OpTypeVector) {
968     uint32_t vectorDim = GetDimension(id);
969     return IsFloatScalarType(GetComponentType(id)) &&
970            (vectorDim == 2 || vectorDim == 4) &&
971            (GetBitWidth(GetComponentType(id)) == 16);
972   }
973 
974   return false;
975 }
976 
IsFloatScalarOrVectorType(uint32_t id) const977 bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
978   const Instruction* inst = FindDef(id);
979   if (!inst) {
980     return false;
981   }
982 
983   if (inst->opcode() == spv::Op::OpTypeFloat) {
984     return true;
985   }
986 
987   if (inst->opcode() == spv::Op::OpTypeVector) {
988     return IsFloatScalarType(GetComponentType(id));
989   }
990 
991   return false;
992 }
993 
IsIntScalarType(uint32_t id) const994 bool ValidationState_t::IsIntScalarType(uint32_t id) const {
995   const Instruction* inst = FindDef(id);
996   return inst && inst->opcode() == spv::Op::OpTypeInt;
997 }
998 
IsIntArrayType(uint32_t id) const999 bool ValidationState_t::IsIntArrayType(uint32_t id) const {
1000   const Instruction* inst = FindDef(id);
1001   if (!inst) {
1002     return false;
1003   }
1004 
1005   if (inst->opcode() == spv::Op::OpTypeArray) {
1006     return IsIntScalarType(GetComponentType(id));
1007   }
1008 
1009   return false;
1010 }
1011 
IsIntVectorType(uint32_t id) const1012 bool ValidationState_t::IsIntVectorType(uint32_t id) const {
1013   const Instruction* inst = FindDef(id);
1014   if (!inst) {
1015     return false;
1016   }
1017 
1018   if (inst->opcode() == spv::Op::OpTypeVector) {
1019     return IsIntScalarType(GetComponentType(id));
1020   }
1021 
1022   return false;
1023 }
1024 
IsIntScalarOrVectorType(uint32_t id) const1025 bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const {
1026   const Instruction* inst = FindDef(id);
1027   if (!inst) {
1028     return false;
1029   }
1030 
1031   if (inst->opcode() == spv::Op::OpTypeInt) {
1032     return true;
1033   }
1034 
1035   if (inst->opcode() == spv::Op::OpTypeVector) {
1036     return IsIntScalarType(GetComponentType(id));
1037   }
1038 
1039   return false;
1040 }
1041 
IsUnsignedIntScalarType(uint32_t id) const1042 bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const {
1043   const Instruction* inst = FindDef(id);
1044   return inst && inst->opcode() == spv::Op::OpTypeInt && inst->word(3) == 0;
1045 }
1046 
IsUnsignedIntVectorType(uint32_t id) const1047 bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const {
1048   const Instruction* inst = FindDef(id);
1049   if (!inst) {
1050     return false;
1051   }
1052 
1053   if (inst->opcode() == spv::Op::OpTypeVector) {
1054     return IsUnsignedIntScalarType(GetComponentType(id));
1055   }
1056 
1057   return false;
1058 }
1059 
IsUnsignedIntScalarOrVectorType(uint32_t id) const1060 bool ValidationState_t::IsUnsignedIntScalarOrVectorType(uint32_t id) const {
1061   const Instruction* inst = FindDef(id);
1062   if (!inst) {
1063     return false;
1064   }
1065 
1066   if (inst->opcode() == spv::Op::OpTypeInt) {
1067     return inst->GetOperandAs<uint32_t>(2) == 0;
1068   }
1069 
1070   if (inst->opcode() == spv::Op::OpTypeVector) {
1071     return IsUnsignedIntScalarType(GetComponentType(id));
1072   }
1073 
1074   return false;
1075 }
1076 
IsSignedIntScalarType(uint32_t id) const1077 bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
1078   const Instruction* inst = FindDef(id);
1079   return inst && inst->opcode() == spv::Op::OpTypeInt && inst->word(3) == 1;
1080 }
1081 
IsSignedIntVectorType(uint32_t id) const1082 bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const {
1083   const Instruction* inst = FindDef(id);
1084   if (!inst) {
1085     return false;
1086   }
1087 
1088   if (inst->opcode() == spv::Op::OpTypeVector) {
1089     return IsSignedIntScalarType(GetComponentType(id));
1090   }
1091 
1092   return false;
1093 }
1094 
IsBoolScalarType(uint32_t id) const1095 bool ValidationState_t::IsBoolScalarType(uint32_t id) const {
1096   const Instruction* inst = FindDef(id);
1097   return inst && inst->opcode() == spv::Op::OpTypeBool;
1098 }
1099 
IsBoolVectorType(uint32_t id) const1100 bool ValidationState_t::IsBoolVectorType(uint32_t id) const {
1101   const Instruction* inst = FindDef(id);
1102   if (!inst) {
1103     return false;
1104   }
1105 
1106   if (inst->opcode() == spv::Op::OpTypeVector) {
1107     return IsBoolScalarType(GetComponentType(id));
1108   }
1109 
1110   return false;
1111 }
1112 
IsBoolScalarOrVectorType(uint32_t id) const1113 bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const {
1114   const Instruction* inst = FindDef(id);
1115   if (!inst) {
1116     return false;
1117   }
1118 
1119   if (inst->opcode() == spv::Op::OpTypeBool) {
1120     return true;
1121   }
1122 
1123   if (inst->opcode() == spv::Op::OpTypeVector) {
1124     return IsBoolScalarType(GetComponentType(id));
1125   }
1126 
1127   return false;
1128 }
1129 
IsFloatMatrixType(uint32_t id) const1130 bool ValidationState_t::IsFloatMatrixType(uint32_t id) const {
1131   const Instruction* inst = FindDef(id);
1132   if (!inst) {
1133     return false;
1134   }
1135 
1136   if (inst->opcode() == spv::Op::OpTypeMatrix) {
1137     return IsFloatScalarType(GetComponentType(id));
1138   }
1139 
1140   return false;
1141 }
1142 
GetMatrixTypeInfo(uint32_t id,uint32_t * num_rows,uint32_t * num_cols,uint32_t * column_type,uint32_t * component_type) const1143 bool ValidationState_t::GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows,
1144                                           uint32_t* num_cols,
1145                                           uint32_t* column_type,
1146                                           uint32_t* component_type) const {
1147   if (!id) return false;
1148 
1149   const Instruction* mat_inst = FindDef(id);
1150   assert(mat_inst);
1151   if (mat_inst->opcode() != spv::Op::OpTypeMatrix) return false;
1152 
1153   const uint32_t vec_type = mat_inst->word(2);
1154   const Instruction* vec_inst = FindDef(vec_type);
1155   assert(vec_inst);
1156 
1157   if (vec_inst->opcode() != spv::Op::OpTypeVector) {
1158     assert(0);
1159     return false;
1160   }
1161 
1162   *num_cols = mat_inst->word(3);
1163   *num_rows = vec_inst->word(3);
1164   *column_type = mat_inst->word(2);
1165   *component_type = vec_inst->word(2);
1166 
1167   return true;
1168 }
1169 
GetStructMemberTypes(uint32_t struct_type_id,std::vector<uint32_t> * member_types) const1170 bool ValidationState_t::GetStructMemberTypes(
1171     uint32_t struct_type_id, std::vector<uint32_t>* member_types) const {
1172   member_types->clear();
1173   if (!struct_type_id) return false;
1174 
1175   const Instruction* inst = FindDef(struct_type_id);
1176   assert(inst);
1177   if (inst->opcode() != spv::Op::OpTypeStruct) return false;
1178 
1179   *member_types =
1180       std::vector<uint32_t>(inst->words().cbegin() + 2, inst->words().cend());
1181 
1182   if (member_types->empty()) return false;
1183 
1184   return true;
1185 }
1186 
IsPointerType(uint32_t id) const1187 bool ValidationState_t::IsPointerType(uint32_t id) const {
1188   const Instruction* inst = FindDef(id);
1189   assert(inst);
1190   return inst->opcode() == spv::Op::OpTypePointer ||
1191          inst->opcode() == spv::Op::OpTypeUntypedPointerKHR;
1192 }
1193 
GetPointerTypeInfo(uint32_t id,uint32_t * data_type,spv::StorageClass * storage_class) const1194 bool ValidationState_t::GetPointerTypeInfo(
1195     uint32_t id, uint32_t* data_type, spv::StorageClass* storage_class) const {
1196   *storage_class = spv::StorageClass::Max;
1197   if (!id) return false;
1198 
1199   const Instruction* inst = FindDef(id);
1200   assert(inst);
1201   if (inst->opcode() == spv::Op::OpTypeUntypedPointerKHR) {
1202     *storage_class = spv::StorageClass(inst->word(2));
1203     *data_type = 0;
1204     return true;
1205   }
1206 
1207   if (inst->opcode() != spv::Op::OpTypePointer) return false;
1208 
1209   *storage_class = spv::StorageClass(inst->word(2));
1210   *data_type = inst->word(3);
1211   return true;
1212 }
1213 
IsAccelerationStructureType(uint32_t id) const1214 bool ValidationState_t::IsAccelerationStructureType(uint32_t id) const {
1215   const Instruction* inst = FindDef(id);
1216   return inst && inst->opcode() == spv::Op::OpTypeAccelerationStructureKHR;
1217 }
1218 
IsCooperativeMatrixType(uint32_t id) const1219 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
1220   const Instruction* inst = FindDef(id);
1221   return inst && (inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV ||
1222                   inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR);
1223 }
1224 
IsCooperativeMatrixNVType(uint32_t id) const1225 bool ValidationState_t::IsCooperativeMatrixNVType(uint32_t id) const {
1226   const Instruction* inst = FindDef(id);
1227   return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV;
1228 }
1229 
IsCooperativeMatrixKHRType(uint32_t id) const1230 bool ValidationState_t::IsCooperativeMatrixKHRType(uint32_t id) const {
1231   const Instruction* inst = FindDef(id);
1232   return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR;
1233 }
1234 
IsCooperativeMatrixAType(uint32_t id) const1235 bool ValidationState_t::IsCooperativeMatrixAType(uint32_t id) const {
1236   if (!IsCooperativeMatrixKHRType(id)) return false;
1237   const Instruction* inst = FindDef(id);
1238   uint64_t matrixUse = 0;
1239   if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
1240     return matrixUse ==
1241            static_cast<uint64_t>(spv::CooperativeMatrixUse::MatrixAKHR);
1242   }
1243   return false;
1244 }
1245 
IsCooperativeMatrixBType(uint32_t id) const1246 bool ValidationState_t::IsCooperativeMatrixBType(uint32_t id) const {
1247   if (!IsCooperativeMatrixKHRType(id)) return false;
1248   const Instruction* inst = FindDef(id);
1249   uint64_t matrixUse = 0;
1250   if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
1251     return matrixUse ==
1252            static_cast<uint64_t>(spv::CooperativeMatrixUse::MatrixBKHR);
1253   }
1254   return false;
1255 }
IsCooperativeMatrixAccType(uint32_t id) const1256 bool ValidationState_t::IsCooperativeMatrixAccType(uint32_t id) const {
1257   if (!IsCooperativeMatrixKHRType(id)) return false;
1258   const Instruction* inst = FindDef(id);
1259   uint64_t matrixUse = 0;
1260   if (EvalConstantValUint64(inst->word(6), &matrixUse)) {
1261     return matrixUse == static_cast<uint64_t>(
1262                             spv::CooperativeMatrixUse::MatrixAccumulatorKHR);
1263   }
1264   return false;
1265 }
1266 
IsFloatCooperativeMatrixType(uint32_t id) const1267 bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
1268   if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
1269     return false;
1270   return IsFloatScalarType(FindDef(id)->word(2));
1271 }
1272 
IsIntCooperativeMatrixType(uint32_t id) const1273 bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
1274   if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
1275     return false;
1276   return IsIntScalarType(FindDef(id)->word(2));
1277 }
1278 
IsUnsignedIntCooperativeMatrixType(uint32_t id) const1279 bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
1280   if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id))
1281     return false;
1282   return IsUnsignedIntScalarType(FindDef(id)->word(2));
1283 }
1284 
1285 // Either a 32 bit 2-component uint vector or a 64 bit uint scalar
IsUnsigned64BitHandle(uint32_t id) const1286 bool ValidationState_t::IsUnsigned64BitHandle(uint32_t id) const {
1287   return ((IsUnsignedIntScalarType(id) && GetBitWidth(id) == 64) ||
1288           (IsUnsignedIntVectorType(id) && GetDimension(id) == 2 &&
1289            GetBitWidth(id) == 32));
1290 }
1291 
CooperativeMatrixShapesMatch(const Instruction * inst,uint32_t result_type_id,uint32_t m2,bool is_conversion,bool swap_row_col)1292 spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
1293     const Instruction* inst, uint32_t result_type_id, uint32_t m2,
1294     bool is_conversion, bool swap_row_col) {
1295   const auto m1_type = FindDef(result_type_id);
1296   const auto m2_type = FindDef(m2);
1297 
1298   if (m1_type->opcode() != m2_type->opcode()) {
1299     return diag(SPV_ERROR_INVALID_DATA, inst)
1300            << "Expected cooperative matrix types";
1301   }
1302 
1303   uint32_t m1_scope_id = m1_type->GetOperandAs<uint32_t>(2);
1304   uint32_t m1_rows_id = m1_type->GetOperandAs<uint32_t>(3);
1305   uint32_t m1_cols_id = m1_type->GetOperandAs<uint32_t>(4);
1306 
1307   uint32_t m2_scope_id = m2_type->GetOperandAs<uint32_t>(2);
1308   uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
1309   uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
1310 
1311   if (swap_row_col) {
1312     std::swap(m1_rows_id, m1_cols_id);
1313   }
1314 
1315   bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
1316        m2_is_const_int32 = false;
1317   uint32_t m1_value = 0, m2_value = 0;
1318 
1319   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1320       EvalInt32IfConst(m1_scope_id);
1321   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1322       EvalInt32IfConst(m2_scope_id);
1323 
1324   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1325     return diag(SPV_ERROR_INVALID_DATA, inst)
1326            << "Expected scopes of Matrix and Result Type to be "
1327            << "identical";
1328   }
1329 
1330   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1331       EvalInt32IfConst(m1_rows_id);
1332   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1333       EvalInt32IfConst(m2_rows_id);
1334 
1335   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1336     return diag(SPV_ERROR_INVALID_DATA, inst)
1337            << "Expected rows of Matrix type and Result Type to be "
1338            << (swap_row_col ? "swapped with columns" : "identical");
1339   }
1340 
1341   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1342       EvalInt32IfConst(m1_cols_id);
1343   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1344       EvalInt32IfConst(m2_cols_id);
1345 
1346   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1347     return diag(SPV_ERROR_INVALID_DATA, inst)
1348            << "Expected columns of Matrix type and Result Type to be "
1349            << (swap_row_col ? "swapped with rows" : "identical");
1350   }
1351 
1352   if (m1_type->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) {
1353     uint32_t m1_use_id = m1_type->GetOperandAs<uint32_t>(5);
1354     uint32_t m2_use_id = m2_type->GetOperandAs<uint32_t>(5);
1355     std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1356         EvalInt32IfConst(m1_use_id);
1357     std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1358         EvalInt32IfConst(m2_use_id);
1359 
1360     if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value &&
1361         // CooperativeMatrixConversionsNV allows conversions from Acc->A/B
1362         !(is_conversion &&
1363           HasCapability(spv::Capability::CooperativeMatrixConversionsNV) &&
1364           m2_value ==
1365               (uint32_t)spv::CooperativeMatrixUse::MatrixAccumulatorKHR)) {
1366       return diag(SPV_ERROR_INVALID_DATA, inst)
1367              << "Expected Use of Matrix type and Result Type to be "
1368              << "identical";
1369     }
1370   }
1371 
1372   return SPV_SUCCESS;
1373 }
1374 
GetOperandTypeId(const Instruction * inst,size_t operand_index) const1375 uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst,
1376                                              size_t operand_index) const {
1377   return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
1378 }
1379 
EvalConstantValUint64(uint32_t id,uint64_t * val) const1380 bool ValidationState_t::EvalConstantValUint64(uint32_t id,
1381                                               uint64_t* val) const {
1382   const Instruction* inst = FindDef(id);
1383   if (!inst) {
1384     assert(0 && "Instruction not found");
1385     return false;
1386   }
1387 
1388   if (!IsIntScalarType(inst->type_id())) return false;
1389 
1390   if (inst->opcode() == spv::Op::OpConstantNull) {
1391     *val = 0;
1392   } else if (inst->opcode() != spv::Op::OpConstant) {
1393     // Spec constant values cannot be evaluated so don't consider constant for
1394     // static validation
1395     return false;
1396   } else if (inst->words().size() == 4) {
1397     *val = inst->word(3);
1398   } else {
1399     assert(inst->words().size() == 5);
1400     *val = inst->word(3);
1401     *val |= uint64_t(inst->word(4)) << 32;
1402   }
1403   return true;
1404 }
1405 
EvalConstantValInt64(uint32_t id,int64_t * val) const1406 bool ValidationState_t::EvalConstantValInt64(uint32_t id, int64_t* val) const {
1407   const Instruction* inst = FindDef(id);
1408   if (!inst) {
1409     assert(0 && "Instruction not found");
1410     return false;
1411   }
1412 
1413   if (!IsIntScalarType(inst->type_id())) return false;
1414 
1415   if (inst->opcode() == spv::Op::OpConstantNull) {
1416     *val = 0;
1417   } else if (inst->opcode() != spv::Op::OpConstant) {
1418     // Spec constant values cannot be evaluated so don't consider constant for
1419     // static validation
1420     return false;
1421   } else if (inst->words().size() == 4) {
1422     *val = int32_t(inst->word(3));
1423   } else {
1424     assert(inst->words().size() == 5);
1425     const uint32_t lo_word = inst->word(3);
1426     const uint32_t hi_word = inst->word(4);
1427     *val = static_cast<int64_t>(uint64_t(lo_word) | uint64_t(hi_word) << 32);
1428   }
1429   return true;
1430 }
1431 
EvalInt32IfConst(uint32_t id) const1432 std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
1433     uint32_t id) const {
1434   const Instruction* const inst = FindDef(id);
1435   assert(inst);
1436   const uint32_t type = inst->type_id();
1437 
1438   if (type == 0 || !IsIntScalarType(type) || GetBitWidth(type) != 32) {
1439     return std::make_tuple(false, false, 0);
1440   }
1441 
1442   // Spec constant values cannot be evaluated so don't consider constant for
1443   // the purpose of this method.
1444   if (!spvOpcodeIsConstant(inst->opcode()) ||
1445       spvOpcodeIsSpecConstant(inst->opcode())) {
1446     return std::make_tuple(true, false, 0);
1447   }
1448 
1449   if (inst->opcode() == spv::Op::OpConstantNull) {
1450     return std::make_tuple(true, true, 0);
1451   }
1452 
1453   assert(inst->words().size() == 4);
1454   return std::make_tuple(true, true, inst->word(3));
1455 }
1456 
ComputeFunctionToEntryPointMapping()1457 void ValidationState_t::ComputeFunctionToEntryPointMapping() {
1458   for (const uint32_t entry_point : entry_points()) {
1459     std::stack<uint32_t> call_stack;
1460     std::set<uint32_t> visited;
1461     call_stack.push(entry_point);
1462     while (!call_stack.empty()) {
1463       const uint32_t called_func_id = call_stack.top();
1464       call_stack.pop();
1465       if (!visited.insert(called_func_id).second) continue;
1466 
1467       function_to_entry_points_[called_func_id].push_back(entry_point);
1468 
1469       const Function* called_func = function(called_func_id);
1470       if (called_func) {
1471         // Other checks should error out on this invalid SPIR-V.
1472         for (const uint32_t new_call : called_func->function_call_targets()) {
1473           call_stack.push(new_call);
1474         }
1475       }
1476     }
1477   }
1478 }
1479 
ComputeRecursiveEntryPoints()1480 void ValidationState_t::ComputeRecursiveEntryPoints() {
1481   for (const Function& func : functions()) {
1482     std::stack<uint32_t> call_stack;
1483     std::set<uint32_t> visited;
1484 
1485     for (const uint32_t new_call : func.function_call_targets()) {
1486       call_stack.push(new_call);
1487     }
1488 
1489     while (!call_stack.empty()) {
1490       const uint32_t called_func_id = call_stack.top();
1491       call_stack.pop();
1492 
1493       if (!visited.insert(called_func_id).second) continue;
1494 
1495       if (called_func_id == func.id()) {
1496         for (const uint32_t entry_point :
1497              function_to_entry_points_[called_func_id])
1498           recursive_entry_points_.insert(entry_point);
1499         break;
1500       }
1501 
1502       const Function* called_func = function(called_func_id);
1503       if (called_func) {
1504         // Other checks should error out on this invalid SPIR-V.
1505         for (const uint32_t new_call : called_func->function_call_targets()) {
1506           call_stack.push(new_call);
1507         }
1508       }
1509     }
1510   }
1511 }
1512 
FunctionEntryPoints(uint32_t func) const1513 const std::vector<uint32_t>& ValidationState_t::FunctionEntryPoints(
1514     uint32_t func) const {
1515   auto iter = function_to_entry_points_.find(func);
1516   if (iter == function_to_entry_points_.end()) {
1517     return empty_ids_;
1518   } else {
1519     return iter->second;
1520   }
1521 }
1522 
EntryPointReferences(uint32_t id) const1523 std::set<uint32_t> ValidationState_t::EntryPointReferences(uint32_t id) const {
1524   std::set<uint32_t> referenced_entry_points;
1525   const auto inst = FindDef(id);
1526   if (!inst) return referenced_entry_points;
1527 
1528   std::vector<const Instruction*> stack;
1529   stack.push_back(inst);
1530   while (!stack.empty()) {
1531     const auto current_inst = stack.back();
1532     stack.pop_back();
1533 
1534     if (const auto func = current_inst->function()) {
1535       // Instruction lives in a function, we can stop searching.
1536       const auto function_entry_points = FunctionEntryPoints(func->id());
1537       referenced_entry_points.insert(function_entry_points.begin(),
1538                                      function_entry_points.end());
1539     } else {
1540       // Instruction is in the global scope, keep searching its uses.
1541       for (auto pair : current_inst->uses()) {
1542         const auto next_inst = pair.first;
1543         stack.push_back(next_inst);
1544       }
1545     }
1546   }
1547 
1548   return referenced_entry_points;
1549 }
1550 
Disassemble(const Instruction & inst) const1551 std::string ValidationState_t::Disassemble(const Instruction& inst) const {
1552   const spv_parsed_instruction_t& c_inst(inst.c_inst());
1553   return Disassemble(c_inst.words, c_inst.num_words);
1554 }
1555 
Disassemble(const uint32_t * words,uint16_t num_words) const1556 std::string ValidationState_t::Disassemble(const uint32_t* words,
1557                                            uint16_t num_words) const {
1558   uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1559                                  SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
1560 
1561   return spvInstructionBinaryToText(context()->target_env, words, num_words,
1562                                     words_, num_words_, disassembly_options);
1563 }
1564 
LogicallyMatch(const Instruction * lhs,const Instruction * rhs,bool check_decorations)1565 bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
1566                                        const Instruction* rhs,
1567                                        bool check_decorations) {
1568   if (lhs->opcode() != rhs->opcode()) {
1569     return false;
1570   }
1571 
1572   if (check_decorations) {
1573     const auto& dec_a = id_decorations(lhs->id());
1574     const auto& dec_b = id_decorations(rhs->id());
1575 
1576     for (const auto& dec : dec_b) {
1577       if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) {
1578         return false;
1579       }
1580     }
1581   }
1582 
1583   if (lhs->opcode() == spv::Op::OpTypeArray) {
1584     // Size operands must match.
1585     if (lhs->GetOperandAs<uint32_t>(2u) != rhs->GetOperandAs<uint32_t>(2u)) {
1586       return false;
1587     }
1588 
1589     // Elements must match or logically match.
1590     const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(1u);
1591     const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(1u);
1592     if (lhs_ele_id == rhs_ele_id) {
1593       return true;
1594     }
1595 
1596     const auto lhs_ele = FindDef(lhs_ele_id);
1597     const auto rhs_ele = FindDef(rhs_ele_id);
1598     if (!lhs_ele || !rhs_ele) {
1599       return false;
1600     }
1601     return LogicallyMatch(lhs_ele, rhs_ele, check_decorations);
1602   } else if (lhs->opcode() == spv::Op::OpTypeStruct) {
1603     // Number of elements must match.
1604     if (lhs->operands().size() != rhs->operands().size()) {
1605       return false;
1606     }
1607 
1608     for (size_t i = 1u; i < lhs->operands().size(); ++i) {
1609       const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(i);
1610       const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(i);
1611       // Elements must match or logically match.
1612       if (lhs_ele_id == rhs_ele_id) {
1613         continue;
1614       }
1615 
1616       const auto lhs_ele = FindDef(lhs_ele_id);
1617       const auto rhs_ele = FindDef(rhs_ele_id);
1618       if (!lhs_ele || !rhs_ele) {
1619         return false;
1620       }
1621 
1622       if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) {
1623         return false;
1624       }
1625     }
1626 
1627     // All checks passed.
1628     return true;
1629   }
1630 
1631   // No other opcodes are acceptable at this point. Arrays and structs are
1632   // caught above and if they're elements are not arrays or structs they are
1633   // required to match exactly.
1634   return false;
1635 }
1636 
TracePointer(const Instruction * inst) const1637 const Instruction* ValidationState_t::TracePointer(
1638     const Instruction* inst) const {
1639   auto base_ptr = inst;
1640   while (base_ptr->opcode() == spv::Op::OpAccessChain ||
1641          base_ptr->opcode() == spv::Op::OpInBoundsAccessChain ||
1642          base_ptr->opcode() == spv::Op::OpPtrAccessChain ||
1643          base_ptr->opcode() == spv::Op::OpInBoundsPtrAccessChain ||
1644          base_ptr->opcode() == spv::Op::OpCopyObject) {
1645     base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
1646   }
1647   return base_ptr;
1648 }
1649 
ContainsType(uint32_t id,const std::function<bool (const Instruction *)> & f,bool traverse_all_types) const1650 bool ValidationState_t::ContainsType(
1651     uint32_t id, const std::function<bool(const Instruction*)>& f,
1652     bool traverse_all_types) const {
1653   const auto inst = FindDef(id);
1654   if (!inst) return false;
1655 
1656   if (f(inst)) return true;
1657 
1658   switch (inst->opcode()) {
1659     case spv::Op::OpTypeArray:
1660     case spv::Op::OpTypeRuntimeArray:
1661     case spv::Op::OpTypeVector:
1662     case spv::Op::OpTypeMatrix:
1663     case spv::Op::OpTypeImage:
1664     case spv::Op::OpTypeSampledImage:
1665     case spv::Op::OpTypeCooperativeMatrixNV:
1666     case spv::Op::OpTypeCooperativeMatrixKHR:
1667       return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
1668                           traverse_all_types);
1669     case spv::Op::OpTypePointer:
1670       if (IsForwardPointer(id)) return false;
1671       if (traverse_all_types) {
1672         return ContainsType(inst->GetOperandAs<uint32_t>(2u), f,
1673                             traverse_all_types);
1674       }
1675       break;
1676     case spv::Op::OpTypeFunction:
1677     case spv::Op::OpTypeStruct:
1678       if (inst->opcode() == spv::Op::OpTypeFunction && !traverse_all_types) {
1679         return false;
1680       }
1681       for (uint32_t i = 1; i < inst->operands().size(); ++i) {
1682         if (ContainsType(inst->GetOperandAs<uint32_t>(i), f,
1683                          traverse_all_types)) {
1684           return true;
1685         }
1686       }
1687       break;
1688     default:
1689       break;
1690   }
1691 
1692   return false;
1693 }
1694 
ContainsSizedIntOrFloatType(uint32_t id,spv::Op type,uint32_t width) const1695 bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, spv::Op type,
1696                                                     uint32_t width) const {
1697   if (type != spv::Op::OpTypeInt && type != spv::Op::OpTypeFloat) return false;
1698 
1699   const auto f = [type, width](const Instruction* inst) {
1700     if (inst->opcode() == type) {
1701       return inst->GetOperandAs<uint32_t>(1u) == width;
1702     }
1703     return false;
1704   };
1705   return ContainsType(id, f);
1706 }
1707 
ContainsLimitedUseIntOrFloatType(uint32_t id) const1708 bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
1709   if ((!HasCapability(spv::Capability::Int16) &&
1710        ContainsSizedIntOrFloatType(id, spv::Op::OpTypeInt, 16)) ||
1711       (!HasCapability(spv::Capability::Int8) &&
1712        ContainsSizedIntOrFloatType(id, spv::Op::OpTypeInt, 8)) ||
1713       (!HasCapability(spv::Capability::Float16) &&
1714        ContainsSizedIntOrFloatType(id, spv::Op::OpTypeFloat, 16))) {
1715     return true;
1716   }
1717   return false;
1718 }
1719 
ContainsRuntimeArray(uint32_t id) const1720 bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const {
1721   const auto f = [](const Instruction* inst) {
1722     return inst->opcode() == spv::Op::OpTypeRuntimeArray;
1723   };
1724   return ContainsType(id, f, /* traverse_all_types = */ false);
1725 }
1726 
ContainsUntypedPointer(uint32_t id) const1727 bool ValidationState_t::ContainsUntypedPointer(uint32_t id) const {
1728   const auto inst = FindDef(id);
1729   if (!inst) return false;
1730   if (!spvOpcodeGeneratesType(inst->opcode())) return false;
1731   if (inst->opcode() == spv::Op::OpTypeUntypedPointerKHR) return true;
1732 
1733   switch (inst->opcode()) {
1734     case spv::Op::OpTypeArray:
1735     case spv::Op::OpTypeRuntimeArray:
1736     case spv::Op::OpTypeVector:
1737     case spv::Op::OpTypeMatrix:
1738     case spv::Op::OpTypeImage:
1739     case spv::Op::OpTypeSampledImage:
1740     case spv::Op::OpTypeCooperativeMatrixNV:
1741       return ContainsUntypedPointer(inst->GetOperandAs<uint32_t>(1u));
1742     case spv::Op::OpTypePointer:
1743       if (IsForwardPointer(id)) return false;
1744       return ContainsUntypedPointer(inst->GetOperandAs<uint32_t>(2u));
1745     case spv::Op::OpTypeFunction:
1746     case spv::Op::OpTypeStruct: {
1747       for (uint32_t i = 1; i < inst->operands().size(); ++i) {
1748         if (ContainsUntypedPointer(inst->GetOperandAs<uint32_t>(i)))
1749           return true;
1750       }
1751       return false;
1752     }
1753     default:
1754       return false;
1755   }
1756 
1757   return false;
1758 }
1759 
IsValidStorageClass(spv::StorageClass storage_class) const1760 bool ValidationState_t::IsValidStorageClass(
1761     spv::StorageClass storage_class) const {
1762   if (spvIsVulkanEnv(context()->target_env)) {
1763     switch (storage_class) {
1764       case spv::StorageClass::UniformConstant:
1765       case spv::StorageClass::Uniform:
1766       case spv::StorageClass::StorageBuffer:
1767       case spv::StorageClass::Input:
1768       case spv::StorageClass::Output:
1769       case spv::StorageClass::Image:
1770       case spv::StorageClass::Workgroup:
1771       case spv::StorageClass::Private:
1772       case spv::StorageClass::Function:
1773       case spv::StorageClass::PushConstant:
1774       case spv::StorageClass::PhysicalStorageBuffer:
1775       case spv::StorageClass::RayPayloadKHR:
1776       case spv::StorageClass::IncomingRayPayloadKHR:
1777       case spv::StorageClass::HitAttributeKHR:
1778       case spv::StorageClass::CallableDataKHR:
1779       case spv::StorageClass::IncomingCallableDataKHR:
1780       case spv::StorageClass::ShaderRecordBufferKHR:
1781       case spv::StorageClass::TaskPayloadWorkgroupEXT:
1782       case spv::StorageClass::HitObjectAttributeNV:
1783       case spv::StorageClass::TileImageEXT:
1784         return true;
1785       default:
1786         return false;
1787     }
1788   }
1789 
1790   return true;
1791 }
1792 
1793 #define VUID_WRAP(vuid) "[" #vuid "] "
1794 
1795 // Currently no 2 VUID share the same id, so no need for |reference|
VkErrorID(uint32_t id,const char *) const1796 std::string ValidationState_t::VkErrorID(uint32_t id,
1797                                          const char* /*reference*/) const {
1798   if (!spvIsVulkanEnv(context_->target_env)) {
1799     return "";
1800   }
1801 
1802   // This large switch case is only searched when an error has occurred.
1803   // If an id is changed, the old case must be modified or removed. Each string
1804   // here is interpreted as being "implemented"
1805 
1806   // Clang format adds spaces between hyphens
1807   // clang-format off
1808   switch (id) {
1809     case 4154:
1810       return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04154);
1811     case 4155:
1812       return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04155);
1813     case 4156:
1814       return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04156);
1815     case 4160:
1816       return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04160);
1817     case 4161:
1818       return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04161);
1819     case 4162:
1820       return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04162);
1821     case 4181:
1822       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04181);
1823     case 4182:
1824       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04182);
1825     case 4183:
1826       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04183);
1827     case 4184:
1828       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04184);
1829     case 4185:
1830       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04185);
1831     case 4186:
1832       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186);
1833     case 4187:
1834       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187);
1835     case 4188:
1836       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188);
1837     case 4189:
1838       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189);
1839     case 4190:
1840       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190);
1841     case 4191:
1842       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191);
1843     case 4196:
1844       return VUID_WRAP(VUID-CullDistance-CullDistance-04196);
1845     case 4197:
1846       return VUID_WRAP(VUID-CullDistance-CullDistance-04197);
1847     case 4198:
1848       return VUID_WRAP(VUID-CullDistance-CullDistance-04198);
1849     case 4199:
1850       return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
1851     case 4200:
1852       return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
1853     case 6735:
1854       return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06735); // Execution Model
1855     case 6736:
1856       return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06736); // input storage
1857     case 6737:
1858       return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06737); // 32 int scalar
1859     case 4205:
1860       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04205);
1861     case 4206:
1862       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04206);
1863     case 4207:
1864       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04207);
1865     case 4208:
1866       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04208);
1867     case 4209:
1868       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04209);
1869     case 4210:
1870       return VUID_WRAP(VUID-FragCoord-FragCoord-04210);
1871     case 4211:
1872       return VUID_WRAP(VUID-FragCoord-FragCoord-04211);
1873     case 4212:
1874       return VUID_WRAP(VUID-FragCoord-FragCoord-04212);
1875     case 4213:
1876       return VUID_WRAP(VUID-FragDepth-FragDepth-04213);
1877     case 4214:
1878       return VUID_WRAP(VUID-FragDepth-FragDepth-04214);
1879     case 4215:
1880       return VUID_WRAP(VUID-FragDepth-FragDepth-04215);
1881     case 4216:
1882       return VUID_WRAP(VUID-FragDepth-FragDepth-04216);
1883     case 4217:
1884       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217);
1885     case 4218:
1886       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218);
1887     case 4219:
1888       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219);
1889     case 4220:
1890       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220);
1891     case 4221:
1892       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221);
1893     case 4222:
1894       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222);
1895     case 4223:
1896       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223);
1897     case 4224:
1898       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224);
1899     case 4225:
1900       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225);
1901     case 4229:
1902       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229);
1903     case 4230:
1904       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230);
1905     case 4231:
1906       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231);
1907     case 4232:
1908       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232);
1909     case 4233:
1910       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233);
1911     case 4234:
1912       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234);
1913     case 4236:
1914       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236);
1915     case 4237:
1916       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04237);
1917     case 4238:
1918       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04238);
1919     case 4239:
1920       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04239);
1921     case 4240:
1922       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
1923     case 4241:
1924       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
1925     case 4242:
1926       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
1927     case 4243:
1928       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
1929     case 4244:
1930       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
1931     case 4245:
1932       return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
1933     case 4246:
1934       return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
1935     case 4247:
1936       return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
1937     case 4248:
1938       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
1939     case 4249:
1940       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
1941     case 4250:
1942       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
1943     case 4251:
1944       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
1945     case 4252:
1946       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
1947     case 4253:
1948       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
1949     case 4254:
1950       return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
1951     case 4255:
1952       return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
1953     case 4256:
1954       return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
1955     case 4257:
1956       return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
1957     case 4258:
1958       return VUID_WRAP(VUID-InvocationId-InvocationId-04258);
1959     case 4259:
1960       return VUID_WRAP(VUID-InvocationId-InvocationId-04259);
1961     case 4263:
1962       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04263);
1963     case 4264:
1964       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
1965     case 4265:
1966       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
1967     case 4266:
1968       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
1969     case 4267:
1970       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
1971     case 4268:
1972       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
1973     case 4269:
1974       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
1975     case 4270:
1976       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
1977     case 4271:
1978       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
1979     case 4272:
1980       return VUID_WRAP(VUID-Layer-Layer-04272);
1981     case 4273:
1982       return VUID_WRAP(VUID-Layer-Layer-04273);
1983     case 4274:
1984       return VUID_WRAP(VUID-Layer-Layer-04274);
1985     case 4275:
1986       return VUID_WRAP(VUID-Layer-Layer-04275);
1987     case 4276:
1988       return VUID_WRAP(VUID-Layer-Layer-04276);
1989     case 4281:
1990       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04281);
1991     case 4282:
1992       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
1993     case 4283:
1994       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
1995     case 4293:
1996       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
1997     case 4294:
1998       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294);
1999     case 4295:
2000       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295);
2001     case 4296:
2002       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296);
2003     case 4297:
2004       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
2005     case 4298:
2006       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
2007     case 4299:
2008       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
2009     case 4300:
2010       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
2011     case 4301:
2012       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
2013     case 4302:
2014       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
2015     case 4303:
2016       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
2017     case 4304:
2018       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
2019     case 4305:
2020       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
2021     case 4306:
2022       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
2023     case 4307:
2024       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
2025     case 4308:
2026       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
2027     case 4309:
2028       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04309);
2029     case 4310:
2030       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04310);
2031     case 4311:
2032       return VUID_WRAP(VUID-PointCoord-PointCoord-04311);
2033     case 4312:
2034       return VUID_WRAP(VUID-PointCoord-PointCoord-04312);
2035     case 4313:
2036       return VUID_WRAP(VUID-PointCoord-PointCoord-04313);
2037     case 4314:
2038       return VUID_WRAP(VUID-PointSize-PointSize-04314);
2039     case 4315:
2040       return VUID_WRAP(VUID-PointSize-PointSize-04315);
2041     case 4316:
2042       return VUID_WRAP(VUID-PointSize-PointSize-04316);
2043     case 4317:
2044       return VUID_WRAP(VUID-PointSize-PointSize-04317);
2045     case 4318:
2046       return VUID_WRAP(VUID-Position-Position-04318);
2047     case 4319:
2048       return VUID_WRAP(VUID-Position-Position-04319);
2049     case 4320:
2050       return VUID_WRAP(VUID-Position-Position-04320);
2051     case 4321:
2052       return VUID_WRAP(VUID-Position-Position-04321);
2053     case 4330:
2054       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330);
2055     case 4334:
2056       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
2057     case 4337:
2058       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
2059     case 4345:
2060       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
2061     case 4346:
2062       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
2063     case 4347:
2064       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
2065     case 4348:
2066       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
2067     case 4349:
2068       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
2069     case 4350:
2070       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
2071     case 4351:
2072       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
2073     case 4352:
2074       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
2075     case 4353:
2076       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
2077     case 4354:
2078       return VUID_WRAP(VUID-SampleId-SampleId-04354);
2079     case 4355:
2080       return VUID_WRAP(VUID-SampleId-SampleId-04355);
2081     case 4356:
2082       return VUID_WRAP(VUID-SampleId-SampleId-04356);
2083     case 4357:
2084       return VUID_WRAP(VUID-SampleMask-SampleMask-04357);
2085     case 4358:
2086       return VUID_WRAP(VUID-SampleMask-SampleMask-04358);
2087     case 4359:
2088       return VUID_WRAP(VUID-SampleMask-SampleMask-04359);
2089     case 4360:
2090       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04360);
2091     case 4361:
2092       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361);
2093     case 4362:
2094       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362);
2095     case 4367:
2096       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367);
2097     case 4368:
2098       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368);
2099     case 4369:
2100       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369);
2101     case 4370:
2102       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370);
2103     case 4371:
2104       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371);
2105     case 4372:
2106       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372);
2107     case 4373:
2108       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373);
2109     case 4374:
2110       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374);
2111     case 4375:
2112       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375);
2113     case 4376:
2114       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376);
2115     case 4377:
2116       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377);
2117     case 4378:
2118       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378);
2119     case 4379:
2120       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379);
2121     case 4380:
2122       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380);
2123     case 4381:
2124       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381);
2125     case 4382:
2126       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382);
2127     case 4383:
2128       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383);
2129     case 4387:
2130       return VUID_WRAP(VUID-TessCoord-TessCoord-04387);
2131     case 4388:
2132       return VUID_WRAP(VUID-TessCoord-TessCoord-04388);
2133     case 4389:
2134       return VUID_WRAP(VUID-TessCoord-TessCoord-04389);
2135     case 4390:
2136       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390);
2137     case 4391:
2138       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391);
2139     case 4392:
2140       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392);
2141     case 4393:
2142       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393);
2143     case 4394:
2144       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394);
2145     case 4395:
2146       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395);
2147     case 4396:
2148       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396);
2149     case 4397:
2150       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397);
2151     case 4398:
2152       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04398);
2153     case 4399:
2154       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04399);
2155     case 4400:
2156       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04400);
2157     case 4401:
2158       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04401);
2159     case 4402:
2160       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04402);
2161     case 4403:
2162       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403);
2163     case 4404:
2164       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404);
2165     case 4405:
2166       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405);
2167     case 4406:
2168       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406);
2169     case 4407:
2170       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04407);
2171     case 4408:
2172       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04408);
2173     case 4422:
2174       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04422);
2175     case 4423:
2176       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04423);
2177     case 4424:
2178       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04424);
2179     case 4425:
2180       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04425);
2181     case 4426:
2182       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
2183     case 4427:
2184       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
2185     case 4428:
2186       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
2187     case 4429:
2188       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
2189     case 4430:
2190       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
2191     case 4431:
2192       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
2193     case 4432:
2194       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
2195     case 4433:
2196       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
2197     case 4434:
2198       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
2199     case 4435:
2200       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
2201     case 4436:
2202       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
2203     case 4484:
2204       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
2205     case 4485:
2206       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485);
2207     case 4486:
2208       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04486);
2209     case 4490:
2210       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04490);
2211     case 4491:
2212       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491);
2213     case 4492:
2214       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492);
2215     case 4633:
2216       return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
2217     case 4634:
2218       return VUID_WRAP(VUID-StandaloneSpirv-None-04634);
2219     case 4635:
2220       return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
2221     case 4636:
2222       return VUID_WRAP(VUID-StandaloneSpirv-None-04636);
2223     case 4637:
2224       return VUID_WRAP(VUID-StandaloneSpirv-None-04637);
2225     case 4638:
2226       return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
2227     case 7321:
2228       return VUID_WRAP(VUID-StandaloneSpirv-None-07321);
2229     case 4640:
2230       return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
2231     case 4641:
2232       return VUID_WRAP(VUID-StandaloneSpirv-None-04641);
2233     case 4642:
2234       return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
2235     case 4643:
2236       return VUID_WRAP(VUID-StandaloneSpirv-None-04643);
2237     case 4644:
2238       return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
2239     case 4645:
2240       return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
2241     case 4650:
2242       return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04650);
2243     case 4651:
2244       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
2245     case 4652:
2246       return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652);
2247     case 4653:
2248       return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
2249     case 4654:
2250       return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
2251     case 4655:
2252       return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655);
2253     case 4656:
2254       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
2255     case 4657:
2256       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
2257     case 4658:
2258       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
2259     case 4659:
2260       return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
2261     case 4663:
2262       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
2263     case 4664:
2264       return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664);
2265     case 4667:
2266       return VUID_WRAP(VUID-StandaloneSpirv-None-04667);
2267     case 4669:
2268       return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
2269     case 4670:
2270       return VUID_WRAP(VUID-StandaloneSpirv-Flat-04670);
2271     case 4675:
2272       return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
2273     case 4677:
2274       return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
2275     case 4680:
2276       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeRuntimeArray-04680);
2277     case 4682:
2278       return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
2279     case 6426:
2280       return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-06426); // formally 04683
2281     case 4685:
2282       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
2283     case 4686:
2284       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
2285     case 4698:
2286       return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698);
2287     case 4699:
2288       return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699);
2289     case 4700:
2290       return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04700);
2291     case 4701:
2292       return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701);
2293     case 4702:
2294       return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04702);
2295     case 4703:
2296       return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703);
2297     case 4704:
2298       return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704);
2299     case 4705:
2300       return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705);
2301     case 4706:
2302       return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04706);
2303     case 7119:
2304       return VUID_WRAP(VUID-StandaloneSpirv-ShaderRecordBufferKHR-07119);
2305     case 4708:
2306       return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708);
2307     case 4710:
2308       return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
2309     case 4711:
2310       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
2311     case 4730:
2312       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730);
2313     case 4731:
2314       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731);
2315     case 4732:
2316       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
2317     case 4733:
2318       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
2319     case 4734:
2320       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734);
2321     case 4744:
2322       return VUID_WRAP(VUID-StandaloneSpirv-Flat-04744);
2323     case 4777:
2324       return VUID_WRAP(VUID-StandaloneSpirv-OpImage-04777);
2325     case 4780:
2326       return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
2327     case 4781:
2328       return VUID_WRAP(VUID-StandaloneSpirv-Base-04781);
2329     case 4915:
2330       return VUID_WRAP(VUID-StandaloneSpirv-Location-04915);
2331     case 4916:
2332       return VUID_WRAP(VUID-StandaloneSpirv-Location-04916);
2333     case 4917:
2334       return VUID_WRAP(VUID-StandaloneSpirv-Location-04917);
2335     case 4918:
2336       return VUID_WRAP(VUID-StandaloneSpirv-Location-04918);
2337     case 4919:
2338       return VUID_WRAP(VUID-StandaloneSpirv-Location-04919);
2339     case 4920:
2340       return VUID_WRAP(VUID-StandaloneSpirv-Component-04920);
2341     case 4921:
2342       return VUID_WRAP(VUID-StandaloneSpirv-Component-04921);
2343     case 4922:
2344       return VUID_WRAP(VUID-StandaloneSpirv-Component-04922);
2345     case 4923:
2346       return VUID_WRAP(VUID-StandaloneSpirv-Component-04923);
2347     case 4924:
2348       return VUID_WRAP(VUID-StandaloneSpirv-Component-04924);
2349     case 6201:
2350       return VUID_WRAP(VUID-StandaloneSpirv-Flat-06201);
2351     case 6202:
2352       return VUID_WRAP(VUID-StandaloneSpirv-Flat-06202);
2353     case 6214:
2354       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214);
2355     case 6491:
2356       return VUID_WRAP(VUID-StandaloneSpirv-DescriptorSet-06491);
2357     case 6671:
2358       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeSampledImage-06671);
2359     case 6672:
2360       return VUID_WRAP(VUID-StandaloneSpirv-Location-06672);
2361     case 6673:
2362       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-06673);
2363     case 6674:
2364       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-06674);
2365     case 6675:
2366       return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06675);
2367     case 6676:
2368       return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06676);
2369     case 6677:
2370       return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-06677);
2371     case 6678:
2372       return VUID_WRAP(VUID-StandaloneSpirv-InputAttachmentIndex-06678);
2373     case 6777:
2374       return VUID_WRAP(VUID-StandaloneSpirv-PerVertexKHR-06777);
2375     case 6778:
2376       return VUID_WRAP(VUID-StandaloneSpirv-Input-06778);
2377     case 6807:
2378       return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06807);
2379     case 6808:
2380       return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
2381     case 6924:
2382       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06924);
2383     case 6925:
2384       return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
2385     case 7041:
2386       return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041);
2387     case 7043:
2388       return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043);
2389     case 7044:
2390       return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044);
2391     case 7047:
2392       return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047);
2393     case 7049:
2394       return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049);
2395     case 7050:
2396       return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050);
2397     case 7053:
2398       return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053);
2399     case 7055:
2400       return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055);
2401     case 7056:
2402       return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056);
2403     case 7102:
2404       return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
2405     case 7320:
2406       return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07320);
2407     case 7290:
2408       return VUID_WRAP(VUID-StandaloneSpirv-Input-07290);
2409     case 7650:
2410       return VUID_WRAP(VUID-StandaloneSpirv-Base-07650);
2411     case 7651:
2412       return VUID_WRAP(VUID-StandaloneSpirv-Base-07651);
2413     case 7652:
2414       return VUID_WRAP(VUID-StandaloneSpirv-Base-07652);
2415     case 7703:
2416       return VUID_WRAP(VUID-StandaloneSpirv-Component-07703);
2417     case 7951:
2418       return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-07951);
2419     case 8721:
2420       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08721);
2421     case 8722:
2422       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722);
2423     case 8973:
2424       return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973);
2425     case 9638:
2426       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-09638);
2427     case 9658:
2428       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-09658);
2429     case 9659:
2430       return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-09659);
2431     default:
2432       return "";  // unknown id
2433   }
2434   // clang-format on
2435 }
2436 
2437 }  // namespace val
2438 }  // namespace spvtools
2439