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