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, ¤t_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