1 // Copyright (c) 2018 Google LLC.
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 <algorithm>
16 #include <vector>
17
18 #include "source/spirv_constant.h"
19 #include "source/spirv_target_env.h"
20 #include "source/val/function.h"
21 #include "source/val/instruction.h"
22 #include "source/val/validate.h"
23 #include "source/val/validation_state.h"
24
25 namespace spvtools {
26 namespace val {
27 namespace {
28
29 // Limit the number of checked locations to 4096. Multiplied by 4 to represent
30 // all the components. This limit is set to be well beyond practical use cases.
31 const uint32_t kMaxLocations = 4096 * 4;
32
33 // Returns true if \c inst is an input or output variable.
is_interface_variable(const Instruction * inst,bool is_spv_1_4)34 bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) {
35 if (is_spv_1_4) {
36 // Starting in SPIR-V 1.4, all global variables are interface variables.
37 return (inst->opcode() == spv::Op::OpVariable ||
38 inst->opcode() == spv::Op::OpUntypedVariableKHR) &&
39 inst->GetOperandAs<spv::StorageClass>(2u) !=
40 spv::StorageClass::Function;
41 } else {
42 return (inst->opcode() == spv::Op::OpVariable ||
43 inst->opcode() == spv::Op::OpUntypedVariableKHR) &&
44 (inst->GetOperandAs<spv::StorageClass>(2u) ==
45 spv::StorageClass::Input ||
46 inst->GetOperandAs<spv::StorageClass>(2u) ==
47 spv::StorageClass::Output);
48 }
49 }
50
51 // Special validation for varibles that are between shader stages
ValidateInputOutputInterfaceVariables(ValidationState_t & _,const Instruction * var)52 spv_result_t ValidateInputOutputInterfaceVariables(ValidationState_t& _,
53 const Instruction* var) {
54 auto var_pointer = _.FindDef(var->GetOperandAs<uint32_t>(0));
55 uint32_t pointer_id = var_pointer->GetOperandAs<uint32_t>(2);
56
57 const auto isPhysicalStorageBuffer = [](const Instruction* insn) {
58 return insn->opcode() == spv::Op::OpTypePointer &&
59 insn->GetOperandAs<spv::StorageClass>(1) ==
60 spv::StorageClass::PhysicalStorageBuffer;
61 };
62
63 if (_.ContainsType(pointer_id, isPhysicalStorageBuffer)) {
64 return _.diag(SPV_ERROR_INVALID_ID, var)
65 << _.VkErrorID(9557) << "Input/Output interface variable id <"
66 << var->id()
67 << "> contains a PhysicalStorageBuffer pointer, which is not "
68 "allowed. If you want to interface shader stages with a "
69 "PhysicalStorageBuffer, cast to a uint64 or uvec2 instead.";
70 }
71 return SPV_SUCCESS;
72 }
73
74 // Checks that \c var is listed as an interface in all the entry points that use
75 // it.
check_interface_variable(ValidationState_t & _,const Instruction * var)76 spv_result_t check_interface_variable(ValidationState_t& _,
77 const Instruction* var) {
78 std::vector<const Function*> functions;
79 std::vector<const Instruction*> uses;
80 for (auto use : var->uses()) {
81 uses.push_back(use.first);
82 }
83 for (uint32_t i = 0; i < uses.size(); ++i) {
84 const auto user = uses[i];
85 if (const Function* func = user->function()) {
86 functions.push_back(func);
87 } else {
88 // In the rare case that the variable is used by another instruction in
89 // the global scope, continue searching for an instruction used in a
90 // function.
91 for (auto use : user->uses()) {
92 uses.push_back(use.first);
93 }
94 }
95 }
96
97 std::sort(functions.begin(), functions.end(),
98 [](const Function* lhs, const Function* rhs) {
99 return lhs->id() < rhs->id();
100 });
101 functions.erase(std::unique(functions.begin(), functions.end()),
102 functions.end());
103
104 std::vector<uint32_t> entry_points;
105 for (const auto func : functions) {
106 for (auto id : _.FunctionEntryPoints(func->id())) {
107 entry_points.push_back(id);
108 }
109 }
110
111 std::sort(entry_points.begin(), entry_points.end());
112 entry_points.erase(std::unique(entry_points.begin(), entry_points.end()),
113 entry_points.end());
114
115 for (auto id : entry_points) {
116 for (const auto& desc : _.entry_point_descriptions(id)) {
117 bool found = false;
118 for (auto interface : desc.interfaces) {
119 if (var->id() == interface) {
120 found = true;
121 break;
122 }
123 }
124 if (!found) {
125 return _.diag(SPV_ERROR_INVALID_ID, var)
126 << "Interface variable id <" << var->id()
127 << "> is used by entry point '" << desc.name << "' id <" << id
128 << ">, but is not listed as an interface";
129 }
130 }
131 }
132
133 if (var->GetOperandAs<spv::StorageClass>(2) == spv::StorageClass::Input ||
134 var->GetOperandAs<spv::StorageClass>(2) == spv::StorageClass::Output) {
135 if (auto error = ValidateInputOutputInterfaceVariables(_, var))
136 return error;
137 }
138
139 return SPV_SUCCESS;
140 }
141
142 // This function assumes a base location has been determined already. As such
143 // any further location decorations are invalid.
144 // TODO: if this code turns out to be slow, there is an opportunity to cache
145 // the result for a given type id.
NumConsumedLocations(ValidationState_t & _,const Instruction * type,uint32_t * num_locations)146 spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type,
147 uint32_t* num_locations) {
148 *num_locations = 0;
149 switch (type->opcode()) {
150 case spv::Op::OpTypeInt:
151 case spv::Op::OpTypeFloat:
152 // Scalars always consume a single location.
153 *num_locations = 1;
154 break;
155 case spv::Op::OpTypeVector:
156 // 3- and 4-component 64-bit vectors consume two locations.
157 if ((_.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeInt, 64) ||
158 _.ContainsSizedIntOrFloatType(type->id(), spv::Op::OpTypeFloat,
159 64)) &&
160 (type->GetOperandAs<uint32_t>(2) > 2)) {
161 *num_locations = 2;
162 } else {
163 *num_locations = 1;
164 }
165 break;
166 case spv::Op::OpTypeMatrix:
167 // Matrices consume locations equivalent to arrays.
168 if (auto error = NumConsumedLocations(
169 _, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
170 return error;
171 }
172 *num_locations *= type->GetOperandAs<uint32_t>(2);
173 break;
174 case spv::Op::OpTypeArray: {
175 // Arrays consume locations equal to the underlying type times the number
176 // of elements in the vector.
177 if (auto error = NumConsumedLocations(
178 _, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
179 return error;
180 }
181 bool is_int = false;
182 bool is_const = false;
183 uint32_t value = 0;
184 // Attempt to evaluate the number of array elements.
185 std::tie(is_int, is_const, value) =
186 _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
187 if (is_int && is_const) *num_locations *= value;
188 break;
189 }
190 case spv::Op::OpTypeStruct: {
191 // Members cannot have location decorations at this point.
192 if (_.HasDecoration(type->id(), spv::Decoration::Location)) {
193 return _.diag(SPV_ERROR_INVALID_DATA, type)
194 << _.VkErrorID(4918) << "Members cannot be assigned a location";
195 }
196
197 // Structs consume locations equal to the sum of the locations consumed
198 // by the members.
199 for (uint32_t i = 1; i < type->operands().size(); ++i) {
200 uint32_t member_locations = 0;
201 if (auto error = NumConsumedLocations(
202 _, _.FindDef(type->GetOperandAs<uint32_t>(i)),
203 &member_locations)) {
204 return error;
205 }
206 *num_locations += member_locations;
207 }
208 break;
209 }
210 case spv::Op::OpTypePointer: {
211 if (_.addressing_model() ==
212 spv::AddressingModel::PhysicalStorageBuffer64 &&
213 type->GetOperandAs<spv::StorageClass>(1) ==
214 spv::StorageClass::PhysicalStorageBuffer) {
215 *num_locations = 1;
216 break;
217 }
218 [[fallthrough]];
219 }
220 default:
221 return _.diag(SPV_ERROR_INVALID_DATA, type)
222 << "Invalid type to assign a location";
223 }
224
225 return SPV_SUCCESS;
226 }
227
228 // Returns the number of components consumed by types that support a component
229 // decoration.
NumConsumedComponents(ValidationState_t & _,const Instruction * type)230 uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) {
231 uint32_t num_components = 0;
232 switch (type->opcode()) {
233 case spv::Op::OpTypeInt:
234 case spv::Op::OpTypeFloat:
235 // 64-bit types consume two components.
236 if (type->GetOperandAs<uint32_t>(1) == 64) {
237 num_components = 2;
238 } else {
239 num_components = 1;
240 }
241 break;
242 case spv::Op::OpTypeVector:
243 // Vectors consume components equal to the underlying type's consumption
244 // times the number of elements in the vector. Note that 3- and 4-element
245 // vectors cannot have a component decoration (i.e. assumed to be zero).
246 num_components =
247 NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
248 num_components *= type->GetOperandAs<uint32_t>(2);
249 break;
250 case spv::Op::OpTypeMatrix:
251 // Matrices consume all components of the location.
252 // Round up to next multiple of 4.
253 num_components =
254 NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
255 num_components *= type->GetOperandAs<uint32_t>(2);
256 num_components = ((num_components + 3) / 4) * 4;
257 break;
258 case spv::Op::OpTypeArray: {
259 // Arrays consume all components of the location.
260 // Round up to next multiple of 4.
261 num_components =
262 NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
263
264 bool is_int = false;
265 bool is_const = false;
266 uint32_t value = 0;
267 // Attempt to evaluate the number of array elements.
268 std::tie(is_int, is_const, value) =
269 _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
270 if (is_int && is_const) num_components *= value;
271
272 num_components = ((num_components + 3) / 4) * 4;
273 return num_components;
274 }
275 case spv::Op::OpTypePointer:
276 if (_.addressing_model() ==
277 spv::AddressingModel::PhysicalStorageBuffer64 &&
278 type->GetOperandAs<spv::StorageClass>(1) ==
279 spv::StorageClass::PhysicalStorageBuffer) {
280 return 2;
281 }
282 break;
283 default:
284 // This is an error that is validated elsewhere.
285 break;
286 }
287
288 return num_components;
289 }
290
291 // Populates |locations| (and/or |output_index1_locations|) with the use
292 // location and component coordinates for |variable|. Indices are calculated as
293 // 4 * location + component.
GetLocationsForVariable(ValidationState_t & _,const Instruction * entry_point,const Instruction * variable,std::unordered_set<uint32_t> * locations,std::unordered_set<uint32_t> * output_index1_locations)294 spv_result_t GetLocationsForVariable(
295 ValidationState_t& _, const Instruction* entry_point,
296 const Instruction* variable, std::unordered_set<uint32_t>* locations,
297 std::unordered_set<uint32_t>* output_index1_locations) {
298 const bool is_fragment = entry_point->GetOperandAs<spv::ExecutionModel>(0) ==
299 spv::ExecutionModel::Fragment;
300 const auto sc_index = 2u;
301 const bool is_output = variable->GetOperandAs<spv::StorageClass>(sc_index) ==
302 spv::StorageClass::Output;
303 auto ptr_type_id = variable->GetOperandAs<uint32_t>(0);
304 auto ptr_type = _.FindDef(ptr_type_id);
305 auto type_id = ptr_type->GetOperandAs<uint32_t>(2);
306 auto type = _.FindDef(type_id);
307
308 // Check for Location, Component and Index decorations on the variable. The
309 // validator allows duplicate decorations if the location/component/index are
310 // equal. Also track Patch and PerTaskNV decorations.
311 bool has_location = false;
312 uint32_t location = 0;
313 uint32_t component = 0;
314 bool has_index = false;
315 uint32_t index = 0;
316 bool has_patch = false;
317 bool has_per_task_nv = false;
318 bool has_per_vertex_khr = false;
319 // Duplicate Location, Component, Index are checked elsewhere.
320 for (auto& dec : _.id_decorations(variable->id())) {
321 if (dec.dec_type() == spv::Decoration::Location) {
322 has_location = true;
323 location = dec.params()[0];
324 } else if (dec.dec_type() == spv::Decoration::Component) {
325 component = dec.params()[0];
326 } else if (dec.dec_type() == spv::Decoration::Index) {
327 if (!is_output || !is_fragment) {
328 return _.diag(SPV_ERROR_INVALID_DATA, variable)
329 << "Index can only be applied to Fragment output variables";
330 }
331 has_index = true;
332 index = dec.params()[0];
333 } else if (dec.dec_type() == spv::Decoration::BuiltIn) {
334 // Don't check built-ins.
335 return SPV_SUCCESS;
336 } else if (dec.dec_type() == spv::Decoration::Patch) {
337 has_patch = true;
338 } else if (dec.dec_type() == spv::Decoration::PerTaskNV) {
339 has_per_task_nv = true;
340 } else if (dec.dec_type() == spv::Decoration::PerVertexKHR) {
341 if (!is_fragment) {
342 return _.diag(SPV_ERROR_INVALID_DATA, variable)
343 << _.VkErrorID(6777)
344 << "PerVertexKHR can only be applied to Fragment Execution "
345 "Models";
346 }
347 if (type->opcode() != spv::Op::OpTypeArray &&
348 type->opcode() != spv::Op::OpTypeRuntimeArray) {
349 return _.diag(SPV_ERROR_INVALID_DATA, variable)
350 << _.VkErrorID(6778)
351 << "PerVertexKHR must be declared as arrays";
352 }
353 has_per_vertex_khr = true;
354 }
355 }
356
357 // Vulkan 15.1.3 (Interface Matching): Tessellation control and mesh
358 // per-vertex outputs and tessellation control, evaluation and geometry
359 // per-vertex inputs have a layer of arraying that is not included in
360 // interface matching.
361 bool is_arrayed = false;
362 switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
363 case spv::ExecutionModel::TessellationControl:
364 if (!has_patch) {
365 is_arrayed = true;
366 }
367 break;
368 case spv::ExecutionModel::TessellationEvaluation:
369 if (!is_output && !has_patch) {
370 is_arrayed = true;
371 }
372 break;
373 case spv::ExecutionModel::Geometry:
374 if (!is_output) {
375 is_arrayed = true;
376 }
377 break;
378 case spv::ExecutionModel::Fragment:
379 if (!is_output && has_per_vertex_khr) {
380 is_arrayed = true;
381 }
382 break;
383 case spv::ExecutionModel::MeshNV:
384 if (is_output && !has_per_task_nv) {
385 is_arrayed = true;
386 }
387 break;
388 default:
389 break;
390 }
391
392 // Unpack arrayness.
393 if (is_arrayed && (type->opcode() == spv::Op::OpTypeArray ||
394 type->opcode() == spv::Op::OpTypeRuntimeArray)) {
395 type_id = type->GetOperandAs<uint32_t>(1);
396 type = _.FindDef(type_id);
397 }
398
399 if (type->opcode() == spv::Op::OpTypeStruct) {
400 // Don't check built-ins.
401 if (_.HasDecoration(type_id, spv::Decoration::BuiltIn)) return SPV_SUCCESS;
402 }
403
404 // Only block-decorated structs don't need a location on the variable.
405 const bool is_block = _.HasDecoration(type_id, spv::Decoration::Block);
406 if (!has_location && !is_block) {
407 const auto vuid = (type->opcode() == spv::Op::OpTypeStruct) ? 4917 : 4916;
408 return _.diag(SPV_ERROR_INVALID_DATA, variable)
409 << _.VkErrorID(vuid) << "Variable must be decorated with a location";
410 }
411
412 const std::string storage_class = is_output ? "output" : "input";
413 if (has_location) {
414 uint32_t num_locations = 0;
415 if (auto error = NumConsumedLocations(_, type, &num_locations))
416 return error;
417 uint32_t num_components = NumConsumedComponents(_, type);
418
419 uint32_t start = location * 4;
420 uint32_t end = (location + num_locations) * 4;
421 if (num_components % 4 != 0) {
422 start += component;
423 end = start + num_components;
424 }
425
426 if (kMaxLocations <= start) {
427 // Too many locations, give up.
428 return SPV_SUCCESS;
429 }
430
431 auto locs = locations;
432 if (has_index && index == 1) locs = output_index1_locations;
433
434 for (uint32_t i = start; i < end; ++i) {
435 if (!locs->insert(i).second) {
436 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
437 << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
438 << "Entry-point has conflicting " << storage_class
439 << " location assignment at location " << i / 4 << ", component "
440 << i % 4;
441 }
442 }
443 } else {
444 // For Block-decorated structs with no location assigned to the variable,
445 // each member of the block must be assigned a location. Also record any
446 // member component assignments. The validator allows duplicate decorations
447 // if they agree on the location/component.
448 std::unordered_map<uint32_t, uint32_t> member_locations;
449 std::unordered_map<uint32_t, uint32_t> member_components;
450 for (auto& dec : _.id_decorations(type_id)) {
451 if (dec.dec_type() == spv::Decoration::Location) {
452 auto where = member_locations.find(dec.struct_member_index());
453 if (where == member_locations.end()) {
454 member_locations[dec.struct_member_index()] = dec.params()[0];
455 } else if (where->second != dec.params()[0]) {
456 return _.diag(SPV_ERROR_INVALID_DATA, type)
457 << "Member index " << dec.struct_member_index()
458 << " has conflicting location assignments";
459 }
460 } else if (dec.dec_type() == spv::Decoration::Component) {
461 auto where = member_components.find(dec.struct_member_index());
462 if (where == member_components.end()) {
463 member_components[dec.struct_member_index()] = dec.params()[0];
464 } else if (where->second != dec.params()[0]) {
465 return _.diag(SPV_ERROR_INVALID_DATA, type)
466 << "Member index " << dec.struct_member_index()
467 << " has conflicting component assignments";
468 }
469 }
470 }
471
472 for (uint32_t i = 1; i < type->operands().size(); ++i) {
473 auto where = member_locations.find(i - 1);
474 if (where == member_locations.end()) {
475 return _.diag(SPV_ERROR_INVALID_DATA, type)
476 << _.VkErrorID(4919) << "Member index " << i - 1
477 << " is missing a location assignment";
478 }
479
480 location = where->second;
481 auto member = _.FindDef(type->GetOperandAs<uint32_t>(i));
482 uint32_t num_locations = 0;
483 if (auto error = NumConsumedLocations(_, member, &num_locations))
484 return error;
485
486 // If the component is not specified, it is assumed to be zero.
487 uint32_t num_components = NumConsumedComponents(_, member);
488 component = 0;
489 if (member_components.count(i - 1)) {
490 component = member_components[i - 1];
491 }
492
493 uint32_t start = location * 4;
494 if (kMaxLocations <= start) {
495 // Too many locations, give up.
496 continue;
497 }
498
499 uint32_t end = (location + num_locations) * 4;
500 if (num_components % 4 != 0) {
501 start += component;
502 end = location * 4 + component + num_components;
503 }
504
505 for (uint32_t l = start; l < end; ++l) {
506 if (!locations->insert(l).second) {
507 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
508 << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
509 << "Entry-point has conflicting " << storage_class
510 << " location assignment at location " << l / 4
511 << ", component " << l % 4;
512 }
513 }
514 }
515 }
516
517 return SPV_SUCCESS;
518 }
519
ValidateLocations(ValidationState_t & _,const Instruction * entry_point)520 spv_result_t ValidateLocations(ValidationState_t& _,
521 const Instruction* entry_point) {
522 // According to Vulkan 14.1 only the following execution models have
523 // locations assigned.
524 // TODO(dneto): SPV_NV_ray_tracing also uses locations on interface variables,
525 // in other shader stages. Similarly, the *provisional* version of
526 // SPV_KHR_ray_tracing did as well, but not the final version.
527 switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
528 case spv::ExecutionModel::Vertex:
529 case spv::ExecutionModel::TessellationControl:
530 case spv::ExecutionModel::TessellationEvaluation:
531 case spv::ExecutionModel::Geometry:
532 case spv::ExecutionModel::Fragment:
533 break;
534 default:
535 return SPV_SUCCESS;
536 }
537
538 // Locations are stored as a combined location and component values.
539 std::unordered_set<uint32_t> input_locations;
540 std::unordered_set<uint32_t> output_locations_index0;
541 std::unordered_set<uint32_t> output_locations_index1;
542 std::unordered_set<uint32_t> patch_locations_index0;
543 std::unordered_set<uint32_t> patch_locations_index1;
544 std::unordered_set<uint32_t> seen;
545 for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
546 auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
547 auto interface_var = _.FindDef(interface_id);
548 const auto sc_index = 2u;
549 auto storage_class =
550 interface_var->GetOperandAs<spv::StorageClass>(sc_index);
551 if (storage_class != spv::StorageClass::Input &&
552 storage_class != spv::StorageClass::Output) {
553 continue;
554 }
555 if (!seen.insert(interface_id).second) {
556 // Pre-1.4 an interface variable could be listed multiple times in an
557 // entry point. Validation for 1.4 or later is done elsewhere.
558 continue;
559 }
560
561 // The two Tessellation stages have a "Patch" variable that interface with
562 // the Location mechanism, but are not suppose to be tied to the "normal"
563 // input/output Location.
564 // TODO - SPIR-V allows the Patch decoration to be applied to struct
565 // members, but is not allowed in GLSL/HLSL
566 bool has_patch = false;
567 for (auto& dec : _.id_decorations(interface_var->id())) {
568 if (dec.dec_type() == spv::Decoration::Patch) {
569 has_patch = true;
570 if (auto error = GetLocationsForVariable(_, entry_point, interface_var,
571 &patch_locations_index0,
572 &patch_locations_index1))
573 return error;
574 break;
575 }
576 }
577 if (has_patch) {
578 continue;
579 }
580
581 auto locations = (storage_class == spv::StorageClass::Input)
582 ? &input_locations
583 : &output_locations_index0;
584 if (auto error = GetLocationsForVariable(
585 _, entry_point, interface_var, locations, &output_locations_index1))
586 return error;
587 }
588
589 return SPV_SUCCESS;
590 }
591
ValidateStorageClass(ValidationState_t & _,const Instruction * entry_point)592 spv_result_t ValidateStorageClass(ValidationState_t& _,
593 const Instruction* entry_point) {
594 bool has_push_constant = false;
595 bool has_ray_payload = false;
596 bool has_hit_attribute = false;
597 bool has_callable_data = false;
598 for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
599 auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
600 auto interface_var = _.FindDef(interface_id);
601 auto storage_class = interface_var->GetOperandAs<spv::StorageClass>(2);
602 switch (storage_class) {
603 case spv::StorageClass::PushConstant: {
604 if (has_push_constant) {
605 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
606 << _.VkErrorID(6673)
607 << "Entry-point has more than one variable with the "
608 "PushConstant storage class in the interface";
609 }
610 has_push_constant = true;
611 break;
612 }
613 case spv::StorageClass::IncomingRayPayloadKHR: {
614 if (has_ray_payload) {
615 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
616 << _.VkErrorID(4700)
617 << "Entry-point has more than one variable with the "
618 "IncomingRayPayloadKHR storage class in the interface";
619 }
620 has_ray_payload = true;
621 break;
622 }
623 case spv::StorageClass::HitAttributeKHR: {
624 if (has_hit_attribute) {
625 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
626 << _.VkErrorID(4702)
627 << "Entry-point has more than one variable with the "
628 "HitAttributeKHR storage class in the interface";
629 }
630 has_hit_attribute = true;
631 break;
632 }
633 case spv::StorageClass::IncomingCallableDataKHR: {
634 if (has_callable_data) {
635 return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
636 << _.VkErrorID(4706)
637 << "Entry-point has more than one variable with the "
638 "IncomingCallableDataKHR storage class in the interface";
639 }
640 has_callable_data = true;
641 break;
642 }
643 default:
644 break;
645 }
646 }
647 return SPV_SUCCESS;
648 }
649
650 } // namespace
651
ValidateInterfaces(ValidationState_t & _)652 spv_result_t ValidateInterfaces(ValidationState_t& _) {
653 bool is_spv_1_4 = _.version() >= SPV_SPIRV_VERSION_WORD(1, 4);
654 for (auto& inst : _.ordered_instructions()) {
655 if (is_interface_variable(&inst, is_spv_1_4)) {
656 if (auto error = check_interface_variable(_, &inst)) {
657 return error;
658 }
659 }
660 }
661
662 if (spvIsVulkanEnv(_.context()->target_env)) {
663 for (auto& inst : _.ordered_instructions()) {
664 if (inst.opcode() == spv::Op::OpEntryPoint) {
665 if (auto error = ValidateLocations(_, &inst)) {
666 return error;
667 }
668 if (auto error = ValidateStorageClass(_, &inst)) {
669 return error;
670 }
671 }
672 if (inst.opcode() == spv::Op::OpTypeVoid) break;
673 }
674 }
675
676 return SPV_SUCCESS;
677 }
678
679 } // namespace val
680 } // namespace spvtools
681