• 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 == SpvStorageClassStorageBuffer ||
330             sc == SpvStorageClassUniform ||
331             sc == SpvStorageClassUniformConstant ||
332             sc == SpvStorageClassWorkgroup || sc == SpvStorageClassPrivate ||
333             sc == SpvStorageClassFunction) {
334           return _.diag(SPV_ERROR_INVALID_ID, target)
335                  << LogStringForDecoration(dec)
336                  << " decoration must not be applied to this storage class";
337         }
338         break;
339       case SpvDecorationIndex:
340         if (sc != SpvStorageClassOutput) {
341           return fail(0) << "must be in the Output storage class";
342         }
343         break;
344       case SpvDecorationBinding:
345       case SpvDecorationDescriptorSet:
346         if (sc != SpvStorageClassStorageBuffer &&
347             sc != SpvStorageClassUniform &&
348             sc != SpvStorageClassUniformConstant) {
349           return fail(0) << "must be in the StorageBuffer, Uniform, or "
350                             "UniformConstant storage class";
351         }
352         break;
353       case SpvDecorationInputAttachmentIndex:
354         if (sc != SpvStorageClassUniformConstant) {
355           return fail(0) << "must be in the UniformConstant storage class";
356         }
357         break;
358       case SpvDecorationFlat:
359       case SpvDecorationNoPerspective:
360       case SpvDecorationCentroid:
361       case SpvDecorationSample:
362         if (sc != SpvStorageClassInput && sc != SpvStorageClassOutput) {
363           return fail(4670) << "storage class must be Input or Output";
364         }
365         break;
366       default:
367         break;
368     }
369   }
370   return SPV_SUCCESS;
371 }
372 
ValidateDecorate(ValidationState_t & _,const Instruction * inst)373 spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
374   const auto decoration = inst->GetOperandAs<SpvDecoration>(1);
375   const auto target_id = inst->GetOperandAs<uint32_t>(0);
376   const auto target = _.FindDef(target_id);
377   if (!target) {
378     return _.diag(SPV_ERROR_INVALID_ID, inst) << "target is not defined";
379   }
380 
381   if (spvIsVulkanEnv(_.context()->target_env)) {
382     if ((decoration == SpvDecorationGLSLShared) ||
383         (decoration == SpvDecorationGLSLPacked)) {
384       return _.diag(SPV_ERROR_INVALID_ID, inst)
385              << _.VkErrorID(4669) << "OpDecorate decoration '"
386              << LogStringForDecoration(decoration)
387              << "' is not valid for the Vulkan execution environment.";
388     }
389   }
390 
391   if (DecorationTakesIdParameters(decoration)) {
392     return _.diag(SPV_ERROR_INVALID_ID, inst)
393            << "Decorations taking ID parameters may not be used with "
394               "OpDecorateId";
395   }
396 
397   if (target->opcode() != SpvOpDecorationGroup) {
398     if (IsMemberDecorationOnly(decoration)) {
399       return _.diag(SPV_ERROR_INVALID_ID, inst)
400              << LogStringForDecoration(decoration)
401              << " can only be applied to structure members";
402     }
403 
404     if (auto error = ValidateDecorationTarget(_, decoration, inst, target)) {
405       return error;
406     }
407   }
408 
409   // TODO: Add validations for all decorations.
410   return SPV_SUCCESS;
411 }
412 
ValidateDecorateId(ValidationState_t & _,const Instruction * inst)413 spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
414   const auto decoration = inst->GetOperandAs<SpvDecoration>(1);
415   if (!DecorationTakesIdParameters(decoration)) {
416     return _.diag(SPV_ERROR_INVALID_ID, inst)
417            << "Decorations that don't take ID parameters may not be used with "
418               "OpDecorateId";
419   }
420 
421   // No member decorations take id parameters, so we don't bother checking if
422   // we are using a member only decoration here.
423 
424   // TODO: Add validations for these decorations.
425   // UniformId is covered elsewhere.
426   return SPV_SUCCESS;
427 }
428 
ValidateMemberDecorate(ValidationState_t & _,const Instruction * inst)429 spv_result_t ValidateMemberDecorate(ValidationState_t& _,
430                                     const Instruction* inst) {
431   const auto struct_type_id = inst->GetOperandAs<uint32_t>(0);
432   const auto struct_type = _.FindDef(struct_type_id);
433   if (!struct_type || SpvOpTypeStruct != struct_type->opcode()) {
434     return _.diag(SPV_ERROR_INVALID_ID, inst)
435            << "OpMemberDecorate Structure type <id> '"
436            << _.getIdName(struct_type_id) << "' is not a struct type.";
437   }
438   const auto member = inst->GetOperandAs<uint32_t>(1);
439   const auto member_count =
440       static_cast<uint32_t>(struct_type->words().size() - 2);
441   if (member_count <= member) {
442     return _.diag(SPV_ERROR_INVALID_ID, inst)
443            << "Index " << member
444            << " provided in OpMemberDecorate for struct <id> "
445            << _.getIdName(struct_type_id)
446            << " is out of bounds. The structure has " << member_count
447            << " members. Largest valid index is " << member_count - 1 << ".";
448   }
449 
450   const auto decoration = inst->GetOperandAs<SpvDecoration>(2);
451   if (IsNotMemberDecoration(decoration)) {
452     return _.diag(SPV_ERROR_INVALID_ID, inst)
453            << LogStringForDecoration(decoration)
454            << " cannot be applied to structure members";
455   }
456 
457   return SPV_SUCCESS;
458 }
459 
ValidateDecorationGroup(ValidationState_t & _,const Instruction * inst)460 spv_result_t ValidateDecorationGroup(ValidationState_t& _,
461                                      const Instruction* inst) {
462   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
463   const auto decoration_group = _.FindDef(decoration_group_id);
464   for (auto pair : decoration_group->uses()) {
465     auto use = pair.first;
466     if (use->opcode() != SpvOpDecorate && use->opcode() != SpvOpGroupDecorate &&
467         use->opcode() != SpvOpGroupMemberDecorate &&
468         use->opcode() != SpvOpName && use->opcode() != SpvOpDecorateId &&
469         !use->IsNonSemantic()) {
470       return _.diag(SPV_ERROR_INVALID_ID, inst)
471              << "Result id of OpDecorationGroup can only "
472              << "be targeted by OpName, OpGroupDecorate, "
473              << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate";
474     }
475   }
476   return SPV_SUCCESS;
477 }
478 
ValidateGroupDecorate(ValidationState_t & _,const Instruction * inst)479 spv_result_t ValidateGroupDecorate(ValidationState_t& _,
480                                    const Instruction* inst) {
481   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
482   auto decoration_group = _.FindDef(decoration_group_id);
483   if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
484     return _.diag(SPV_ERROR_INVALID_ID, inst)
485            << "OpGroupDecorate Decoration group <id> '"
486            << _.getIdName(decoration_group_id)
487            << "' is not a decoration group.";
488   }
489   for (unsigned i = 1; i < inst->operands().size(); ++i) {
490     auto target_id = inst->GetOperandAs<uint32_t>(i);
491     auto target = _.FindDef(target_id);
492     if (!target || target->opcode() == SpvOpDecorationGroup) {
493       return _.diag(SPV_ERROR_INVALID_ID, inst)
494              << "OpGroupDecorate may not target OpDecorationGroup <id> '"
495              << _.getIdName(target_id) << "'";
496     }
497   }
498   return SPV_SUCCESS;
499 }
500 
ValidateGroupMemberDecorate(ValidationState_t & _,const Instruction * inst)501 spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
502                                          const Instruction* inst) {
503   const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
504   const auto decoration_group = _.FindDef(decoration_group_id);
505   if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) {
506     return _.diag(SPV_ERROR_INVALID_ID, inst)
507            << "OpGroupMemberDecorate Decoration group <id> '"
508            << _.getIdName(decoration_group_id)
509            << "' is not a decoration group.";
510   }
511   // Grammar checks ensures that the number of arguments to this instruction
512   // is an odd number: 1 decoration group + (id,literal) pairs.
513   for (size_t i = 1; i + 1 < inst->operands().size(); i += 2) {
514     const uint32_t struct_id = inst->GetOperandAs<uint32_t>(i);
515     const uint32_t index = inst->GetOperandAs<uint32_t>(i + 1);
516     auto struct_instr = _.FindDef(struct_id);
517     if (!struct_instr || SpvOpTypeStruct != struct_instr->opcode()) {
518       return _.diag(SPV_ERROR_INVALID_ID, inst)
519              << "OpGroupMemberDecorate Structure type <id> '"
520              << _.getIdName(struct_id) << "' is not a struct type.";
521     }
522     const uint32_t num_struct_members =
523         static_cast<uint32_t>(struct_instr->words().size() - 2);
524     if (index >= num_struct_members) {
525       return _.diag(SPV_ERROR_INVALID_ID, inst)
526              << "Index " << index
527              << " provided in OpGroupMemberDecorate for struct <id> "
528              << _.getIdName(struct_id)
529              << " is out of bounds. The structure has " << num_struct_members
530              << " members. Largest valid index is " << num_struct_members - 1
531              << ".";
532     }
533   }
534   return SPV_SUCCESS;
535 }
536 
537 // Registers necessary decoration(s) for the appropriate IDs based on the
538 // instruction.
RegisterDecorations(ValidationState_t & _,const Instruction * inst)539 spv_result_t RegisterDecorations(ValidationState_t& _,
540                                  const Instruction* inst) {
541   switch (inst->opcode()) {
542     case SpvOpDecorate:
543     case SpvOpDecorateId: {
544       const uint32_t target_id = inst->word(1);
545       const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(2));
546       std::vector<uint32_t> dec_params;
547       if (inst->words().size() > 3) {
548         dec_params.insert(dec_params.end(), inst->words().begin() + 3,
549                           inst->words().end());
550       }
551       _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params));
552       break;
553     }
554     case SpvOpMemberDecorate: {
555       const uint32_t struct_id = inst->word(1);
556       const uint32_t index = inst->word(2);
557       const SpvDecoration dec_type = static_cast<SpvDecoration>(inst->word(3));
558       std::vector<uint32_t> dec_params;
559       if (inst->words().size() > 4) {
560         dec_params.insert(dec_params.end(), inst->words().begin() + 4,
561                           inst->words().end());
562       }
563       _.RegisterDecorationForId(struct_id,
564                                 Decoration(dec_type, dec_params, index));
565       break;
566     }
567     case SpvOpDecorationGroup: {
568       // We don't need to do anything right now. Assigning decorations to groups
569       // will be taken care of via OpGroupDecorate.
570       break;
571     }
572     case SpvOpGroupDecorate: {
573       // Word 1 is the group <id>. All subsequent words are target <id>s that
574       // are going to be decorated with the decorations.
575       const uint32_t decoration_group_id = inst->word(1);
576       std::vector<Decoration>& group_decorations =
577           _.id_decorations(decoration_group_id);
578       for (size_t i = 2; i < inst->words().size(); ++i) {
579         const uint32_t target_id = inst->word(i);
580         _.RegisterDecorationsForId(target_id, group_decorations.begin(),
581                                    group_decorations.end());
582       }
583       break;
584     }
585     case SpvOpGroupMemberDecorate: {
586       // Word 1 is the Decoration Group <id> followed by (struct<id>,literal)
587       // pairs. All decorations of the group should be applied to all the struct
588       // members that are specified in the instructions.
589       const uint32_t decoration_group_id = inst->word(1);
590       std::vector<Decoration>& group_decorations =
591           _.id_decorations(decoration_group_id);
592       // Grammar checks ensures that the number of arguments to this instruction
593       // is an odd number: 1 decoration group + (id,literal) pairs.
594       for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) {
595         const uint32_t struct_id = inst->word(i);
596         const uint32_t index = inst->word(i + 1);
597         // ID validation phase ensures this is in fact a struct instruction and
598         // that the index is not out of bound.
599         _.RegisterDecorationsForStructMember(struct_id, index,
600                                              group_decorations.begin(),
601                                              group_decorations.end());
602       }
603       break;
604     }
605     default:
606       break;
607   }
608   return SPV_SUCCESS;
609 }
610 
611 }  // namespace
612 
AnnotationPass(ValidationState_t & _,const Instruction * inst)613 spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) {
614   switch (inst->opcode()) {
615     case SpvOpDecorate:
616       if (auto error = ValidateDecorate(_, inst)) return error;
617       break;
618     case SpvOpDecorateId:
619       if (auto error = ValidateDecorateId(_, inst)) return error;
620       break;
621     // TODO(dneto): SpvOpDecorateStringGOOGLE
622     // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253
623     case SpvOpMemberDecorate:
624       if (auto error = ValidateMemberDecorate(_, inst)) return error;
625       break;
626     case SpvOpDecorationGroup:
627       if (auto error = ValidateDecorationGroup(_, inst)) return error;
628       break;
629     case SpvOpGroupDecorate:
630       if (auto error = ValidateGroupDecorate(_, inst)) return error;
631       break;
632     case SpvOpGroupMemberDecorate:
633       if (auto error = ValidateGroupMemberDecorate(_, inst)) return error;
634       break;
635     default:
636       break;
637   }
638 
639   // In order to validate decoration rules, we need to know all the decorations
640   // that are applied to any given <id>.
641   RegisterDecorations(_, inst);
642 
643   return SPV_SUCCESS;
644 }
645 
646 }  // namespace val
647 }  // namespace spvtools
648