xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/val/validate_interfaces.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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