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