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