• 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 "source/opcode.h"
16 #include "source/spirv_target_env.h"
17 #include "source/val/instruction.h"
18 #include "source/val/validate.h"
19 #include "source/val/validation_state.h"
20 
21 namespace spvtools {
22 namespace val {
23 namespace {
24 
LogStringForDecoration(uint32_t decoration)25 std::string LogStringForDecoration(uint32_t decoration) {
26   switch (decoration) {
27     case SpvDecorationRelaxedPrecision:
28       return "RelaxedPrecision";
29     case SpvDecorationSpecId:
30       return "SpecId";
31     case SpvDecorationBlock:
32       return "Block";
33     case SpvDecorationBufferBlock:
34       return "BufferBlock";
35     case SpvDecorationRowMajor:
36       return "RowMajor";
37     case SpvDecorationColMajor:
38       return "ColMajor";
39     case SpvDecorationArrayStride:
40       return "ArrayStride";
41     case SpvDecorationMatrixStride:
42       return "MatrixStride";
43     case SpvDecorationGLSLShared:
44       return "GLSLShared";
45     case SpvDecorationGLSLPacked:
46       return "GLSLPacked";
47     case SpvDecorationCPacked:
48       return "CPacked";
49     case SpvDecorationBuiltIn:
50       return "BuiltIn";
51     case SpvDecorationNoPerspective:
52       return "NoPerspective";
53     case SpvDecorationFlat:
54       return "Flat";
55     case SpvDecorationPatch:
56       return "Patch";
57     case SpvDecorationCentroid:
58       return "Centroid";
59     case SpvDecorationSample:
60       return "Sample";
61     case SpvDecorationInvariant:
62       return "Invariant";
63     case SpvDecorationRestrict:
64       return "Restrict";
65     case SpvDecorationAliased:
66       return "Aliased";
67     case SpvDecorationVolatile:
68       return "Volatile";
69     case SpvDecorationConstant:
70       return "Constant";
71     case SpvDecorationCoherent:
72       return "Coherent";
73     case SpvDecorationNonWritable:
74       return "NonWritable";
75     case SpvDecorationNonReadable:
76       return "NonReadable";
77     case SpvDecorationUniform:
78       return "Uniform";
79     case SpvDecorationSaturatedConversion:
80       return "SaturatedConversion";
81     case SpvDecorationStream:
82       return "Stream";
83     case SpvDecorationLocation:
84       return "Location";
85     case SpvDecorationComponent:
86       return "Component";
87     case SpvDecorationIndex:
88       return "Index";
89     case SpvDecorationBinding:
90       return "Binding";
91     case SpvDecorationDescriptorSet:
92       return "DescriptorSet";
93     case SpvDecorationOffset:
94       return "Offset";
95     case SpvDecorationXfbBuffer:
96       return "XfbBuffer";
97     case SpvDecorationXfbStride:
98       return "XfbStride";
99     case SpvDecorationFuncParamAttr:
100       return "FuncParamAttr";
101     case SpvDecorationFPRoundingMode:
102       return "FPRoundingMode";
103     case SpvDecorationFPFastMathMode:
104       return "FPFastMathMode";
105     case SpvDecorationLinkageAttributes:
106       return "LinkageAttributes";
107     case SpvDecorationNoContraction:
108       return "NoContraction";
109     case SpvDecorationInputAttachmentIndex:
110       return "InputAttachmentIndex";
111     case SpvDecorationAlignment:
112       return "Alignment";
113     case SpvDecorationMaxByteOffset:
114       return "MaxByteOffset";
115     case SpvDecorationAlignmentId:
116       return "AlignmentId";
117     case SpvDecorationMaxByteOffsetId:
118       return "MaxByteOffsetId";
119     case SpvDecorationNoSignedWrap:
120       return "NoSignedWrap";
121     case SpvDecorationNoUnsignedWrap:
122       return "NoUnsignedWrap";
123     case SpvDecorationExplicitInterpAMD:
124       return "ExplicitInterpAMD";
125     case SpvDecorationOverrideCoverageNV:
126       return "OverrideCoverageNV";
127     case SpvDecorationPassthroughNV:
128       return "PassthroughNV";
129     case SpvDecorationViewportRelativeNV:
130       return "ViewportRelativeNV";
131     case SpvDecorationSecondaryViewportRelativeNV:
132       return "SecondaryViewportRelativeNV";
133     case SpvDecorationPerPrimitiveNV:
134       return "PerPrimitiveNV";
135     case SpvDecorationPerViewNV:
136       return "PerViewNV";
137     case SpvDecorationPerTaskNV:
138       return "PerTaskNV";
139     case SpvDecorationPerVertexNV:
140       return "PerVertexNV";
141     case SpvDecorationNonUniform:
142       return "NonUniform";
143     case SpvDecorationRestrictPointer:
144       return "RestrictPointer";
145     case SpvDecorationAliasedPointer:
146       return "AliasedPointer";
147     case SpvDecorationCounterBuffer:
148       return "CounterBuffer";
149     case SpvDecorationHlslSemanticGOOGLE:
150       return "HlslSemanticGOOGLE";
151     default:
152       break;
153   }
154   return "Unknown";
155 }
156 
157 // Returns true if the decoration takes ID parameters.
158 // TODO(dneto): This can be generated from the grammar.
DecorationTakesIdParameters(SpvDecoration type)159 bool DecorationTakesIdParameters(SpvDecoration type) {
160   switch (type) {
161     case SpvDecorationUniformId:
162     case SpvDecorationAlignmentId:
163     case SpvDecorationMaxByteOffsetId:
164     case SpvDecorationHlslCounterBufferGOOGLE:
165       return true;
166     default:
167       break;
168   }
169   return false;
170 }
171 
IsMemberDecorationOnly(SpvDecoration dec)172 bool IsMemberDecorationOnly(SpvDecoration dec) {
173   switch (dec) {
174     case SpvDecorationRowMajor:
175     case SpvDecorationColMajor:
176     case SpvDecorationMatrixStride:
177       // SPIR-V spec bug? Offset is generated on variables when dealing with
178       // transform feedback.
179       // case SpvDecorationOffset:
180       return true;
181     default:
182       break;
183   }
184   return false;
185 }
186 
IsNotMemberDecoration(SpvDecoration dec)187 bool IsNotMemberDecoration(SpvDecoration dec) {
188   switch (dec) {
189     case SpvDecorationSpecId:
190     case SpvDecorationBlock:
191     case SpvDecorationBufferBlock:
192     case SpvDecorationArrayStride:
193     case SpvDecorationGLSLShared:
194     case SpvDecorationGLSLPacked:
195     case SpvDecorationCPacked:
196     // TODO: https://github.com/KhronosGroup/glslang/issues/703:
197     // glslang applies Restrict to structure members.
198     // case SpvDecorationRestrict:
199     case SpvDecorationAliased:
200     case SpvDecorationConstant:
201     case SpvDecorationUniform:
202     case SpvDecorationUniformId:
203     case SpvDecorationSaturatedConversion:
204     case SpvDecorationIndex:
205     case SpvDecorationBinding:
206     case SpvDecorationDescriptorSet:
207     case SpvDecorationFuncParamAttr:
208     case SpvDecorationFPRoundingMode:
209     case SpvDecorationFPFastMathMode:
210     case SpvDecorationLinkageAttributes:
211     case SpvDecorationNoContraction:
212     case SpvDecorationInputAttachmentIndex:
213     case SpvDecorationAlignment:
214     case SpvDecorationMaxByteOffset:
215     case SpvDecorationAlignmentId:
216     case SpvDecorationMaxByteOffsetId:
217     case SpvDecorationNoSignedWrap:
218     case SpvDecorationNoUnsignedWrap:
219     case SpvDecorationNonUniform:
220     case SpvDecorationRestrictPointer:
221     case SpvDecorationAliasedPointer:
222     case SpvDecorationCounterBuffer:
223       return true;
224     default:
225       break;
226   }
227   return false;
228 }
229 
ValidateDecorationTarget(ValidationState_t & _,SpvDecoration dec,const Instruction * inst,const Instruction * target)230 spv_result_t ValidateDecorationTarget(ValidationState_t& _, SpvDecoration dec,
231                                       const Instruction* inst,
232                                       const Instruction* target) {
233   auto fail = [&_, dec, inst, target](uint32_t vuid) -> DiagnosticStream {
234     DiagnosticStream ds = std::move(
235         _.diag(SPV_ERROR_INVALID_ID, inst)
236         << _.VkErrorID(vuid) << LogStringForDecoration(dec)
237         << " decoration on target <id> '" << _.getIdName(target->id()) << "' ");
238     return ds;
239   };
240   switch (dec) {
241     case SpvDecorationSpecId:
242       if (!spvOpcodeIsScalarSpecConstant(target->opcode())) {
243         return fail(0) << "must be a scalar specialization constant";
244       }
245       break;
246     case SpvDecorationBlock:
247     case SpvDecorationBufferBlock:
248     case SpvDecorationGLSLShared:
249     case SpvDecorationGLSLPacked:
250     case SpvDecorationCPacked:
251       if (target->opcode() != SpvOpTypeStruct) {
252         return fail(0) << "must be a structure type";
253       }
254       break;
255     case SpvDecorationArrayStride:
256       if (target->opcode() != SpvOpTypeArray &&
257           target->opcode() != SpvOpTypeRuntimeArray &&
258           target->opcode() != SpvOpTypePointer) {
259         return fail(0) << "must be an array or pointer type";
260       }
261       break;
262     case SpvDecorationBuiltIn:
263       if (target->opcode() != SpvOpVariable &&
264           !spvOpcodeIsConstant(target->opcode())) {
265         return _.diag(SPV_ERROR_INVALID_DATA, inst)
266                << "BuiltIns can only target variables, structure members or "
267                   "constants";
268       }
269       if (_.HasCapability(SpvCapabilityShader) &&
270           inst->GetOperandAs<SpvBuiltIn>(2) == SpvBuiltInWorkgroupSize) {
271         if (!spvOpcodeIsConstant(target->opcode())) {
272           return fail(0) << "must be a constant for WorkgroupSize";
273         }
274       } else if (target->opcode() != SpvOpVariable) {
275         return fail(0) << "must be a variable";
276       }
277       break;
278     case SpvDecorationNoPerspective:
279     case SpvDecorationFlat:
280     case SpvDecorationPatch:
281     case SpvDecorationCentroid:
282     case SpvDecorationSample:
283     case SpvDecorationRestrict:
284     case SpvDecorationAliased:
285     case SpvDecorationVolatile:
286     case SpvDecorationCoherent:
287     case SpvDecorationNonWritable:
288     case SpvDecorationNonReadable:
289     case SpvDecorationXfbBuffer:
290     case SpvDecorationXfbStride:
291     case SpvDecorationComponent:
292     case SpvDecorationStream:
293     case SpvDecorationRestrictPointer:
294     case SpvDecorationAliasedPointer:
295       if (target->opcode() != SpvOpVariable &&
296           target->opcode() != SpvOpFunctionParameter) {
297         return fail(0) << "must be a memory object declaration";
298       }
299       if (_.GetIdOpcode(target->type_id()) != SpvOpTypePointer) {
300         return fail(0) << "must be a pointer type";
301       }
302       break;
303     case SpvDecorationInvariant:
304     case SpvDecorationConstant:
305     case SpvDecorationLocation:
306     case SpvDecorationIndex:
307     case SpvDecorationBinding:
308     case SpvDecorationDescriptorSet:
309     case SpvDecorationInputAttachmentIndex:
310       if (target->opcode() != SpvOpVariable) {
311         return fail(0) << "must be a variable";
312       }
313       break;
314     default:
315       break;
316   }
317 
318   if (spvIsVulkanEnv(_.context()->target_env)) {
319     // The following were all checked as pointer types above.
320     SpvStorageClass sc = SpvStorageClassUniform;
321     const auto type = _.FindDef(target->type_id());
322     if (type && type->operands().size() > 2) {
323       sc = type->GetOperandAs<SpvStorageClass>(1);
324     }
325     switch (dec) {
326       case SpvDecorationLocation:
327       case SpvDecorationComponent:
328         // Location is used for input, output and ray tracing stages.
329         if (sc != SpvStorageClassInput && sc != SpvStorageClassOutput &&
330             sc != SpvStorageClassRayPayloadKHR &&
331             sc != SpvStorageClassIncomingRayPayloadKHR &&
332             sc != SpvStorageClassHitAttributeKHR &&
333             sc != SpvStorageClassCallableDataKHR &&
334             sc != SpvStorageClassIncomingCallableDataKHR &&
335             sc != SpvStorageClassShaderRecordBufferKHR) {
336           return _.diag(SPV_ERROR_INVALID_ID, target)
337                  << _.VkErrorID(6672) << LogStringForDecoration(dec)
338                  << " decoration must not be applied to this storage class";
339         }
340         break;
341       case SpvDecorationIndex:
342         // Langauge from SPIR-V definition of Index
343         if (sc != SpvStorageClassOutput) {
344           return fail(0) << "must be in the Output storage class";
345         }
346         break;
347       case SpvDecorationBinding:
348       case SpvDecorationDescriptorSet:
349         if (sc != SpvStorageClassStorageBuffer &&
350             sc != SpvStorageClassUniform &&
351             sc != SpvStorageClassUniformConstant) {
352           return fail(6491) << "must be in the StorageBuffer, Uniform, or "
353                                "UniformConstant storage class";
354         }
355         break;
356       case SpvDecorationInputAttachmentIndex:
357         if (sc != SpvStorageClassUniformConstant) {
358           return fail(6678) << "must be in the UniformConstant storage class";
359         }
360         break;
361       case SpvDecorationFlat:
362       case SpvDecorationNoPerspective:
363       case SpvDecorationCentroid:
364       case SpvDecorationSample:
365         if (sc != SpvStorageClassInput && sc != SpvStorageClassOutput) {
366           return fail(4670) << "storage class must be Input or Output";
367         }
368         break;
369       default:
370         break;
371     }
372   }
373   return SPV_SUCCESS;
374 }
375 
ValidateDecorate(ValidationState_t & _,const Instruction * inst)376 spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
377   const auto decoration = inst->GetOperandAs<SpvDecoration>(1);
378   const auto target_id = inst->GetOperandAs<uint32_t>(0);
379   const auto target = _.FindDef(target_id);
380   if (!target) {
381     return _.diag(SPV_ERROR_INVALID_ID, inst) << "target is not defined";
382   }
383 
384   if (spvIsVulkanEnv(_.context()->target_env)) {
385     if ((decoration == SpvDecorationGLSLShared) ||
386         (decoration == SpvDecorationGLSLPacked)) {
387       return _.diag(SPV_ERROR_INVALID_ID, inst)
388              << _.VkErrorID(4669) << "OpDecorate decoration '"
389              << LogStringForDecoration(decoration)
390              << "' is not valid for the Vulkan execution environment.";
391     }
392   }
393 
394   if (DecorationTakesIdParameters(decoration)) {
395     return _.diag(SPV_ERROR_INVALID_ID, inst)
396            << "Decorations taking ID parameters may not be used with "
397               "OpDecorateId";
398   }
399 
400   if (target->opcode() != SpvOpDecorationGroup) {
401     if (IsMemberDecorationOnly(decoration)) {
402       return _.diag(SPV_ERROR_INVALID_ID, inst)
403              << LogStringForDecoration(decoration)
404              << " can only be applied to structure members";
405     }
406 
407     if (auto error = ValidateDecorationTarget(_, decoration, inst, target)) {
408       return error;
409     }
410   }
411 
412   // TODO: Add validations for all decorations.
413   return SPV_SUCCESS;
414 }
415 
ValidateDecorateId(ValidationState_t & _,const Instruction * inst)416 spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
417   const auto decoration = inst->GetOperandAs<SpvDecoration>(1);
418   if (!DecorationTakesIdParameters(decoration)) {
419     return _.diag(SPV_ERROR_INVALID_ID, inst)
420            << "Decorations that don't take ID parameters may not be used with "
421               "OpDecorateId";
422   }
423 
424   // No member decorations take id parameters, so we don't bother checking if
425   // we are using a member only decoration here.
426 
427   // TODO: Add validations for these decorations.
428   // UniformId is covered elsewhere.
429   return SPV_SUCCESS;
430 }
431 
ValidateMemberDecorate(ValidationState_t & _,const Instruction * inst)432 spv_result_t ValidateMemberDecorate(ValidationState_t& _,
433                                     const Instruction* inst) {
434   const auto struct_type_id = inst->GetOperandAs<uint32_t>(0);
435   const auto struct_type = _.FindDef(struct_type_id);
436   if (!struct_type || SpvOpTypeStruct != struct_type->opcode()) {
437     return _.diag(SPV_ERROR_INVALID_ID, inst)
438            << "OpMemberDecorate Structure type <id> '"
439            << _.getIdName(struct_type_id) << "' is not a struct type.";
440   }
441   const auto member = inst->GetOperandAs<uint32_t>(1);
442   const auto member_count =
443       static_cast<uint32_t>(struct_type->words().size() - 2);
444   if (member_count <= member) {
445     return _.diag(SPV_ERROR_INVALID_ID, inst)
446            << "Index " << member
447            << " provided in OpMemberDecorate for struct <id> "
448            << _.getIdName(struct_type_id)
449            << " is out of bounds. The structure has " << member_count
450            << " members. Largest valid index is " << member_count - 1 << ".";
451   }
452 
453   const auto decoration = inst->GetOperandAs<SpvDecoration>(2);
454   if (IsNotMemberDecoration(decoration)) {
455     return _.diag(SPV_ERROR_INVALID_ID, inst)
456            << LogStringForDecoration(decoration)
457            << " cannot be applied to structure members";
458   }
459 
460   return SPV_SUCCESS;
461 }
462 
ValidateDecorationGroup(ValidationState_t & _,const Instruction * inst)463 spv_result_t ValidateDecorationGroup(ValidationState_t& _,
464                                      const Instruction* inst) {
465   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
466   const auto decoration_group = _.FindDef(decoration_group_id);
467   for (auto pair : decoration_group->uses()) {
468     auto use = pair.first;
469     if (use->opcode() != SpvOpDecorate && use->opcode() != SpvOpGroupDecorate &&
470         use->opcode() != SpvOpGroupMemberDecorate &&
471         use->opcode() != SpvOpName && use->opcode() != SpvOpDecorateId &&
472         !use->IsNonSemantic()) {
473       return _.diag(SPV_ERROR_INVALID_ID, inst)
474              << "Result id of OpDecorationGroup can only "
475              << "be targeted by OpName, OpGroupDecorate, "
476              << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate";
477     }
478   }
479   return SPV_SUCCESS;
480 }
481 
ValidateGroupDecorate(ValidationState_t & _,const Instruction * inst)482 spv_result_t ValidateGroupDecorate(ValidationState_t& _,
483                                    const Instruction* inst) {
484   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
485   auto decoration_group = _.FindDef(decoration_group_id);
486   if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
487     return _.diag(SPV_ERROR_INVALID_ID, inst)
488            << "OpGroupDecorate Decoration group <id> '"
489            << _.getIdName(decoration_group_id)
490            << "' is not a decoration group.";
491   }
492   for (unsigned i = 1; i < inst->operands().size(); ++i) {
493     auto target_id = inst->GetOperandAs<uint32_t>(i);
494     auto target = _.FindDef(target_id);
495     if (!target || target->opcode() == SpvOpDecorationGroup) {
496       return _.diag(SPV_ERROR_INVALID_ID, inst)
497              << "OpGroupDecorate may not target OpDecorationGroup <id> '"
498              << _.getIdName(target_id) << "'";
499     }
500   }
501   return SPV_SUCCESS;
502 }
503 
ValidateGroupMemberDecorate(ValidationState_t & _,const Instruction * inst)504 spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
505                                          const Instruction* inst) {
506   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
507   const auto decoration_group = _.FindDef(decoration_group_id);
508   if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
509     return _.diag(SPV_ERROR_INVALID_ID, inst)
510            << "OpGroupMemberDecorate Decoration group <id> '"
511            << _.getIdName(decoration_group_id)
512            << "' is not a decoration group.";
513   }
514   // Grammar checks ensures that the number of arguments to this instruction
515   // is an odd number: 1 decoration group + (id,literal) pairs.
516   for (size_t i = 1; i + 1 < inst->operands().size(); i += 2) {
517     const uint32_t struct_id = inst->GetOperandAs<uint32_t>(i);
518     const uint32_t index = inst->GetOperandAs<uint32_t>(i + 1);
519     auto struct_instr = _.FindDef(struct_id);
520     if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) {
521       return _.diag(SPV_ERROR_INVALID_ID, inst)
522              << "OpGroupMemberDecorate Structure type <id> '"
523              << _.getIdName(struct_id) << "' is not a struct type.";
524     }
525     const uint32_t num_struct_members =
526         static_cast<uint32_t>(struct_instr->words().size() - 2);
527     if (index >= num_struct_members) {
528       return _.diag(SPV_ERROR_INVALID_ID, inst)
529              << "Index " << index
530              << " provided in OpGroupMemberDecorate for struct <id> "
531              << _.getIdName(struct_id)
532              << " is out of bounds. The structure has " << num_struct_members
533              << " members. Largest valid index is " << num_struct_members - 1
534              << ".";
535     }
536   }
537   return SPV_SUCCESS;
538 }
539 
540 // Registers necessary decoration(s) for the appropriate IDs based on the
541 // instruction.
RegisterDecorations(ValidationState_t & _,const Instruction * inst)542 spv_result_t RegisterDecorations(ValidationState_t& _,
543                                  const Instruction* inst) {
544   switch (inst->opcode()) {
545     case SpvOpDecorate:
546     case SpvOpDecorateId: {
547       const uint32_t target_id = inst->word(1);
548       const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(2));
549       std::vector<uint32_t> dec_params;
550       if (inst->words().size() > 3) {
551         dec_params.insert(dec_params.end(), inst->words().begin() + 3,
552                           inst->words().end());
553       }
554       _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params));
555       break;
556     }
557     case SpvOpMemberDecorate: {
558       const uint32_t struct_id = inst->word(1);
559       const uint32_t index = inst->word(2);
560       const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(3));
561       std::vector<uint32_t> dec_params;
562       if (inst->words().size() > 4) {
563         dec_params.insert(dec_params.end(), inst->words().begin() + 4,
564                           inst->words().end());
565       }
566       _.RegisterDecorationForId(struct_id,
567                                 Decoration(dec_type, dec_params, index));
568       break;
569     }
570     case SpvOpDecorationGroup: {
571       // We don't need to do anything right now. Assigning decorations to groups
572       // will be taken care of via OpGroupDecorate.
573       break;
574     }
575     case SpvOpGroupDecorate: {
576       // Word 1 is the group <id>. All subsequent words are target <id>s that
577       // are going to be decorated with the decorations.
578       const uint32_t decoration_group_id = inst->word(1);
579       std::vector<Decoration>& group_decorations =
580           _.id_decorations(decoration_group_id);
581       for (size_t i = 2; i < inst->words().size(); ++i) {
582         const uint32_t target_id = inst->word(i);
583         _.RegisterDecorationsForId(target_id, group_decorations.begin(),
584                                    group_decorations.end());
585       }
586       break;
587     }
588     case SpvOpGroupMemberDecorate: {
589       // Word 1 is the Decoration Group <id> followed by (struct<id>,literal)
590       // pairs. All decorations of the group should be applied to all the struct
591       // members that are specified in the instructions.
592       const uint32_t decoration_group_id = inst->word(1);
593       std::vector<Decoration>& group_decorations =
594           _.id_decorations(decoration_group_id);
595       // Grammar checks ensures that the number of arguments to this instruction
596       // is an odd number: 1 decoration group + (id,literal) pairs.
597       for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) {
598         const uint32_t struct_id = inst->word(i);
599         const uint32_t index = inst->word(i + 1);
600         // ID validation phase ensures this is in fact a struct instruction and
601         // that the index is not out of bound.
602         _.RegisterDecorationsForStructMember(struct_id, index,
603                                              group_decorations.begin(),
604                                              group_decorations.end());
605       }
606       break;
607     }
608     default:
609       break;
610   }
611   return SPV_SUCCESS;
612 }
613 
614 }  // namespace
615 
AnnotationPass(ValidationState_t & _,const Instruction * inst)616 spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) {
617   switch (inst->opcode()) {
618     case SpvOpDecorate:
619       if (auto error = ValidateDecorate(_, inst)) return error;
620       break;
621     case SpvOpDecorateId:
622       if (auto error = ValidateDecorateId(_, inst)) return error;
623       break;
624     // TODO(dneto): SpvOpDecorateStringGOOGLE
625     // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253
626     case SpvOpMemberDecorate:
627       if (auto error = ValidateMemberDecorate(_, inst)) return error;
628       break;
629     case SpvOpDecorationGroup:
630       if (auto error = ValidateDecorationGroup(_, inst)) return error;
631       break;
632     case SpvOpGroupDecorate:
633       if (auto error = ValidateGroupDecorate(_, inst)) return error;
634       break;
635     case SpvOpGroupMemberDecorate:
636       if (auto error = ValidateGroupMemberDecorate(_, inst)) return error;
637       break;
638     default:
639       break;
640   }
641 
642   // In order to validate decoration rules, we need to know all the decorations
643   // that are applied to any given <id>.
644   RegisterDecorations(_, inst);
645 
646   return SPV_SUCCESS;
647 }
648 
649 }  // namespace val
650 }  // namespace spvtools
651