Coverage Report

Created: 2025-07-23 06:18

/src/spirv-tools/source/val/validate_annotation.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2018 Google LLC.
2
// Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights
3
// reserved.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
//     http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
17
#include "source/opcode.h"
18
#include "source/spirv_target_env.h"
19
#include "source/val/instruction.h"
20
#include "source/val/validate.h"
21
#include "source/val/validation_state.h"
22
23
namespace spvtools {
24
namespace val {
25
namespace {
26
27
// Returns true if the decoration takes ID parameters.
28
// TODO(dneto): This can be generated from the grammar.
29
1.41M
bool DecorationTakesIdParameters(spv::Decoration type) {
30
1.41M
  switch (type) {
31
0
    case spv::Decoration::UniformId:
32
0
    case spv::Decoration::AlignmentId:
33
0
    case spv::Decoration::MaxByteOffsetId:
34
0
    case spv::Decoration::HlslCounterBufferGOOGLE:
35
0
    case spv::Decoration::NodeMaxPayloadsAMDX:
36
0
    case spv::Decoration::NodeSharesPayloadLimitsWithAMDX:
37
0
    case spv::Decoration::PayloadNodeArraySizeAMDX:
38
0
    case spv::Decoration::PayloadNodeNameAMDX:
39
0
    case spv::Decoration::PayloadNodeBaseIndexAMDX:
40
0
      return true;
41
1.41M
    default:
42
1.41M
      break;
43
1.41M
  }
44
1.41M
  return false;
45
1.41M
}
46
47
273k
bool IsMemberDecorationOnly(spv::Decoration dec) {
48
273k
  switch (dec) {
49
2
    case spv::Decoration::RowMajor:
50
6
    case spv::Decoration::ColMajor:
51
7
    case spv::Decoration::MatrixStride:
52
      // SPIR-V spec bug? Offset is generated on variables when dealing with
53
      // transform feedback.
54
      // case spv::Decoration::Offset:
55
7
      return true;
56
273k
    default:
57
273k
      break;
58
273k
  }
59
273k
  return false;
60
273k
}
61
62
6.94k
bool IsNotMemberDecoration(spv::Decoration dec) {
63
6.94k
  switch (dec) {
64
3
    case spv::Decoration::SpecId:
65
6
    case spv::Decoration::Block:
66
9
    case spv::Decoration::BufferBlock:
67
12
    case spv::Decoration::ArrayStride:
68
15
    case spv::Decoration::GLSLShared:
69
18
    case spv::Decoration::GLSLPacked:
70
18
    case spv::Decoration::CPacked:
71
    // TODO: https://github.com/KhronosGroup/glslang/issues/703:
72
    // glslang applies Restrict to structure members.
73
    // case spv::Decoration::Restrict:
74
21
    case spv::Decoration::Aliased:
75
21
    case spv::Decoration::Constant:
76
24
    case spv::Decoration::Uniform:
77
24
    case spv::Decoration::UniformId:
78
24
    case spv::Decoration::SaturatedConversion:
79
27
    case spv::Decoration::Index:
80
30
    case spv::Decoration::Binding:
81
34
    case spv::Decoration::DescriptorSet:
82
35
    case spv::Decoration::FuncParamAttr:
83
38
    case spv::Decoration::FPRoundingMode:
84
39
    case spv::Decoration::FPFastMathMode:
85
39
    case spv::Decoration::LinkageAttributes:
86
42
    case spv::Decoration::NoContraction:
87
44
    case spv::Decoration::InputAttachmentIndex:
88
45
    case spv::Decoration::Alignment:
89
45
    case spv::Decoration::MaxByteOffset:
90
45
    case spv::Decoration::AlignmentId:
91
45
    case spv::Decoration::MaxByteOffsetId:
92
45
    case spv::Decoration::NoSignedWrap:
93
45
    case spv::Decoration::NoUnsignedWrap:
94
45
    case spv::Decoration::NonUniform:
95
45
    case spv::Decoration::RestrictPointer:
96
45
    case spv::Decoration::AliasedPointer:
97
45
    case spv::Decoration::CounterBuffer:
98
45
      return true;
99
6.90k
    default:
100
6.90k
      break;
101
6.94k
  }
102
6.90k
  return false;
103
6.94k
}
104
105
spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
106
                                      const Instruction* inst,
107
273k
                                      const Instruction* target) {
108
273k
  auto fail = [&_, dec, inst, target](uint32_t vuid) -> DiagnosticStream {
109
106
    DiagnosticStream ds = std::move(
110
106
        _.diag(SPV_ERROR_INVALID_ID, inst)
111
106
        << _.VkErrorID(vuid) << _.SpvDecorationString(dec)
112
106
        << " decoration on target <id> " << _.getIdName(target->id()) << " ");
113
106
    return ds;
114
106
  };
115
273k
  switch (dec) {
116
32
    case spv::Decoration::SpecId:
117
32
      if (!spvOpcodeIsScalarSpecConstant(target->opcode())) {
118
6
        return fail(0) << "must be a scalar specialization constant";
119
6
      }
120
26
      break;
121
3.40k
    case spv::Decoration::Block:
122
3.94k
    case spv::Decoration::BufferBlock:
123
4.16k
    case spv::Decoration::GLSLShared:
124
4.76k
    case spv::Decoration::GLSLPacked:
125
4.84k
    case spv::Decoration::CPacked:
126
4.84k
      if (target->opcode() != spv::Op::OpTypeStruct) {
127
7
        return fail(0) << "must be a structure type";
128
7
      }
129
4.83k
      break;
130
4.83k
    case spv::Decoration::ArrayStride:
131
1.21k
      if (target->opcode() != spv::Op::OpTypeArray &&
132
1.21k
          target->opcode() != spv::Op::OpTypeRuntimeArray &&
133
1.21k
          target->opcode() != spv::Op::OpTypePointer &&
134
1.21k
          target->opcode() != spv::Op::OpTypeUntypedPointerKHR) {
135
13
        return fail(0) << "must be an array or pointer type";
136
13
      }
137
1.19k
      break;
138
3.47k
    case spv::Decoration::BuiltIn:
139
3.47k
      if (target->opcode() != spv::Op::OpVariable &&
140
3.47k
          target->opcode() != spv::Op::OpUntypedVariableKHR &&
141
3.47k
          !spvOpcodeIsConstant(target->opcode())) {
142
3
        return _.diag(SPV_ERROR_INVALID_DATA, inst)
143
3
               << "BuiltIns can only target variables, structure members or "
144
3
                  "constants";
145
3
      }
146
3.47k
      if (_.HasCapability(spv::Capability::Shader) &&
147
3.47k
          inst->GetOperandAs<spv::BuiltIn>(2) == spv::BuiltIn::WorkgroupSize) {
148
222
        if (!spvOpcodeIsConstant(target->opcode())) {
149
3
          return fail(0) << "must be a constant for WorkgroupSize";
150
3
        }
151
3.25k
      } else if (target->opcode() != spv::Op::OpVariable &&
152
3.25k
                 target->opcode() != spv::Op::OpUntypedVariableKHR) {
153
7
        return fail(0) << "must be a variable";
154
7
      }
155
3.46k
      break;
156
3.46k
    case spv::Decoration::NoPerspective:
157
34.7k
    case spv::Decoration::Flat:
158
34.8k
    case spv::Decoration::Patch:
159
38.9k
    case spv::Decoration::Centroid:
160
39.1k
    case spv::Decoration::Sample:
161
53.8k
    case spv::Decoration::Restrict:
162
137k
    case spv::Decoration::Aliased:
163
143k
    case spv::Decoration::Volatile:
164
144k
    case spv::Decoration::Coherent:
165
145k
    case spv::Decoration::NonWritable:
166
145k
    case spv::Decoration::NonReadable:
167
145k
    case spv::Decoration::XfbBuffer:
168
145k
    case spv::Decoration::XfbStride:
169
146k
    case spv::Decoration::Component:
170
146k
    case spv::Decoration::Stream:
171
146k
    case spv::Decoration::RestrictPointer:
172
146k
    case spv::Decoration::AliasedPointer:
173
146k
    case spv::Decoration::PerPrimitiveEXT:
174
146k
      if (target->opcode() != spv::Op::OpVariable &&
175
146k
          target->opcode() != spv::Op::OpUntypedVariableKHR &&
176
146k
          target->opcode() != spv::Op::OpFunctionParameter &&
177
146k
          target->opcode() != spv::Op::OpRawAccessChainNV) {
178
39
        return fail(0) << "must be a memory object declaration";
179
39
      }
180
146k
      if (!_.IsPointerType(target->type_id())) {
181
3
        return fail(0) << "must be a pointer type";
182
3
      }
183
146k
      break;
184
146k
    case spv::Decoration::Invariant:
185
1.51k
    case spv::Decoration::Constant:
186
7.54k
    case spv::Decoration::Location:
187
10.6k
    case spv::Decoration::Index:
188
15.5k
    case spv::Decoration::Binding:
189
19.2k
    case spv::Decoration::DescriptorSet:
190
19.2k
    case spv::Decoration::InputAttachmentIndex:
191
19.2k
      if (target->opcode() != spv::Op::OpVariable &&
192
19.2k
          target->opcode() != spv::Op::OpUntypedVariableKHR) {
193
28
        return fail(0) << "must be a variable";
194
28
      }
195
19.2k
      break;
196
98.3k
    default:
197
98.3k
      break;
198
273k
  }
199
200
273k
  if (spvIsVulkanEnv(_.context()->target_env)) {
201
    // The following were all checked as pointer types above.
202
0
    spv::StorageClass sc = spv::StorageClass::Uniform;
203
0
    const auto type = _.FindDef(target->type_id());
204
0
    if (type && type->operands().size() > 2) {
205
0
      sc = type->GetOperandAs<spv::StorageClass>(1);
206
0
    }
207
0
    switch (dec) {
208
0
      case spv::Decoration::Location:
209
0
      case spv::Decoration::Component:
210
        // Location is used for input, output, tile image, and ray tracing
211
        // stages.
212
0
        if (sc != spv::StorageClass::Input && sc != spv::StorageClass::Output &&
213
0
            sc != spv::StorageClass::RayPayloadKHR &&
214
0
            sc != spv::StorageClass::IncomingRayPayloadKHR &&
215
0
            sc != spv::StorageClass::HitAttributeKHR &&
216
0
            sc != spv::StorageClass::CallableDataKHR &&
217
0
            sc != spv::StorageClass::IncomingCallableDataKHR &&
218
0
            sc != spv::StorageClass::ShaderRecordBufferKHR &&
219
0
            sc != spv::StorageClass::HitObjectAttributeNV &&
220
0
            sc != spv::StorageClass::TileImageEXT) {
221
0
          return _.diag(SPV_ERROR_INVALID_ID, target)
222
0
                 << _.VkErrorID(6672) << _.SpvDecorationString(dec)
223
0
                 << " decoration must not be applied to this storage class";
224
0
        }
225
0
        break;
226
0
      case spv::Decoration::Index:
227
        // Langauge from SPIR-V definition of Index
228
0
        if (sc != spv::StorageClass::Output) {
229
0
          return fail(0) << "must be in the Output storage class";
230
0
        }
231
0
        break;
232
0
      case spv::Decoration::Binding:
233
0
      case spv::Decoration::DescriptorSet:
234
0
        if (sc != spv::StorageClass::StorageBuffer &&
235
0
            sc != spv::StorageClass::Uniform &&
236
0
            sc != spv::StorageClass::UniformConstant &&
237
0
            sc != spv::StorageClass::TileAttachmentQCOM) {
238
0
          return fail(6491) << "must be in the StorageBuffer, Uniform, or "
239
0
                               "UniformConstant storage class";
240
0
        }
241
0
        break;
242
0
      case spv::Decoration::InputAttachmentIndex:
243
0
        if (sc != spv::StorageClass::UniformConstant) {
244
0
          return fail(6678) << "must be in the UniformConstant storage class";
245
0
        }
246
0
        break;
247
0
      case spv::Decoration::Flat:
248
0
      case spv::Decoration::NoPerspective:
249
0
      case spv::Decoration::Centroid:
250
0
      case spv::Decoration::Sample:
251
0
        if (sc != spv::StorageClass::Input && sc != spv::StorageClass::Output) {
252
0
          return fail(4670) << "storage class must be Input or Output";
253
0
        }
254
0
        break;
255
0
      case spv::Decoration::PerVertexKHR:
256
0
        if (sc != spv::StorageClass::Input) {
257
0
          return fail(6777) << "storage class must be Input";
258
0
        }
259
0
        break;
260
0
      default:
261
0
        break;
262
0
    }
263
0
  }
264
273k
  return SPV_SUCCESS;
265
273k
}
266
267
1.41M
spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) {
268
1.41M
  const auto decoration = inst->GetOperandAs<spv::Decoration>(1);
269
1.41M
  const auto target_id = inst->GetOperandAs<uint32_t>(0);
270
1.41M
  const auto target = _.FindDef(target_id);
271
1.41M
  if (!target) {
272
0
    return _.diag(SPV_ERROR_INVALID_ID, inst) << "target is not defined";
273
0
  }
274
275
1.41M
  if (spvIsVulkanEnv(_.context()->target_env)) {
276
0
    if ((decoration == spv::Decoration::GLSLShared) ||
277
0
        (decoration == spv::Decoration::GLSLPacked)) {
278
0
      return _.diag(SPV_ERROR_INVALID_ID, inst)
279
0
             << _.VkErrorID(4669) << "OpDecorate decoration '"
280
0
             << _.SpvDecorationString(decoration)
281
0
             << "' is not valid for the Vulkan execution environment.";
282
0
    }
283
0
  }
284
285
1.41M
  if (decoration == spv::Decoration::FPFastMathMode) {
286
2.35k
    if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) {
287
0
      return _.diag(SPV_ERROR_INVALID_ID, inst)
288
0
             << "FPFastMathMode and NoContraction cannot decorate the same "
289
0
                "target";
290
0
    }
291
2.35k
    auto mask = inst->GetOperandAs<spv::FPFastMathModeMask>(2);
292
2.35k
    if ((mask & spv::FPFastMathModeMask::AllowTransform) !=
293
2.35k
            spv::FPFastMathModeMask::MaskNone &&
294
2.35k
        ((mask & (spv::FPFastMathModeMask::AllowContract |
295
0
                  spv::FPFastMathModeMask::AllowReassoc)) !=
296
0
         (spv::FPFastMathModeMask::AllowContract |
297
0
          spv::FPFastMathModeMask::AllowReassoc))) {
298
0
      return _.diag(SPV_ERROR_INVALID_DATA, inst)
299
0
             << "AllowReassoc and AllowContract must be specified when "
300
0
                "AllowTransform is specified";
301
0
    }
302
2.35k
  }
303
304
  // This is checked from both sides since we register decorations as we go.
305
1.41M
  if (decoration == spv::Decoration::NoContraction) {
306
97.3k
    if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) {
307
0
      return _.diag(SPV_ERROR_INVALID_ID, inst)
308
0
             << "FPFastMathMode and NoContraction cannot decorate the same "
309
0
                "target";
310
0
    }
311
97.3k
  }
312
313
1.41M
  if (DecorationTakesIdParameters(decoration)) {
314
0
    return _.diag(SPV_ERROR_INVALID_ID, inst)
315
0
           << "Decorations taking ID parameters may not be used with "
316
0
              "OpDecorateId";
317
0
  }
318
319
1.41M
  if (target->opcode() != spv::Op::OpDecorationGroup) {
320
273k
    if (IsMemberDecorationOnly(decoration)) {
321
7
      return _.diag(SPV_ERROR_INVALID_ID, inst)
322
7
             << _.SpvDecorationString(decoration)
323
7
             << " can only be applied to structure members";
324
7
    }
325
326
273k
    if (auto error = ValidateDecorationTarget(_, decoration, inst, target)) {
327
109
      return error;
328
109
    }
329
273k
  }
330
331
  // TODO: Add validations for all decorations.
332
1.41M
  return SPV_SUCCESS;
333
1.41M
}
334
335
0
spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) {
336
0
  const auto decoration = inst->GetOperandAs<spv::Decoration>(1);
337
0
  if (!DecorationTakesIdParameters(decoration)) {
338
0
    return _.diag(SPV_ERROR_INVALID_ID, inst)
339
0
           << "Decorations that don't take ID parameters may not be used with "
340
0
              "OpDecorateId";
341
0
  }
342
343
  // No member decorations take id parameters, so we don't bother checking if
344
  // we are using a member only decoration here.
345
346
  // TODO: Add validations for these decorations.
347
  // UniformId is covered elsewhere.
348
0
  return SPV_SUCCESS;
349
0
}
350
351
spv_result_t ValidateMemberDecorate(ValidationState_t& _,
352
7.03k
                                    const Instruction* inst) {
353
7.03k
  const auto struct_type_id = inst->GetOperandAs<uint32_t>(0);
354
7.03k
  const auto struct_type = _.FindDef(struct_type_id);
355
7.03k
  if (!struct_type || spv::Op::OpTypeStruct != struct_type->opcode()) {
356
14
    return _.diag(SPV_ERROR_INVALID_ID, inst)
357
14
           << "OpMemberDecorate Structure type <id> "
358
14
           << _.getIdName(struct_type_id) << " is not a struct type.";
359
14
  }
360
7.01k
  const auto member = inst->GetOperandAs<uint32_t>(1);
361
7.01k
  const auto member_count =
362
7.01k
      static_cast<uint32_t>(struct_type->words().size() - 2);
363
7.01k
  if (member_count <= member) {
364
71
    return _.diag(SPV_ERROR_INVALID_ID, inst)
365
71
           << "Index " << member
366
71
           << " provided in OpMemberDecorate for struct <id> "
367
71
           << _.getIdName(struct_type_id)
368
71
           << " is out of bounds. The structure has " << member_count
369
71
           << " members. Largest valid index is " << member_count - 1 << ".";
370
71
  }
371
372
6.94k
  const auto decoration = inst->GetOperandAs<spv::Decoration>(2);
373
6.94k
  if (IsNotMemberDecoration(decoration)) {
374
45
    return _.diag(SPV_ERROR_INVALID_ID, inst)
375
45
           << _.SpvDecorationString(decoration)
376
45
           << " cannot be applied to structure members";
377
45
  }
378
379
6.90k
  return SPV_SUCCESS;
380
6.94k
}
381
382
spv_result_t ValidateDecorationGroup(ValidationState_t& _,
383
5.06k
                                     const Instruction* inst) {
384
5.06k
  const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
385
5.06k
  const auto decoration_group = _.FindDef(decoration_group_id);
386
7.88M
  for (auto pair : decoration_group->uses()) {
387
7.88M
    auto use = pair.first;
388
7.88M
    if (use->opcode() != spv::Op::OpDecorate &&
389
7.88M
        use->opcode() != spv::Op::OpGroupDecorate &&
390
7.88M
        use->opcode() != spv::Op::OpGroupMemberDecorate &&
391
7.88M
        use->opcode() != spv::Op::OpName &&
392
7.88M
        use->opcode() != spv::Op::OpDecorateId && !use->IsNonSemantic()) {
393
9
      return _.diag(SPV_ERROR_INVALID_ID, inst)
394
9
             << "Result id of OpDecorationGroup can only "
395
9
             << "be targeted by OpName, OpGroupDecorate, "
396
9
             << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate";
397
9
    }
398
7.88M
  }
399
5.06k
  return SPV_SUCCESS;
400
5.06k
}
401
402
spv_result_t ValidateGroupDecorate(ValidationState_t& _,
403
5.60M
                                   const Instruction* inst) {
404
5.60M
  const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
405
5.60M
  auto decoration_group = _.FindDef(decoration_group_id);
406
5.60M
  if (!decoration_group ||
407
5.60M
      spv::Op::OpDecorationGroup != decoration_group->opcode()) {
408
3
    return _.diag(SPV_ERROR_INVALID_ID, inst)
409
3
           << "OpGroupDecorate Decoration group <id> "
410
3
           << _.getIdName(decoration_group_id) << " is not a decoration group.";
411
3
  }
412
5.61M
  for (unsigned i = 1; i < inst->operands().size(); ++i) {
413
12.9k
    auto target_id = inst->GetOperandAs<uint32_t>(i);
414
12.9k
    auto target = _.FindDef(target_id);
415
12.9k
    if (!target || target->opcode() == spv::Op::OpDecorationGroup) {
416
12
      return _.diag(SPV_ERROR_INVALID_ID, inst)
417
12
             << "OpGroupDecorate may not target OpDecorationGroup <id> "
418
12
             << _.getIdName(target_id);
419
12
    }
420
12.9k
  }
421
5.60M
  return SPV_SUCCESS;
422
5.60M
}
423
424
spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _,
425
1.14M
                                         const Instruction* inst) {
426
1.14M
  const auto decoration_group_id = inst->GetOperandAs<uint32_t>(0);
427
1.14M
  const auto decoration_group = _.FindDef(decoration_group_id);
428
1.14M
  if (!decoration_group ||
429
1.14M
      spv::Op::OpDecorationGroup != decoration_group->opcode()) {
430
3
    return _.diag(SPV_ERROR_INVALID_ID, inst)
431
3
           << "OpGroupMemberDecorate Decoration group <id> "
432
3
           << _.getIdName(decoration_group_id) << " is not a decoration group.";
433
3
  }
434
  // Grammar checks ensures that the number of arguments to this instruction
435
  // is an odd number: 1 decoration group + (id,literal) pairs.
436
1.14M
  for (size_t i = 1; i + 1 < inst->operands().size(); i += 2) {
437
2.79k
    const uint32_t struct_id = inst->GetOperandAs<uint32_t>(i);
438
2.79k
    const uint32_t index = inst->GetOperandAs<uint32_t>(i + 1);
439
2.79k
    auto struct_instr = _.FindDef(struct_id);
440
2.79k
    if (!struct_instr || spv::Op::OpTypeStruct != struct_instr->opcode()) {
441
11
      return _.diag(SPV_ERROR_INVALID_ID, inst)
442
11
             << "OpGroupMemberDecorate Structure type <id> "
443
11
             << _.getIdName(struct_id) << " is not a struct type.";
444
11
    }
445
2.77k
    const uint32_t num_struct_members =
446
2.77k
        static_cast<uint32_t>(struct_instr->words().size() - 2);
447
2.77k
    if (index >= num_struct_members) {
448
47
      return _.diag(SPV_ERROR_INVALID_ID, inst)
449
47
             << "Index " << index
450
47
             << " provided in OpGroupMemberDecorate for struct <id> "
451
47
             << _.getIdName(struct_id)
452
47
             << " is out of bounds. The structure has " << num_struct_members
453
47
             << " members. Largest valid index is " << num_struct_members - 1
454
47
             << ".";
455
47
    }
456
2.77k
  }
457
1.14M
  return SPV_SUCCESS;
458
1.14M
}
459
460
// Registers necessary decoration(s) for the appropriate IDs based on the
461
// instruction.
462
spv_result_t RegisterDecorations(ValidationState_t& _,
463
11.0M
                                 const Instruction* inst) {
464
11.0M
  switch (inst->opcode()) {
465
1.41M
    case spv::Op::OpDecorate:
466
1.41M
    case spv::Op::OpDecorateId: {
467
1.41M
      const uint32_t target_id = inst->word(1);
468
1.41M
      const spv::Decoration dec_type =
469
1.41M
          static_cast<spv::Decoration>(inst->word(2));
470
1.41M
      std::vector<uint32_t> dec_params;
471
1.41M
      if (inst->words().size() > 3) {
472
902k
        dec_params.insert(dec_params.end(), inst->words().begin() + 3,
473
902k
                          inst->words().end());
474
902k
      }
475
1.41M
      _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params));
476
1.41M
      break;
477
1.41M
    }
478
6.90k
    case spv::Op::OpMemberDecorate: {
479
6.90k
      const uint32_t struct_id = inst->word(1);
480
6.90k
      const uint32_t index = inst->word(2);
481
6.90k
      const spv::Decoration dec_type =
482
6.90k
          static_cast<spv::Decoration>(inst->word(3));
483
6.90k
      std::vector<uint32_t> dec_params;
484
6.90k
      if (inst->words().size() > 4) {
485
4.72k
        dec_params.insert(dec_params.end(), inst->words().begin() + 4,
486
4.72k
                          inst->words().end());
487
4.72k
      }
488
6.90k
      _.RegisterDecorationForId(struct_id,
489
6.90k
                                Decoration(dec_type, dec_params, index));
490
6.90k
      break;
491
1.41M
    }
492
5.06k
    case spv::Op::OpDecorationGroup: {
493
      // We don't need to do anything right now. Assigning decorations to groups
494
      // will be taken care of via OpGroupDecorate.
495
5.06k
      break;
496
1.41M
    }
497
5.60M
    case spv::Op::OpGroupDecorate: {
498
      // Word 1 is the group <id>. All subsequent words are target <id>s that
499
      // are going to be decorated with the decorations.
500
5.60M
      const uint32_t decoration_group_id = inst->word(1);
501
5.60M
      std::set<Decoration>& group_decorations =
502
5.60M
          _.id_decorations(decoration_group_id);
503
5.61M
      for (size_t i = 2; i < inst->words().size(); ++i) {
504
12.9k
        const uint32_t target_id = inst->word(i);
505
12.9k
        _.RegisterDecorationsForId(target_id, group_decorations.begin(),
506
12.9k
                                   group_decorations.end());
507
12.9k
      }
508
5.60M
      break;
509
1.41M
    }
510
1.14M
    case spv::Op::OpGroupMemberDecorate: {
511
      // Word 1 is the Decoration Group <id> followed by (struct<id>,literal)
512
      // pairs. All decorations of the group should be applied to all the struct
513
      // members that are specified in the instructions.
514
1.14M
      const uint32_t decoration_group_id = inst->word(1);
515
1.14M
      std::set<Decoration>& group_decorations =
516
1.14M
          _.id_decorations(decoration_group_id);
517
      // Grammar checks ensures that the number of arguments to this instruction
518
      // is an odd number: 1 decoration group + (id,literal) pairs.
519
1.14M
      for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) {
520
2.72k
        const uint32_t struct_id = inst->word(i);
521
2.72k
        const uint32_t index = inst->word(i + 1);
522
        // ID validation phase ensures this is in fact a struct instruction and
523
        // that the index is not out of bound.
524
2.72k
        _.RegisterDecorationsForStructMember(struct_id, index,
525
2.72k
                                             group_decorations.begin(),
526
2.72k
                                             group_decorations.end());
527
2.72k
      }
528
1.14M
      break;
529
1.41M
    }
530
2.83M
    default:
531
2.83M
      break;
532
11.0M
  }
533
11.0M
  return SPV_SUCCESS;
534
11.0M
}
535
536
}  // namespace
537
538
11.0M
spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) {
539
11.0M
  switch (inst->opcode()) {
540
1.41M
    case spv::Op::OpDecorate:
541
1.41M
      if (auto error = ValidateDecorate(_, inst)) return error;
542
1.41M
      break;
543
1.41M
    case spv::Op::OpDecorateId:
544
0
      if (auto error = ValidateDecorateId(_, inst)) return error;
545
0
      break;
546
    // TODO(dneto): spv::Op::OpDecorateStringGOOGLE
547
    // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253
548
7.03k
    case spv::Op::OpMemberDecorate:
549
7.03k
      if (auto error = ValidateMemberDecorate(_, inst)) return error;
550
6.90k
      break;
551
6.90k
    case spv::Op::OpDecorationGroup:
552
5.06k
      if (auto error = ValidateDecorationGroup(_, inst)) return error;
553
5.06k
      break;
554
5.60M
    case spv::Op::OpGroupDecorate:
555
5.60M
      if (auto error = ValidateGroupDecorate(_, inst)) return error;
556
5.60M
      break;
557
5.60M
    case spv::Op::OpGroupMemberDecorate:
558
1.14M
      if (auto error = ValidateGroupMemberDecorate(_, inst)) return error;
559
1.14M
      break;
560
2.83M
    default:
561
2.83M
      break;
562
11.0M
  }
563
564
  // In order to validate decoration rules, we need to know all the decorations
565
  // that are applied to any given <id>.
566
11.0M
  RegisterDecorations(_, inst);
567
568
11.0M
  return SPV_SUCCESS;
569
11.0M
}
570
571
}  // namespace val
572
}  // namespace spvtools