• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/val/validation_state.h"
16 
17 #include <cassert>
18 #include <stack>
19 #include <utility>
20 
21 #include "source/opcode.h"
22 #include "source/spirv_constant.h"
23 #include "source/spirv_target_env.h"
24 #include "source/val/basic_block.h"
25 #include "source/val/construct.h"
26 #include "source/val/function.h"
27 #include "spirv-tools/libspirv.h"
28 
29 namespace spvtools {
30 namespace val {
31 namespace {
32 
InstructionLayoutSection(ModuleLayoutSection current_section,SpvOp op)33 ModuleLayoutSection InstructionLayoutSection(
34     ModuleLayoutSection current_section, SpvOp op) {
35   // See Section 2.4
36   if (spvOpcodeGeneratesType(op) || spvOpcodeIsConstant(op))
37     return kLayoutTypes;
38 
39   switch (op) {
40     case SpvOpCapability:
41       return kLayoutCapabilities;
42     case SpvOpExtension:
43       return kLayoutExtensions;
44     case SpvOpExtInstImport:
45       return kLayoutExtInstImport;
46     case SpvOpMemoryModel:
47       return kLayoutMemoryModel;
48     case SpvOpEntryPoint:
49       return kLayoutEntryPoint;
50     case SpvOpExecutionMode:
51     case SpvOpExecutionModeId:
52       return kLayoutExecutionMode;
53     case SpvOpSourceContinued:
54     case SpvOpSource:
55     case SpvOpSourceExtension:
56     case SpvOpString:
57       return kLayoutDebug1;
58     case SpvOpName:
59     case SpvOpMemberName:
60       return kLayoutDebug2;
61     case SpvOpModuleProcessed:
62       return kLayoutDebug3;
63     case SpvOpDecorate:
64     case SpvOpMemberDecorate:
65     case SpvOpGroupDecorate:
66     case SpvOpGroupMemberDecorate:
67     case SpvOpDecorationGroup:
68     case SpvOpDecorateId:
69     case SpvOpDecorateStringGOOGLE:
70     case SpvOpMemberDecorateStringGOOGLE:
71       return kLayoutAnnotations;
72     case SpvOpTypeForwardPointer:
73       return kLayoutTypes;
74     case SpvOpVariable:
75       if (current_section == kLayoutTypes) return kLayoutTypes;
76       return kLayoutFunctionDefinitions;
77     case SpvOpExtInst:
78       // SpvOpExtInst is only allowed in types section for certain extended
79       // instruction sets. This will be checked separately.
80       if (current_section == kLayoutTypes) return kLayoutTypes;
81       return kLayoutFunctionDefinitions;
82     case SpvOpLine:
83     case SpvOpNoLine:
84     case SpvOpUndef:
85       if (current_section == kLayoutTypes) return kLayoutTypes;
86       return kLayoutFunctionDefinitions;
87     case SpvOpFunction:
88     case SpvOpFunctionParameter:
89     case SpvOpFunctionEnd:
90       if (current_section == kLayoutFunctionDeclarations)
91         return kLayoutFunctionDeclarations;
92       return kLayoutFunctionDefinitions;
93     default:
94       break;
95   }
96   return kLayoutFunctionDefinitions;
97 }
98 
IsInstructionInLayoutSection(ModuleLayoutSection layout,SpvOp op)99 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
100   return layout == InstructionLayoutSection(layout, op);
101 }
102 
103 // Counts the number of instructions and functions in the file.
CountInstructions(void * user_data,const spv_parsed_instruction_t * inst)104 spv_result_t CountInstructions(void* user_data,
105                                const spv_parsed_instruction_t* inst) {
106   ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
107   if (inst->opcode == SpvOpFunction) _.increment_total_functions();
108   _.increment_total_instructions();
109 
110   return SPV_SUCCESS;
111 }
112 
setHeader(void * user_data,spv_endianness_t,uint32_t,uint32_t version,uint32_t generator,uint32_t id_bound,uint32_t)113 spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t,
114                        uint32_t version, uint32_t generator, uint32_t id_bound,
115                        uint32_t) {
116   ValidationState_t& vstate =
117       *(reinterpret_cast<ValidationState_t*>(user_data));
118   vstate.setIdBound(id_bound);
119   vstate.setGenerator(generator);
120   vstate.setVersion(version);
121 
122   return SPV_SUCCESS;
123 }
124 
125 // Add features based on SPIR-V core version number.
UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature * features,uint32_t version)126 void UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature* features,
127                                        uint32_t version) {
128   assert(features);
129   if (version >= SPV_SPIRV_VERSION_WORD(1, 4)) {
130     features->select_between_composites = true;
131     features->copy_memory_permits_two_memory_accesses = true;
132     features->uconvert_spec_constant_op = true;
133     features->nonwritable_var_in_function_or_private = true;
134   }
135 }
136 
137 }  // namespace
138 
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)139 ValidationState_t::ValidationState_t(const spv_const_context ctx,
140                                      const spv_const_validator_options opt,
141                                      const uint32_t* words,
142                                      const size_t num_words,
143                                      const uint32_t max_warnings)
144     : context_(ctx),
145       options_(opt),
146       words_(words),
147       num_words_(num_words),
148       unresolved_forward_ids_{},
149       operand_names_{},
150       current_layout_section_(kLayoutCapabilities),
151       module_functions_(),
152       module_capabilities_(),
153       module_extensions_(),
154       ordered_instructions_(),
155       all_definitions_(),
156       global_vars_(),
157       local_vars_(),
158       struct_nesting_depth_(),
159       struct_has_nested_blockorbufferblock_struct_(),
160       grammar_(ctx),
161       addressing_model_(SpvAddressingModelMax),
162       memory_model_(SpvMemoryModelMax),
163       pointer_size_and_alignment_(0),
164       in_function_(false),
165       num_of_warnings_(0),
166       max_num_of_warnings_(max_warnings) {
167   assert(opt && "Validator options may not be Null.");
168 
169   const auto env = context_->target_env;
170 
171   if (spvIsVulkanEnv(env)) {
172     // Vulkan 1.1 includes VK_KHR_relaxed_block_layout in core.
173     if (env != SPV_ENV_VULKAN_1_0) {
174       features_.env_relaxed_block_layout = true;
175     }
176   }
177 
178   // Only attempt to count if we have words, otherwise let the other validation
179   // fail and generate an error.
180   if (num_words > 0) {
181     // Count the number of instructions in the binary.
182     // This parse should not produce any error messages. Hijack the context and
183     // replace the message consumer so that we do not pollute any state in input
184     // consumer.
185     spv_context_t hijacked_context = *ctx;
186     hijacked_context.consumer = [](spv_message_level_t, const char*,
__anonbf7ee5f90202(spv_message_level_t, const char*, const spv_position_t&, const char*) 187                                    const spv_position_t&, const char*) {};
188     spvBinaryParse(&hijacked_context, this, words, num_words, setHeader,
189                    CountInstructions,
190                    /* diagnostic = */ nullptr);
191     preallocateStorage();
192   }
193   UpdateFeaturesBasedOnSpirvVersion(&features_, version_);
194 
195   friendly_mapper_ = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
196       context_, words_, num_words_);
197   name_mapper_ = friendly_mapper_->GetNameMapper();
198 }
199 
preallocateStorage()200 void ValidationState_t::preallocateStorage() {
201   ordered_instructions_.reserve(total_instructions_);
202   module_functions_.reserve(total_functions_);
203 }
204 
ForwardDeclareId(uint32_t id)205 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
206   unresolved_forward_ids_.insert(id);
207   return SPV_SUCCESS;
208 }
209 
RemoveIfForwardDeclared(uint32_t id)210 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
211   unresolved_forward_ids_.erase(id);
212   return SPV_SUCCESS;
213 }
214 
RegisterForwardPointer(uint32_t id)215 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
216   forward_pointer_ids_.insert(id);
217   return SPV_SUCCESS;
218 }
219 
IsForwardPointer(uint32_t id) const220 bool ValidationState_t::IsForwardPointer(uint32_t id) const {
221   return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
222 }
223 
AssignNameToId(uint32_t id,std::string name)224 void ValidationState_t::AssignNameToId(uint32_t id, std::string name) {
225   operand_names_[id] = name;
226 }
227 
getIdName(uint32_t id) const228 std::string ValidationState_t::getIdName(uint32_t id) const {
229   const std::string id_name = name_mapper_(id);
230 
231   std::stringstream out;
232   out << id << "[%" << id_name << "]";
233   return out.str();
234 }
235 
unresolved_forward_id_count() const236 size_t ValidationState_t::unresolved_forward_id_count() const {
237   return unresolved_forward_ids_.size();
238 }
239 
UnresolvedForwardIds() const240 std::vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
241   std::vector<uint32_t> out(std::begin(unresolved_forward_ids_),
242                             std::end(unresolved_forward_ids_));
243   return out;
244 }
245 
IsDefinedId(uint32_t id) const246 bool ValidationState_t::IsDefinedId(uint32_t id) const {
247   return all_definitions_.find(id) != std::end(all_definitions_);
248 }
249 
FindDef(uint32_t id) const250 const Instruction* ValidationState_t::FindDef(uint32_t id) const {
251   auto it = all_definitions_.find(id);
252   if (it == all_definitions_.end()) return nullptr;
253   return it->second;
254 }
255 
FindDef(uint32_t id)256 Instruction* ValidationState_t::FindDef(uint32_t id) {
257   auto it = all_definitions_.find(id);
258   if (it == all_definitions_.end()) return nullptr;
259   return it->second;
260 }
261 
current_layout_section() const262 ModuleLayoutSection ValidationState_t::current_layout_section() const {
263   return current_layout_section_;
264 }
265 
ProgressToNextLayoutSectionOrder()266 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
267   // Guard against going past the last element(kLayoutFunctionDefinitions)
268   if (current_layout_section_ <= kLayoutFunctionDefinitions) {
269     current_layout_section_ =
270         static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
271   }
272 }
273 
IsOpcodeInPreviousLayoutSection(SpvOp op)274 bool ValidationState_t::IsOpcodeInPreviousLayoutSection(SpvOp op) {
275   ModuleLayoutSection section =
276       InstructionLayoutSection(current_layout_section_, op);
277   return section < current_layout_section_;
278 }
279 
IsOpcodeInCurrentLayoutSection(SpvOp op)280 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
281   return IsInstructionInLayoutSection(current_layout_section_, op);
282 }
283 
diag(spv_result_t error_code,const Instruction * inst)284 DiagnosticStream ValidationState_t::diag(spv_result_t error_code,
285                                          const Instruction* inst) {
286   if (error_code == SPV_WARNING) {
287     if (num_of_warnings_ == max_num_of_warnings_) {
288       DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code)
289           << "Other warnings have been suppressed.\n";
290     }
291     if (num_of_warnings_ >= max_num_of_warnings_) {
292       return DiagnosticStream({0, 0, 0}, nullptr, "", error_code);
293     }
294     ++num_of_warnings_;
295   }
296 
297   std::string disassembly;
298   if (inst) disassembly = Disassemble(*inst);
299 
300   return DiagnosticStream({0, 0, inst ? inst->LineNum() : 0},
301                           context_->consumer, disassembly, error_code);
302 }
303 
functions()304 std::vector<Function>& ValidationState_t::functions() {
305   return module_functions_;
306 }
307 
current_function()308 Function& ValidationState_t::current_function() {
309   assert(in_function_body());
310   return module_functions_.back();
311 }
312 
current_function() const313 const Function& ValidationState_t::current_function() const {
314   assert(in_function_body());
315   return module_functions_.back();
316 }
317 
function(uint32_t id) const318 const Function* ValidationState_t::function(uint32_t id) const {
319   const auto it = id_to_function_.find(id);
320   if (it == id_to_function_.end()) return nullptr;
321   return it->second;
322 }
323 
function(uint32_t id)324 Function* ValidationState_t::function(uint32_t id) {
325   auto it = id_to_function_.find(id);
326   if (it == id_to_function_.end()) return nullptr;
327   return it->second;
328 }
329 
in_function_body() const330 bool ValidationState_t::in_function_body() const { return in_function_; }
331 
in_block() const332 bool ValidationState_t::in_block() const {
333   return module_functions_.empty() == false &&
334          module_functions_.back().current_block() != nullptr;
335 }
336 
RegisterCapability(SpvCapability cap)337 void ValidationState_t::RegisterCapability(SpvCapability cap) {
338   // Avoid redundant work.  Otherwise the recursion could induce work
339   // quadrdatic in the capability dependency depth. (Ok, not much, but
340   // it's something.)
341   if (module_capabilities_.Contains(cap)) return;
342 
343   module_capabilities_.Add(cap);
344   spv_operand_desc desc;
345   if (SPV_SUCCESS ==
346       grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
347     CapabilitySet(desc->numCapabilities, desc->capabilities)
348         .ForEach([this](SpvCapability c) { RegisterCapability(c); });
349   }
350 
351   switch (cap) {
352     case SpvCapabilityKernel:
353       features_.group_ops_reduce_and_scans = true;
354       break;
355     case SpvCapabilityInt8:
356       features_.use_int8_type = true;
357       features_.declare_int8_type = true;
358       break;
359     case SpvCapabilityStorageBuffer8BitAccess:
360     case SpvCapabilityUniformAndStorageBuffer8BitAccess:
361     case SpvCapabilityStoragePushConstant8:
362     case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
363       features_.declare_int8_type = true;
364       break;
365     case SpvCapabilityInt16:
366       features_.declare_int16_type = true;
367       break;
368     case SpvCapabilityFloat16:
369     case SpvCapabilityFloat16Buffer:
370       features_.declare_float16_type = true;
371       break;
372     case SpvCapabilityStorageUniformBufferBlock16:
373     case SpvCapabilityStorageUniform16:
374     case SpvCapabilityStoragePushConstant16:
375     case SpvCapabilityStorageInputOutput16:
376     case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
377       features_.declare_int16_type = true;
378       features_.declare_float16_type = true;
379       features_.free_fp_rounding_mode = true;
380       break;
381     case SpvCapabilityVariablePointers:
382       features_.variable_pointers = true;
383       features_.variable_pointers_storage_buffer = true;
384       break;
385     case SpvCapabilityVariablePointersStorageBuffer:
386       features_.variable_pointers_storage_buffer = true;
387       break;
388     default:
389       break;
390   }
391 }
392 
RegisterExtension(Extension ext)393 void ValidationState_t::RegisterExtension(Extension ext) {
394   if (module_extensions_.Contains(ext)) return;
395 
396   module_extensions_.Add(ext);
397 
398   switch (ext) {
399     case kSPV_AMD_gpu_shader_half_float:
400     case kSPV_AMD_gpu_shader_half_float_fetch:
401       // SPV_AMD_gpu_shader_half_float enables float16 type.
402       // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
403       features_.declare_float16_type = true;
404       break;
405     case kSPV_AMD_gpu_shader_int16:
406       // This is not yet in the extension, but it's recommended for it.
407       // See https://github.com/KhronosGroup/glslang/issues/848
408       features_.uconvert_spec_constant_op = true;
409       break;
410     case kSPV_AMD_shader_ballot:
411       // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
412       // enables the use of group operations Reduce, InclusiveScan,
413       // and ExclusiveScan.  Enable it manually.
414       // https://github.com/KhronosGroup/SPIRV-Tools/issues/991
415       features_.group_ops_reduce_and_scans = true;
416       break;
417     default:
418       break;
419   }
420 }
421 
HasAnyOfCapabilities(const CapabilitySet & capabilities) const422 bool ValidationState_t::HasAnyOfCapabilities(
423     const CapabilitySet& capabilities) const {
424   return module_capabilities_.HasAnyOf(capabilities);
425 }
426 
HasAnyOfExtensions(const ExtensionSet & extensions) const427 bool ValidationState_t::HasAnyOfExtensions(
428     const ExtensionSet& extensions) const {
429   return module_extensions_.HasAnyOf(extensions);
430 }
431 
set_addressing_model(SpvAddressingModel am)432 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
433   addressing_model_ = am;
434   switch (am) {
435     case SpvAddressingModelPhysical32:
436       pointer_size_and_alignment_ = 4;
437       break;
438     default:
439     // fall through
440     case SpvAddressingModelPhysical64:
441     case SpvAddressingModelPhysicalStorageBuffer64EXT:
442       pointer_size_and_alignment_ = 8;
443       break;
444   }
445 }
446 
addressing_model() const447 SpvAddressingModel ValidationState_t::addressing_model() const {
448   return addressing_model_;
449 }
450 
set_memory_model(SpvMemoryModel mm)451 void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
452   memory_model_ = mm;
453 }
454 
memory_model() const455 SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
456 
RegisterFunction(uint32_t id,uint32_t ret_type_id,SpvFunctionControlMask function_control,uint32_t function_type_id)457 spv_result_t ValidationState_t::RegisterFunction(
458     uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
459     uint32_t function_type_id) {
460   assert(in_function_body() == false &&
461          "RegisterFunction can only be called when parsing the binary outside "
462          "of another function");
463   in_function_ = true;
464   module_functions_.emplace_back(id, ret_type_id, function_control,
465                                  function_type_id);
466   id_to_function_.emplace(id, &current_function());
467 
468   // TODO(umar): validate function type and type_id
469 
470   return SPV_SUCCESS;
471 }
472 
RegisterFunctionEnd()473 spv_result_t ValidationState_t::RegisterFunctionEnd() {
474   assert(in_function_body() == true &&
475          "RegisterFunctionEnd can only be called when parsing the binary "
476          "inside of another function");
477   assert(in_block() == false &&
478          "RegisterFunctionParameter can only be called when parsing the binary "
479          "ouside of a block");
480   current_function().RegisterFunctionEnd();
481   in_function_ = false;
482   return SPV_SUCCESS;
483 }
484 
AddOrderedInstruction(const spv_parsed_instruction_t * inst)485 Instruction* ValidationState_t::AddOrderedInstruction(
486     const spv_parsed_instruction_t* inst) {
487   ordered_instructions_.emplace_back(inst);
488   ordered_instructions_.back().SetLineNum(ordered_instructions_.size());
489   return &ordered_instructions_.back();
490 }
491 
492 // Improves diagnostic messages by collecting names of IDs
RegisterDebugInstruction(const Instruction * inst)493 void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
494   switch (inst->opcode()) {
495     case SpvOpName: {
496       const auto target = inst->GetOperandAs<uint32_t>(0);
497       const auto* str = reinterpret_cast<const char*>(inst->words().data() +
498                                                       inst->operand(1).offset);
499       AssignNameToId(target, str);
500       break;
501     }
502     case SpvOpMemberName: {
503       const auto target = inst->GetOperandAs<uint32_t>(0);
504       const auto* str = reinterpret_cast<const char*>(inst->words().data() +
505                                                       inst->operand(2).offset);
506       AssignNameToId(target, str);
507       break;
508     }
509     case SpvOpSourceContinued:
510     case SpvOpSource:
511     case SpvOpSourceExtension:
512     case SpvOpString:
513     case SpvOpLine:
514     case SpvOpNoLine:
515     default:
516       break;
517   }
518 }
519 
RegisterInstruction(Instruction * inst)520 void ValidationState_t::RegisterInstruction(Instruction* inst) {
521   if (inst->id()) all_definitions_.insert(std::make_pair(inst->id(), inst));
522 
523   // If the instruction is using an OpTypeSampledImage as an operand, it should
524   // be recorded. The validator will ensure that all usages of an
525   // OpTypeSampledImage and its definition are in the same basic block.
526   for (uint16_t i = 0; i < inst->operands().size(); ++i) {
527     const spv_parsed_operand_t& operand = inst->operand(i);
528     if (SPV_OPERAND_TYPE_ID == operand.type) {
529       const uint32_t operand_word = inst->word(operand.offset);
530       Instruction* operand_inst = FindDef(operand_word);
531       if (operand_inst && SpvOpSampledImage == operand_inst->opcode()) {
532         RegisterSampledImageConsumer(operand_word, inst);
533       }
534     }
535   }
536 }
537 
getSampledImageConsumers(uint32_t sampled_image_id) const538 std::vector<Instruction*> ValidationState_t::getSampledImageConsumers(
539     uint32_t sampled_image_id) const {
540   std::vector<Instruction*> result;
541   auto iter = sampled_image_consumers_.find(sampled_image_id);
542   if (iter != sampled_image_consumers_.end()) {
543     result = iter->second;
544   }
545   return result;
546 }
547 
RegisterSampledImageConsumer(uint32_t sampled_image_id,Instruction * consumer)548 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
549                                                      Instruction* consumer) {
550   sampled_image_consumers_[sampled_image_id].push_back(consumer);
551 }
552 
getIdBound() const553 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
554 
setIdBound(const uint32_t bound)555 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
556 
RegisterUniqueTypeDeclaration(const Instruction * inst)557 bool ValidationState_t::RegisterUniqueTypeDeclaration(const Instruction* inst) {
558   std::vector<uint32_t> key;
559   key.push_back(static_cast<uint32_t>(inst->opcode()));
560   for (size_t index = 0; index < inst->operands().size(); ++index) {
561     const spv_parsed_operand_t& operand = inst->operand(index);
562 
563     if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
564 
565     const int words_begin = operand.offset;
566     const int words_end = words_begin + operand.num_words;
567     assert(words_end <= static_cast<int>(inst->words().size()));
568 
569     key.insert(key.end(), inst->words().begin() + words_begin,
570                inst->words().begin() + words_end);
571   }
572 
573   return unique_type_declarations_.insert(std::move(key)).second;
574 }
575 
GetTypeId(uint32_t id) const576 uint32_t ValidationState_t::GetTypeId(uint32_t id) const {
577   const Instruction* inst = FindDef(id);
578   return inst ? inst->type_id() : 0;
579 }
580 
GetIdOpcode(uint32_t id) const581 SpvOp ValidationState_t::GetIdOpcode(uint32_t id) const {
582   const Instruction* inst = FindDef(id);
583   return inst ? inst->opcode() : SpvOpNop;
584 }
585 
GetComponentType(uint32_t id) const586 uint32_t ValidationState_t::GetComponentType(uint32_t id) const {
587   const Instruction* inst = FindDef(id);
588   assert(inst);
589 
590   switch (inst->opcode()) {
591     case SpvOpTypeFloat:
592     case SpvOpTypeInt:
593     case SpvOpTypeBool:
594       return id;
595 
596     case SpvOpTypeVector:
597       return inst->word(2);
598 
599     case SpvOpTypeMatrix:
600       return GetComponentType(inst->word(2));
601 
602     case SpvOpTypeCooperativeMatrixNV:
603       return inst->word(2);
604 
605     default:
606       break;
607   }
608 
609   if (inst->type_id()) return GetComponentType(inst->type_id());
610 
611   assert(0);
612   return 0;
613 }
614 
GetDimension(uint32_t id) const615 uint32_t ValidationState_t::GetDimension(uint32_t id) const {
616   const Instruction* inst = FindDef(id);
617   assert(inst);
618 
619   switch (inst->opcode()) {
620     case SpvOpTypeFloat:
621     case SpvOpTypeInt:
622     case SpvOpTypeBool:
623       return 1;
624 
625     case SpvOpTypeVector:
626     case SpvOpTypeMatrix:
627       return inst->word(3);
628 
629     case SpvOpTypeCooperativeMatrixNV:
630       // Actual dimension isn't known, return 0
631       return 0;
632 
633     default:
634       break;
635   }
636 
637   if (inst->type_id()) return GetDimension(inst->type_id());
638 
639   assert(0);
640   return 0;
641 }
642 
GetBitWidth(uint32_t id) const643 uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
644   const uint32_t component_type_id = GetComponentType(id);
645   const Instruction* inst = FindDef(component_type_id);
646   assert(inst);
647 
648   if (inst->opcode() == SpvOpTypeFloat || inst->opcode() == SpvOpTypeInt)
649     return inst->word(2);
650 
651   if (inst->opcode() == SpvOpTypeBool) return 1;
652 
653   assert(0);
654   return 0;
655 }
656 
IsVoidType(uint32_t id) const657 bool ValidationState_t::IsVoidType(uint32_t id) const {
658   const Instruction* inst = FindDef(id);
659   assert(inst);
660   return inst->opcode() == SpvOpTypeVoid;
661 }
662 
IsFloatScalarType(uint32_t id) const663 bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
664   const Instruction* inst = FindDef(id);
665   assert(inst);
666   return inst->opcode() == SpvOpTypeFloat;
667 }
668 
IsFloatVectorType(uint32_t id) const669 bool ValidationState_t::IsFloatVectorType(uint32_t id) const {
670   const Instruction* inst = FindDef(id);
671   assert(inst);
672 
673   if (inst->opcode() == SpvOpTypeVector) {
674     return IsFloatScalarType(GetComponentType(id));
675   }
676 
677   return false;
678 }
679 
IsFloatScalarOrVectorType(uint32_t id) const680 bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
681   const Instruction* inst = FindDef(id);
682   assert(inst);
683 
684   if (inst->opcode() == SpvOpTypeFloat) {
685     return true;
686   }
687 
688   if (inst->opcode() == SpvOpTypeVector) {
689     return IsFloatScalarType(GetComponentType(id));
690   }
691 
692   return false;
693 }
694 
IsIntScalarType(uint32_t id) const695 bool ValidationState_t::IsIntScalarType(uint32_t id) const {
696   const Instruction* inst = FindDef(id);
697   assert(inst);
698   return inst->opcode() == SpvOpTypeInt;
699 }
700 
IsIntVectorType(uint32_t id) const701 bool ValidationState_t::IsIntVectorType(uint32_t id) const {
702   const Instruction* inst = FindDef(id);
703   assert(inst);
704 
705   if (inst->opcode() == SpvOpTypeVector) {
706     return IsIntScalarType(GetComponentType(id));
707   }
708 
709   return false;
710 }
711 
IsIntScalarOrVectorType(uint32_t id) const712 bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const {
713   const Instruction* inst = FindDef(id);
714   assert(inst);
715 
716   if (inst->opcode() == SpvOpTypeInt) {
717     return true;
718   }
719 
720   if (inst->opcode() == SpvOpTypeVector) {
721     return IsIntScalarType(GetComponentType(id));
722   }
723 
724   return false;
725 }
726 
IsUnsignedIntScalarType(uint32_t id) const727 bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const {
728   const Instruction* inst = FindDef(id);
729   assert(inst);
730   return inst->opcode() == SpvOpTypeInt && inst->word(3) == 0;
731 }
732 
IsUnsignedIntVectorType(uint32_t id) const733 bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const {
734   const Instruction* inst = FindDef(id);
735   assert(inst);
736 
737   if (inst->opcode() == SpvOpTypeVector) {
738     return IsUnsignedIntScalarType(GetComponentType(id));
739   }
740 
741   return false;
742 }
743 
IsSignedIntScalarType(uint32_t id) const744 bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
745   const Instruction* inst = FindDef(id);
746   assert(inst);
747   return inst->opcode() == SpvOpTypeInt && inst->word(3) == 1;
748 }
749 
IsSignedIntVectorType(uint32_t id) const750 bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const {
751   const Instruction* inst = FindDef(id);
752   assert(inst);
753 
754   if (inst->opcode() == SpvOpTypeVector) {
755     return IsSignedIntScalarType(GetComponentType(id));
756   }
757 
758   return false;
759 }
760 
IsBoolScalarType(uint32_t id) const761 bool ValidationState_t::IsBoolScalarType(uint32_t id) const {
762   const Instruction* inst = FindDef(id);
763   assert(inst);
764   return inst->opcode() == SpvOpTypeBool;
765 }
766 
IsBoolVectorType(uint32_t id) const767 bool ValidationState_t::IsBoolVectorType(uint32_t id) const {
768   const Instruction* inst = FindDef(id);
769   assert(inst);
770 
771   if (inst->opcode() == SpvOpTypeVector) {
772     return IsBoolScalarType(GetComponentType(id));
773   }
774 
775   return false;
776 }
777 
IsBoolScalarOrVectorType(uint32_t id) const778 bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const {
779   const Instruction* inst = FindDef(id);
780   assert(inst);
781 
782   if (inst->opcode() == SpvOpTypeBool) {
783     return true;
784   }
785 
786   if (inst->opcode() == SpvOpTypeVector) {
787     return IsBoolScalarType(GetComponentType(id));
788   }
789 
790   return false;
791 }
792 
IsFloatMatrixType(uint32_t id) const793 bool ValidationState_t::IsFloatMatrixType(uint32_t id) const {
794   const Instruction* inst = FindDef(id);
795   assert(inst);
796 
797   if (inst->opcode() == SpvOpTypeMatrix) {
798     return IsFloatScalarType(GetComponentType(id));
799   }
800 
801   return false;
802 }
803 
GetMatrixTypeInfo(uint32_t id,uint32_t * num_rows,uint32_t * num_cols,uint32_t * column_type,uint32_t * component_type) const804 bool ValidationState_t::GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows,
805                                           uint32_t* num_cols,
806                                           uint32_t* column_type,
807                                           uint32_t* component_type) const {
808   if (!id) return false;
809 
810   const Instruction* mat_inst = FindDef(id);
811   assert(mat_inst);
812   if (mat_inst->opcode() != SpvOpTypeMatrix) return false;
813 
814   const uint32_t vec_type = mat_inst->word(2);
815   const Instruction* vec_inst = FindDef(vec_type);
816   assert(vec_inst);
817 
818   if (vec_inst->opcode() != SpvOpTypeVector) {
819     assert(0);
820     return false;
821   }
822 
823   *num_cols = mat_inst->word(3);
824   *num_rows = vec_inst->word(3);
825   *column_type = mat_inst->word(2);
826   *component_type = vec_inst->word(2);
827 
828   return true;
829 }
830 
GetStructMemberTypes(uint32_t struct_type_id,std::vector<uint32_t> * member_types) const831 bool ValidationState_t::GetStructMemberTypes(
832     uint32_t struct_type_id, std::vector<uint32_t>* member_types) const {
833   member_types->clear();
834   if (!struct_type_id) return false;
835 
836   const Instruction* inst = FindDef(struct_type_id);
837   assert(inst);
838   if (inst->opcode() != SpvOpTypeStruct) return false;
839 
840   *member_types =
841       std::vector<uint32_t>(inst->words().cbegin() + 2, inst->words().cend());
842 
843   if (member_types->empty()) return false;
844 
845   return true;
846 }
847 
IsPointerType(uint32_t id) const848 bool ValidationState_t::IsPointerType(uint32_t id) const {
849   const Instruction* inst = FindDef(id);
850   assert(inst);
851   return inst->opcode() == SpvOpTypePointer;
852 }
853 
GetPointerTypeInfo(uint32_t id,uint32_t * data_type,uint32_t * storage_class) const854 bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
855                                            uint32_t* storage_class) const {
856   if (!id) return false;
857 
858   const Instruction* inst = FindDef(id);
859   assert(inst);
860   if (inst->opcode() != SpvOpTypePointer) return false;
861 
862   *storage_class = inst->word(2);
863   *data_type = inst->word(3);
864   return true;
865 }
866 
IsCooperativeMatrixType(uint32_t id) const867 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
868   const Instruction* inst = FindDef(id);
869   assert(inst);
870   return inst->opcode() == SpvOpTypeCooperativeMatrixNV;
871 }
872 
IsFloatCooperativeMatrixType(uint32_t id) const873 bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
874   if (!IsCooperativeMatrixType(id)) return false;
875   return IsFloatScalarType(FindDef(id)->word(2));
876 }
877 
IsIntCooperativeMatrixType(uint32_t id) const878 bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
879   if (!IsCooperativeMatrixType(id)) return false;
880   return IsIntScalarType(FindDef(id)->word(2));
881 }
882 
IsUnsignedIntCooperativeMatrixType(uint32_t id) const883 bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
884   if (!IsCooperativeMatrixType(id)) return false;
885   return IsUnsignedIntScalarType(FindDef(id)->word(2));
886 }
887 
CooperativeMatrixShapesMatch(const Instruction * inst,uint32_t m1,uint32_t m2)888 spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
889     const Instruction* inst, uint32_t m1, uint32_t m2) {
890   const auto m1_type = FindDef(m1);
891   const auto m2_type = FindDef(m2);
892 
893   if (m1_type->opcode() != SpvOpTypeCooperativeMatrixNV ||
894       m2_type->opcode() != SpvOpTypeCooperativeMatrixNV) {
895     return diag(SPV_ERROR_INVALID_DATA, inst)
896            << "Expected cooperative matrix types";
897   }
898 
899   uint32_t m1_scope_id = m1_type->GetOperandAs<uint32_t>(2);
900   uint32_t m1_rows_id = m1_type->GetOperandAs<uint32_t>(3);
901   uint32_t m1_cols_id = m1_type->GetOperandAs<uint32_t>(4);
902 
903   uint32_t m2_scope_id = m2_type->GetOperandAs<uint32_t>(2);
904   uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
905   uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
906 
907   bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
908        m2_is_const_int32 = false;
909   uint32_t m1_value = 0, m2_value = 0;
910 
911   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
912       EvalInt32IfConst(m1_scope_id);
913   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
914       EvalInt32IfConst(m2_scope_id);
915 
916   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
917     return diag(SPV_ERROR_INVALID_DATA, inst)
918            << "Expected scopes of Matrix and Result Type to be "
919            << "identical";
920   }
921 
922   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
923       EvalInt32IfConst(m1_rows_id);
924   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
925       EvalInt32IfConst(m2_rows_id);
926 
927   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
928     return diag(SPV_ERROR_INVALID_DATA, inst)
929            << "Expected rows of Matrix type and Result Type to be "
930            << "identical";
931   }
932 
933   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
934       EvalInt32IfConst(m1_cols_id);
935   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
936       EvalInt32IfConst(m2_cols_id);
937 
938   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
939     return diag(SPV_ERROR_INVALID_DATA, inst)
940            << "Expected columns of Matrix type and Result Type to be "
941            << "identical";
942   }
943 
944   return SPV_SUCCESS;
945 }
946 
GetOperandTypeId(const Instruction * inst,size_t operand_index) const947 uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst,
948                                              size_t operand_index) const {
949   return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
950 }
951 
GetConstantValUint64(uint32_t id,uint64_t * val) const952 bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const {
953   const Instruction* inst = FindDef(id);
954   if (!inst) {
955     assert(0 && "Instruction not found");
956     return false;
957   }
958 
959   if (inst->opcode() != SpvOpConstant && inst->opcode() != SpvOpSpecConstant)
960     return false;
961 
962   if (!IsIntScalarType(inst->type_id())) return false;
963 
964   if (inst->words().size() == 4) {
965     *val = inst->word(3);
966   } else {
967     assert(inst->words().size() == 5);
968     *val = inst->word(3);
969     *val |= uint64_t(inst->word(4)) << 32;
970   }
971   return true;
972 }
973 
EvalInt32IfConst(uint32_t id) const974 std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
975     uint32_t id) const {
976   const Instruction* const inst = FindDef(id);
977   assert(inst);
978   const uint32_t type = inst->type_id();
979 
980   if (type == 0 || !IsIntScalarType(type) || GetBitWidth(type) != 32) {
981     return std::make_tuple(false, false, 0);
982   }
983 
984   // Spec constant values cannot be evaluated so don't consider constant for
985   // the purpose of this method.
986   if (!spvOpcodeIsConstant(inst->opcode()) ||
987       spvOpcodeIsSpecConstant(inst->opcode())) {
988     return std::make_tuple(true, false, 0);
989   }
990 
991   if (inst->opcode() == SpvOpConstantNull) {
992     return std::make_tuple(true, true, 0);
993   }
994 
995   assert(inst->words().size() == 4);
996   return std::make_tuple(true, true, inst->word(3));
997 }
998 
ComputeFunctionToEntryPointMapping()999 void ValidationState_t::ComputeFunctionToEntryPointMapping() {
1000   for (const uint32_t entry_point : entry_points()) {
1001     std::stack<uint32_t> call_stack;
1002     std::set<uint32_t> visited;
1003     call_stack.push(entry_point);
1004     while (!call_stack.empty()) {
1005       const uint32_t called_func_id = call_stack.top();
1006       call_stack.pop();
1007       if (!visited.insert(called_func_id).second) continue;
1008 
1009       function_to_entry_points_[called_func_id].push_back(entry_point);
1010 
1011       const Function* called_func = function(called_func_id);
1012       if (called_func) {
1013         // Other checks should error out on this invalid SPIR-V.
1014         for (const uint32_t new_call : called_func->function_call_targets()) {
1015           call_stack.push(new_call);
1016         }
1017       }
1018     }
1019   }
1020 }
1021 
ComputeRecursiveEntryPoints()1022 void ValidationState_t::ComputeRecursiveEntryPoints() {
1023   for (const Function& func : functions()) {
1024     std::stack<uint32_t> call_stack;
1025     std::set<uint32_t> visited;
1026 
1027     for (const uint32_t new_call : func.function_call_targets()) {
1028       call_stack.push(new_call);
1029     }
1030 
1031     while (!call_stack.empty()) {
1032       const uint32_t called_func_id = call_stack.top();
1033       call_stack.pop();
1034 
1035       if (!visited.insert(called_func_id).second) continue;
1036 
1037       if (called_func_id == func.id()) {
1038         for (const uint32_t entry_point :
1039              function_to_entry_points_[called_func_id])
1040           recursive_entry_points_.insert(entry_point);
1041         break;
1042       }
1043 
1044       const Function* called_func = function(called_func_id);
1045       if (called_func) {
1046         // Other checks should error out on this invalid SPIR-V.
1047         for (const uint32_t new_call : called_func->function_call_targets()) {
1048           call_stack.push(new_call);
1049         }
1050       }
1051     }
1052   }
1053 }
1054 
FunctionEntryPoints(uint32_t func) const1055 const std::vector<uint32_t>& ValidationState_t::FunctionEntryPoints(
1056     uint32_t func) const {
1057   auto iter = function_to_entry_points_.find(func);
1058   if (iter == function_to_entry_points_.end()) {
1059     return empty_ids_;
1060   } else {
1061     return iter->second;
1062   }
1063 }
1064 
EntryPointReferences(uint32_t id) const1065 std::set<uint32_t> ValidationState_t::EntryPointReferences(uint32_t id) const {
1066   std::set<uint32_t> referenced_entry_points;
1067   const auto inst = FindDef(id);
1068   if (!inst) return referenced_entry_points;
1069 
1070   std::vector<const Instruction*> stack;
1071   stack.push_back(inst);
1072   while (!stack.empty()) {
1073     const auto current_inst = stack.back();
1074     stack.pop_back();
1075 
1076     if (const auto func = current_inst->function()) {
1077       // Instruction lives in a function, we can stop searching.
1078       const auto function_entry_points = FunctionEntryPoints(func->id());
1079       referenced_entry_points.insert(function_entry_points.begin(),
1080                                      function_entry_points.end());
1081     } else {
1082       // Instruction is in the global scope, keep searching its uses.
1083       for (auto pair : current_inst->uses()) {
1084         const auto next_inst = pair.first;
1085         stack.push_back(next_inst);
1086       }
1087     }
1088   }
1089 
1090   return referenced_entry_points;
1091 }
1092 
Disassemble(const Instruction & inst) const1093 std::string ValidationState_t::Disassemble(const Instruction& inst) const {
1094   const spv_parsed_instruction_t& c_inst(inst.c_inst());
1095   return Disassemble(c_inst.words, c_inst.num_words);
1096 }
1097 
Disassemble(const uint32_t * words,uint16_t num_words) const1098 std::string ValidationState_t::Disassemble(const uint32_t* words,
1099                                            uint16_t num_words) const {
1100   uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1101                                  SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
1102 
1103   return spvInstructionBinaryToText(context()->target_env, words, num_words,
1104                                     words_, num_words_, disassembly_options);
1105 }
1106 
LogicallyMatch(const Instruction * lhs,const Instruction * rhs,bool check_decorations)1107 bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
1108                                        const Instruction* rhs,
1109                                        bool check_decorations) {
1110   if (lhs->opcode() != rhs->opcode()) {
1111     return false;
1112   }
1113 
1114   if (check_decorations) {
1115     const auto& dec_a = id_decorations(lhs->id());
1116     const auto& dec_b = id_decorations(rhs->id());
1117 
1118     for (const auto& dec : dec_b) {
1119       if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) {
1120         return false;
1121       }
1122     }
1123   }
1124 
1125   if (lhs->opcode() == SpvOpTypeArray) {
1126     // Size operands must match.
1127     if (lhs->GetOperandAs<uint32_t>(2u) != rhs->GetOperandAs<uint32_t>(2u)) {
1128       return false;
1129     }
1130 
1131     // Elements must match or logically match.
1132     const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(1u);
1133     const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(1u);
1134     if (lhs_ele_id == rhs_ele_id) {
1135       return true;
1136     }
1137 
1138     const auto lhs_ele = FindDef(lhs_ele_id);
1139     const auto rhs_ele = FindDef(rhs_ele_id);
1140     if (!lhs_ele || !rhs_ele) {
1141       return false;
1142     }
1143     return LogicallyMatch(lhs_ele, rhs_ele, check_decorations);
1144   } else if (lhs->opcode() == SpvOpTypeStruct) {
1145     // Number of elements must match.
1146     if (lhs->operands().size() != rhs->operands().size()) {
1147       return false;
1148     }
1149 
1150     for (size_t i = 1u; i < lhs->operands().size(); ++i) {
1151       const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(i);
1152       const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(i);
1153       // Elements must match or logically match.
1154       if (lhs_ele_id == rhs_ele_id) {
1155         continue;
1156       }
1157 
1158       const auto lhs_ele = FindDef(lhs_ele_id);
1159       const auto rhs_ele = FindDef(rhs_ele_id);
1160       if (!lhs_ele || !rhs_ele) {
1161         return false;
1162       }
1163 
1164       if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) {
1165         return false;
1166       }
1167     }
1168 
1169     // All checks passed.
1170     return true;
1171   }
1172 
1173   // No other opcodes are acceptable at this point. Arrays and structs are
1174   // caught above and if they're elements are not arrays or structs they are
1175   // required to match exactly.
1176   return false;
1177 }
1178 
TracePointer(const Instruction * inst) const1179 const Instruction* ValidationState_t::TracePointer(
1180     const Instruction* inst) const {
1181   auto base_ptr = inst;
1182   while (base_ptr->opcode() == SpvOpAccessChain ||
1183          base_ptr->opcode() == SpvOpInBoundsAccessChain ||
1184          base_ptr->opcode() == SpvOpPtrAccessChain ||
1185          base_ptr->opcode() == SpvOpInBoundsPtrAccessChain ||
1186          base_ptr->opcode() == SpvOpCopyObject) {
1187     base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
1188   }
1189   return base_ptr;
1190 }
1191 
ContainsSizedIntOrFloatType(uint32_t id,SpvOp type,uint32_t width) const1192 bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
1193                                                     uint32_t width) const {
1194   if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
1195 
1196   const auto inst = FindDef(id);
1197   if (!inst) return false;
1198 
1199   if (inst->opcode() == type) {
1200     return inst->GetOperandAs<uint32_t>(1u) == width;
1201   }
1202 
1203   switch (inst->opcode()) {
1204     case SpvOpTypeArray:
1205     case SpvOpTypeRuntimeArray:
1206     case SpvOpTypeVector:
1207     case SpvOpTypeMatrix:
1208     case SpvOpTypeImage:
1209     case SpvOpTypeSampledImage:
1210     case SpvOpTypeCooperativeMatrixNV:
1211       return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(1u), type,
1212                                          width);
1213     case SpvOpTypePointer:
1214       if (IsForwardPointer(id)) return false;
1215       return ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(2u), type,
1216                                          width);
1217     case SpvOpTypeFunction:
1218     case SpvOpTypeStruct: {
1219       for (uint32_t i = 1; i < inst->operands().size(); ++i) {
1220         if (ContainsSizedIntOrFloatType(inst->GetOperandAs<uint32_t>(i), type,
1221                                         width))
1222           return true;
1223       }
1224       return false;
1225     }
1226     default:
1227       return false;
1228   }
1229 }
1230 
ContainsLimitedUseIntOrFloatType(uint32_t id) const1231 bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
1232   if ((!HasCapability(SpvCapabilityInt16) &&
1233        ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 16)) ||
1234       (!HasCapability(SpvCapabilityInt8) &&
1235        ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 8)) ||
1236       (!HasCapability(SpvCapabilityFloat16) &&
1237        ContainsSizedIntOrFloatType(id, SpvOpTypeFloat, 16))) {
1238     return true;
1239   }
1240   return false;
1241 }
1242 
IsValidStorageClass(SpvStorageClass storage_class) const1243 bool ValidationState_t::IsValidStorageClass(
1244     SpvStorageClass storage_class) const {
1245   if (spvIsVulkanEnv(context()->target_env)) {
1246     switch (storage_class) {
1247       case SpvStorageClassUniformConstant:
1248       case SpvStorageClassUniform:
1249       case SpvStorageClassStorageBuffer:
1250       case SpvStorageClassInput:
1251       case SpvStorageClassOutput:
1252       case SpvStorageClassImage:
1253       case SpvStorageClassWorkgroup:
1254       case SpvStorageClassPrivate:
1255       case SpvStorageClassFunction:
1256       case SpvStorageClassPushConstant:
1257       case SpvStorageClassPhysicalStorageBuffer:
1258       case SpvStorageClassRayPayloadNV:
1259       case SpvStorageClassIncomingRayPayloadNV:
1260       case SpvStorageClassHitAttributeNV:
1261       case SpvStorageClassCallableDataNV:
1262       case SpvStorageClassIncomingCallableDataNV:
1263       case SpvStorageClassShaderRecordBufferNV:
1264         return true;
1265       default:
1266         return false;
1267     }
1268   }
1269 
1270   return true;
1271 }
1272 
1273 #define VUID_WRAP(vuid) "[" #vuid "] "
1274 
1275 // Currently no 2 VUID share the same id, so no need for |reference|
VkErrorID(uint32_t id,const char *) const1276 std::string ValidationState_t::VkErrorID(uint32_t id,
1277                                          const char* /*reference*/) const {
1278   if (!spvIsVulkanEnv(context_->target_env)) {
1279     return "";
1280   }
1281 
1282   // This large switch case is only searched when an error has occured.
1283   // If an id is changed, the old case must be modified or removed. Each string
1284   // here is interpreted as being "implemented"
1285 
1286   // Clang format adds spaces between hyphens
1287   // clang-format off
1288   switch (id) {
1289     case 4181:
1290       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04181);
1291     case 4182:
1292       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04182);
1293     case 4183:
1294       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04183);
1295     case 4184:
1296       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04184);
1297     case 4185:
1298       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04185);
1299     case 4186:
1300       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186);
1301     case 4187:
1302       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187);
1303     case 4188:
1304       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188);
1305     case 4189:
1306       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189);
1307     case 4190:
1308       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190);
1309     case 4191:
1310       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191);
1311     case 4196:
1312       return VUID_WRAP(VUID-CullDistance-CullDistance-04196);
1313     case 4197:
1314       return VUID_WRAP(VUID-CullDistance-CullDistance-04197);
1315     case 4198:
1316       return VUID_WRAP(VUID-CullDistance-CullDistance-04198);
1317     case 4199:
1318       return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
1319     case 4200:
1320       return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
1321     case 4205:
1322       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04205);
1323     case 4206:
1324       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04206);
1325     case 4207:
1326       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04207);
1327     case 4208:
1328       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04208);
1329     case 4209:
1330       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04209);
1331     case 4210:
1332       return VUID_WRAP(VUID-FragCoord-FragCoord-04210);
1333     case 4211:
1334       return VUID_WRAP(VUID-FragCoord-FragCoord-04211);
1335     case 4212:
1336       return VUID_WRAP(VUID-FragCoord-FragCoord-04212);
1337     case 4213:
1338       return VUID_WRAP(VUID-FragDepth-FragDepth-04213);
1339     case 4214:
1340       return VUID_WRAP(VUID-FragDepth-FragDepth-04214);
1341     case 4215:
1342       return VUID_WRAP(VUID-FragDepth-FragDepth-04215);
1343     case 4216:
1344       return VUID_WRAP(VUID-FragDepth-FragDepth-04216);
1345     case 4217:
1346       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217);
1347     case 4218:
1348       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218);
1349     case 4219:
1350       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219);
1351     case 4220:
1352       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220);
1353     case 4221:
1354       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221);
1355     case 4222:
1356       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222);
1357     case 4223:
1358       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223);
1359     case 4224:
1360       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224);
1361     case 4225:
1362       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225);
1363     case 4229:
1364       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229);
1365     case 4230:
1366       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230);
1367     case 4231:
1368       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231);
1369     case 4232:
1370       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232);
1371     case 4233:
1372       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233);
1373     case 4234:
1374       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234);
1375     case 4236:
1376       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236);
1377     case 4237:
1378       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04237);
1379     case 4238:
1380       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04238);
1381     case 4239:
1382       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04239);
1383     case 4240:
1384       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
1385     case 4241:
1386       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
1387     case 4242:
1388       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
1389     case 4243:
1390       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
1391     case 4244:
1392       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
1393     case 4245:
1394       return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
1395     case 4246:
1396       return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
1397     case 4247:
1398       return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
1399     case 4248:
1400       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
1401     case 4249:
1402       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
1403     case 4250:
1404       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
1405     case 4251:
1406       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
1407     case 4252:
1408       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
1409     case 4253:
1410       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
1411     case 4254:
1412       return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
1413     case 4255:
1414       return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
1415     case 4256:
1416       return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
1417     case 4257:
1418       return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
1419     case 4258:
1420       return VUID_WRAP(VUID-InvocationId-InvocationId-04258);
1421     case 4259:
1422       return VUID_WRAP(VUID-InvocationId-InvocationId-04259);
1423     case 4263:
1424       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04263);
1425     case 4264:
1426       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
1427     case 4265:
1428       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
1429     case 4266:
1430       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
1431     case 4267:
1432       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
1433     case 4268:
1434       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
1435     case 4269:
1436       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
1437     case 4270:
1438       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
1439     case 4271:
1440       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
1441     case 4272:
1442       return VUID_WRAP(VUID-Layer-Layer-04272);
1443     case 4273:
1444       return VUID_WRAP(VUID-Layer-Layer-04273);
1445     case 4274:
1446       return VUID_WRAP(VUID-Layer-Layer-04274);
1447     case 4275:
1448       return VUID_WRAP(VUID-Layer-Layer-04275);
1449     case 4276:
1450       return VUID_WRAP(VUID-Layer-Layer-04276);
1451     case 4281:
1452       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04281);
1453     case 4282:
1454       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
1455     case 4283:
1456       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
1457     case 4293:
1458       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
1459     case 4294:
1460       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294);
1461     case 4295:
1462       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295);
1463     case 4296:
1464       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296);
1465     case 4297:
1466       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
1467     case 4298:
1468       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
1469     case 4299:
1470       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
1471     case 4300:
1472       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
1473     case 4301:
1474       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
1475     case 4302:
1476       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
1477     case 4303:
1478       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
1479     case 4304:
1480       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
1481     case 4305:
1482       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
1483     case 4306:
1484       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
1485     case 4307:
1486       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
1487     case 4308:
1488       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
1489     case 4309:
1490       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04309);
1491     case 4310:
1492       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04310);
1493     case 4311:
1494       return VUID_WRAP(VUID-PointCoord-PointCoord-04311);
1495     case 4312:
1496       return VUID_WRAP(VUID-PointCoord-PointCoord-04312);
1497     case 4313:
1498       return VUID_WRAP(VUID-PointCoord-PointCoord-04313);
1499     case 4314:
1500       return VUID_WRAP(VUID-PointSize-PointSize-04314);
1501     case 4315:
1502       return VUID_WRAP(VUID-PointSize-PointSize-04315);
1503     case 4316:
1504       return VUID_WRAP(VUID-PointSize-PointSize-04316);
1505     case 4317:
1506       return VUID_WRAP(VUID-PointSize-PointSize-04317);
1507     case 4318:
1508       return VUID_WRAP(VUID-Position-Position-04318);
1509     case 4319:
1510       return VUID_WRAP(VUID-Position-Position-04319);
1511     case 4320:
1512       return VUID_WRAP(VUID-Position-Position-04320);
1513     case 4321:
1514       return VUID_WRAP(VUID-Position-Position-04321);
1515     case 4330:
1516       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330);
1517     case 4334:
1518       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
1519     case 4337:
1520       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
1521     case 4345:
1522       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
1523     case 4346:
1524       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
1525     case 4347:
1526       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
1527     case 4348:
1528       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
1529     case 4349:
1530       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
1531     case 4350:
1532       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
1533     case 4351:
1534       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
1535     case 4352:
1536       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
1537     case 4353:
1538       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
1539     case 4354:
1540       return VUID_WRAP(VUID-SampleId-SampleId-04354);
1541     case 4355:
1542       return VUID_WRAP(VUID-SampleId-SampleId-04355);
1543     case 4356:
1544       return VUID_WRAP(VUID-SampleId-SampleId-04356);
1545     case 4357:
1546       return VUID_WRAP(VUID-SampleMask-SampleMask-04357);
1547     case 4358:
1548       return VUID_WRAP(VUID-SampleMask-SampleMask-04358);
1549     case 4359:
1550       return VUID_WRAP(VUID-SampleMask-SampleMask-04359);
1551     case 4360:
1552       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04360);
1553     case 4361:
1554       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361);
1555     case 4362:
1556       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362);
1557     case 4367:
1558       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367);
1559     case 4368:
1560       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368);
1561     case 4369:
1562       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369);
1563     case 4370:
1564       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370);
1565     case 4371:
1566       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371);
1567     case 4372:
1568       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372);
1569     case 4373:
1570       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373);
1571     case 4374:
1572       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374);
1573     case 4375:
1574       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375);
1575     case 4376:
1576       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376);
1577     case 4377:
1578       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377);
1579     case 4378:
1580       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378);
1581     case 4379:
1582       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379);
1583     case 4380:
1584       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380);
1585     case 4381:
1586       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381);
1587     case 4382:
1588       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382);
1589     case 4383:
1590       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383);
1591     case 4387:
1592       return VUID_WRAP(VUID-TessCoord-TessCoord-04387);
1593     case 4388:
1594       return VUID_WRAP(VUID-TessCoord-TessCoord-04388);
1595     case 4389:
1596       return VUID_WRAP(VUID-TessCoord-TessCoord-04389);
1597     case 4390:
1598       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390);
1599     case 4391:
1600       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391);
1601     case 4392:
1602       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392);
1603     case 4393:
1604       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393);
1605     case 4394:
1606       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394);
1607     case 4395:
1608       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395);
1609     case 4396:
1610       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396);
1611     case 4397:
1612       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397);
1613     case 4398:
1614       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04398);
1615     case 4399:
1616       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04399);
1617     case 4400:
1618       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04400);
1619     case 4401:
1620       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04401);
1621     case 4402:
1622       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04402);
1623     case 4403:
1624       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403);
1625     case 4404:
1626       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404);
1627     case 4405:
1628       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405);
1629     case 4406:
1630       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406);
1631     case 4407:
1632       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04407);
1633     case 4408:
1634       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04408);
1635     case 4422:
1636       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04422);
1637     case 4423:
1638       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04423);
1639     case 4424:
1640       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04424);
1641     case 4425:
1642       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04425);
1643     case 4426:
1644       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
1645     case 4427:
1646       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
1647     case 4428:
1648       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
1649     case 4429:
1650       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
1651     case 4430:
1652       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
1653     case 4431:
1654       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
1655     case 4432:
1656       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
1657     case 4433:
1658       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
1659     case 4434:
1660       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
1661     case 4435:
1662       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
1663     case 4436:
1664       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
1665     case 4484:
1666       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
1667     case 4485:
1668       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485);
1669     case 4486:
1670       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04486);
1671     case 4490:
1672       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04490);
1673     case 4491:
1674       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491);
1675     case 4492:
1676       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492);
1677     case 4633:
1678       return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
1679     case 4635:
1680       return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
1681     case 4638:
1682       return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
1683     case 4639:
1684       return VUID_WRAP(VUID-StandaloneSpirv-None-04639);
1685     case 4640:
1686       return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
1687     case 4642:
1688       return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
1689     case 4651:
1690       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
1691     case 4652:
1692       return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652);
1693     case 4653:
1694       return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
1695     case 4654:
1696       return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
1697     case 4656:
1698       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
1699     case 4657:
1700       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
1701     case 4658:
1702       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
1703     case 4659:
1704       return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
1705     case 4662:
1706       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
1707     case 4663:
1708       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
1709     case 4669:
1710       return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
1711     case 4675:
1712       return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
1713     case 4677:
1714       return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
1715     case 4683:
1716       return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-04683);
1717     case 4685:
1718       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
1719     case 4686:
1720       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
1721     case 4710:
1722       return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
1723     case 4711:
1724       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
1725     case 4730:
1726       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730);
1727     case 4731:
1728       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731);
1729     case 4732:
1730       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
1731     case 4733:
1732       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
1733     default:
1734       return "";  // unknown id
1735   };
1736   // clang-format on
1737 }
1738 
1739 }  // namespace val
1740 }  // namespace spvtools
1741