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 case SpvOpSamplerImageAddressingModeNV:
94 return kLayoutSamplerImageAddressMode;
95 default:
96 break;
97 }
98 return kLayoutFunctionDefinitions;
99 }
100
IsInstructionInLayoutSection(ModuleLayoutSection layout,SpvOp op)101 bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) {
102 return layout == InstructionLayoutSection(layout, op);
103 }
104
105 // Counts the number of instructions and functions in the file.
CountInstructions(void * user_data,const spv_parsed_instruction_t * inst)106 spv_result_t CountInstructions(void* user_data,
107 const spv_parsed_instruction_t* inst) {
108 ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
109 if (inst->opcode == SpvOpFunction) _.increment_total_functions();
110 _.increment_total_instructions();
111
112 return SPV_SUCCESS;
113 }
114
setHeader(void * user_data,spv_endianness_t,uint32_t,uint32_t version,uint32_t generator,uint32_t id_bound,uint32_t)115 spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t,
116 uint32_t version, uint32_t generator, uint32_t id_bound,
117 uint32_t) {
118 ValidationState_t& vstate =
119 *(reinterpret_cast<ValidationState_t*>(user_data));
120 vstate.setIdBound(id_bound);
121 vstate.setGenerator(generator);
122 vstate.setVersion(version);
123
124 return SPV_SUCCESS;
125 }
126
127 // Add features based on SPIR-V core version number.
UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature * features,uint32_t version)128 void UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature* features,
129 uint32_t version) {
130 assert(features);
131 if (version >= SPV_SPIRV_VERSION_WORD(1, 4)) {
132 features->select_between_composites = true;
133 features->copy_memory_permits_two_memory_accesses = true;
134 features->uconvert_spec_constant_op = true;
135 features->nonwritable_var_in_function_or_private = true;
136 }
137 }
138
139 } // namespace
140
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)141 ValidationState_t::ValidationState_t(const spv_const_context ctx,
142 const spv_const_validator_options opt,
143 const uint32_t* words,
144 const size_t num_words,
145 const uint32_t max_warnings)
146 : context_(ctx),
147 options_(opt),
148 words_(words),
149 num_words_(num_words),
150 unresolved_forward_ids_{},
151 operand_names_{},
152 current_layout_section_(kLayoutCapabilities),
153 module_functions_(),
154 module_capabilities_(),
155 module_extensions_(),
156 ordered_instructions_(),
157 all_definitions_(),
158 global_vars_(),
159 local_vars_(),
160 struct_nesting_depth_(),
161 struct_has_nested_blockorbufferblock_struct_(),
162 grammar_(ctx),
163 addressing_model_(SpvAddressingModelMax),
164 memory_model_(SpvMemoryModelMax),
165 pointer_size_and_alignment_(0),
166 sampler_image_addressing_mode_(0),
167 in_function_(false),
168 num_of_warnings_(0),
169 max_num_of_warnings_(max_warnings) {
170 assert(opt && "Validator options may not be Null.");
171
172 const auto env = context_->target_env;
173
174 if (spvIsVulkanEnv(env)) {
175 // Vulkan 1.1 includes VK_KHR_relaxed_block_layout in core.
176 if (env != SPV_ENV_VULKAN_1_0) {
177 features_.env_relaxed_block_layout = true;
178 }
179 }
180
181 // LocalSizeId is only disallowed prior to Vulkan 1.3 without maintenance4.
182 switch (env) {
183 case SPV_ENV_VULKAN_1_0:
184 case SPV_ENV_VULKAN_1_1:
185 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
186 case SPV_ENV_VULKAN_1_2:
187 features_.env_allow_localsizeid = false;
188 break;
189 default:
190 features_.env_allow_localsizeid = true;
191 break;
192 }
193
194 // Only attempt to count if we have words, otherwise let the other validation
195 // fail and generate an error.
196 if (num_words > 0) {
197 // Count the number of instructions in the binary.
198 // This parse should not produce any error messages. Hijack the context and
199 // replace the message consumer so that we do not pollute any state in input
200 // consumer.
201 spv_context_t hijacked_context = *ctx;
202 hijacked_context.consumer = [](spv_message_level_t, const char*,
__anon0d43d9700202(spv_message_level_t, const char*, const spv_position_t&, const char*) 203 const spv_position_t&, const char*) {};
204 spvBinaryParse(&hijacked_context, this, words, num_words, setHeader,
205 CountInstructions,
206 /* diagnostic = */ nullptr);
207 preallocateStorage();
208 }
209 UpdateFeaturesBasedOnSpirvVersion(&features_, version_);
210
211 name_mapper_ = spvtools::GetTrivialNameMapper();
212 if (options_->use_friendly_names) {
213 friendly_mapper_ = spvtools::MakeUnique<spvtools::FriendlyNameMapper>(
214 context_, words_, num_words_);
215 name_mapper_ = friendly_mapper_->GetNameMapper();
216 }
217 }
218
preallocateStorage()219 void ValidationState_t::preallocateStorage() {
220 ordered_instructions_.reserve(total_instructions_);
221 module_functions_.reserve(total_functions_);
222 }
223
ForwardDeclareId(uint32_t id)224 spv_result_t ValidationState_t::ForwardDeclareId(uint32_t id) {
225 unresolved_forward_ids_.insert(id);
226 return SPV_SUCCESS;
227 }
228
RemoveIfForwardDeclared(uint32_t id)229 spv_result_t ValidationState_t::RemoveIfForwardDeclared(uint32_t id) {
230 unresolved_forward_ids_.erase(id);
231 return SPV_SUCCESS;
232 }
233
RegisterForwardPointer(uint32_t id)234 spv_result_t ValidationState_t::RegisterForwardPointer(uint32_t id) {
235 forward_pointer_ids_.insert(id);
236 return SPV_SUCCESS;
237 }
238
IsForwardPointer(uint32_t id) const239 bool ValidationState_t::IsForwardPointer(uint32_t id) const {
240 return (forward_pointer_ids_.find(id) != forward_pointer_ids_.end());
241 }
242
AssignNameToId(uint32_t id,std::string name)243 void ValidationState_t::AssignNameToId(uint32_t id, std::string name) {
244 operand_names_[id] = name;
245 }
246
getIdName(uint32_t id) const247 std::string ValidationState_t::getIdName(uint32_t id) const {
248 const std::string id_name = name_mapper_(id);
249
250 std::stringstream out;
251 out << "'" << id << "[%" << id_name << "]'";
252 return out.str();
253 }
254
unresolved_forward_id_count() const255 size_t ValidationState_t::unresolved_forward_id_count() const {
256 return unresolved_forward_ids_.size();
257 }
258
UnresolvedForwardIds() const259 std::vector<uint32_t> ValidationState_t::UnresolvedForwardIds() const {
260 std::vector<uint32_t> out(std::begin(unresolved_forward_ids_),
261 std::end(unresolved_forward_ids_));
262 return out;
263 }
264
IsDefinedId(uint32_t id) const265 bool ValidationState_t::IsDefinedId(uint32_t id) const {
266 return all_definitions_.find(id) != std::end(all_definitions_);
267 }
268
FindDef(uint32_t id) const269 const Instruction* ValidationState_t::FindDef(uint32_t id) const {
270 auto it = all_definitions_.find(id);
271 if (it == all_definitions_.end()) return nullptr;
272 return it->second;
273 }
274
FindDef(uint32_t id)275 Instruction* ValidationState_t::FindDef(uint32_t id) {
276 auto it = all_definitions_.find(id);
277 if (it == all_definitions_.end()) return nullptr;
278 return it->second;
279 }
280
current_layout_section() const281 ModuleLayoutSection ValidationState_t::current_layout_section() const {
282 return current_layout_section_;
283 }
284
ProgressToNextLayoutSectionOrder()285 void ValidationState_t::ProgressToNextLayoutSectionOrder() {
286 // Guard against going past the last element(kLayoutFunctionDefinitions)
287 if (current_layout_section_ <= kLayoutFunctionDefinitions) {
288 current_layout_section_ =
289 static_cast<ModuleLayoutSection>(current_layout_section_ + 1);
290 }
291 }
292
IsOpcodeInPreviousLayoutSection(SpvOp op)293 bool ValidationState_t::IsOpcodeInPreviousLayoutSection(SpvOp op) {
294 ModuleLayoutSection section =
295 InstructionLayoutSection(current_layout_section_, op);
296 return section < current_layout_section_;
297 }
298
IsOpcodeInCurrentLayoutSection(SpvOp op)299 bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) {
300 return IsInstructionInLayoutSection(current_layout_section_, op);
301 }
302
diag(spv_result_t error_code,const Instruction * inst)303 DiagnosticStream ValidationState_t::diag(spv_result_t error_code,
304 const Instruction* inst) {
305 if (error_code == SPV_WARNING) {
306 if (num_of_warnings_ == max_num_of_warnings_) {
307 DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code)
308 << "Other warnings have been suppressed.\n";
309 }
310 if (num_of_warnings_ >= max_num_of_warnings_) {
311 return DiagnosticStream({0, 0, 0}, nullptr, "", error_code);
312 }
313 ++num_of_warnings_;
314 }
315
316 std::string disassembly;
317 if (inst) disassembly = Disassemble(*inst);
318
319 return DiagnosticStream({0, 0, inst ? inst->LineNum() : 0},
320 context_->consumer, disassembly, error_code);
321 }
322
functions()323 std::vector<Function>& ValidationState_t::functions() {
324 return module_functions_;
325 }
326
current_function()327 Function& ValidationState_t::current_function() {
328 assert(in_function_body());
329 return module_functions_.back();
330 }
331
current_function() const332 const Function& ValidationState_t::current_function() const {
333 assert(in_function_body());
334 return module_functions_.back();
335 }
336
function(uint32_t id) const337 const Function* ValidationState_t::function(uint32_t id) const {
338 const auto it = id_to_function_.find(id);
339 if (it == id_to_function_.end()) return nullptr;
340 return it->second;
341 }
342
function(uint32_t id)343 Function* ValidationState_t::function(uint32_t id) {
344 auto it = id_to_function_.find(id);
345 if (it == id_to_function_.end()) return nullptr;
346 return it->second;
347 }
348
in_function_body() const349 bool ValidationState_t::in_function_body() const { return in_function_; }
350
in_block() const351 bool ValidationState_t::in_block() const {
352 return module_functions_.empty() == false &&
353 module_functions_.back().current_block() != nullptr;
354 }
355
RegisterCapability(SpvCapability cap)356 void ValidationState_t::RegisterCapability(SpvCapability cap) {
357 // Avoid redundant work. Otherwise the recursion could induce work
358 // quadrdatic in the capability dependency depth. (Ok, not much, but
359 // it's something.)
360 if (module_capabilities_.Contains(cap)) return;
361
362 module_capabilities_.Add(cap);
363 spv_operand_desc desc;
364 if (SPV_SUCCESS ==
365 grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) {
366 CapabilitySet(desc->numCapabilities, desc->capabilities)
367 .ForEach([this](SpvCapability c) { RegisterCapability(c); });
368 }
369
370 switch (cap) {
371 case SpvCapabilityKernel:
372 features_.group_ops_reduce_and_scans = true;
373 break;
374 case SpvCapabilityInt8:
375 features_.use_int8_type = true;
376 features_.declare_int8_type = true;
377 break;
378 case SpvCapabilityStorageBuffer8BitAccess:
379 case SpvCapabilityUniformAndStorageBuffer8BitAccess:
380 case SpvCapabilityStoragePushConstant8:
381 case SpvCapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR:
382 features_.declare_int8_type = true;
383 break;
384 case SpvCapabilityInt16:
385 features_.declare_int16_type = true;
386 break;
387 case SpvCapabilityFloat16:
388 case SpvCapabilityFloat16Buffer:
389 features_.declare_float16_type = true;
390 break;
391 case SpvCapabilityStorageUniformBufferBlock16:
392 case SpvCapabilityStorageUniform16:
393 case SpvCapabilityStoragePushConstant16:
394 case SpvCapabilityStorageInputOutput16:
395 case SpvCapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR:
396 features_.declare_int16_type = true;
397 features_.declare_float16_type = true;
398 features_.free_fp_rounding_mode = true;
399 break;
400 case SpvCapabilityVariablePointers:
401 case SpvCapabilityVariablePointersStorageBuffer:
402 features_.variable_pointers = true;
403 break;
404 default:
405 // TODO(dneto): For now don't validate SPV_NV_ray_tracing, which uses
406 // capability SpvCapabilityRayTracingNV.
407 // SpvCapabilityRayTracingProvisionalKHR would need the same treatment.
408 // One of the differences going from SPV_KHR_ray_tracing from
409 // provisional to final spec was the provisional spec uses Locations
410 // for variables in certain storage classes, just like the
411 // SPV_NV_ray_tracing extension. So it mimics the NVIDIA extension.
412 // The final SPV_KHR_ray_tracing uses a different capability token
413 // number, so it doesn't fall into this case.
414 break;
415 }
416 }
417
RegisterExtension(Extension ext)418 void ValidationState_t::RegisterExtension(Extension ext) {
419 if (module_extensions_.Contains(ext)) return;
420
421 module_extensions_.Add(ext);
422
423 switch (ext) {
424 case kSPV_AMD_gpu_shader_half_float:
425 case kSPV_AMD_gpu_shader_half_float_fetch:
426 // SPV_AMD_gpu_shader_half_float enables float16 type.
427 // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375
428 features_.declare_float16_type = true;
429 break;
430 case kSPV_AMD_gpu_shader_int16:
431 // This is not yet in the extension, but it's recommended for it.
432 // See https://github.com/KhronosGroup/glslang/issues/848
433 features_.uconvert_spec_constant_op = true;
434 break;
435 case kSPV_AMD_shader_ballot:
436 // The grammar doesn't encode the fact that SPV_AMD_shader_ballot
437 // enables the use of group operations Reduce, InclusiveScan,
438 // and ExclusiveScan. Enable it manually.
439 // https://github.com/KhronosGroup/SPIRV-Tools/issues/991
440 features_.group_ops_reduce_and_scans = true;
441 break;
442 default:
443 break;
444 }
445 }
446
HasAnyOfCapabilities(const CapabilitySet & capabilities) const447 bool ValidationState_t::HasAnyOfCapabilities(
448 const CapabilitySet& capabilities) const {
449 return module_capabilities_.HasAnyOf(capabilities);
450 }
451
HasAnyOfExtensions(const ExtensionSet & extensions) const452 bool ValidationState_t::HasAnyOfExtensions(
453 const ExtensionSet& extensions) const {
454 return module_extensions_.HasAnyOf(extensions);
455 }
456
set_addressing_model(SpvAddressingModel am)457 void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
458 addressing_model_ = am;
459 switch (am) {
460 case SpvAddressingModelPhysical32:
461 pointer_size_and_alignment_ = 4;
462 break;
463 default:
464 // fall through
465 case SpvAddressingModelPhysical64:
466 case SpvAddressingModelPhysicalStorageBuffer64:
467 pointer_size_and_alignment_ = 8;
468 break;
469 }
470 }
471
addressing_model() const472 SpvAddressingModel ValidationState_t::addressing_model() const {
473 return addressing_model_;
474 }
475
set_memory_model(SpvMemoryModel mm)476 void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
477 memory_model_ = mm;
478 }
479
memory_model() const480 SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
481
set_samplerimage_variable_address_mode(uint32_t bit_width)482 void ValidationState_t::set_samplerimage_variable_address_mode(
483 uint32_t bit_width) {
484 sampler_image_addressing_mode_ = bit_width;
485 }
486
samplerimage_variable_address_mode() const487 uint32_t ValidationState_t::samplerimage_variable_address_mode() const {
488 return sampler_image_addressing_mode_;
489 }
490
RegisterFunction(uint32_t id,uint32_t ret_type_id,SpvFunctionControlMask function_control,uint32_t function_type_id)491 spv_result_t ValidationState_t::RegisterFunction(
492 uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
493 uint32_t function_type_id) {
494 assert(in_function_body() == false &&
495 "RegisterFunction can only be called when parsing the binary outside "
496 "of another function");
497 in_function_ = true;
498 module_functions_.emplace_back(id, ret_type_id, function_control,
499 function_type_id);
500 id_to_function_.emplace(id, ¤t_function());
501
502 // TODO(umar): validate function type and type_id
503
504 return SPV_SUCCESS;
505 }
506
RegisterFunctionEnd()507 spv_result_t ValidationState_t::RegisterFunctionEnd() {
508 assert(in_function_body() == true &&
509 "RegisterFunctionEnd can only be called when parsing the binary "
510 "inside of another function");
511 assert(in_block() == false &&
512 "RegisterFunctionParameter can only be called when parsing the binary "
513 "outside of a block");
514 current_function().RegisterFunctionEnd();
515 in_function_ = false;
516 return SPV_SUCCESS;
517 }
518
AddOrderedInstruction(const spv_parsed_instruction_t * inst)519 Instruction* ValidationState_t::AddOrderedInstruction(
520 const spv_parsed_instruction_t* inst) {
521 ordered_instructions_.emplace_back(inst);
522 ordered_instructions_.back().SetLineNum(ordered_instructions_.size());
523 return &ordered_instructions_.back();
524 }
525
526 // Improves diagnostic messages by collecting names of IDs
RegisterDebugInstruction(const Instruction * inst)527 void ValidationState_t::RegisterDebugInstruction(const Instruction* inst) {
528 switch (inst->opcode()) {
529 case SpvOpName: {
530 const auto target = inst->GetOperandAs<uint32_t>(0);
531 const std::string str = inst->GetOperandAs<std::string>(1);
532 AssignNameToId(target, str);
533 break;
534 }
535 case SpvOpMemberName: {
536 const auto target = inst->GetOperandAs<uint32_t>(0);
537 const std::string str = inst->GetOperandAs<std::string>(2);
538 AssignNameToId(target, str);
539 break;
540 }
541 case SpvOpSourceContinued:
542 case SpvOpSource:
543 case SpvOpSourceExtension:
544 case SpvOpString:
545 case SpvOpLine:
546 case SpvOpNoLine:
547 default:
548 break;
549 }
550 }
551
RegisterInstruction(Instruction * inst)552 void ValidationState_t::RegisterInstruction(Instruction* inst) {
553 if (inst->id()) all_definitions_.insert(std::make_pair(inst->id(), inst));
554
555 // Some validation checks are easier by getting all the consumers
556 for (size_t i = 0; i < inst->operands().size(); ++i) {
557 const spv_parsed_operand_t& operand = inst->operand(i);
558 if ((SPV_OPERAND_TYPE_ID == operand.type) ||
559 (SPV_OPERAND_TYPE_TYPE_ID == operand.type)) {
560 const uint32_t operand_word = inst->word(operand.offset);
561 Instruction* operand_inst = FindDef(operand_word);
562 if (!operand_inst) {
563 continue;
564 }
565
566 // If the instruction is using an OpTypeSampledImage as an operand, it
567 // should be recorded. The validator will ensure that all usages of an
568 // OpTypeSampledImage and its definition are in the same basic block.
569 if ((SPV_OPERAND_TYPE_ID == operand.type) &&
570 (SpvOpSampledImage == operand_inst->opcode())) {
571 RegisterSampledImageConsumer(operand_word, inst);
572 }
573
574 // In order to track storage classes (not Function) used per execution
575 // model we can't use RegisterExecutionModelLimitation on instructions
576 // like OpTypePointer which are going to be in the pre-function section.
577 // Instead just need to register storage class usage for consumers in a
578 // function block.
579 if (inst->function()) {
580 if (operand_inst->opcode() == SpvOpTypePointer) {
581 RegisterStorageClassConsumer(
582 operand_inst->GetOperandAs<SpvStorageClass>(1), inst);
583 } else if (operand_inst->opcode() == SpvOpVariable) {
584 RegisterStorageClassConsumer(
585 operand_inst->GetOperandAs<SpvStorageClass>(2), inst);
586 }
587 }
588 }
589 }
590 }
591
getSampledImageConsumers(uint32_t sampled_image_id) const592 std::vector<Instruction*> ValidationState_t::getSampledImageConsumers(
593 uint32_t sampled_image_id) const {
594 std::vector<Instruction*> result;
595 auto iter = sampled_image_consumers_.find(sampled_image_id);
596 if (iter != sampled_image_consumers_.end()) {
597 result = iter->second;
598 }
599 return result;
600 }
601
RegisterSampledImageConsumer(uint32_t sampled_image_id,Instruction * consumer)602 void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id,
603 Instruction* consumer) {
604 sampled_image_consumers_[sampled_image_id].push_back(consumer);
605 }
606
RegisterStorageClassConsumer(SpvStorageClass storage_class,Instruction * consumer)607 void ValidationState_t::RegisterStorageClassConsumer(
608 SpvStorageClass storage_class, Instruction* consumer) {
609 if (spvIsVulkanEnv(context()->target_env)) {
610 if (storage_class == SpvStorageClassOutput) {
611 std::string errorVUID = VkErrorID(4644);
612 function(consumer->function()->id())
613 ->RegisterExecutionModelLimitation([errorVUID](
614 SpvExecutionModel model,
615 std::string* message) {
616 if (model == SpvExecutionModelGLCompute ||
617 model == SpvExecutionModelRayGenerationKHR ||
618 model == SpvExecutionModelIntersectionKHR ||
619 model == SpvExecutionModelAnyHitKHR ||
620 model == SpvExecutionModelClosestHitKHR ||
621 model == SpvExecutionModelMissKHR ||
622 model == SpvExecutionModelCallableKHR) {
623 if (message) {
624 *message =
625 errorVUID +
626 "in Vulkan environment, Output Storage Class must not be "
627 "used in GLCompute, RayGenerationKHR, IntersectionKHR, "
628 "AnyHitKHR, ClosestHitKHR, MissKHR, or CallableKHR "
629 "execution models";
630 }
631 return false;
632 }
633 return true;
634 });
635 }
636
637 if (storage_class == SpvStorageClassWorkgroup) {
638 std::string errorVUID = VkErrorID(4645);
639 function(consumer->function()->id())
640 ->RegisterExecutionModelLimitation([errorVUID](
641 SpvExecutionModel model,
642 std::string* message) {
643 if (model != SpvExecutionModelGLCompute &&
644 model != SpvExecutionModelTaskNV &&
645 model != SpvExecutionModelMeshNV &&
646 model != SpvExecutionModelTaskEXT &&
647 model != SpvExecutionModelMeshEXT) {
648 if (message) {
649 *message =
650 errorVUID +
651 "in Vulkan environment, Workgroup Storage Class is limited "
652 "to MeshNV, TaskNV, and GLCompute execution model";
653 }
654 return false;
655 }
656 return true;
657 });
658 }
659 }
660
661 if (storage_class == SpvStorageClassCallableDataKHR) {
662 std::string errorVUID = VkErrorID(4704);
663 function(consumer->function()->id())
664 ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
665 std::string* message) {
666 if (model != SpvExecutionModelRayGenerationKHR &&
667 model != SpvExecutionModelClosestHitKHR &&
668 model != SpvExecutionModelCallableKHR &&
669 model != SpvExecutionModelMissKHR) {
670 if (message) {
671 *message = errorVUID +
672 "CallableDataKHR Storage Class is limited to "
673 "RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
674 "MissKHR execution model";
675 }
676 return false;
677 }
678 return true;
679 });
680 } else if (storage_class == SpvStorageClassIncomingCallableDataKHR) {
681 std::string errorVUID = VkErrorID(4705);
682 function(consumer->function()->id())
683 ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
684 std::string* message) {
685 if (model != SpvExecutionModelCallableKHR) {
686 if (message) {
687 *message = errorVUID +
688 "IncomingCallableDataKHR Storage Class is limited to "
689 "CallableKHR execution model";
690 }
691 return false;
692 }
693 return true;
694 });
695 } else if (storage_class == SpvStorageClassRayPayloadKHR) {
696 std::string errorVUID = VkErrorID(4698);
697 function(consumer->function()->id())
698 ->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
699 std::string* message) {
700 if (model != SpvExecutionModelRayGenerationKHR &&
701 model != SpvExecutionModelClosestHitKHR &&
702 model != SpvExecutionModelMissKHR) {
703 if (message) {
704 *message =
705 errorVUID +
706 "RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
707 "ClosestHitKHR, and MissKHR execution model";
708 }
709 return false;
710 }
711 return true;
712 });
713 } else if (storage_class == SpvStorageClassHitAttributeKHR) {
714 std::string errorVUID = VkErrorID(4701);
715 function(consumer->function()->id())
716 ->RegisterExecutionModelLimitation(
717 [errorVUID](SpvExecutionModel model, std::string* message) {
718 if (model != SpvExecutionModelIntersectionKHR &&
719 model != SpvExecutionModelAnyHitKHR &&
720 model != SpvExecutionModelClosestHitKHR) {
721 if (message) {
722 *message = errorVUID +
723 "HitAttributeKHR Storage Class is limited to "
724 "IntersectionKHR, AnyHitKHR, sand ClosestHitKHR "
725 "execution model";
726 }
727 return false;
728 }
729 return true;
730 });
731 } else if (storage_class == SpvStorageClassIncomingRayPayloadKHR) {
732 std::string errorVUID = VkErrorID(4699);
733 function(consumer->function()->id())
734 ->RegisterExecutionModelLimitation(
735 [errorVUID](SpvExecutionModel model, std::string* message) {
736 if (model != SpvExecutionModelAnyHitKHR &&
737 model != SpvExecutionModelClosestHitKHR &&
738 model != SpvExecutionModelMissKHR) {
739 if (message) {
740 *message =
741 errorVUID +
742 "IncomingRayPayloadKHR Storage Class is limited to "
743 "AnyHitKHR, ClosestHitKHR, and MissKHR execution model";
744 }
745 return false;
746 }
747 return true;
748 });
749 } else if (storage_class == SpvStorageClassShaderRecordBufferKHR) {
750 std::string errorVUID = VkErrorID(7119);
751 function(consumer->function()->id())
752 ->RegisterExecutionModelLimitation(
753 [errorVUID](SpvExecutionModel model, std::string* message) {
754 if (model != SpvExecutionModelRayGenerationKHR &&
755 model != SpvExecutionModelIntersectionKHR &&
756 model != SpvExecutionModelAnyHitKHR &&
757 model != SpvExecutionModelClosestHitKHR &&
758 model != SpvExecutionModelCallableKHR &&
759 model != SpvExecutionModelMissKHR) {
760 if (message) {
761 *message =
762 errorVUID +
763 "ShaderRecordBufferKHR Storage Class is limited to "
764 "RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
765 "ClosestHitKHR, CallableKHR, and MissKHR execution model";
766 }
767 return false;
768 }
769 return true;
770 });
771 } else if (storage_class == SpvStorageClassTaskPayloadWorkgroupEXT) {
772 function(consumer->function()->id())
773 ->RegisterExecutionModelLimitation(
774 [](SpvExecutionModel model, std::string* message) {
775 if (model != SpvExecutionModelTaskEXT &&
776 model != SpvExecutionModelMeshEXT) {
777 if (message) {
778 *message =
779 "TaskPayloadWorkgroupEXT Storage Class is limited to "
780 "TaskEXT and MeshKHR execution model";
781 }
782 return false;
783 }
784 return true;
785 });
786 }
787 }
788
getIdBound() const789 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
790
setIdBound(const uint32_t bound)791 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
792
RegisterUniqueTypeDeclaration(const Instruction * inst)793 bool ValidationState_t::RegisterUniqueTypeDeclaration(const Instruction* inst) {
794 std::vector<uint32_t> key;
795 key.push_back(static_cast<uint32_t>(inst->opcode()));
796 for (size_t index = 0; index < inst->operands().size(); ++index) {
797 const spv_parsed_operand_t& operand = inst->operand(index);
798
799 if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
800
801 const int words_begin = operand.offset;
802 const int words_end = words_begin + operand.num_words;
803 assert(words_end <= static_cast<int>(inst->words().size()));
804
805 key.insert(key.end(), inst->words().begin() + words_begin,
806 inst->words().begin() + words_end);
807 }
808
809 return unique_type_declarations_.insert(std::move(key)).second;
810 }
811
GetTypeId(uint32_t id) const812 uint32_t ValidationState_t::GetTypeId(uint32_t id) const {
813 const Instruction* inst = FindDef(id);
814 return inst ? inst->type_id() : 0;
815 }
816
GetIdOpcode(uint32_t id) const817 SpvOp ValidationState_t::GetIdOpcode(uint32_t id) const {
818 const Instruction* inst = FindDef(id);
819 return inst ? inst->opcode() : SpvOpNop;
820 }
821
GetComponentType(uint32_t id) const822 uint32_t ValidationState_t::GetComponentType(uint32_t id) const {
823 const Instruction* inst = FindDef(id);
824 assert(inst);
825
826 switch (inst->opcode()) {
827 case SpvOpTypeFloat:
828 case SpvOpTypeInt:
829 case SpvOpTypeBool:
830 return id;
831
832 case SpvOpTypeVector:
833 return inst->word(2);
834
835 case SpvOpTypeMatrix:
836 return GetComponentType(inst->word(2));
837
838 case SpvOpTypeCooperativeMatrixNV:
839 return inst->word(2);
840
841 default:
842 break;
843 }
844
845 if (inst->type_id()) return GetComponentType(inst->type_id());
846
847 assert(0);
848 return 0;
849 }
850
GetDimension(uint32_t id) const851 uint32_t ValidationState_t::GetDimension(uint32_t id) const {
852 const Instruction* inst = FindDef(id);
853 assert(inst);
854
855 switch (inst->opcode()) {
856 case SpvOpTypeFloat:
857 case SpvOpTypeInt:
858 case SpvOpTypeBool:
859 return 1;
860
861 case SpvOpTypeVector:
862 case SpvOpTypeMatrix:
863 return inst->word(3);
864
865 case SpvOpTypeCooperativeMatrixNV:
866 // Actual dimension isn't known, return 0
867 return 0;
868
869 default:
870 break;
871 }
872
873 if (inst->type_id()) return GetDimension(inst->type_id());
874
875 assert(0);
876 return 0;
877 }
878
GetBitWidth(uint32_t id) const879 uint32_t ValidationState_t::GetBitWidth(uint32_t id) const {
880 const uint32_t component_type_id = GetComponentType(id);
881 const Instruction* inst = FindDef(component_type_id);
882 assert(inst);
883
884 if (inst->opcode() == SpvOpTypeFloat || inst->opcode() == SpvOpTypeInt)
885 return inst->word(2);
886
887 if (inst->opcode() == SpvOpTypeBool) return 1;
888
889 assert(0);
890 return 0;
891 }
892
IsVoidType(uint32_t id) const893 bool ValidationState_t::IsVoidType(uint32_t id) const {
894 const Instruction* inst = FindDef(id);
895 return inst && inst->opcode() == SpvOpTypeVoid;
896 }
897
IsFloatScalarType(uint32_t id) const898 bool ValidationState_t::IsFloatScalarType(uint32_t id) const {
899 const Instruction* inst = FindDef(id);
900 return inst && inst->opcode() == SpvOpTypeFloat;
901 }
902
IsFloatVectorType(uint32_t id) const903 bool ValidationState_t::IsFloatVectorType(uint32_t id) const {
904 const Instruction* inst = FindDef(id);
905 if (!inst) {
906 return false;
907 }
908
909 if (inst->opcode() == SpvOpTypeVector) {
910 return IsFloatScalarType(GetComponentType(id));
911 }
912
913 return false;
914 }
915
IsFloatScalarOrVectorType(uint32_t id) const916 bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const {
917 const Instruction* inst = FindDef(id);
918 if (!inst) {
919 return false;
920 }
921
922 if (inst->opcode() == SpvOpTypeFloat) {
923 return true;
924 }
925
926 if (inst->opcode() == SpvOpTypeVector) {
927 return IsFloatScalarType(GetComponentType(id));
928 }
929
930 return false;
931 }
932
IsIntScalarType(uint32_t id) const933 bool ValidationState_t::IsIntScalarType(uint32_t id) const {
934 const Instruction* inst = FindDef(id);
935 return inst && inst->opcode() == SpvOpTypeInt;
936 }
937
IsIntVectorType(uint32_t id) const938 bool ValidationState_t::IsIntVectorType(uint32_t id) const {
939 const Instruction* inst = FindDef(id);
940 if (!inst) {
941 return false;
942 }
943
944 if (inst->opcode() == SpvOpTypeVector) {
945 return IsIntScalarType(GetComponentType(id));
946 }
947
948 return false;
949 }
950
IsIntScalarOrVectorType(uint32_t id) const951 bool ValidationState_t::IsIntScalarOrVectorType(uint32_t id) const {
952 const Instruction* inst = FindDef(id);
953 if (!inst) {
954 return false;
955 }
956
957 if (inst->opcode() == SpvOpTypeInt) {
958 return true;
959 }
960
961 if (inst->opcode() == SpvOpTypeVector) {
962 return IsIntScalarType(GetComponentType(id));
963 }
964
965 return false;
966 }
967
IsUnsignedIntScalarType(uint32_t id) const968 bool ValidationState_t::IsUnsignedIntScalarType(uint32_t id) const {
969 const Instruction* inst = FindDef(id);
970 return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 0;
971 }
972
IsUnsignedIntVectorType(uint32_t id) const973 bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const {
974 const Instruction* inst = FindDef(id);
975 if (!inst) {
976 return false;
977 }
978
979 if (inst->opcode() == SpvOpTypeVector) {
980 return IsUnsignedIntScalarType(GetComponentType(id));
981 }
982
983 return false;
984 }
985
IsSignedIntScalarType(uint32_t id) const986 bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const {
987 const Instruction* inst = FindDef(id);
988 return inst && inst->opcode() == SpvOpTypeInt && inst->word(3) == 1;
989 }
990
IsSignedIntVectorType(uint32_t id) const991 bool ValidationState_t::IsSignedIntVectorType(uint32_t id) const {
992 const Instruction* inst = FindDef(id);
993 if (!inst) {
994 return false;
995 }
996
997 if (inst->opcode() == SpvOpTypeVector) {
998 return IsSignedIntScalarType(GetComponentType(id));
999 }
1000
1001 return false;
1002 }
1003
IsBoolScalarType(uint32_t id) const1004 bool ValidationState_t::IsBoolScalarType(uint32_t id) const {
1005 const Instruction* inst = FindDef(id);
1006 return inst && inst->opcode() == SpvOpTypeBool;
1007 }
1008
IsBoolVectorType(uint32_t id) const1009 bool ValidationState_t::IsBoolVectorType(uint32_t id) const {
1010 const Instruction* inst = FindDef(id);
1011 if (!inst) {
1012 return false;
1013 }
1014
1015 if (inst->opcode() == SpvOpTypeVector) {
1016 return IsBoolScalarType(GetComponentType(id));
1017 }
1018
1019 return false;
1020 }
1021
IsBoolScalarOrVectorType(uint32_t id) const1022 bool ValidationState_t::IsBoolScalarOrVectorType(uint32_t id) const {
1023 const Instruction* inst = FindDef(id);
1024 if (!inst) {
1025 return false;
1026 }
1027
1028 if (inst->opcode() == SpvOpTypeBool) {
1029 return true;
1030 }
1031
1032 if (inst->opcode() == SpvOpTypeVector) {
1033 return IsBoolScalarType(GetComponentType(id));
1034 }
1035
1036 return false;
1037 }
1038
IsFloatMatrixType(uint32_t id) const1039 bool ValidationState_t::IsFloatMatrixType(uint32_t id) const {
1040 const Instruction* inst = FindDef(id);
1041 if (!inst) {
1042 return false;
1043 }
1044
1045 if (inst->opcode() == SpvOpTypeMatrix) {
1046 return IsFloatScalarType(GetComponentType(id));
1047 }
1048
1049 return false;
1050 }
1051
GetMatrixTypeInfo(uint32_t id,uint32_t * num_rows,uint32_t * num_cols,uint32_t * column_type,uint32_t * component_type) const1052 bool ValidationState_t::GetMatrixTypeInfo(uint32_t id, uint32_t* num_rows,
1053 uint32_t* num_cols,
1054 uint32_t* column_type,
1055 uint32_t* component_type) const {
1056 if (!id) return false;
1057
1058 const Instruction* mat_inst = FindDef(id);
1059 assert(mat_inst);
1060 if (mat_inst->opcode() != SpvOpTypeMatrix) return false;
1061
1062 const uint32_t vec_type = mat_inst->word(2);
1063 const Instruction* vec_inst = FindDef(vec_type);
1064 assert(vec_inst);
1065
1066 if (vec_inst->opcode() != SpvOpTypeVector) {
1067 assert(0);
1068 return false;
1069 }
1070
1071 *num_cols = mat_inst->word(3);
1072 *num_rows = vec_inst->word(3);
1073 *column_type = mat_inst->word(2);
1074 *component_type = vec_inst->word(2);
1075
1076 return true;
1077 }
1078
GetStructMemberTypes(uint32_t struct_type_id,std::vector<uint32_t> * member_types) const1079 bool ValidationState_t::GetStructMemberTypes(
1080 uint32_t struct_type_id, std::vector<uint32_t>* member_types) const {
1081 member_types->clear();
1082 if (!struct_type_id) return false;
1083
1084 const Instruction* inst = FindDef(struct_type_id);
1085 assert(inst);
1086 if (inst->opcode() != SpvOpTypeStruct) return false;
1087
1088 *member_types =
1089 std::vector<uint32_t>(inst->words().cbegin() + 2, inst->words().cend());
1090
1091 if (member_types->empty()) return false;
1092
1093 return true;
1094 }
1095
IsPointerType(uint32_t id) const1096 bool ValidationState_t::IsPointerType(uint32_t id) const {
1097 const Instruction* inst = FindDef(id);
1098 return inst && inst->opcode() == SpvOpTypePointer;
1099 }
1100
GetPointerTypeInfo(uint32_t id,uint32_t * data_type,uint32_t * storage_class) const1101 bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type,
1102 uint32_t* storage_class) const {
1103 if (!id) return false;
1104
1105 const Instruction* inst = FindDef(id);
1106 assert(inst);
1107 if (inst->opcode() != SpvOpTypePointer) return false;
1108
1109 *storage_class = inst->word(2);
1110 *data_type = inst->word(3);
1111 return true;
1112 }
1113
IsAccelerationStructureType(uint32_t id) const1114 bool ValidationState_t::IsAccelerationStructureType(uint32_t id) const {
1115 const Instruction* inst = FindDef(id);
1116 return inst && inst->opcode() == SpvOpTypeAccelerationStructureKHR;
1117 }
1118
IsCooperativeMatrixType(uint32_t id) const1119 bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const {
1120 const Instruction* inst = FindDef(id);
1121 return inst && inst->opcode() == SpvOpTypeCooperativeMatrixNV;
1122 }
1123
IsFloatCooperativeMatrixType(uint32_t id) const1124 bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const {
1125 if (!IsCooperativeMatrixType(id)) return false;
1126 return IsFloatScalarType(FindDef(id)->word(2));
1127 }
1128
IsIntCooperativeMatrixType(uint32_t id) const1129 bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const {
1130 if (!IsCooperativeMatrixType(id)) return false;
1131 return IsIntScalarType(FindDef(id)->word(2));
1132 }
1133
IsUnsignedIntCooperativeMatrixType(uint32_t id) const1134 bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const {
1135 if (!IsCooperativeMatrixType(id)) return false;
1136 return IsUnsignedIntScalarType(FindDef(id)->word(2));
1137 }
1138
1139 // Either a 32 bit 2-component uint vector or a 64 bit uint scalar
IsUnsigned64BitHandle(uint32_t id) const1140 bool ValidationState_t::IsUnsigned64BitHandle(uint32_t id) const {
1141 return ((IsUnsignedIntScalarType(id) && GetBitWidth(id) == 64) ||
1142 (IsUnsignedIntVectorType(id) && GetDimension(id) == 2 &&
1143 GetBitWidth(id) == 32));
1144 }
1145
CooperativeMatrixShapesMatch(const Instruction * inst,uint32_t m1,uint32_t m2)1146 spv_result_t ValidationState_t::CooperativeMatrixShapesMatch(
1147 const Instruction* inst, uint32_t m1, uint32_t m2) {
1148 const auto m1_type = FindDef(m1);
1149 const auto m2_type = FindDef(m2);
1150
1151 if (m1_type->opcode() != SpvOpTypeCooperativeMatrixNV ||
1152 m2_type->opcode() != SpvOpTypeCooperativeMatrixNV) {
1153 return diag(SPV_ERROR_INVALID_DATA, inst)
1154 << "Expected cooperative matrix types";
1155 }
1156
1157 uint32_t m1_scope_id = m1_type->GetOperandAs<uint32_t>(2);
1158 uint32_t m1_rows_id = m1_type->GetOperandAs<uint32_t>(3);
1159 uint32_t m1_cols_id = m1_type->GetOperandAs<uint32_t>(4);
1160
1161 uint32_t m2_scope_id = m2_type->GetOperandAs<uint32_t>(2);
1162 uint32_t m2_rows_id = m2_type->GetOperandAs<uint32_t>(3);
1163 uint32_t m2_cols_id = m2_type->GetOperandAs<uint32_t>(4);
1164
1165 bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false,
1166 m2_is_const_int32 = false;
1167 uint32_t m1_value = 0, m2_value = 0;
1168
1169 std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1170 EvalInt32IfConst(m1_scope_id);
1171 std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1172 EvalInt32IfConst(m2_scope_id);
1173
1174 if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1175 return diag(SPV_ERROR_INVALID_DATA, inst)
1176 << "Expected scopes of Matrix and Result Type to be "
1177 << "identical";
1178 }
1179
1180 std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1181 EvalInt32IfConst(m1_rows_id);
1182 std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1183 EvalInt32IfConst(m2_rows_id);
1184
1185 if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1186 return diag(SPV_ERROR_INVALID_DATA, inst)
1187 << "Expected rows of Matrix type and Result Type to be "
1188 << "identical";
1189 }
1190
1191 std::tie(m1_is_int32, m1_is_const_int32, m1_value) =
1192 EvalInt32IfConst(m1_cols_id);
1193 std::tie(m2_is_int32, m2_is_const_int32, m2_value) =
1194 EvalInt32IfConst(m2_cols_id);
1195
1196 if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) {
1197 return diag(SPV_ERROR_INVALID_DATA, inst)
1198 << "Expected columns of Matrix type and Result Type to be "
1199 << "identical";
1200 }
1201
1202 return SPV_SUCCESS;
1203 }
1204
GetOperandTypeId(const Instruction * inst,size_t operand_index) const1205 uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst,
1206 size_t operand_index) const {
1207 return GetTypeId(inst->GetOperandAs<uint32_t>(operand_index));
1208 }
1209
GetConstantValUint64(uint32_t id,uint64_t * val) const1210 bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const {
1211 const Instruction* inst = FindDef(id);
1212 if (!inst) {
1213 assert(0 && "Instruction not found");
1214 return false;
1215 }
1216
1217 if (inst->opcode() != SpvOpConstant && inst->opcode() != SpvOpSpecConstant)
1218 return false;
1219
1220 if (!IsIntScalarType(inst->type_id())) return false;
1221
1222 if (inst->words().size() == 4) {
1223 *val = inst->word(3);
1224 } else {
1225 assert(inst->words().size() == 5);
1226 *val = inst->word(3);
1227 *val |= uint64_t(inst->word(4)) << 32;
1228 }
1229 return true;
1230 }
1231
EvalInt32IfConst(uint32_t id) const1232 std::tuple<bool, bool, uint32_t> ValidationState_t::EvalInt32IfConst(
1233 uint32_t id) const {
1234 const Instruction* const inst = FindDef(id);
1235 assert(inst);
1236 const uint32_t type = inst->type_id();
1237
1238 if (type == 0 || !IsIntScalarType(type) || GetBitWidth(type) != 32) {
1239 return std::make_tuple(false, false, 0);
1240 }
1241
1242 // Spec constant values cannot be evaluated so don't consider constant for
1243 // the purpose of this method.
1244 if (!spvOpcodeIsConstant(inst->opcode()) ||
1245 spvOpcodeIsSpecConstant(inst->opcode())) {
1246 return std::make_tuple(true, false, 0);
1247 }
1248
1249 if (inst->opcode() == SpvOpConstantNull) {
1250 return std::make_tuple(true, true, 0);
1251 }
1252
1253 assert(inst->words().size() == 4);
1254 return std::make_tuple(true, true, inst->word(3));
1255 }
1256
ComputeFunctionToEntryPointMapping()1257 void ValidationState_t::ComputeFunctionToEntryPointMapping() {
1258 for (const uint32_t entry_point : entry_points()) {
1259 std::stack<uint32_t> call_stack;
1260 std::set<uint32_t> visited;
1261 call_stack.push(entry_point);
1262 while (!call_stack.empty()) {
1263 const uint32_t called_func_id = call_stack.top();
1264 call_stack.pop();
1265 if (!visited.insert(called_func_id).second) continue;
1266
1267 function_to_entry_points_[called_func_id].push_back(entry_point);
1268
1269 const Function* called_func = function(called_func_id);
1270 if (called_func) {
1271 // Other checks should error out on this invalid SPIR-V.
1272 for (const uint32_t new_call : called_func->function_call_targets()) {
1273 call_stack.push(new_call);
1274 }
1275 }
1276 }
1277 }
1278 }
1279
ComputeRecursiveEntryPoints()1280 void ValidationState_t::ComputeRecursiveEntryPoints() {
1281 for (const Function& func : functions()) {
1282 std::stack<uint32_t> call_stack;
1283 std::set<uint32_t> visited;
1284
1285 for (const uint32_t new_call : func.function_call_targets()) {
1286 call_stack.push(new_call);
1287 }
1288
1289 while (!call_stack.empty()) {
1290 const uint32_t called_func_id = call_stack.top();
1291 call_stack.pop();
1292
1293 if (!visited.insert(called_func_id).second) continue;
1294
1295 if (called_func_id == func.id()) {
1296 for (const uint32_t entry_point :
1297 function_to_entry_points_[called_func_id])
1298 recursive_entry_points_.insert(entry_point);
1299 break;
1300 }
1301
1302 const Function* called_func = function(called_func_id);
1303 if (called_func) {
1304 // Other checks should error out on this invalid SPIR-V.
1305 for (const uint32_t new_call : called_func->function_call_targets()) {
1306 call_stack.push(new_call);
1307 }
1308 }
1309 }
1310 }
1311 }
1312
FunctionEntryPoints(uint32_t func) const1313 const std::vector<uint32_t>& ValidationState_t::FunctionEntryPoints(
1314 uint32_t func) const {
1315 auto iter = function_to_entry_points_.find(func);
1316 if (iter == function_to_entry_points_.end()) {
1317 return empty_ids_;
1318 } else {
1319 return iter->second;
1320 }
1321 }
1322
EntryPointReferences(uint32_t id) const1323 std::set<uint32_t> ValidationState_t::EntryPointReferences(uint32_t id) const {
1324 std::set<uint32_t> referenced_entry_points;
1325 const auto inst = FindDef(id);
1326 if (!inst) return referenced_entry_points;
1327
1328 std::vector<const Instruction*> stack;
1329 stack.push_back(inst);
1330 while (!stack.empty()) {
1331 const auto current_inst = stack.back();
1332 stack.pop_back();
1333
1334 if (const auto func = current_inst->function()) {
1335 // Instruction lives in a function, we can stop searching.
1336 const auto function_entry_points = FunctionEntryPoints(func->id());
1337 referenced_entry_points.insert(function_entry_points.begin(),
1338 function_entry_points.end());
1339 } else {
1340 // Instruction is in the global scope, keep searching its uses.
1341 for (auto pair : current_inst->uses()) {
1342 const auto next_inst = pair.first;
1343 stack.push_back(next_inst);
1344 }
1345 }
1346 }
1347
1348 return referenced_entry_points;
1349 }
1350
Disassemble(const Instruction & inst) const1351 std::string ValidationState_t::Disassemble(const Instruction& inst) const {
1352 const spv_parsed_instruction_t& c_inst(inst.c_inst());
1353 return Disassemble(c_inst.words, c_inst.num_words);
1354 }
1355
Disassemble(const uint32_t * words,uint16_t num_words) const1356 std::string ValidationState_t::Disassemble(const uint32_t* words,
1357 uint16_t num_words) const {
1358 uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1359 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES;
1360
1361 return spvInstructionBinaryToText(context()->target_env, words, num_words,
1362 words_, num_words_, disassembly_options);
1363 }
1364
LogicallyMatch(const Instruction * lhs,const Instruction * rhs,bool check_decorations)1365 bool ValidationState_t::LogicallyMatch(const Instruction* lhs,
1366 const Instruction* rhs,
1367 bool check_decorations) {
1368 if (lhs->opcode() != rhs->opcode()) {
1369 return false;
1370 }
1371
1372 if (check_decorations) {
1373 const auto& dec_a = id_decorations(lhs->id());
1374 const auto& dec_b = id_decorations(rhs->id());
1375
1376 for (const auto& dec : dec_b) {
1377 if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) {
1378 return false;
1379 }
1380 }
1381 }
1382
1383 if (lhs->opcode() == SpvOpTypeArray) {
1384 // Size operands must match.
1385 if (lhs->GetOperandAs<uint32_t>(2u) != rhs->GetOperandAs<uint32_t>(2u)) {
1386 return false;
1387 }
1388
1389 // Elements must match or logically match.
1390 const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(1u);
1391 const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(1u);
1392 if (lhs_ele_id == rhs_ele_id) {
1393 return true;
1394 }
1395
1396 const auto lhs_ele = FindDef(lhs_ele_id);
1397 const auto rhs_ele = FindDef(rhs_ele_id);
1398 if (!lhs_ele || !rhs_ele) {
1399 return false;
1400 }
1401 return LogicallyMatch(lhs_ele, rhs_ele, check_decorations);
1402 } else if (lhs->opcode() == SpvOpTypeStruct) {
1403 // Number of elements must match.
1404 if (lhs->operands().size() != rhs->operands().size()) {
1405 return false;
1406 }
1407
1408 for (size_t i = 1u; i < lhs->operands().size(); ++i) {
1409 const auto lhs_ele_id = lhs->GetOperandAs<uint32_t>(i);
1410 const auto rhs_ele_id = rhs->GetOperandAs<uint32_t>(i);
1411 // Elements must match or logically match.
1412 if (lhs_ele_id == rhs_ele_id) {
1413 continue;
1414 }
1415
1416 const auto lhs_ele = FindDef(lhs_ele_id);
1417 const auto rhs_ele = FindDef(rhs_ele_id);
1418 if (!lhs_ele || !rhs_ele) {
1419 return false;
1420 }
1421
1422 if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) {
1423 return false;
1424 }
1425 }
1426
1427 // All checks passed.
1428 return true;
1429 }
1430
1431 // No other opcodes are acceptable at this point. Arrays and structs are
1432 // caught above and if they're elements are not arrays or structs they are
1433 // required to match exactly.
1434 return false;
1435 }
1436
TracePointer(const Instruction * inst) const1437 const Instruction* ValidationState_t::TracePointer(
1438 const Instruction* inst) const {
1439 auto base_ptr = inst;
1440 while (base_ptr->opcode() == SpvOpAccessChain ||
1441 base_ptr->opcode() == SpvOpInBoundsAccessChain ||
1442 base_ptr->opcode() == SpvOpPtrAccessChain ||
1443 base_ptr->opcode() == SpvOpInBoundsPtrAccessChain ||
1444 base_ptr->opcode() == SpvOpCopyObject) {
1445 base_ptr = FindDef(base_ptr->GetOperandAs<uint32_t>(2u));
1446 }
1447 return base_ptr;
1448 }
1449
ContainsType(uint32_t id,const std::function<bool (const Instruction *)> & f,bool traverse_all_types) const1450 bool ValidationState_t::ContainsType(
1451 uint32_t id, const std::function<bool(const Instruction*)>& f,
1452 bool traverse_all_types) const {
1453 const auto inst = FindDef(id);
1454 if (!inst) return false;
1455
1456 if (f(inst)) return true;
1457
1458 switch (inst->opcode()) {
1459 case SpvOpTypeArray:
1460 case SpvOpTypeRuntimeArray:
1461 case SpvOpTypeVector:
1462 case SpvOpTypeMatrix:
1463 case SpvOpTypeImage:
1464 case SpvOpTypeSampledImage:
1465 case SpvOpTypeCooperativeMatrixNV:
1466 return ContainsType(inst->GetOperandAs<uint32_t>(1u), f,
1467 traverse_all_types);
1468 case SpvOpTypePointer:
1469 if (IsForwardPointer(id)) return false;
1470 if (traverse_all_types) {
1471 return ContainsType(inst->GetOperandAs<uint32_t>(2u), f,
1472 traverse_all_types);
1473 }
1474 break;
1475 case SpvOpTypeFunction:
1476 case SpvOpTypeStruct:
1477 if (inst->opcode() == SpvOpTypeFunction && !traverse_all_types) {
1478 return false;
1479 }
1480 for (uint32_t i = 1; i < inst->operands().size(); ++i) {
1481 if (ContainsType(inst->GetOperandAs<uint32_t>(i), f,
1482 traverse_all_types)) {
1483 return true;
1484 }
1485 }
1486 break;
1487 default:
1488 break;
1489 }
1490
1491 return false;
1492 }
1493
ContainsSizedIntOrFloatType(uint32_t id,SpvOp type,uint32_t width) const1494 bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type,
1495 uint32_t width) const {
1496 if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false;
1497
1498 const auto f = [type, width](const Instruction* inst) {
1499 if (inst->opcode() == type) {
1500 return inst->GetOperandAs<uint32_t>(1u) == width;
1501 }
1502 return false;
1503 };
1504 return ContainsType(id, f);
1505 }
1506
ContainsLimitedUseIntOrFloatType(uint32_t id) const1507 bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const {
1508 if ((!HasCapability(SpvCapabilityInt16) &&
1509 ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 16)) ||
1510 (!HasCapability(SpvCapabilityInt8) &&
1511 ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 8)) ||
1512 (!HasCapability(SpvCapabilityFloat16) &&
1513 ContainsSizedIntOrFloatType(id, SpvOpTypeFloat, 16))) {
1514 return true;
1515 }
1516 return false;
1517 }
1518
ContainsRuntimeArray(uint32_t id) const1519 bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const {
1520 const auto f = [](const Instruction* inst) {
1521 return inst->opcode() == SpvOpTypeRuntimeArray;
1522 };
1523 return ContainsType(id, f, /* traverse_all_types = */ false);
1524 }
1525
IsValidStorageClass(SpvStorageClass storage_class) const1526 bool ValidationState_t::IsValidStorageClass(
1527 SpvStorageClass storage_class) const {
1528 if (spvIsVulkanEnv(context()->target_env)) {
1529 switch (storage_class) {
1530 case SpvStorageClassUniformConstant:
1531 case SpvStorageClassUniform:
1532 case SpvStorageClassStorageBuffer:
1533 case SpvStorageClassInput:
1534 case SpvStorageClassOutput:
1535 case SpvStorageClassImage:
1536 case SpvStorageClassWorkgroup:
1537 case SpvStorageClassPrivate:
1538 case SpvStorageClassFunction:
1539 case SpvStorageClassPushConstant:
1540 case SpvStorageClassPhysicalStorageBuffer:
1541 case SpvStorageClassRayPayloadKHR:
1542 case SpvStorageClassIncomingRayPayloadKHR:
1543 case SpvStorageClassHitAttributeKHR:
1544 case SpvStorageClassCallableDataKHR:
1545 case SpvStorageClassIncomingCallableDataKHR:
1546 case SpvStorageClassShaderRecordBufferKHR:
1547 case SpvStorageClassTaskPayloadWorkgroupEXT:
1548 return true;
1549 default:
1550 return false;
1551 }
1552 }
1553
1554 return true;
1555 }
1556
1557 #define VUID_WRAP(vuid) "[" #vuid "] "
1558
1559 // Currently no 2 VUID share the same id, so no need for |reference|
VkErrorID(uint32_t id,const char *) const1560 std::string ValidationState_t::VkErrorID(uint32_t id,
1561 const char* /*reference*/) const {
1562 if (!spvIsVulkanEnv(context_->target_env)) {
1563 return "";
1564 }
1565
1566 // This large switch case is only searched when an error has occurred.
1567 // If an id is changed, the old case must be modified or removed. Each string
1568 // here is interpreted as being "implemented"
1569
1570 // Clang format adds spaces between hyphens
1571 // clang-format off
1572 switch (id) {
1573 case 4154:
1574 return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04154);
1575 case 4155:
1576 return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04155);
1577 case 4156:
1578 return VUID_WRAP(VUID-BaryCoordKHR-BaryCoordKHR-04156);
1579 case 4160:
1580 return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04160);
1581 case 4161:
1582 return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04161);
1583 case 4162:
1584 return VUID_WRAP(VUID-BaryCoordNoPerspKHR-BaryCoordNoPerspKHR-04162);
1585 case 4181:
1586 return VUID_WRAP(VUID-BaseInstance-BaseInstance-04181);
1587 case 4182:
1588 return VUID_WRAP(VUID-BaseInstance-BaseInstance-04182);
1589 case 4183:
1590 return VUID_WRAP(VUID-BaseInstance-BaseInstance-04183);
1591 case 4184:
1592 return VUID_WRAP(VUID-BaseVertex-BaseVertex-04184);
1593 case 4185:
1594 return VUID_WRAP(VUID-BaseVertex-BaseVertex-04185);
1595 case 4186:
1596 return VUID_WRAP(VUID-BaseVertex-BaseVertex-04186);
1597 case 4187:
1598 return VUID_WRAP(VUID-ClipDistance-ClipDistance-04187);
1599 case 4188:
1600 return VUID_WRAP(VUID-ClipDistance-ClipDistance-04188);
1601 case 4189:
1602 return VUID_WRAP(VUID-ClipDistance-ClipDistance-04189);
1603 case 4190:
1604 return VUID_WRAP(VUID-ClipDistance-ClipDistance-04190);
1605 case 4191:
1606 return VUID_WRAP(VUID-ClipDistance-ClipDistance-04191);
1607 case 4196:
1608 return VUID_WRAP(VUID-CullDistance-CullDistance-04196);
1609 case 4197:
1610 return VUID_WRAP(VUID-CullDistance-CullDistance-04197);
1611 case 4198:
1612 return VUID_WRAP(VUID-CullDistance-CullDistance-04198);
1613 case 4199:
1614 return VUID_WRAP(VUID-CullDistance-CullDistance-04199);
1615 case 4200:
1616 return VUID_WRAP(VUID-CullDistance-CullDistance-04200);
1617 case 6735:
1618 return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06735); // Execution Model
1619 case 6736:
1620 return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06736); // input storage
1621 case 6737:
1622 return VUID_WRAP(VUID-CullMaskKHR-CullMaskKHR-06737); // 32 int scalar
1623 case 4205:
1624 return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04205);
1625 case 4206:
1626 return VUID_WRAP(VUID-DeviceIndex-DeviceIndex-04206);
1627 case 4207:
1628 return VUID_WRAP(VUID-DrawIndex-DrawIndex-04207);
1629 case 4208:
1630 return VUID_WRAP(VUID-DrawIndex-DrawIndex-04208);
1631 case 4209:
1632 return VUID_WRAP(VUID-DrawIndex-DrawIndex-04209);
1633 case 4210:
1634 return VUID_WRAP(VUID-FragCoord-FragCoord-04210);
1635 case 4211:
1636 return VUID_WRAP(VUID-FragCoord-FragCoord-04211);
1637 case 4212:
1638 return VUID_WRAP(VUID-FragCoord-FragCoord-04212);
1639 case 4213:
1640 return VUID_WRAP(VUID-FragDepth-FragDepth-04213);
1641 case 4214:
1642 return VUID_WRAP(VUID-FragDepth-FragDepth-04214);
1643 case 4215:
1644 return VUID_WRAP(VUID-FragDepth-FragDepth-04215);
1645 case 4216:
1646 return VUID_WRAP(VUID-FragDepth-FragDepth-04216);
1647 case 4217:
1648 return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04217);
1649 case 4218:
1650 return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04218);
1651 case 4219:
1652 return VUID_WRAP(VUID-FragInvocationCountEXT-FragInvocationCountEXT-04219);
1653 case 4220:
1654 return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04220);
1655 case 4221:
1656 return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04221);
1657 case 4222:
1658 return VUID_WRAP(VUID-FragSizeEXT-FragSizeEXT-04222);
1659 case 4223:
1660 return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04223);
1661 case 4224:
1662 return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04224);
1663 case 4225:
1664 return VUID_WRAP(VUID-FragStencilRefEXT-FragStencilRefEXT-04225);
1665 case 4229:
1666 return VUID_WRAP(VUID-FrontFacing-FrontFacing-04229);
1667 case 4230:
1668 return VUID_WRAP(VUID-FrontFacing-FrontFacing-04230);
1669 case 4231:
1670 return VUID_WRAP(VUID-FrontFacing-FrontFacing-04231);
1671 case 4232:
1672 return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04232);
1673 case 4233:
1674 return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04233);
1675 case 4234:
1676 return VUID_WRAP(VUID-FullyCoveredEXT-FullyCoveredEXT-04234);
1677 case 4236:
1678 return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04236);
1679 case 4237:
1680 return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04237);
1681 case 4238:
1682 return VUID_WRAP(VUID-GlobalInvocationId-GlobalInvocationId-04238);
1683 case 4239:
1684 return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04239);
1685 case 4240:
1686 return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
1687 case 4241:
1688 return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
1689 case 4242:
1690 return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
1691 case 4243:
1692 return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
1693 case 4244:
1694 return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
1695 case 4245:
1696 return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
1697 case 4246:
1698 return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
1699 case 4247:
1700 return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
1701 case 4248:
1702 return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
1703 case 4249:
1704 return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
1705 case 4250:
1706 return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
1707 case 4251:
1708 return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
1709 case 4252:
1710 return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
1711 case 4253:
1712 return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
1713 case 4254:
1714 return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
1715 case 4255:
1716 return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
1717 case 4256:
1718 return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
1719 case 4257:
1720 return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
1721 case 4258:
1722 return VUID_WRAP(VUID-InvocationId-InvocationId-04258);
1723 case 4259:
1724 return VUID_WRAP(VUID-InvocationId-InvocationId-04259);
1725 case 4263:
1726 return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04263);
1727 case 4264:
1728 return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
1729 case 4265:
1730 return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
1731 case 4266:
1732 return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
1733 case 4267:
1734 return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
1735 case 4268:
1736 return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
1737 case 4269:
1738 return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
1739 case 4270:
1740 return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
1741 case 4271:
1742 return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
1743 case 4272:
1744 return VUID_WRAP(VUID-Layer-Layer-04272);
1745 case 4273:
1746 return VUID_WRAP(VUID-Layer-Layer-04273);
1747 case 4274:
1748 return VUID_WRAP(VUID-Layer-Layer-04274);
1749 case 4275:
1750 return VUID_WRAP(VUID-Layer-Layer-04275);
1751 case 4276:
1752 return VUID_WRAP(VUID-Layer-Layer-04276);
1753 case 4281:
1754 return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04281);
1755 case 4282:
1756 return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04282);
1757 case 4283:
1758 return VUID_WRAP(VUID-LocalInvocationId-LocalInvocationId-04283);
1759 case 4293:
1760 return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04293);
1761 case 4294:
1762 return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04294);
1763 case 4295:
1764 return VUID_WRAP(VUID-NumSubgroups-NumSubgroups-04295);
1765 case 4296:
1766 return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04296);
1767 case 4297:
1768 return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
1769 case 4298:
1770 return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
1771 case 4299:
1772 return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
1773 case 4300:
1774 return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
1775 case 4301:
1776 return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
1777 case 4302:
1778 return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
1779 case 4303:
1780 return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
1781 case 4304:
1782 return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
1783 case 4305:
1784 return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
1785 case 4306:
1786 return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
1787 case 4307:
1788 return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
1789 case 4308:
1790 return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
1791 case 4309:
1792 return VUID_WRAP(VUID-PatchVertices-PatchVertices-04309);
1793 case 4310:
1794 return VUID_WRAP(VUID-PatchVertices-PatchVertices-04310);
1795 case 4311:
1796 return VUID_WRAP(VUID-PointCoord-PointCoord-04311);
1797 case 4312:
1798 return VUID_WRAP(VUID-PointCoord-PointCoord-04312);
1799 case 4313:
1800 return VUID_WRAP(VUID-PointCoord-PointCoord-04313);
1801 case 4314:
1802 return VUID_WRAP(VUID-PointSize-PointSize-04314);
1803 case 4315:
1804 return VUID_WRAP(VUID-PointSize-PointSize-04315);
1805 case 4316:
1806 return VUID_WRAP(VUID-PointSize-PointSize-04316);
1807 case 4317:
1808 return VUID_WRAP(VUID-PointSize-PointSize-04317);
1809 case 4318:
1810 return VUID_WRAP(VUID-Position-Position-04318);
1811 case 4319:
1812 return VUID_WRAP(VUID-Position-Position-04319);
1813 case 4320:
1814 return VUID_WRAP(VUID-Position-Position-04320);
1815 case 4321:
1816 return VUID_WRAP(VUID-Position-Position-04321);
1817 case 4330:
1818 return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330);
1819 case 4334:
1820 return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
1821 case 4337:
1822 return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
1823 case 4345:
1824 return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
1825 case 4346:
1826 return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
1827 case 4347:
1828 return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
1829 case 4348:
1830 return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
1831 case 4349:
1832 return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
1833 case 4350:
1834 return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
1835 case 4351:
1836 return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
1837 case 4352:
1838 return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
1839 case 4353:
1840 return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
1841 case 4354:
1842 return VUID_WRAP(VUID-SampleId-SampleId-04354);
1843 case 4355:
1844 return VUID_WRAP(VUID-SampleId-SampleId-04355);
1845 case 4356:
1846 return VUID_WRAP(VUID-SampleId-SampleId-04356);
1847 case 4357:
1848 return VUID_WRAP(VUID-SampleMask-SampleMask-04357);
1849 case 4358:
1850 return VUID_WRAP(VUID-SampleMask-SampleMask-04358);
1851 case 4359:
1852 return VUID_WRAP(VUID-SampleMask-SampleMask-04359);
1853 case 4360:
1854 return VUID_WRAP(VUID-SamplePosition-SamplePosition-04360);
1855 case 4361:
1856 return VUID_WRAP(VUID-SamplePosition-SamplePosition-04361);
1857 case 4362:
1858 return VUID_WRAP(VUID-SamplePosition-SamplePosition-04362);
1859 case 4367:
1860 return VUID_WRAP(VUID-SubgroupId-SubgroupId-04367);
1861 case 4368:
1862 return VUID_WRAP(VUID-SubgroupId-SubgroupId-04368);
1863 case 4369:
1864 return VUID_WRAP(VUID-SubgroupId-SubgroupId-04369);
1865 case 4370:
1866 return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04370);
1867 case 4371:
1868 return VUID_WRAP(VUID-SubgroupEqMask-SubgroupEqMask-04371);
1869 case 4372:
1870 return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04372);
1871 case 4373:
1872 return VUID_WRAP(VUID-SubgroupGeMask-SubgroupGeMask-04373);
1873 case 4374:
1874 return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04374);
1875 case 4375:
1876 return VUID_WRAP(VUID-SubgroupGtMask-SubgroupGtMask-04375);
1877 case 4376:
1878 return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04376);
1879 case 4377:
1880 return VUID_WRAP(VUID-SubgroupLeMask-SubgroupLeMask-04377);
1881 case 4378:
1882 return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04378);
1883 case 4379:
1884 return VUID_WRAP(VUID-SubgroupLtMask-SubgroupLtMask-04379);
1885 case 4380:
1886 return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04380);
1887 case 4381:
1888 return VUID_WRAP(VUID-SubgroupLocalInvocationId-SubgroupLocalInvocationId-04381);
1889 case 4382:
1890 return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04382);
1891 case 4383:
1892 return VUID_WRAP(VUID-SubgroupSize-SubgroupSize-04383);
1893 case 4387:
1894 return VUID_WRAP(VUID-TessCoord-TessCoord-04387);
1895 case 4388:
1896 return VUID_WRAP(VUID-TessCoord-TessCoord-04388);
1897 case 4389:
1898 return VUID_WRAP(VUID-TessCoord-TessCoord-04389);
1899 case 4390:
1900 return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04390);
1901 case 4391:
1902 return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04391);
1903 case 4392:
1904 return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04392);
1905 case 4393:
1906 return VUID_WRAP(VUID-TessLevelOuter-TessLevelOuter-04393);
1907 case 4394:
1908 return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04394);
1909 case 4395:
1910 return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04395);
1911 case 4396:
1912 return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04396);
1913 case 4397:
1914 return VUID_WRAP(VUID-TessLevelInner-TessLevelInner-04397);
1915 case 4398:
1916 return VUID_WRAP(VUID-VertexIndex-VertexIndex-04398);
1917 case 4399:
1918 return VUID_WRAP(VUID-VertexIndex-VertexIndex-04399);
1919 case 4400:
1920 return VUID_WRAP(VUID-VertexIndex-VertexIndex-04400);
1921 case 4401:
1922 return VUID_WRAP(VUID-ViewIndex-ViewIndex-04401);
1923 case 4402:
1924 return VUID_WRAP(VUID-ViewIndex-ViewIndex-04402);
1925 case 4403:
1926 return VUID_WRAP(VUID-ViewIndex-ViewIndex-04403);
1927 case 4404:
1928 return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04404);
1929 case 4405:
1930 return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04405);
1931 case 4406:
1932 return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04406);
1933 case 4407:
1934 return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04407);
1935 case 4408:
1936 return VUID_WRAP(VUID-ViewportIndex-ViewportIndex-04408);
1937 case 4422:
1938 return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04422);
1939 case 4423:
1940 return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04423);
1941 case 4424:
1942 return VUID_WRAP(VUID-WorkgroupId-WorkgroupId-04424);
1943 case 4425:
1944 return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04425);
1945 case 4426:
1946 return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
1947 case 4427:
1948 return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
1949 case 4428:
1950 return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
1951 case 4429:
1952 return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
1953 case 4430:
1954 return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
1955 case 4431:
1956 return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
1957 case 4432:
1958 return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
1959 case 4433:
1960 return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
1961 case 4434:
1962 return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
1963 case 4435:
1964 return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
1965 case 4436:
1966 return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
1967 case 4484:
1968 return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
1969 case 4485:
1970 return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04485);
1971 case 4486:
1972 return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04486);
1973 case 4490:
1974 return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04490);
1975 case 4491:
1976 return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04491);
1977 case 4492:
1978 return VUID_WRAP(VUID-ShadingRateKHR-ShadingRateKHR-04492);
1979 case 4633:
1980 return VUID_WRAP(VUID-StandaloneSpirv-None-04633);
1981 case 4634:
1982 return VUID_WRAP(VUID-StandaloneSpirv-None-04634);
1983 case 4635:
1984 return VUID_WRAP(VUID-StandaloneSpirv-None-04635);
1985 case 4636:
1986 return VUID_WRAP(VUID-StandaloneSpirv-None-04636);
1987 case 4637:
1988 return VUID_WRAP(VUID-StandaloneSpirv-None-04637);
1989 case 4638:
1990 return VUID_WRAP(VUID-StandaloneSpirv-None-04638);
1991 case 7321:
1992 return VUID_WRAP(VUID-StandaloneSpirv-None-07321);
1993 case 4640:
1994 return VUID_WRAP(VUID-StandaloneSpirv-None-04640);
1995 case 4641:
1996 return VUID_WRAP(VUID-StandaloneSpirv-None-04641);
1997 case 4642:
1998 return VUID_WRAP(VUID-StandaloneSpirv-None-04642);
1999 case 4643:
2000 return VUID_WRAP(VUID-StandaloneSpirv-None-04643);
2001 case 4644:
2002 return VUID_WRAP(VUID-StandaloneSpirv-None-04644);
2003 case 4645:
2004 return VUID_WRAP(VUID-StandaloneSpirv-None-04645);
2005 case 4651:
2006 return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651);
2007 case 4652:
2008 return VUID_WRAP(VUID-StandaloneSpirv-OpReadClockKHR-04652);
2009 case 4653:
2010 return VUID_WRAP(VUID-StandaloneSpirv-OriginLowerLeft-04653);
2011 case 4654:
2012 return VUID_WRAP(VUID-StandaloneSpirv-PixelCenterInteger-04654);
2013 case 4655:
2014 return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-04655);
2015 case 4656:
2016 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04656);
2017 case 4657:
2018 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-04657);
2019 case 4658:
2020 return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658);
2021 case 4659:
2022 return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659);
2023 case 4662:
2024 return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662);
2025 case 4663:
2026 return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663);
2027 case 4664:
2028 return VUID_WRAP(VUID-StandaloneSpirv-OpImageGather-04664);
2029 case 4667:
2030 return VUID_WRAP(VUID-StandaloneSpirv-None-04667);
2031 case 4669:
2032 return VUID_WRAP(VUID-StandaloneSpirv-GLSLShared-04669);
2033 case 4670:
2034 return VUID_WRAP(VUID-StandaloneSpirv-Flat-04670);
2035 case 4675:
2036 return VUID_WRAP(VUID-StandaloneSpirv-FPRoundingMode-04675);
2037 case 4677:
2038 return VUID_WRAP(VUID-StandaloneSpirv-Invariant-04677);
2039 case 4680:
2040 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeRuntimeArray-04680);
2041 case 4682:
2042 return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04682);
2043 case 6426:
2044 return VUID_WRAP(VUID-StandaloneSpirv-LocalSize-06426); // formally 04683
2045 case 4685:
2046 return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
2047 case 4686:
2048 return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
2049 case 4698:
2050 return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698);
2051 case 4699:
2052 return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699);
2053 case 4701:
2054 return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701);
2055 case 4703:
2056 return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703);
2057 case 4704:
2058 return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704);
2059 case 4705:
2060 return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705);
2061 case 7119:
2062 return VUID_WRAP(VUID-StandaloneSpirv-ShaderRecordBufferKHR-07119);
2063 case 4708:
2064 return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708);
2065 case 4710:
2066 return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04710);
2067 case 4711:
2068 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeForwardPointer-04711);
2069 case 4730:
2070 return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicStore-04730);
2071 case 4731:
2072 return VUID_WRAP(VUID-StandaloneSpirv-OpAtomicLoad-04731);
2073 case 4732:
2074 return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04732);
2075 case 4733:
2076 return VUID_WRAP(VUID-StandaloneSpirv-OpMemoryBarrier-04733);
2077 case 4734:
2078 return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04734);
2079 case 4744:
2080 return VUID_WRAP(VUID-StandaloneSpirv-Flat-04744);
2081 case 4777:
2082 return VUID_WRAP(VUID-StandaloneSpirv-OpImage-04777);
2083 case 4780:
2084 return VUID_WRAP(VUID-StandaloneSpirv-Result-04780);
2085 case 4781:
2086 return VUID_WRAP(VUID-StandaloneSpirv-Base-04781);
2087 case 4915:
2088 return VUID_WRAP(VUID-StandaloneSpirv-Location-04915);
2089 case 4916:
2090 return VUID_WRAP(VUID-StandaloneSpirv-Location-04916);
2091 case 4917:
2092 return VUID_WRAP(VUID-StandaloneSpirv-Location-04917);
2093 case 4918:
2094 return VUID_WRAP(VUID-StandaloneSpirv-Location-04918);
2095 case 4919:
2096 return VUID_WRAP(VUID-StandaloneSpirv-Location-04919);
2097 case 6201:
2098 return VUID_WRAP(VUID-StandaloneSpirv-Flat-06201);
2099 case 6202:
2100 return VUID_WRAP(VUID-StandaloneSpirv-Flat-06202);
2101 case 6214:
2102 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-06214);
2103 case 6491:
2104 return VUID_WRAP(VUID-StandaloneSpirv-DescriptorSet-06491);
2105 case 6671:
2106 return VUID_WRAP(VUID-StandaloneSpirv-OpTypeSampledImage-06671);
2107 case 6672:
2108 return VUID_WRAP(VUID-StandaloneSpirv-Location-06672);
2109 case 6674:
2110 return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-06674);
2111 case 6675:
2112 return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06675);
2113 case 6676:
2114 return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06676);
2115 case 6677:
2116 return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-06677);
2117 case 6678:
2118 return VUID_WRAP(VUID-StandaloneSpirv-InputAttachmentIndex-06678);
2119 case 6777:
2120 return VUID_WRAP(VUID-StandaloneSpirv-PerVertexKHR-06777);
2121 case 6778:
2122 return VUID_WRAP(VUID-StandaloneSpirv-Input-06778);
2123 case 6807:
2124 return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06807);
2125 case 6808:
2126 return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808);
2127 case 6925:
2128 return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925);
2129 case 6997:
2130 return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-06997);
2131 case 7102:
2132 return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102);
2133 case 7320:
2134 return VUID_WRAP(VUID-StandaloneSpirv-ExecutionModel-07320);
2135 case 7290:
2136 return VUID_WRAP(VUID-StandaloneSpirv-Input-07290);
2137 default:
2138 return ""; // unknown id
2139 }
2140 // clang-format on
2141 }
2142
2143 } // namespace val
2144 } // namespace spvtools
2145