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   // LocalSizeId is always allowed in non-Vulkan environments.
179   features_.env_allow_localsizeid = !spvIsVulkanEnv(env);
180 
181   // Only attempt to count if we have words, otherwise let the other validation
182   // fail and generate an error.
183   if (num_words > 0) {
184     // Count the number of instructions in the binary.
185     // This parse should not produce any error messages. Hijack the context and
186     // replace the message consumer so that we do not pollute any state in input
187     // consumer.
188     spv_context_t hijacked_context = *ctx;
189     hijacked_context.consumer = [](spv_message_level_t, const char*,
__anona037d8090202(spv_message_level_t, const char*, const spv_position_t&, const char*) 190                                    const spv_position_t&, const char*) {};
191     spvBinaryParse(&hijacked_context, this, words, num_words, setHeader,
192                    CountInstructions,
193                    /* diagnostic = */ nullptr);
194     preallocateStorage();
195   }
196   UpdateFeaturesBasedOnSpirvVersion(&features_, version_);
197 
198   friendly_mapper_ = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
199       context_, words_, num_words_);
200   name_mapper_ = friendly_mapper_->GetNameMapper();
201 }
202 
preallocateStorage()203 void ValidationState_t::preallocateStorage() {
204   ordered_instructions_.reserve(total_instructions_);
205   module_functions_.reserve(total_functions_);
206 }
207 
ForwardDeclareId(uint32_t id)208 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
209   unresolved_forward_ids_.insert(id);
210   return SPV_SUCCESS;
211 }
212 
RemoveIfForwardDeclared(uint32_t id)213 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
214   unresolved_forward_ids_.erase(id);
215   return SPV_SUCCESS;
216 }
217 
RegisterForwardPointer(uint32_t id)218 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
219   forward_pointer_ids_.insert(id);
220   return SPV_SUCCESS;
221 }
222 
IsForwardPointer(uint32_t id) const223 bool ValidationState_t::IsForwardPointer(uint32_t id) const {
224   return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
225 }
226 
AssignNameToId(uint32_t id,std::string name)227 void ValidationState_t::AssignNameToId(uint32_t id, std::string name) {
228   operand_names_[id] = name;
229 }
230 
getIdName(uint32_t id) const231 std::string ValidationState_t::getIdName(uint32_t id) const {
232   const std::string id_name = name_mapper_(id);
233 
234   std::stringstream out;
235   out << id << "[%" << id_name << "]";
236   return out.str();
237 }
238 
unresolved_forward_id_count() const239 size_t ValidationState_t::unresolved_forward_id_count() const {
240   return unresolved_forward_ids_.size();
241 }
242 
UnresolvedForwardIds() const243 std::vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
244   std::vector<uint32_t> out(std::begin(unresolved_forward_ids_),
245                             std::end(unresolved_forward_ids_));
246   return out;
247 }
248 
IsDefinedId(uint32_t id) const249 bool ValidationState_t::IsDefinedId(uint32_t id) const {
250   return all_definitions_.find(id) != std::end(all_definitions_);
251 }
252 
FindDef(uint32_t id) const253 const Instruction* ValidationState_t::FindDef(uint32_t id) const {
254   auto it = all_definitions_.find(id);
255   if (it == all_definitions_.end()) return nullptr;
256   return it->second;
257 }
258 
FindDef(uint32_t id)259 Instruction* ValidationState_t::FindDef(uint32_t id) {
260   auto it = all_definitions_.find(id);
261   if (it == all_definitions_.end()) return nullptr;
262   return it->second;
263 }
264 
current_layout_section() const265 ModuleLayoutSection ValidationState_t::current_layout_section() const {
266   return current_layout_section_;
267 }
268 
ProgressToNextLayoutSectionOrder()269 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
270   // Guard against going past the last element(kLayoutFunctionDefinitions)
271   if (current_layout_section_ <= kLayoutFunctionDefinitions) {
272     current_layout_section_ =
273         static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
274   }
275 }
276 
IsOpcodeInPreviousLayoutSection(SpvOp op)277 bool ValidationState_t::IsOpcodeInPreviousLayoutSection(SpvOp op) {
278   ModuleLayoutSection section =
279       InstructionLayoutSection(current_layout_section_, op);
280   return section < current_layout_section_;
281 }
282 
IsOpcodeInCurrentLayoutSection(SpvOp op)283 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
284   return IsInstructionInLayoutSection(current_layout_section_, op);
285 }
286 
diag(spv_result_t error_code,const Instruction * inst)287 DiagnosticStream ValidationState_t::diag(spv_result_t error_code,
288                                          const Instruction* inst) {
289   if (error_code == SPV_WARNING) {
290     if (num_of_warnings_ == max_num_of_warnings_) {
291       DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code)
292           << "Other warnings have been suppressed.\n";
293     }
294     if (num_of_warnings_ >= max_num_of_warnings_) {
295       return DiagnosticStream({0, 0, 0}, nullptr, "", error_code);
296     }
297     ++num_of_warnings_;
298   }
299 
300   std::string disassembly;
301   if (inst) disassembly = Disassemble(*inst);
302 
303   return DiagnosticStream({0, 0, inst ? inst->LineNum() : 0},
304                           context_->consumer, disassembly, error_code);
305 }
306 
functions()307 std::vector<Function>& ValidationState_t::functions() {
308   return module_functions_;
309 }
310 
current_function()311 Function& ValidationState_t::current_function() {
312   assert(in_function_body());
313   return module_functions_.back();
314 }
315 
current_function() const316 const Function& ValidationState_t::current_function() const {
317   assert(in_function_body());
318   return module_functions_.back();
319 }
320 
function(uint32_t id) const321 const Function* ValidationState_t::function(uint32_t id) const {
322   const auto it = id_to_function_.find(id);
323   if (it == id_to_function_.end()) return nullptr;
324   return it->second;
325 }
326 
function(uint32_t id)327 Function* ValidationState_t::function(uint32_t id) {
328   auto it = id_to_function_.find(id);
329   if (it == id_to_function_.end()) return nullptr;
330   return it->second;
331 }
332 
in_function_body() const333 bool ValidationState_t::in_function_body() const { return in_function_; }
334 
in_block() const335 bool ValidationState_t::in_block() const {
336   return module_functions_.empty() == false &&
337          module_functions_.back().current_block() != nullptr;
338 }
339 
RegisterCapability(SpvCapability cap)340 void ValidationState_t::RegisterCapability(SpvCapability cap) {
341   // Avoid redundant work.  Otherwise the recursion could induce work
342   // quadrdatic in the capability dependency depth. (Ok, not much, but
343   // it's something.)
344   if (module_capabilities_.Contains(cap)) return;
345 
346   module_capabilities_.Add(cap);
347   spv_operand_desc desc;
348   if (SPV_SUCCESS ==
349       grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
350     CapabilitySet(desc->numCapabilities, desc->capabilities)
351         .ForEach([this](SpvCapability c) { RegisterCapability(c); });
352   }
353 
354   switch (cap) {
355     case SpvCapabilityKernel:
356       features_.group_ops_reduce_and_scans = true;
357       break;
358     case SpvCapabilityInt8:
359       features_.use_int8_type = true;
360       features_.declare_int8_type = true;
361       break;
362     case SpvCapabilityStorageBuffer8BitAccess:
363     case SpvCapabilityUniformAndStorageBuffer8BitAccess:
364     case SpvCapabilityStoragePushConstant8:
365     case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
366       features_.declare_int8_type = true;
367       break;
368     case SpvCapabilityInt16:
369       features_.declare_int16_type = true;
370       break;
371     case SpvCapabilityFloat16:
372     case SpvCapabilityFloat16Buffer:
373       features_.declare_float16_type = true;
374       break;
375     case SpvCapabilityStorageUniformBufferBlock16:
376     case SpvCapabilityStorageUniform16:
377     case SpvCapabilityStoragePushConstant16:
378     case SpvCapabilityStorageInputOutput16:
379     case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
380       features_.declare_int16_type = true;
381       features_.declare_float16_type = true;
382       features_.free_fp_rounding_mode = true;
383       break;
384     case SpvCapabilityVariablePointers:
385       features_.variable_pointers = true;
386       features_.variable_pointers_storage_buffer = true;
387       break;
388     case SpvCapabilityVariablePointersStorageBuffer:
389       features_.variable_pointers_storage_buffer = true;
390       break;
391     default:
392       break;
393   }
394 }
395 
RegisterExtension(Extension ext)396 void ValidationState_t::RegisterExtension(Extension ext) {
397   if (module_extensions_.Contains(ext)) return;
398 
399   module_extensions_.Add(ext);
400 
401   switch (ext) {
402     case kSPV_AMD_gpu_shader_half_float:
403     case kSPV_AMD_gpu_shader_half_float_fetch:
404       // SPV_AMD_gpu_shader_half_float enables float16 type.
405       // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
406       features_.declare_float16_type = true;
407       break;
408     case kSPV_AMD_gpu_shader_int16:
409       // This is not yet in the extension, but it's recommended for it.
410       // See https://github.com/KhronosGroup/glslang/issues/848
411       features_.uconvert_spec_constant_op = true;
412       break;
413     case kSPV_AMD_shader_ballot:
414       // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
415       // enables the use of group operations Reduce, InclusiveScan,
416       // and ExclusiveScan.  Enable it manually.
417       // https://github.com/KhronosGroup/SPIRV-Tools/issues/991
418       features_.group_ops_reduce_and_scans = true;
419       break;
420     default:
421       break;
422   }
423 }
424 
HasAnyOfCapabilities(const CapabilitySet & capabilities) const425 bool ValidationState_t::HasAnyOfCapabilities(
426     const CapabilitySet& capabilities) const {
427   return module_capabilities_.HasAnyOf(capabilities);
428 }
429 
HasAnyOfExtensions(const ExtensionSet & extensions) const430 bool ValidationState_t::HasAnyOfExtensions(
431     const ExtensionSet& extensions) const {
432   return module_extensions_.HasAnyOf(extensions);
433 }
434 
set_addressing_model(SpvAddressingModel am)435 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
436   addressing_model_ = am;
437   switch (am) {
438     case SpvAddressingModelPhysical32:
439       pointer_size_and_alignment_ = 4;
440       break;
441     default:
442     // fall through
443     case SpvAddressingModelPhysical64:
444     case SpvAddressingModelPhysicalStorageBuffer64EXT:
445       pointer_size_and_alignment_ = 8;
446       break;
447   }
448 }
449 
addressing_model() const450 SpvAddressingModel ValidationState_t::addressing_model() const {
451   return addressing_model_;
452 }
453 
set_memory_model(SpvMemoryModel mm)454 void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
455   memory_model_ = mm;
456 }
457 
memory_model() const458 SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
459 
RegisterFunction(uint32_t id,uint32_t ret_type_id,SpvFunctionControlMask function_control,uint32_t function_type_id)460 spv_result_t ValidationState_t::RegisterFunction(
461     uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
462     uint32_t function_type_id) {
463   assert(in_function_body() == false &&
464          "RegisterFunction can only be called when parsing the binary outside "
465          "of another function");
466   in_function_ = true;
467   module_functions_.emplace_back(id, ret_type_id, function_control,
468                                  function_type_id);
469   id_to_function_.emplace(id, &current_function());
470 
471   // TODO(umar): validate function type and type_id
472 
473   return SPV_SUCCESS;
474 }
475 
RegisterFunctionEnd()476 spv_result_t ValidationState_t::RegisterFunctionEnd() {
477   assert(in_function_body() == true &&
478          "RegisterFunctionEnd can only be called when parsing the binary "
479          "inside of another function");
480   assert(in_block() == false &&
481          "RegisterFunctionParameter can only be called when parsing the binary "
482          "ouside of a block");
483   current_function().RegisterFunctionEnd();
484   in_function_ = false;
485   return SPV_SUCCESS;
486 }
487 
AddOrderedInstruction(const spv_parsed_instruction_t * inst)488 Instruction* ValidationState_t::AddOrderedInstruction(
489     const spv_parsed_instruction_t* inst) {
490   ordered_instructions_.emplace_back(inst);
491   ordered_instructions_.back().SetLineNum(ordered_instructions_.size());
492   return &ordered_instructions_.back();
493 }
494 
495 // Improves diagnostic messages by collecting names of IDs
RegisterDebugInstruction(const Instruction * inst)496 void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
497   switch (inst->opcode()) {
498     case SpvOpName: {
499       const auto target = inst->GetOperandAs<uint32_t>(0);
500       const auto* str = reinterpret_cast<const char*>(inst->words().data() +
501                                                       inst->operand(1).offset);
502       AssignNameToId(target, str);
503       break;
504     }
505     case SpvOpMemberName: {
506       const auto target = inst->GetOperandAs<uint32_t>(0);
507       const auto* str = reinterpret_cast<const char*>(inst->words().data() +
508                                                       inst->operand(2).offset);
509       AssignNameToId(target, str);
510       break;
511     }
512     case SpvOpSourceContinued:
513     case SpvOpSource:
514     case SpvOpSourceExtension:
515     case SpvOpString:
516     case SpvOpLine:
517     case SpvOpNoLine:
518     default:
519       break;
520   }
521 }
522 
RegisterInstruction(Instruction * inst)523 void ValidationState_t::RegisterInstruction(Instruction* inst) {
524   if (inst->id()) all_definitions_.insert(std::make_pair(inst->id(), inst));
525 
526   // Some validation checks are easier by getting all the consumers
527   for (uint16_t i = 0; i < inst->operands().size(); ++i) {
528     const spv_parsed_operand_t& operand = inst->operand(i);
529     if ((SPV_OPERAND_TYPE_ID == operand.type) ||
530         (SPV_OPERAND_TYPE_TYPE_ID == operand.type)) {
531       const uint32_t operand_word = inst->word(operand.offset);
532       Instruction* operand_inst = FindDef(operand_word);
533       if (!operand_inst) {
534         continue;
535       }
536 
537       // If the instruction is using an OpTypeSampledImage as an operand, it
538       // should be recorded. The validator will ensure that all usages of an
539       // OpTypeSampledImage and its definition are in the same basic block.
540       if ((SPV_OPERAND_TYPE_ID == operand.type) &&
541           (SpvOpSampledImage == operand_inst->opcode())) {
542         RegisterSampledImageConsumer(operand_word, inst);
543       }
544 
545       // In order to track storage classes (not Function) used per execution
546       // model we can't use RegisterExecutionModelLimitation on instructions
547       // like OpTypePointer which are going to be in the pre-function section.
548       // Instead just need to register storage class usage for consumers in a
549       // function block.
550       if (inst->function()) {
551         if (operand_inst->opcode() == SpvOpTypePointer) {
552           RegisterStorageClassConsumer(
553               operand_inst->GetOperandAs<SpvStorageClass>(1), inst);
554         } else if (operand_inst->opcode() == SpvOpVariable) {
555           RegisterStorageClassConsumer(
556               operand_inst->GetOperandAs<SpvStorageClass>(2), inst);
557         }
558       }
559     }
560   }
561 }
562 
getSampledImageConsumers(uint32_t sampled_image_id) const563 std::vector<Instruction*> ValidationState_t::getSampledImageConsumers(
564     uint32_t sampled_image_id) const {
565   std::vector<Instruction*> result;
566   auto iter = sampled_image_consumers_.find(sampled_image_id);
567   if (iter != sampled_image_consumers_.end()) {
568     result = iter->second;
569   }
570   return result;
571 }
572 
RegisterSampledImageConsumer(uint32_t sampled_image_id,Instruction * consumer)573 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
574                                                      Instruction* consumer) {
575   sampled_image_consumers_[sampled_image_id].push_back(consumer);
576 }
577 
RegisterStorageClassConsumer(SpvStorageClass storage_class,Instruction * consumer)578 void ValidationState_t::RegisterStorageClassConsumer(
579     SpvStorageClass storage_class, Instruction* consumer) {
580   if (spvIsVulkanEnv(context()->target_env)) {
581     if (storage_class == SpvStorageClassOutput) {
582       std::string errorVUID = VkErrorID(4644);
583       function(consumer->function()->id())
584           ->RegisterExecutionModelLimitation([errorVUID](
585               SpvExecutionModel model, std::string* message) {
586             if (model == SpvExecutionModelGLCompute ||
587                 model == SpvExecutionModelRayGenerationKHR ||
588                 model == SpvExecutionModelIntersectionKHR ||
589                 model == SpvExecutionModelAnyHitKHR ||
590                 model == SpvExecutionModelClosestHitKHR ||
591                 model == SpvExecutionModelMissKHR ||
592                 model == SpvExecutionModelCallableKHR) {
593               if (message) {
594                 *message =
595                     errorVUID +
596                     "in Vulkan evironment, Output Storage Class must not be "
597                     "used in GLCompute, RayGenerationKHR, IntersectionKHR, "
598                     "AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
599                     "execution models";
600               }
601               return false;
602             }
603             return true;
604           });
605     }
606 
607     if (storage_class == SpvStorageClassWorkgroup) {
608       std::string errorVUID = VkErrorID(4645);
609       function(consumer->function()->id())
610           ->RegisterExecutionModelLimitation([errorVUID](
611               SpvExecutionModel model, std::string* message) {
612             if (model != SpvExecutionModelGLCompute &&
613                 model != SpvExecutionModelTaskNV &&
614                 model != SpvExecutionModelMeshNV) {
615               if (message) {
616                 *message =
617                     errorVUID +
618                     "in Vulkan evironment, Workgroup Storage Class is limited "
619                     "to MeshNV, TaskNV, and GLCompute execution model";
620               }
621               return false;
622             }
623             return true;
624           });
625     }
626   }
627 }
628 
getIdBound() const629 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
630 
setIdBound(const uint32_t bound)631 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
632 
RegisterUniqueTypeDeclaration(const Instruction * inst)633 bool ValidationState_t::RegisterUniqueTypeDeclaration(const Instruction* inst) {
634   std::vector<uint32_t> key;
635   key.push_back(static_cast<uint32_t>(inst->opcode()));
636   for (size_t index = 0; index < inst->operands().size(); ++index) {
637     const spv_parsed_operand_t& operand = inst->operand(index);
638 
639     if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
640 
641     const int words_begin = operand.offset;
642     const int words_end = words_begin + operand.num_words;
643     assert(words_end <= static_cast<int>(inst->words().size()));
644 
645     key.insert(key.end(), inst->words().begin() + words_begin,
646                inst->words().begin() + words_end);
647   }
648 
649   return unique_type_declarations_.insert(std::move(key)).second;
650 }
651 
GetTypeId(uint32_t id) const652 uint32_t ValidationState_t::GetTypeId(uint32_t id) const {
653   const Instruction* inst = FindDef(id);
654   return inst ? inst->type_id() : 0;
655 }
656 
GetIdOpcode(uint32_t id) const657 SpvOp ValidationState_t::GetIdOpcode(uint32_t id) const {
658   const Instruction* inst = FindDef(id);
659   return inst ? inst->opcode() : SpvOpNop;
660 }
661 
GetComponentType(uint32_t id) const662 uint32_t ValidationState_t::GetComponentType(uint32_t id) const {
663   const Instruction* inst = FindDef(id);
664   assert(inst);
665 
666   switch (inst->opcode()) {
667     case SpvOpTypeFloat:
668     case SpvOpTypeInt:
669     case SpvOpTypeBool:
670       return id;
671 
672     case SpvOpTypeVector:
673       return inst->word(2);
674 
675     case SpvOpTypeMatrix:
676       return GetComponentType(inst->word(2));
677 
678     case SpvOpTypeCooperativeMatrixNV:
679       return inst->word(2);
680 
681     default:
682       break;
683   }
684 
685   if (inst->type_id()) return GetComponentType(inst->type_id());
686 
687   assert(0);
688   return 0;
689 }
690 
GetDimension(uint32_t id) const691 uint32_t ValidationState_t::GetDimension(uint32_t id) const {
692   const Instruction* inst = FindDef(id);
693   assert(inst);
694 
695   switch (inst->opcode()) {
696     case SpvOpTypeFloat:
697     case SpvOpTypeInt:
698     case SpvOpTypeBool:
699       return 1;
700 
701     case SpvOpTypeVector:
702     case SpvOpTypeMatrix:
703       return inst->word(3);
704 
705     case SpvOpTypeCooperativeMatrixNV:
706       // Actual dimension isn't known, return 0
707       return 0;
708 
709     default:
710       break;
711   }
712 
713   if (inst->type_id()) return GetDimension(inst->type_id());
714 
715   assert(0);
716   return 0;
717 }
718 
GetBitWidth(uint32_t id) const719 uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
720   const uint32_t component_type_id = GetComponentType(id);
721   const Instruction* inst = FindDef(component_type_id);
722   assert(inst);
723 
724   if (inst->opcode() == SpvOpTypeFloat || inst->opcode() == SpvOpTypeInt)
725     return inst->word(2);
726 
727   if (inst->opcode() == SpvOpTypeBool) return 1;
728 
729   assert(0);
730   return 0;
731 }
732 
IsVoidType(uint32_t id) const733 bool ValidationState_t::IsVoidType(uint32_t id) const {
734   const Instruction* inst = FindDef(id);
735   return inst && inst->opcode() == SpvOpTypeVoid;
736 }
737 
IsFloatScalarType(uint32_t id) const738 bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
739   const Instruction* inst = FindDef(id);
740   return inst && inst->opcode() == SpvOpTypeFloat;
741 }
742 
IsFloatVectorType(uint32_t id) const743 bool ValidationState_t::IsFloatVectorType(uint32_t id) const {
744   const Instruction* inst = FindDef(id);
745   if (!inst) {
746     return false;
747   }
748 
749   if (inst->opcode() == SpvOpTypeVector) {
750     return IsFloatScalarType(GetComponentType(id));
751   }
752 
753   return false;
754 }
755 
IsFloatScalarOrVectorType(uint32_t id) const756 bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
757   const Instruction* inst = FindDef(id);
758   if (!inst) {
759     return false;
760   }
761 
762   if (inst->opcode() == SpvOpTypeFloat) {
763     return true;
764   }
765 
766   if (inst->opcode() == SpvOpTypeVector) {
767     return IsFloatScalarType(GetComponentType(id));
768   }
769 
770   return false;
771 }
772 
IsIntScalarType(uint32_t id) const773 bool ValidationState_t::IsIntScalarType(uint32_t id) const {
774   const Instruction* inst = FindDef(id);
775   return inst && inst->opcode() == SpvOpTypeInt;
776 }
777 
IsIntVectorType(uint32_t id) const778 bool ValidationState_t::IsIntVectorType(uint32_t id) const {
779   const Instruction* inst = FindDef(id);
780   if (!inst) {
781     return false;
782   }
783 
784   if (inst->opcode() == SpvOpTypeVector) {
785     return IsIntScalarType(GetComponentType(id));
786   }
787 
788   return false;
789 }
790 
IsIntScalarOrVectorType(uint32_t id) const791 bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const {
792   const Instruction* inst = FindDef(id);
793   if (!inst) {
794     return false;
795   }
796 
797   if (inst->opcode() == SpvOpTypeInt) {
798     return true;
799   }
800 
801   if (inst->opcode() == SpvOpTypeVector) {
802     return IsIntScalarType(GetComponentType(id));
803   }
804 
805   return false;
806 }
807 
IsUnsignedIntScalarType(uint32_t id) const808 bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const {
809   const Instruction* inst = FindDef(id);
810   return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 0;
811 }
812 
IsUnsignedIntVectorType(uint32_t id) const813 bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const {
814   const Instruction* inst = FindDef(id);
815   if (!inst) {
816     return false;
817   }
818 
819   if (inst->opcode() == SpvOpTypeVector) {
820     return IsUnsignedIntScalarType(GetComponentType(id));
821   }
822 
823   return false;
824 }
825 
IsSignedIntScalarType(uint32_t id) const826 bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
827   const Instruction* inst = FindDef(id);
828   return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 1;
829 }
830 
IsSignedIntVectorType(uint32_t id) const831 bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const {
832   const Instruction* inst = FindDef(id);
833   if (!inst) {
834     return false;
835   }
836 
837   if (inst->opcode() == SpvOpTypeVector) {
838     return IsSignedIntScalarType(GetComponentType(id));
839   }
840 
841   return false;
842 }
843 
IsBoolScalarType(uint32_t id) const844 bool ValidationState_t::IsBoolScalarType(uint32_t id) const {
845   const Instruction* inst = FindDef(id);
846   return inst && inst->opcode() == SpvOpTypeBool;
847 }
848 
IsBoolVectorType(uint32_t id) const849 bool ValidationState_t::IsBoolVectorType(uint32_t id) const {
850   const Instruction* inst = FindDef(id);
851   if (!inst) {
852     return false;
853   }
854 
855   if (inst->opcode() == SpvOpTypeVector) {
856     return IsBoolScalarType(GetComponentType(id));
857   }
858 
859   return false;
860 }
861 
IsBoolScalarOrVectorType(uint32_t id) const862 bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const {
863   const Instruction* inst = FindDef(id);
864   if (!inst) {
865     return false;
866   }
867 
868   if (inst->opcode() == SpvOpTypeBool) {
869     return true;
870   }
871 
872   if (inst->opcode() == SpvOpTypeVector) {
873     return IsBoolScalarType(GetComponentType(id));
874   }
875 
876   return false;
877 }
878 
IsFloatMatrixType(uint32_t id) const879 bool ValidationState_t::IsFloatMatrixType(uint32_t id) const {
880   const Instruction* inst = FindDef(id);
881   if (!inst) {
882     return false;
883   }
884 
885   if (inst->opcode() == SpvOpTypeMatrix) {
886     return IsFloatScalarType(GetComponentType(id));
887   }
888 
889   return false;
890 }
891 
GetMatrixTypeInfo(uint32_t id,uint32_t * num_rows,uint32_t * num_cols,uint32_t * column_type,uint32_t * component_type) const892 bool ValidationState_t::GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows,
893                                           uint32_t* num_cols,
894                                           uint32_t* column_type,
895                                           uint32_t* component_type) const {
896   if (!id) return false;
897 
898   const Instruction* mat_inst = FindDef(id);
899   assert(mat_inst);
900   if (mat_inst->opcode() != SpvOpTypeMatrix) return false;
901 
902   const uint32_t vec_type = mat_inst->word(2);
903   const Instruction* vec_inst = FindDef(vec_type);
904   assert(vec_inst);
905 
906   if (vec_inst->opcode() != SpvOpTypeVector) {
907     assert(0);
908     return false;
909   }
910 
911   *num_cols = mat_inst->word(3);
912   *num_rows = vec_inst->word(3);
913   *column_type = mat_inst->word(2);
914   *component_type = vec_inst->word(2);
915 
916   return true;
917 }
918 
GetStructMemberTypes(uint32_t struct_type_id,std::vector<uint32_t> * member_types) const919 bool ValidationState_t::GetStructMemberTypes(
920     uint32_t struct_type_id, std::vector<uint32_t>* member_types) const {
921   member_types->clear();
922   if (!struct_type_id) return false;
923 
924   const Instruction* inst = FindDef(struct_type_id);
925   assert(inst);
926   if (inst->opcode() != SpvOpTypeStruct) return false;
927 
928   *member_types =
929       std::vector<uint32_t>(inst->words().cbegin() + 2, inst->words().cend());
930 
931   if (member_types->empty()) return false;
932 
933   return true;
934 }
935 
IsPointerType(uint32_t id) const936 bool ValidationState_t::IsPointerType(uint32_t id) const {
937   const Instruction* inst = FindDef(id);
938   return inst && inst->opcode() == SpvOpTypePointer;
939 }
940 
GetPointerTypeInfo(uint32_t id,uint32_t * data_type,uint32_t * storage_class) const941 bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
942                                            uint32_t* storage_class) const {
943   if (!id) return false;
944 
945   const Instruction* inst = FindDef(id);
946   assert(inst);
947   if (inst->opcode() != SpvOpTypePointer) return false;
948 
949   *storage_class = inst->word(2);
950   *data_type = inst->word(3);
951   return true;
952 }
953 
IsCooperativeMatrixType(uint32_t id) const954 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
955   const Instruction* inst = FindDef(id);
956   return inst && inst->opcode() == SpvOpTypeCooperativeMatrixNV;
957 }
958 
IsFloatCooperativeMatrixType(uint32_t id) const959 bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
960   if (!IsCooperativeMatrixType(id)) return false;
961   return IsFloatScalarType(FindDef(id)->word(2));
962 }
963 
IsIntCooperativeMatrixType(uint32_t id) const964 bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
965   if (!IsCooperativeMatrixType(id)) return false;
966   return IsIntScalarType(FindDef(id)->word(2));
967 }
968 
IsUnsignedIntCooperativeMatrixType(uint32_t id) const969 bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
970   if (!IsCooperativeMatrixType(id)) return false;
971   return IsUnsignedIntScalarType(FindDef(id)->word(2));
972 }
973 
CooperativeMatrixShapesMatch(const Instruction * inst,uint32_t m1,uint32_t m2)974 spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
975     const Instruction* inst, uint32_t m1, uint32_t m2) {
976   const auto m1_type = FindDef(m1);
977   const auto m2_type = FindDef(m2);
978 
979   if (m1_type->opcode() != SpvOpTypeCooperativeMatrixNV ||
980       m2_type->opcode() != SpvOpTypeCooperativeMatrixNV) {
981     return diag(SPV_ERROR_INVALID_DATA, inst)
982            << "Expected cooperative matrix types";
983   }
984 
985   uint32_t m1_scope_id = m1_type->GetOperandAs<uint32_t>(2);
986   uint32_t m1_rows_id = m1_type->GetOperandAs<uint32_t>(3);
987   uint32_t m1_cols_id = m1_type->GetOperandAs<uint32_t>(4);
988 
989   uint32_t m2_scope_id = m2_type->GetOperandAs<uint32_t>(2);
990   uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
991   uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
992 
993   bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
994        m2_is_const_int32 = false;
995   uint32_t m1_value = 0, m2_value = 0;
996 
997   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
998       EvalInt32IfConst(m1_scope_id);
999   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1000       EvalInt32IfConst(m2_scope_id);
1001 
1002   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1003     return diag(SPV_ERROR_INVALID_DATA, inst)
1004            << "Expected scopes of Matrix and Result Type to be "
1005            << "identical";
1006   }
1007 
1008   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1009       EvalInt32IfConst(m1_rows_id);
1010   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1011       EvalInt32IfConst(m2_rows_id);
1012 
1013   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1014     return diag(SPV_ERROR_INVALID_DATA, inst)
1015            << "Expected rows of Matrix type and Result Type to be "
1016            << "identical";
1017   }
1018 
1019   std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1020       EvalInt32IfConst(m1_cols_id);
1021   std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1022       EvalInt32IfConst(m2_cols_id);
1023 
1024   if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1025     return diag(SPV_ERROR_INVALID_DATA, inst)
1026            << "Expected columns of Matrix type and Result Type to be "
1027            << "identical";
1028   }
1029 
1030   return SPV_SUCCESS;
1031 }
1032 
GetOperandTypeId(const Instruction * inst,size_t operand_index) const1033 uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst,
1034                                              size_t operand_index) const {
1035   return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
1036 }
1037 
GetConstantValUint64(uint32_t id,uint64_t * val) const1038 bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const {
1039   const Instruction* inst = FindDef(id);
1040   if (!inst) {
1041     assert(0 && "Instruction not found");
1042     return false;
1043   }
1044 
1045   if (inst->opcode() != SpvOpConstant && inst->opcode() != SpvOpSpecConstant)
1046     return false;
1047 
1048   if (!IsIntScalarType(inst->type_id())) return false;
1049 
1050   if (inst->words().size() == 4) {
1051     *val = inst->word(3);
1052   } else {
1053     assert(inst->words().size() == 5);
1054     *val = inst->word(3);
1055     *val |= uint64_t(inst->word(4)) << 32;
1056   }
1057   return true;
1058 }
1059 
EvalInt32IfConst(uint32_t id) const1060 std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
1061     uint32_t id) const {
1062   const Instruction* const inst = FindDef(id);
1063   assert(inst);
1064   const uint32_t type = inst->type_id();
1065 
1066   if (type == 0 || !IsIntScalarType(type) || GetBitWidth(type) != 32) {
1067     return std::make_tuple(false, false, 0);
1068   }
1069 
1070   // Spec constant values cannot be evaluated so don't consider constant for
1071   // the purpose of this method.
1072   if (!spvOpcodeIsConstant(inst->opcode()) ||
1073       spvOpcodeIsSpecConstant(inst->opcode())) {
1074     return std::make_tuple(true, false, 0);
1075   }
1076 
1077   if (inst->opcode() == SpvOpConstantNull) {
1078     return std::make_tuple(true, true, 0);
1079   }
1080 
1081   assert(inst->words().size() == 4);
1082   return std::make_tuple(true, true, inst->word(3));
1083 }
1084 
ComputeFunctionToEntryPointMapping()1085 void ValidationState_t::ComputeFunctionToEntryPointMapping() {
1086   for (const uint32_t entry_point : entry_points()) {
1087     std::stack<uint32_t> call_stack;
1088     std::set<uint32_t> visited;
1089     call_stack.push(entry_point);
1090     while (!call_stack.empty()) {
1091       const uint32_t called_func_id = call_stack.top();
1092       call_stack.pop();
1093       if (!visited.insert(called_func_id).second) continue;
1094 
1095       function_to_entry_points_[called_func_id].push_back(entry_point);
1096 
1097       const Function* called_func = function(called_func_id);
1098       if (called_func) {
1099         // Other checks should error out on this invalid SPIR-V.
1100         for (const uint32_t new_call : called_func->function_call_targets()) {
1101           call_stack.push(new_call);
1102         }
1103       }
1104     }
1105   }
1106 }
1107 
ComputeRecursiveEntryPoints()1108 void ValidationState_t::ComputeRecursiveEntryPoints() {
1109   for (const Function& func : functions()) {
1110     std::stack<uint32_t> call_stack;
1111     std::set<uint32_t> visited;
1112 
1113     for (const uint32_t new_call : func.function_call_targets()) {
1114       call_stack.push(new_call);
1115     }
1116 
1117     while (!call_stack.empty()) {
1118       const uint32_t called_func_id = call_stack.top();
1119       call_stack.pop();
1120 
1121       if (!visited.insert(called_func_id).second) continue;
1122 
1123       if (called_func_id == func.id()) {
1124         for (const uint32_t entry_point :
1125              function_to_entry_points_[called_func_id])
1126           recursive_entry_points_.insert(entry_point);
1127         break;
1128       }
1129 
1130       const Function* called_func = function(called_func_id);
1131       if (called_func) {
1132         // Other checks should error out on this invalid SPIR-V.
1133         for (const uint32_t new_call : called_func->function_call_targets()) {
1134           call_stack.push(new_call);
1135         }
1136       }
1137     }
1138   }
1139 }
1140 
FunctionEntryPoints(uint32_t func) const1141 const std::vector<uint32_t>& ValidationState_t::FunctionEntryPoints(
1142     uint32_t func) const {
1143   auto iter = function_to_entry_points_.find(func);
1144   if (iter == function_to_entry_points_.end()) {
1145     return empty_ids_;
1146   } else {
1147     return iter->second;
1148   }
1149 }
1150 
EntryPointReferences(uint32_t id) const1151 std::set<uint32_t> ValidationState_t::EntryPointReferences(uint32_t id) const {
1152   std::set<uint32_t> referenced_entry_points;
1153   const auto inst = FindDef(id);
1154   if (!inst) return referenced_entry_points;
1155 
1156   std::vector<const Instruction*> stack;
1157   stack.push_back(inst);
1158   while (!stack.empty()) {
1159     const auto current_inst = stack.back();
1160     stack.pop_back();
1161 
1162     if (const auto func = current_inst->function()) {
1163       // Instruction lives in a function, we can stop searching.
1164       const auto function_entry_points = FunctionEntryPoints(func->id());
1165       referenced_entry_points.insert(function_entry_points.begin(),
1166                                      function_entry_points.end());
1167     } else {
1168       // Instruction is in the global scope, keep searching its uses.
1169       for (auto pair : current_inst->uses()) {
1170         const auto next_inst = pair.first;
1171         stack.push_back(next_inst);
1172       }
1173     }
1174   }
1175 
1176   return referenced_entry_points;
1177 }
1178 
Disassemble(const Instruction & inst) const1179 std::string ValidationState_t::Disassemble(const Instruction& inst) const {
1180   const spv_parsed_instruction_t& c_inst(inst.c_inst());
1181   return Disassemble(c_inst.words, c_inst.num_words);
1182 }
1183 
Disassemble(const uint32_t * words,uint16_t num_words) const1184 std::string ValidationState_t::Disassemble(const uint32_t* words,
1185                                            uint16_t num_words) const {
1186   uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1187                                  SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
1188 
1189   return spvInstructionBinaryToText(context()->target_env, words, num_words,
1190                                     words_, num_words_, disassembly_options);
1191 }
1192 
LogicallyMatch(const Instruction * lhs,const Instruction * rhs,bool check_decorations)1193 bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
1194                                        const Instruction* rhs,
1195                                        bool check_decorations) {
1196   if (lhs->opcode() != rhs->opcode()) {
1197     return false;
1198   }
1199 
1200   if (check_decorations) {
1201     const auto& dec_a = id_decorations(lhs->id());
1202     const auto& dec_b = id_decorations(rhs->id());
1203 
1204     for (const auto& dec : dec_b) {
1205       if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) {
1206         return false;
1207       }
1208     }
1209   }
1210 
1211   if (lhs->opcode() == SpvOpTypeArray) {
1212     // Size operands must match.
1213     if (lhs->GetOperandAs<uint32_t>(2u) != rhs->GetOperandAs<uint32_t>(2u)) {
1214       return false;
1215     }
1216 
1217     // Elements must match or logically match.
1218     const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(1u);
1219     const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(1u);
1220     if (lhs_ele_id == rhs_ele_id) {
1221       return true;
1222     }
1223 
1224     const auto lhs_ele = FindDef(lhs_ele_id);
1225     const auto rhs_ele = FindDef(rhs_ele_id);
1226     if (!lhs_ele || !rhs_ele) {
1227       return false;
1228     }
1229     return LogicallyMatch(lhs_ele, rhs_ele, check_decorations);
1230   } else if (lhs->opcode() == SpvOpTypeStruct) {
1231     // Number of elements must match.
1232     if (lhs->operands().size() != rhs->operands().size()) {
1233       return false;
1234     }
1235 
1236     for (size_t i = 1u; i < lhs->operands().size(); ++i) {
1237       const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(i);
1238       const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(i);
1239       // Elements must match or logically match.
1240       if (lhs_ele_id == rhs_ele_id) {
1241         continue;
1242       }
1243 
1244       const auto lhs_ele = FindDef(lhs_ele_id);
1245       const auto rhs_ele = FindDef(rhs_ele_id);
1246       if (!lhs_ele || !rhs_ele) {
1247         return false;
1248       }
1249 
1250       if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) {
1251         return false;
1252       }
1253     }
1254 
1255     // All checks passed.
1256     return true;
1257   }
1258 
1259   // No other opcodes are acceptable at this point. Arrays and structs are
1260   // caught above and if they're elements are not arrays or structs they are
1261   // required to match exactly.
1262   return false;
1263 }
1264 
TracePointer(const Instruction * inst) const1265 const Instruction* ValidationState_t::TracePointer(
1266     const Instruction* inst) const {
1267   auto base_ptr = inst;
1268   while (base_ptr->opcode() == SpvOpAccessChain ||
1269          base_ptr->opcode() == SpvOpInBoundsAccessChain ||
1270          base_ptr->opcode() == SpvOpPtrAccessChain ||
1271          base_ptr->opcode() == SpvOpInBoundsPtrAccessChain ||
1272          base_ptr->opcode() == SpvOpCopyObject) {
1273     base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
1274   }
1275   return base_ptr;
1276 }
1277 
ContainsType(uint32_t id,const std::function<bool (const Instruction *)> & f,bool traverse_all_types) const1278 bool ValidationState_t::ContainsType(
1279     uint32_t id, const std::function<bool(const Instruction*)>& f,
1280     bool traverse_all_types) const {
1281   const auto inst = FindDef(id);
1282   if (!inst) return false;
1283 
1284   if (f(inst)) return true;
1285 
1286   switch (inst->opcode()) {
1287     case SpvOpTypeArray:
1288     case SpvOpTypeRuntimeArray:
1289     case SpvOpTypeVector:
1290     case SpvOpTypeMatrix:
1291     case SpvOpTypeImage:
1292     case SpvOpTypeSampledImage:
1293     case SpvOpTypeCooperativeMatrixNV:
1294       return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
1295                           traverse_all_types);
1296     case SpvOpTypePointer:
1297       if (IsForwardPointer(id)) return false;
1298       if (traverse_all_types) {
1299         return ContainsType(inst->GetOperandAs<uint32_t>(2u), f,
1300                             traverse_all_types);
1301       }
1302       break;
1303     case SpvOpTypeFunction:
1304     case SpvOpTypeStruct:
1305       if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) {
1306         return false;
1307       }
1308       for (uint32_t i = 1; i < inst->operands().size(); ++i) {
1309         if (ContainsType(inst->GetOperandAs<uint32_t>(i), f,
1310                          traverse_all_types)) {
1311           return true;
1312         }
1313       }
1314       break;
1315     default:
1316       break;
1317   }
1318 
1319   return false;
1320 }
1321 
ContainsSizedIntOrFloatType(uint32_t id,SpvOp type,uint32_t width) const1322 bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
1323                                                     uint32_t width) const {
1324   if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
1325 
1326   const auto f = [type, width](const Instruction* inst) {
1327     if (inst->opcode() == type) {
1328       return inst->GetOperandAs<uint32_t>(1u) == width;
1329     }
1330     return false;
1331   };
1332   return ContainsType(id, f);
1333 }
1334 
ContainsLimitedUseIntOrFloatType(uint32_t id) const1335 bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
1336   if ((!HasCapability(SpvCapabilityInt16) &&
1337        ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 16)) ||
1338       (!HasCapability(SpvCapabilityInt8) &&
1339        ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 8)) ||
1340       (!HasCapability(SpvCapabilityFloat16) &&
1341        ContainsSizedIntOrFloatType(id, SpvOpTypeFloat, 16))) {
1342     return true;
1343   }
1344   return false;
1345 }
1346 
ContainsRuntimeArray(uint32_t id) const1347 bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const {
1348   const auto f = [](const Instruction* inst) {
1349     return inst->opcode() == SpvOpTypeRuntimeArray;
1350   };
1351   return ContainsType(id, f, /* traverse_all_types = */ false);
1352 }
1353 
IsValidStorageClass(SpvStorageClass storage_class) const1354 bool ValidationState_t::IsValidStorageClass(
1355     SpvStorageClass storage_class) const {
1356   if (spvIsVulkanEnv(context()->target_env)) {
1357     switch (storage_class) {
1358       case SpvStorageClassUniformConstant:
1359       case SpvStorageClassUniform:
1360       case SpvStorageClassStorageBuffer:
1361       case SpvStorageClassInput:
1362       case SpvStorageClassOutput:
1363       case SpvStorageClassImage:
1364       case SpvStorageClassWorkgroup:
1365       case SpvStorageClassPrivate:
1366       case SpvStorageClassFunction:
1367       case SpvStorageClassPushConstant:
1368       case SpvStorageClassPhysicalStorageBuffer:
1369       case SpvStorageClassRayPayloadKHR:
1370       case SpvStorageClassIncomingRayPayloadKHR:
1371       case SpvStorageClassHitAttributeKHR:
1372       case SpvStorageClassCallableDataKHR:
1373       case SpvStorageClassIncomingCallableDataKHR:
1374       case SpvStorageClassShaderRecordBufferKHR:
1375         return true;
1376       default:
1377         return false;
1378     }
1379   }
1380 
1381   return true;
1382 }
1383 
1384 #define VUID_WRAP(vuid) "[" #vuid "] "
1385 
1386 // Currently no 2 VUID share the same id, so no need for |reference|
VkErrorID(uint32_t id,const char *) const1387 std::string ValidationState_t::VkErrorID(uint32_t id,
1388                                          const char* /*reference*/) const {
1389   if (!spvIsVulkanEnv(context_->target_env)) {
1390     return "";
1391   }
1392 
1393   // This large switch case is only searched when an error has occured.
1394   // If an id is changed, the old case must be modified or removed. Each string
1395   // here is interpreted as being "implemented"
1396 
1397   // Clang format adds spaces between hyphens
1398   // clang-format off
1399   switch (id) {
1400     case 4181:
1401       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04181);
1402     case 4182:
1403       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04182);
1404     case 4183:
1405       return VUID_WRAP(VUID-BaseInstance-BaseInstance-04183);
1406     case 4184:
1407       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04184);
1408     case 4185:
1409       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04185);
1410     case 4186:
1411       return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186);
1412     case 4187:
1413       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187);
1414     case 4188:
1415       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188);
1416     case 4189:
1417       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189);
1418     case 4190:
1419       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190);
1420     case 4191:
1421       return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191);
1422     case 4196:
1423       return VUID_WRAP(VUID-CullDistance-CullDistance-04196);
1424     case 4197:
1425       return VUID_WRAP(VUID-CullDistance-CullDistance-04197);
1426     case 4198:
1427       return VUID_WRAP(VUID-CullDistance-CullDistance-04198);
1428     case 4199:
1429       return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
1430     case 4200:
1431       return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
1432     case 4205:
1433       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04205);
1434     case 4206:
1435       return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04206);
1436     case 4207:
1437       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04207);
1438     case 4208:
1439       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04208);
1440     case 4209:
1441       return VUID_WRAP(VUID-DrawIndex-DrawIndex-04209);
1442     case 4210:
1443       return VUID_WRAP(VUID-FragCoord-FragCoord-04210);
1444     case 4211:
1445       return VUID_WRAP(VUID-FragCoord-FragCoord-04211);
1446     case 4212:
1447       return VUID_WRAP(VUID-FragCoord-FragCoord-04212);
1448     case 4213:
1449       return VUID_WRAP(VUID-FragDepth-FragDepth-04213);
1450     case 4214:
1451       return VUID_WRAP(VUID-FragDepth-FragDepth-04214);
1452     case 4215:
1453       return VUID_WRAP(VUID-FragDepth-FragDepth-04215);
1454     case 4216:
1455       return VUID_WRAP(VUID-FragDepth-FragDepth-04216);
1456     case 4217:
1457       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217);
1458     case 4218:
1459       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218);
1460     case 4219:
1461       return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219);
1462     case 4220:
1463       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220);
1464     case 4221:
1465       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221);
1466     case 4222:
1467       return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222);
1468     case 4223:
1469       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223);
1470     case 4224:
1471       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224);
1472     case 4225:
1473       return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225);
1474     case 4229:
1475       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229);
1476     case 4230:
1477       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230);
1478     case 4231:
1479       return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231);
1480     case 4232:
1481       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232);
1482     case 4233:
1483       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233);
1484     case 4234:
1485       return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234);
1486     case 4236:
1487       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236);
1488     case 4237:
1489       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04237);
1490     case 4238:
1491       return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04238);
1492     case 4239:
1493       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04239);
1494     case 4240:
1495       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
1496     case 4241:
1497       return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
1498     case 4242:
1499       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
1500     case 4243:
1501       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
1502     case 4244:
1503       return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
1504     case 4245:
1505       return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
1506     case 4246:
1507       return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
1508     case 4247:
1509       return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
1510     case 4248:
1511       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
1512     case 4249:
1513       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
1514     case 4250:
1515       return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
1516     case 4251:
1517       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
1518     case 4252:
1519       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
1520     case 4253:
1521       return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
1522     case 4254:
1523       return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
1524     case 4255:
1525       return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
1526     case 4256:
1527       return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
1528     case 4257:
1529       return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
1530     case 4258:
1531       return VUID_WRAP(VUID-InvocationId-InvocationId-04258);
1532     case 4259:
1533       return VUID_WRAP(VUID-InvocationId-InvocationId-04259);
1534     case 4263:
1535       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04263);
1536     case 4264:
1537       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
1538     case 4265:
1539       return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
1540     case 4266:
1541       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
1542     case 4267:
1543       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
1544     case 4268:
1545       return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
1546     case 4269:
1547       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
1548     case 4270:
1549       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
1550     case 4271:
1551       return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
1552     case 4272:
1553       return VUID_WRAP(VUID-Layer-Layer-04272);
1554     case 4273:
1555       return VUID_WRAP(VUID-Layer-Layer-04273);
1556     case 4274:
1557       return VUID_WRAP(VUID-Layer-Layer-04274);
1558     case 4275:
1559       return VUID_WRAP(VUID-Layer-Layer-04275);
1560     case 4276:
1561       return VUID_WRAP(VUID-Layer-Layer-04276);
1562     case 4281:
1563       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04281);
1564     case 4282:
1565       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
1566     case 4283:
1567       return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
1568     case 4293:
1569       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
1570     case 4294:
1571       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294);
1572     case 4295:
1573       return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295);
1574     case 4296:
1575       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296);
1576     case 4297:
1577       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
1578     case 4298:
1579       return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
1580     case 4299:
1581       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
1582     case 4300:
1583       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
1584     case 4301:
1585       return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
1586     case 4302:
1587       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
1588     case 4303:
1589       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
1590     case 4304:
1591       return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
1592     case 4305:
1593       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
1594     case 4306:
1595       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
1596     case 4307:
1597       return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
1598     case 4308:
1599       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
1600     case 4309:
1601       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04309);
1602     case 4310:
1603       return VUID_WRAP(VUID-PatchVertices-PatchVertices-04310);
1604     case 4311:
1605       return VUID_WRAP(VUID-PointCoord-PointCoord-04311);
1606     case 4312:
1607       return VUID_WRAP(VUID-PointCoord-PointCoord-04312);
1608     case 4313:
1609       return VUID_WRAP(VUID-PointCoord-PointCoord-04313);
1610     case 4314:
1611       return VUID_WRAP(VUID-PointSize-PointSize-04314);
1612     case 4315:
1613       return VUID_WRAP(VUID-PointSize-PointSize-04315);
1614     case 4316:
1615       return VUID_WRAP(VUID-PointSize-PointSize-04316);
1616     case 4317:
1617       return VUID_WRAP(VUID-PointSize-PointSize-04317);
1618     case 4318:
1619       return VUID_WRAP(VUID-Position-Position-04318);
1620     case 4319:
1621       return VUID_WRAP(VUID-Position-Position-04319);
1622     case 4320:
1623       return VUID_WRAP(VUID-Position-Position-04320);
1624     case 4321:
1625       return VUID_WRAP(VUID-Position-Position-04321);
1626     case 4330:
1627       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330);
1628     case 4334:
1629       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
1630     case 4337:
1631       return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
1632     case 4345:
1633       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
1634     case 4346:
1635       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
1636     case 4347:
1637       return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
1638     case 4348:
1639       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
1640     case 4349:
1641       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
1642     case 4350:
1643       return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
1644     case 4351:
1645       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
1646     case 4352:
1647       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
1648     case 4353:
1649       return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
1650     case 4354:
1651       return VUID_WRAP(VUID-SampleId-SampleId-04354);
1652     case 4355:
1653       return VUID_WRAP(VUID-SampleId-SampleId-04355);
1654     case 4356:
1655       return VUID_WRAP(VUID-SampleId-SampleId-04356);
1656     case 4357:
1657       return VUID_WRAP(VUID-SampleMask-SampleMask-04357);
1658     case 4358:
1659       return VUID_WRAP(VUID-SampleMask-SampleMask-04358);
1660     case 4359:
1661       return VUID_WRAP(VUID-SampleMask-SampleMask-04359);
1662     case 4360:
1663       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04360);
1664     case 4361:
1665       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361);
1666     case 4362:
1667       return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362);
1668     case 4367:
1669       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367);
1670     case 4368:
1671       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368);
1672     case 4369:
1673       return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369);
1674     case 4370:
1675       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370);
1676     case 4371:
1677       return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371);
1678     case 4372:
1679       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372);
1680     case 4373:
1681       return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373);
1682     case 4374:
1683       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374);
1684     case 4375:
1685       return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375);
1686     case 4376:
1687       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376);
1688     case 4377:
1689       return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377);
1690     case 4378:
1691       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378);
1692     case 4379:
1693       return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379);
1694     case 4380:
1695       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380);
1696     case 4381:
1697       return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381);
1698     case 4382:
1699       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382);
1700     case 4383:
1701       return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383);
1702     case 4387:
1703       return VUID_WRAP(VUID-TessCoord-TessCoord-04387);
1704     case 4388:
1705       return VUID_WRAP(VUID-TessCoord-TessCoord-04388);
1706     case 4389:
1707       return VUID_WRAP(VUID-TessCoord-TessCoord-04389);
1708     case 4390:
1709       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390);
1710     case 4391:
1711       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391);
1712     case 4392:
1713       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392);
1714     case 4393:
1715       return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393);
1716     case 4394:
1717       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394);
1718     case 4395:
1719       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395);
1720     case 4396:
1721       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396);
1722     case 4397:
1723       return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397);
1724     case 4398:
1725       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04398);
1726     case 4399:
1727       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04399);
1728     case 4400:
1729       return VUID_WRAP(VUID-VertexIndex-VertexIndex-04400);
1730     case 4401:
1731       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04401);
1732     case 4402:
1733       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04402);
1734     case 4403:
1735       return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403);
1736     case 4404:
1737       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404);
1738     case 4405:
1739       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405);
1740     case 4406:
1741       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406);
1742     case 4407:
1743       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04407);
1744     case 4408:
1745       return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04408);
1746     case 4422:
1747       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04422);
1748     case 4423:
1749       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04423);
1750     case 4424:
1751       return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04424);
1752     case 4425:
1753       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04425);
1754     case 4426:
1755       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
1756     case 4427:
1757       return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
1758     case 4428:
1759       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
1760     case 4429:
1761       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
1762     case 4430:
1763       return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
1764     case 4431:
1765       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
1766     case 4432:
1767       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
1768     case 4433:
1769       return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
1770     case 4434:
1771       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
1772     case 4435:
1773       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
1774     case 4436:
1775       return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
1776     case 4484:
1777       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
1778     case 4485:
1779       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485);
1780     case 4486:
1781       return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04486);
1782     case 4490:
1783       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04490);
1784     case 4491:
1785       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491);
1786     case 4492:
1787       return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492);
1788     case 4633:
1789       return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
1790     case 4634:
1791       return VUID_WRAP(VUID-StandaloneSpirv-None-04634);
1792     case 4635:
1793       return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
1794     case 4636:
1795       return VUID_WRAP(VUID-StandaloneSpirv-None-04636);
1796     case 4637:
1797       return VUID_WRAP(VUID-StandaloneSpirv-None-04637);
1798     case 4638:
1799       return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
1800     case 4639:
1801       return VUID_WRAP(VUID-StandaloneSpirv-None-04639);
1802     case 4640:
1803       return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
1804     case 4641:
1805       return VUID_WRAP(VUID-StandaloneSpirv-None-04641);
1806     case 4642:
1807       return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
1808     case 4643:
1809       return VUID_WRAP(VUID-StandaloneSpirv-None-04643);
1810     case 4644:
1811       return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
1812     case 4645:
1813       return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
1814     case 4651:
1815       return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
1816     case 4652:
1817       return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652);
1818     case 4653:
1819       return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
1820     case 4654:
1821       return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
1822     case 4655:
1823       return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655);
1824     case 4656:
1825       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
1826     case 4657:
1827       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
1828     case 4658:
1829       return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
1830     case 4659:
1831       return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
1832     case 4662:
1833       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
1834     case 4663:
1835       return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
1836     case 4664:
1837       return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664);
1838     case 4667:
1839       return VUID_WRAP(VUID-StandaloneSpirv-None-04667);
1840     case 4669:
1841       return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
1842     case 4670:
1843       return VUID_WRAP(VUID-StandaloneSpirv-Flat-04670);
1844     case 4675:
1845       return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
1846     case 4677:
1847       return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
1848     case 4682:
1849       return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
1850     case 6426:
1851       return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-06426); // formally 04683
1852     case 4685:
1853       return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
1854     case 4686:
1855       return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
1856     case 4710:
1857       return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
1858     case 4711:
1859       return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
1860     case 4730:
1861       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730);
1862     case 4731:
1863       return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731);
1864     case 4732:
1865       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
1866     case 4733:
1867       return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
1868     case 4780:
1869       return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
1870     default:
1871       return "";  // unknown id
1872   }
1873   // clang-format on
1874 }
1875 
1876 }  // namespace val
1877 }  // namespace spvtools
1878