• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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