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