Coverage Report

Created: 2026-09-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/val/validate_builtins.cpp
Line
Count
Source
1
// Copyright (c) 2018 Google LLC.
2
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3
// reserved.
4
// Copyright (C) 2026 Qualcomm Technologies, Inc.
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
//     http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17
18
// Validates correctness of built-in variables.
19
20
#include <array>
21
#include <cstdint>
22
#include <functional>
23
#include <list>
24
#include <map>
25
#include <set>
26
#include <sstream>
27
#include <string>
28
#include <unordered_map>
29
#include <vector>
30
31
#include "source/opcode.h"
32
#include "source/spirv_target_env.h"
33
#include "source/val/instruction.h"
34
#include "source/val/validate.h"
35
#include "source/val/validation_state.h"
36
#include "spirv/unified1/spirv.hpp11"
37
38
namespace spvtools {
39
namespace val {
40
namespace {
41
42
// Returns a short textual description of the id defined by the given
43
// instruction.
44
0
std::string GetIdDesc(const Instruction& inst) {
45
0
  std::ostringstream ss;
46
0
  ss << "ID <" << inst.id() << "> (Op" << spvOpcodeString(inst.opcode()) << ")";
47
0
  return ss.str();
48
0
}
49
50
// Gets underlying data type which is
51
// - member type if instruction is OpTypeStruct
52
//   (member index is taken from decoration).
53
// - data type if id creates a pointer.
54
// - type of the constant if instruction is OpConst or OpSpecConst.
55
//
56
// Fails in any other case. The function is based on built-ins allowed by
57
// the Vulkan spec.
58
// TODO: If non-Vulkan validation rules are added then it might need
59
// to be refactored.
60
spv_result_t GetUnderlyingType(ValidationState_t& _,
61
                               const Decoration& decoration,
62
                               const Instruction& inst,
63
0
                               uint32_t* underlying_type) {
64
0
  if (decoration.struct_member_index() != Decoration::kInvalidMember) {
65
0
    if (inst.opcode() != spv::Op::OpTypeStruct) {
66
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
67
0
             << GetIdDesc(inst)
68
0
             << "Attempted to get underlying data type via member index for "
69
0
                "non-struct type.";
70
0
    }
71
0
    *underlying_type = inst.word(decoration.struct_member_index() + 2);
72
0
    return SPV_SUCCESS;
73
0
  }
74
75
0
  if (inst.opcode() == spv::Op::OpTypeStruct) {
76
0
    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
77
0
           << GetIdDesc(inst)
78
0
           << " did not find an member index to get underlying data type for "
79
0
              "struct type.";
80
0
  }
81
82
0
  if (spvOpcodeIsConstant(inst.opcode())) {
83
0
    *underlying_type = inst.type_id();
84
0
    return SPV_SUCCESS;
85
0
  }
86
87
0
  spv::StorageClass storage_class;
88
0
  if (!_.GetPointerTypeInfo(inst.type_id(), underlying_type, &storage_class)) {
89
0
    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
90
0
           << GetIdDesc(inst)
91
0
           << " is decorated with BuiltIn. BuiltIn decoration should only be "
92
0
              "applied to struct types, variables and constants.";
93
0
  }
94
0
  return SPV_SUCCESS;
95
0
}
96
97
// Returns Storage Class used by the instruction if applicable.
98
// Returns spv::StorageClass::Max if not.
99
0
spv::StorageClass GetStorageClass(const Instruction& inst) {
100
0
  switch (inst.opcode()) {
101
0
    case spv::Op::OpTypePointer:
102
0
    case spv::Op::OpTypeUntypedPointerKHR:
103
0
    case spv::Op::OpTypeForwardPointer: {
104
0
      return spv::StorageClass(inst.word(2));
105
0
    }
106
0
    case spv::Op::OpVariable: {
107
0
      return spv::StorageClass(inst.word(3));
108
0
    }
109
0
    case spv::Op::OpUntypedVariableKHR: {
110
0
      return spv::StorageClass(inst.word(4));
111
0
    }
112
0
    case spv::Op::OpGenericCastToPtrExplicit: {
113
0
      return spv::StorageClass(inst.word(4));
114
0
    }
115
0
    default: { break; }
116
0
  }
117
0
  return spv::StorageClass::Max;
118
0
}
119
120
typedef enum VUIDError_ {
121
  VUIDErrorExecutionModel = 0,
122
  VUIDErrorStorageClass = 1,
123
  VUIDErrorType = 2,
124
  VUIDErrorMax,
125
} VUIDError;
126
127
const static uint32_t NumVUIDBuiltins = 45;
128
129
typedef struct {
130
  spv::BuiltIn builtIn;
131
  uint32_t vuid[VUIDErrorMax];  // execution mode, storage class, type VUIDs
132
} BuiltinVUIDMapping;
133
134
// Many built-ins have the same checks (Storage Class, Type, etc)
135
// This table provides a nice LUT for the VUIDs
136
std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
137
    // clang-format off
138
    {spv::BuiltIn::SubgroupEqMask,            {0,    4370, 4371}},
139
    {spv::BuiltIn::SubgroupGeMask,            {0,    4372, 4373}},
140
    {spv::BuiltIn::SubgroupGtMask,            {0,    4374, 4375}},
141
    {spv::BuiltIn::SubgroupLeMask,            {0,    4376, 4377}},
142
    {spv::BuiltIn::SubgroupLtMask,            {0,    4378, 4379}},
143
    {spv::BuiltIn::SubgroupLocalInvocationId, {0,    4380, 4381}},
144
    {spv::BuiltIn::SubgroupSize,              {0,    4382, 4383}},
145
    {spv::BuiltIn::GlobalInvocationId,        {4236, 4237, 4238}},
146
    {spv::BuiltIn::LocalInvocationId,         {4281, 4282, 4283}},
147
    {spv::BuiltIn::NumWorkgroups,             {4296, 4297, 4298}},
148
    {spv::BuiltIn::NumSubgroups,              {4293, 4294, 4295}},
149
    {spv::BuiltIn::SubgroupId,                {4367, 4368, 4369}},
150
    {spv::BuiltIn::WorkgroupId,               {4422, 4423, 4424}},
151
    {spv::BuiltIn::HitKindKHR,                {4242, 4243, 4244}},
152
    {spv::BuiltIn::HitTNV,                    {4245, 4246, 4247}},
153
    {spv::BuiltIn::InstanceCustomIndexKHR,    {4251, 4252, 4253}},
154
    {spv::BuiltIn::InstanceId,                {4254, 4255, 4256}},
155
    {spv::BuiltIn::RayGeometryIndexKHR,       {4345, 4346, 4347}},
156
    {spv::BuiltIn::ObjectRayDirectionKHR,     {4299, 4300, 4301}},
157
    {spv::BuiltIn::ObjectRayOriginKHR,        {4302, 4303, 4304}},
158
    {spv::BuiltIn::ObjectToWorldKHR,          {4305, 4306, 4307}},
159
    {spv::BuiltIn::WorldToObjectKHR,          {4434, 4435, 4436}},
160
    {spv::BuiltIn::IncomingRayFlagsKHR,       {4248, 4249, 4250}},
161
    {spv::BuiltIn::RayTminKHR,                {4351, 4352, 4353}},
162
    {spv::BuiltIn::RayTmaxKHR,                {4348, 4349, 4350}},
163
    {spv::BuiltIn::WorldRayDirectionKHR,      {4428, 4429, 4430}},
164
    {spv::BuiltIn::WorldRayOriginKHR,         {4431, 4432, 4433}},
165
    {spv::BuiltIn::LaunchIdKHR,               {4266, 4267, 4268}},
166
    {spv::BuiltIn::LaunchSizeKHR,             {4269, 4270, 4271}},
167
    {spv::BuiltIn::FragInvocationCountEXT,    {4217, 4218, 4219}},
168
    {spv::BuiltIn::FragSizeEXT,               {4220, 4221, 4222}},
169
    {spv::BuiltIn::FragStencilRefEXT,         {4223, 4224, 4225}},
170
    {spv::BuiltIn::FullyCoveredEXT,           {4232, 4233, 4234}},
171
    {spv::BuiltIn::CullMaskKHR,               {6735, 6736, 6737}},
172
    {spv::BuiltIn::BaryCoordKHR,              {4154, 4155, 4156}},
173
    {spv::BuiltIn::BaryCoordNoPerspKHR,       {4160, 4161, 4162}},
174
    {spv::BuiltIn::LocalInvocationIndex,      {4284, 4285, 4286}},
175
    {spv::BuiltIn::PrimitivePointIndicesEXT,  {7041, 7043, 7044}},
176
    {spv::BuiltIn::PrimitiveLineIndicesEXT,   {7047, 7049, 7050}},
177
    {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}},
178
    {spv::BuiltIn::CullPrimitiveEXT,          {7034, 7035, 7036}},
179
    {spv::BuiltIn::HitTriangleVertexPositionsKHR, {8747, 8748, 8749}},
180
    {spv::BuiltIn::TileOffsetQCOM,    {10626, 10627, 10628}},
181
    {spv::BuiltIn::TileDimensionQCOM, {10629, 10630, 10631}},
182
    {spv::BuiltIn::TileApronSizeQCOM, {10632, 10633, 10634}},
183
    // clang-format on
184
}};
185
186
0
uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
187
0
  uint32_t vuid = 0;
188
0
  for (const auto& iter: builtinVUIDInfo) {
189
0
    if (iter.builtIn == builtIn) {
190
0
      assert(type < VUIDErrorMax);
191
0
      vuid = iter.vuid[type];
192
0
      break;
193
0
    }
194
0
  }
195
0
  return vuid;
196
0
}
197
198
bool IsExecutionModelValidForRtBuiltIn(spv::BuiltIn builtin,
199
0
                                       spv::ExecutionModel stage) {
200
0
  switch (builtin) {
201
0
    case spv::BuiltIn::HitKindKHR:
202
0
    case spv::BuiltIn::HitTNV:
203
0
    case spv::BuiltIn::HitTriangleVertexPositionsKHR:
204
0
      if (stage == spv::ExecutionModel::AnyHitKHR ||
205
0
          stage == spv::ExecutionModel::ClosestHitKHR) {
206
0
        return true;
207
0
      }
208
0
      break;
209
0
    case spv::BuiltIn::InstanceCustomIndexKHR:
210
0
    case spv::BuiltIn::InstanceId:
211
0
    case spv::BuiltIn::RayGeometryIndexKHR:
212
0
    case spv::BuiltIn::ObjectRayDirectionKHR:
213
0
    case spv::BuiltIn::ObjectRayOriginKHR:
214
0
    case spv::BuiltIn::ObjectToWorldKHR:
215
0
    case spv::BuiltIn::WorldToObjectKHR:
216
0
      switch (stage) {
217
0
        case spv::ExecutionModel::IntersectionKHR:
218
0
        case spv::ExecutionModel::AnyHitKHR:
219
0
        case spv::ExecutionModel::ClosestHitKHR:
220
0
          return true;
221
0
        default:
222
0
          return false;
223
0
      }
224
0
      break;
225
0
    case spv::BuiltIn::IncomingRayFlagsKHR:
226
0
    case spv::BuiltIn::RayTminKHR:
227
0
    case spv::BuiltIn::RayTmaxKHR:
228
0
    case spv::BuiltIn::WorldRayDirectionKHR:
229
0
    case spv::BuiltIn::WorldRayOriginKHR:
230
0
    case spv::BuiltIn::CullMaskKHR:
231
0
      switch (stage) {
232
0
        case spv::ExecutionModel::IntersectionKHR:
233
0
        case spv::ExecutionModel::AnyHitKHR:
234
0
        case spv::ExecutionModel::ClosestHitKHR:
235
0
        case spv::ExecutionModel::MissKHR:
236
0
          return true;
237
0
        default:
238
0
          return false;
239
0
      }
240
0
      break;
241
0
    case spv::BuiltIn::LaunchIdKHR:
242
0
    case spv::BuiltIn::LaunchSizeKHR:
243
0
      switch (stage) {
244
0
        case spv::ExecutionModel::RayGenerationKHR:
245
0
        case spv::ExecutionModel::IntersectionKHR:
246
0
        case spv::ExecutionModel::AnyHitKHR:
247
0
        case spv::ExecutionModel::ClosestHitKHR:
248
0
        case spv::ExecutionModel::MissKHR:
249
0
        case spv::ExecutionModel::CallableKHR:
250
0
          return true;
251
0
        default:
252
0
          return false;
253
0
      }
254
0
      break;
255
0
    default:
256
0
      break;
257
0
  }
258
0
  return false;
259
0
}
260
261
0
bool IsVolatileSemanticsBuiltIn(spv::BuiltIn builtin) {
262
0
  switch (builtin) {
263
0
    case spv::BuiltIn::SMIDNV:
264
0
    case spv::BuiltIn::WarpIDNV:
265
0
    case spv::BuiltIn::SubgroupSize:
266
0
    case spv::BuiltIn::SubgroupLocalInvocationId:
267
0
    case spv::BuiltIn::SubgroupEqMask:
268
0
    case spv::BuiltIn::SubgroupGeMask:
269
0
    case spv::BuiltIn::SubgroupGtMask:
270
0
    case spv::BuiltIn::SubgroupLeMask:
271
0
    case spv::BuiltIn::SubgroupLtMask:
272
0
    case spv::BuiltIn::RayTmaxKHR:
273
0
      return true;
274
0
    default:
275
0
      return false;
276
0
  }
277
0
}
278
279
// Some background: certain ray tracing inputs can change when you
280
// execute a "repack" instruction or cast a dependent ray or whatever.
281
// SPIR-V needs to have them marked as volatile so each load would actually
282
// load rather than use a stale cached value
283
//
284
// These stages/builtin are listed in the Vulkan Spec and found in VU
285
// 04678/04679
286
0
bool NeedsVolatileSemantics(spv::BuiltIn builtin, spv::ExecutionModel stage) {
287
0
  if (builtin == spv::BuiltIn::RayTmaxKHR) {
288
0
    return stage == spv::ExecutionModel::IntersectionKHR;
289
0
  }
290
0
  if (!IsVolatileSemanticsBuiltIn(builtin)) return false;
291
292
0
  switch (stage) {
293
0
    case spv::ExecutionModel::RayGenerationKHR:
294
0
    case spv::ExecutionModel::ClosestHitKHR:
295
0
    case spv::ExecutionModel::MissKHR:
296
0
    case spv::ExecutionModel::IntersectionKHR:
297
0
    case spv::ExecutionModel::CallableKHR:
298
0
      return true;
299
0
    default:
300
0
      return false;
301
0
  }
302
0
}
303
304
// Helper class managing validation of built-ins.
305
// TODO: Generic functionality of this class can be moved into
306
// ValidationState_t to be made available to other users.
307
class BuiltInsValidator {
308
 public:
309
23.5k
  BuiltInsValidator(ValidationState_t& vstate) : _(vstate) {}
310
311
  // Run validation.
312
  spv_result_t Run();
313
314
 private:
315
  // Goes through all decorations in the module, if decoration is BuiltIn
316
  // calls ValidateSingleBuiltInAtDefinition().
317
  spv_result_t ValidateBuiltInsAtDefinition();
318
319
  // Validates the instruction defining an id with built-in decoration.
320
  // Can be called multiple times for the same id, if multiple built-ins are
321
  // specified. Seeds id_to_at_reference_checks_ with decorated ids if needed.
322
  spv_result_t ValidateSingleBuiltInAtDefinition(const Decoration& decoration,
323
                                                 const Instruction& inst);
324
  spv_result_t ValidateSingleBuiltInAtDefinitionVulkan(
325
      const Decoration& decoration, const Instruction& inst,
326
      const spv::BuiltIn label);
327
328
  // The following section contains functions which are called when id defined
329
  // by |inst| is decorated with BuiltIn |decoration|.
330
  // Most functions are specific to a single built-in and have naming scheme:
331
  // ValidateXYZAtDefinition. Some functions are common to multiple kinds of
332
  // BuiltIn.
333
  spv_result_t ValidateClipOrCullDistanceAtDefinition(
334
      const Decoration& decoration, const Instruction& inst);
335
  spv_result_t ValidateFragCoordAtDefinition(const Decoration& decoration,
336
                                             const Instruction& inst);
337
  spv_result_t ValidateFragDepthAtDefinition(const Decoration& decoration,
338
                                             const Instruction& inst);
339
  spv_result_t ValidateFrontFacingAtDefinition(const Decoration& decoration,
340
                                               const Instruction& inst);
341
  spv_result_t ValidateHelperInvocationAtDefinition(
342
      const Decoration& decoration, const Instruction& inst);
343
  spv_result_t ValidateInvocationIdAtDefinition(const Decoration& decoration,
344
                                                const Instruction& inst);
345
  spv_result_t ValidateInstanceIndexAtDefinition(const Decoration& decoration,
346
                                                 const Instruction& inst);
347
  spv_result_t ValidateLayerOrViewportIndexAtDefinition(
348
      const Decoration& decoration, const Instruction& inst);
349
  spv_result_t ValidatePatchVerticesAtDefinition(const Decoration& decoration,
350
                                                 const Instruction& inst);
351
  spv_result_t ValidatePointCoordAtDefinition(const Decoration& decoration,
352
                                              const Instruction& inst);
353
  spv_result_t ValidatePointSizeAtDefinition(const Decoration& decoration,
354
                                             const Instruction& inst);
355
  spv_result_t ValidatePositionAtDefinition(const Decoration& decoration,
356
                                            const Instruction& inst);
357
  spv_result_t ValidatePrimitiveIdAtDefinition(const Decoration& decoration,
358
                                               const Instruction& inst);
359
  spv_result_t ValidateSampleIdAtDefinition(const Decoration& decoration,
360
                                            const Instruction& inst);
361
  spv_result_t ValidateSampleMaskAtDefinition(const Decoration& decoration,
362
                                              const Instruction& inst);
363
  spv_result_t ValidateSamplePositionAtDefinition(const Decoration& decoration,
364
                                                  const Instruction& inst);
365
  spv_result_t ValidateTessCoordAtDefinition(const Decoration& decoration,
366
                                             const Instruction& inst);
367
  spv_result_t ValidateTessLevelOuterAtDefinition(const Decoration& decoration,
368
                                                  const Instruction& inst);
369
  spv_result_t ValidateTessLevelInnerAtDefinition(const Decoration& decoration,
370
                                                  const Instruction& inst);
371
  spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
372
                                               const Instruction& inst);
373
  spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
374
                                            const Instruction& inst);
375
  spv_result_t ValidateLocalInvocationIndexAtDefinition(
376
      const Decoration& decoration, const Instruction& inst);
377
  spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
378
                                                 const Instruction& inst);
379
  spv_result_t ValidateBaseInstanceOrVertexAtDefinition(
380
      const Decoration& decoration, const Instruction& inst);
381
  spv_result_t ValidateDrawIndexAtDefinition(const Decoration& decoration,
382
                                             const Instruction& inst);
383
  spv_result_t ValidateViewIndexAtDefinition(const Decoration& decoration,
384
                                             const Instruction& inst);
385
  spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration,
386
                                               const Instruction& inst);
387
  spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
388
                                               const Instruction& inst);
389
  spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration,
390
                                               const Instruction& inst);
391
  spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration,
392
                                               const Instruction& inst);
393
  spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration,
394
                                               const Instruction& inst);
395
  // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
396
  spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
397
      const Decoration& decoration, const Instruction& inst);
398
  spv_result_t ValidateNVSMOrARMCoreBuiltinsAtDefinition(const Decoration& decoration,
399
                                              const Instruction& inst);
400
  // Used for BaryCoord, BaryCoordNoPersp.
401
  spv_result_t ValidateFragmentShaderF32Vec3InputAtDefinition(
402
      const Decoration& decoration, const Instruction& inst);
403
  // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
404
  // SubgroupLeMask.
405
  spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
406
                                                const Instruction& inst);
407
  // Used for SubgroupLocalInvocationId, SubgroupSize.
408
  spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
409
                                            const Instruction& inst);
410
  // Used for SubgroupId, NumSubgroups.
411
  spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
412
                                                   const Instruction& inst);
413
414
  spv_result_t ValidatePrimitiveShadingRateAtDefinition(
415
      const Decoration& decoration, const Instruction& inst);
416
417
  spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
418
                                               const Instruction& inst);
419
420
  spv_result_t ValidateDescriptorHeapAtDefinition(const Decoration& decoration,
421
                                                  const Instruction& inst);
422
423
  spv_result_t ValidateRayTracingBuiltinsAtDefinition(
424
      const Decoration& decoration, const Instruction& inst);
425
426
  spv_result_t ValidateVolatileSemantics(const Decoration& decoration,
427
                                         const Instruction& inst);
428
  spv_result_t ValidateVolatileLoads(const Decoration& decoration,
429
                                     const Instruction& pointer,
430
                                     spv::ExecutionModel stage);
431
432
  spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition(
433
      const Decoration& decoration, const Instruction& inst);
434
435
  spv_result_t ValidateTileQCOMBuiltinAtDefinition(const Decoration& decoration,
436
                                                   const Instruction& inst);
437
438
  // Used as a common method for validating MeshEXT builtins
439
  spv_result_t ValidateMeshBuiltinInterfaceRules(
440
      const Decoration& decoration, const Instruction& inst,
441
      spv::Op scalar_type, const Instruction& referenced_from_inst);
442
  spv_result_t ValidatePrimitiveShadingRateInterfaceRules(
443
      const Decoration& decoration, const Instruction& inst,
444
      const Instruction& referenced_from_inst);
445
  // Builtin that needs check incase **not** used with MeshEXT
446
  spv_result_t ValidateNonMeshInterfaceRules(
447
      const Decoration& decoration, const Instruction& inst,
448
      const Instruction& referenced_from_inst);
449
450
  // The following section contains functions which are called when id defined
451
  // by |referenced_inst| is
452
  // 1. referenced by |referenced_from_inst|
453
  // 2. dependent on |built_in_inst| which is decorated with BuiltIn
454
  // |decoration|. Most functions are specific to a single built-in and have
455
  // naming scheme: ValidateXYZAtReference. Some functions are common to
456
  // multiple kinds of BuiltIn.
457
  spv_result_t ValidateFragCoordAtReference(
458
      const Decoration& decoration, const Instruction& built_in_inst,
459
      const Instruction& referenced_inst,
460
      const Instruction& referenced_from_inst);
461
462
  spv_result_t ValidateFragDepthAtReference(
463
      const Decoration& decoration, const Instruction& built_in_inst,
464
      const Instruction& referenced_inst,
465
      const Instruction& referenced_from_inst);
466
467
  spv_result_t ValidateFrontFacingAtReference(
468
      const Decoration& decoration, const Instruction& built_in_inst,
469
      const Instruction& referenced_inst,
470
      const Instruction& referenced_from_inst);
471
472
  spv_result_t ValidateHelperInvocationAtReference(
473
      const Decoration& decoration, const Instruction& built_in_inst,
474
      const Instruction& referenced_inst,
475
      const Instruction& referenced_from_inst);
476
477
  spv_result_t ValidateInvocationIdAtReference(
478
      const Decoration& decoration, const Instruction& built_in_inst,
479
      const Instruction& referenced_inst,
480
      const Instruction& referenced_from_inst);
481
482
  spv_result_t ValidateInstanceIndexAtReference(
483
      const Decoration& decoration, const Instruction& built_in_inst,
484
      const Instruction& referenced_inst,
485
      const Instruction& referenced_from_inst);
486
487
  spv_result_t ValidatePatchVerticesAtReference(
488
      const Decoration& decoration, const Instruction& built_in_inst,
489
      const Instruction& referenced_inst,
490
      const Instruction& referenced_from_inst);
491
492
  spv_result_t ValidatePointCoordAtReference(
493
      const Decoration& decoration, const Instruction& built_in_inst,
494
      const Instruction& referenced_inst,
495
      const Instruction& referenced_from_inst);
496
497
  spv_result_t ValidatePointSizeAtReference(
498
      const Decoration& decoration, const Instruction& built_in_inst,
499
      const Instruction& referenced_inst,
500
      const Instruction& referenced_from_inst);
501
502
  spv_result_t ValidatePositionAtReference(
503
      const Decoration& decoration, const Instruction& built_in_inst,
504
      const Instruction& referenced_inst,
505
      const Instruction& referenced_from_inst);
506
507
  spv_result_t ValidatePrimitiveIdAtReference(
508
      const Decoration& decoration, const Instruction& built_in_inst,
509
      const Instruction& referenced_inst,
510
      const Instruction& referenced_from_inst);
511
512
  spv_result_t ValidateSampleIdAtReference(
513
      const Decoration& decoration, const Instruction& built_in_inst,
514
      const Instruction& referenced_inst,
515
      const Instruction& referenced_from_inst);
516
517
  spv_result_t ValidateSampleMaskAtReference(
518
      const Decoration& decoration, const Instruction& built_in_inst,
519
      const Instruction& referenced_inst,
520
      const Instruction& referenced_from_inst);
521
522
  spv_result_t ValidateSamplePositionAtReference(
523
      const Decoration& decoration, const Instruction& built_in_inst,
524
      const Instruction& referenced_inst,
525
      const Instruction& referenced_from_inst);
526
527
  spv_result_t ValidateTessCoordAtReference(
528
      const Decoration& decoration, const Instruction& built_in_inst,
529
      const Instruction& referenced_inst,
530
      const Instruction& referenced_from_inst);
531
532
  spv_result_t ValidateTessLevelAtReference(
533
      const Decoration& decoration, const Instruction& built_in_inst,
534
      const Instruction& referenced_inst,
535
      const Instruction& referenced_from_inst);
536
537
  spv_result_t ValidateLocalInvocationIndexAtReference(
538
      const Decoration& decoration, const Instruction& built_in_inst,
539
      const Instruction& referenced_inst,
540
      const Instruction& referenced_from_inst);
541
542
  spv_result_t ValidateVertexIndexAtReference(
543
      const Decoration& decoration, const Instruction& built_in_inst,
544
      const Instruction& referenced_inst,
545
      const Instruction& referenced_from_inst);
546
547
  spv_result_t ValidateLayerOrViewportIndexAtReference(
548
      const Decoration& decoration, const Instruction& built_in_inst,
549
      const Instruction& referenced_inst,
550
      const Instruction& referenced_from_inst);
551
552
  spv_result_t ValidateWorkgroupSizeAtReference(
553
      const Decoration& decoration, const Instruction& built_in_inst,
554
      const Instruction& referenced_inst,
555
      const Instruction& referenced_from_inst);
556
557
  spv_result_t ValidateClipOrCullDistanceAtReference(
558
      const Decoration& decoration, const Instruction& built_in_inst,
559
      const Instruction& referenced_inst,
560
      const Instruction& referenced_from_inst);
561
562
  spv_result_t ValidateBaseInstanceOrVertexAtReference(
563
      const Decoration& decoration, const Instruction& built_in_inst,
564
      const Instruction& referenced_inst,
565
      const Instruction& referenced_from_inst);
566
567
  spv_result_t ValidateDrawIndexAtReference(
568
      const Decoration& decoration, const Instruction& built_in_inst,
569
      const Instruction& referenced_inst,
570
      const Instruction& referenced_from_inst);
571
572
  spv_result_t ValidateViewIndexAtReference(
573
      const Decoration& decoration, const Instruction& built_in_inst,
574
      const Instruction& referenced_inst,
575
      const Instruction& referenced_from_inst);
576
577
  spv_result_t ValidateDeviceIndexAtReference(
578
      const Decoration& decoration, const Instruction& built_in_inst,
579
      const Instruction& referenced_inst,
580
      const Instruction& referenced_from_inst);
581
582
  spv_result_t ValidateFragInvocationCountAtReference(
583
      const Decoration& decoration, const Instruction& built_in_inst,
584
      const Instruction& referenced_inst,
585
      const Instruction& referenced_from_inst);
586
587
  spv_result_t ValidateFragSizeAtReference(
588
      const Decoration& decoration, const Instruction& built_in_inst,
589
      const Instruction& referenced_inst,
590
      const Instruction& referenced_from_inst);
591
592
  spv_result_t ValidateFragStencilRefAtReference(
593
      const Decoration& decoration, const Instruction& built_in_inst,
594
      const Instruction& referenced_inst,
595
      const Instruction& referenced_from_inst);
596
597
  spv_result_t ValidateFullyCoveredAtReference(
598
      const Decoration& decoration, const Instruction& built_in_inst,
599
      const Instruction& referenced_inst,
600
      const Instruction& referenced_from_inst);
601
602
  // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
603
  spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
604
      const Decoration& decoration, const Instruction& built_in_inst,
605
      const Instruction& referenced_inst,
606
      const Instruction& referenced_from_inst);
607
608
  // Used for BaryCoord, BaryCoordNoPersp.
609
  spv_result_t ValidateFragmentShaderF32Vec3InputAtReference(
610
      const Decoration& decoration, const Instruction& built_in_inst,
611
      const Instruction& referenced_inst,
612
      const Instruction& referenced_from_inst);
613
614
  // Used for SubgroupId and NumSubgroups.
615
  spv_result_t ValidateComputeI32InputAtReference(
616
      const Decoration& decoration, const Instruction& built_in_inst,
617
      const Instruction& referenced_inst,
618
      const Instruction& referenced_from_inst);
619
620
  spv_result_t ValidateNVSMOrARMCoreBuiltinsAtReference(
621
      const Decoration& decoration, const Instruction& built_in_inst,
622
      const Instruction& referenced_inst,
623
      const Instruction& referenced_from_inst);
624
625
  spv_result_t ValidatePrimitiveShadingRateAtReference(
626
      const Decoration& decoration, const Instruction& built_in_inst,
627
      const Instruction& referenced_inst,
628
      const Instruction& referenced_from_inst);
629
630
  spv_result_t ValidateShadingRateAtReference(
631
      const Decoration& decoration, const Instruction& built_in_inst,
632
      const Instruction& referenced_inst,
633
      const Instruction& referenced_from_inst);
634
635
  spv_result_t ValidateRayTracingBuiltinsAtReference(
636
      const Decoration& decoration, const Instruction& built_in_inst,
637
      const Instruction& referenced_inst,
638
      const Instruction& referenced_from_inst);
639
640
  spv_result_t ValidateMeshShadingEXTBuiltinsAtReference(
641
      const Decoration& decoration, const Instruction& built_in_inst,
642
      const Instruction& referenced_inst,
643
      const Instruction& referenced_from_inst);
644
645
  spv_result_t ValidateTileQCOMBuiltinAtReference(
646
      const Decoration& decoration, const Instruction& built_in_inst,
647
      const Instruction& referenced_inst,
648
      const Instruction& referenced_from_inst);
649
650
  // Validates that |built_in_inst| is not (even indirectly) referenced from
651
  // within a function which can be called with |execution_model|.
652
  //
653
  // |vuid| - Vulkan ID for the error, or a negative value if none.
654
  // |comment| - text explaining why the restriction was imposed.
655
  // |decoration| - BuiltIn decoration which causes the restriction.
656
  // |referenced_inst| - instruction which is dependent on |built_in_inst| and
657
  //                     defines the id which was referenced.
658
  // |referenced_from_inst| - instruction which references id defined by
659
  //                          |referenced_inst| from within a function.
660
  spv_result_t ValidateNotCalledWithExecutionModel(
661
      int vuid, const char* comment, spv::ExecutionModel execution_model,
662
      const Decoration& decoration, const Instruction& built_in_inst,
663
      const Instruction& referenced_inst,
664
      const Instruction& referenced_from_inst);
665
666
  // The following section contains functions which check that the decorated
667
  // variable has the type specified in the function name. |diag| would be
668
  // called with a corresponding error message, if validation is not successful.
669
  spv_result_t ValidateBool(
670
      const Decoration& decoration, const Instruction& inst,
671
      const std::function<spv_result_t(const std::string& message)>& diag);
672
  spv_result_t ValidateBlockTypeOrArrayedType(
673
      const Decoration& decoration, const Instruction& inst,
674
      bool& present_in_block, spv::Op expected_scalar_type,
675
      const std::function<spv_result_t(const std::string& message)>& diag);
676
  spv_result_t ValidateI(
677
      const Decoration& decoration, const Instruction& inst,
678
      const std::function<spv_result_t(const std::string& message)>& diag);
679
  spv_result_t ValidateI32(
680
      const Decoration& decoration, const Instruction& inst,
681
      const std::function<spv_result_t(const std::string& message)>& diag);
682
  spv_result_t ValidateI32Vec(
683
      const Decoration& decoration, const Instruction& inst,
684
      uint32_t num_components,
685
      const std::function<spv_result_t(const std::string& message)>& diag);
686
  spv_result_t ValidateU32Vec(
687
      const Decoration& decoration, const Instruction& inst,
688
      uint32_t num_components,
689
      const std::function<spv_result_t(const std::string& message)>& diag);
690
  spv_result_t ValidateI32Arr(
691
      const Decoration& decoration, const Instruction& inst,
692
      const std::function<spv_result_t(const std::string& message)>& diag);
693
  spv_result_t ValidateArrayedI32Vec(
694
      const Decoration& decoration, const Instruction& inst,
695
      uint32_t num_components,
696
      const std::function<spv_result_t(const std::string& message)>& diag);
697
  spv_result_t ValidateOptionalArrayedI32(
698
      const Decoration& decoration, const Instruction& inst,
699
      const std::function<spv_result_t(const std::string& message)>& diag);
700
  spv_result_t ValidateI32Helper(
701
      const Decoration& decoration, const Instruction& inst,
702
      const std::function<spv_result_t(const std::string& message)>& diag,
703
      uint32_t underlying_type);
704
  spv_result_t ValidateF32(
705
      const Decoration& decoration, const Instruction& inst,
706
      const std::function<spv_result_t(const std::string& message)>& diag);
707
  spv_result_t ValidateOptionalArrayedF32(
708
      const Decoration& decoration, const Instruction& inst,
709
      const std::function<spv_result_t(const std::string& message)>& diag);
710
  spv_result_t ValidateF32Helper(
711
      const Decoration& decoration, const Instruction& inst,
712
      const std::function<spv_result_t(const std::string& message)>& diag,
713
      uint32_t underlying_type);
714
  spv_result_t ValidateF32Vec(
715
      const Decoration& decoration, const Instruction& inst,
716
      uint32_t num_components,
717
      const std::function<spv_result_t(const std::string& message)>& diag);
718
  spv_result_t ValidateOptionalArrayedF32Vec(
719
      const Decoration& decoration, const Instruction& inst,
720
      uint32_t num_components,
721
      const std::function<spv_result_t(const std::string& message)>& diag);
722
  spv_result_t ValidateArrayedF32Vec(
723
      const Decoration& decoration, const Instruction& inst,
724
      uint32_t num_components, uint32_t array_length,
725
      const std::function<spv_result_t(const std::string& message)>& diag);
726
  spv_result_t ValidateF32VecHelper(
727
      const Decoration& decoration, const Instruction& inst,
728
      uint32_t num_components,
729
      const std::function<spv_result_t(const std::string& message)>& diag,
730
      uint32_t underlying_type);
731
  // If |num_components| is zero, the number of components is not checked.
732
  spv_result_t ValidateF32Arr(
733
      const Decoration& decoration, const Instruction& inst,
734
      uint32_t num_components,
735
      const std::function<spv_result_t(const std::string& message)>& diag);
736
  spv_result_t ValidateOptionalArrayedF32Arr(
737
      const Decoration& decoration, const Instruction& inst,
738
      uint32_t num_components,
739
      const std::function<spv_result_t(const std::string& message)>& diag);
740
  spv_result_t ValidateF32ArrHelper(
741
      const Decoration& decoration, const Instruction& inst,
742
      uint32_t num_components,
743
      const std::function<spv_result_t(const std::string& message)>& diag,
744
      uint32_t underlying_type);
745
  spv_result_t ValidateF32Mat(
746
      const Decoration& decoration, const Instruction& inst,
747
      uint32_t req_num_rows, uint32_t req_num_columns,
748
      const std::function<spv_result_t(const std::string& message)>& diag);
749
750
  // Generates strings like "Member #0 of struct ID <2>".
751
  std::string GetDefinitionDesc(const Decoration& decoration,
752
                                const Instruction& inst) const;
753
754
  // Generates strings like "ID <51> (OpTypePointer) is referencing ID <2>
755
  // (OpTypeStruct) which is decorated with BuiltIn Position".
756
  std::string GetReferenceDesc(
757
      const Decoration& decoration, const Instruction& built_in_inst,
758
      const Instruction& referenced_inst,
759
      const Instruction& referenced_from_inst,
760
      spv::ExecutionModel execution_model = spv::ExecutionModel::Max) const;
761
762
  // Generates strings like "ID <51> (OpTypePointer) uses storage class
763
  // UniformConstant".
764
  std::string GetStorageClassDesc(const Instruction& inst) const;
765
766
  uint64_t GetArrayLength(uint32_t interface_var_id);
767
768
  // Updates inner working of the class. Is called sequentially for every
769
  // instruction.
770
  void Update(const Instruction& inst);
771
772
0
  bool IsBulitinInEntryPoint(const Instruction& inst, uint32_t entry_point) {
773
0
    auto get_underlying_type_id = [&](const Instruction* ifx_var) {
774
0
      auto pointer_type_inst = _.FindDef(ifx_var->type_id());
775
0
      auto type_inst = _.FindDef(pointer_type_inst->GetOperandAs<uint32_t>(2));
776
0
      while (type_inst->opcode() == spv::Op::OpTypeArray) {
777
0
        type_inst = _.FindDef(type_inst->GetOperandAs<uint32_t>(1));
778
0
      };
779
0
      return type_inst->id();
780
0
    };
781
782
0
    for (const auto& desc : _.entry_point_descriptions(entry_point)) {
783
0
      for (auto interface : desc.interfaces) {
784
0
        if (inst.opcode() == spv::Op::OpTypeStruct) {
785
0
          auto varInst = _.FindDef(interface);
786
0
          if (inst.id() == get_underlying_type_id(varInst)) {
787
0
            return true;
788
0
          }
789
0
        } else if (inst.id() == interface) {
790
0
          return true;
791
0
        }
792
0
      }
793
0
    }
794
0
    return false;
795
0
  }
796
797
  // Check if "inst" is an interface variable or type of a interface varibale
798
  // of any mesh entry point. Populate entry_point_interface_id with all
799
  // entry points and interface variables that refer to the "inst"
800
  bool IsMeshInterfaceVar(
801
      const Instruction& inst,
802
0
      std::map<uint32_t, uint32_t>& entry_point_interface_id) {
803
0
    auto get_underlying_type_id = [&](const Instruction* ifx_var) {
804
0
      auto pointer_type_inst = _.FindDef(ifx_var->type_id());
805
0
      auto type_inst = _.FindDef(pointer_type_inst->GetOperandAs<uint32_t>(2));
806
0
      while (type_inst->opcode() == spv::Op::OpTypeArray) {
807
0
        type_inst = _.FindDef(type_inst->GetOperandAs<uint32_t>(1));
808
0
      };
809
0
      return type_inst->id();
810
0
    };
811
812
0
    for (const uint32_t entry_point : _.entry_points()) {
813
0
      const auto* models = _.GetExecutionModels(entry_point);
814
0
      if (models->find(spv::ExecutionModel::MeshEXT) != models->end() ||
815
0
          models->find(spv::ExecutionModel::MeshNV) != models->end()) {
816
0
        for (const auto& desc : _.entry_point_descriptions(entry_point)) {
817
0
          for (auto interface : desc.interfaces) {
818
0
            if (inst.opcode() == spv::Op::OpTypeStruct) {
819
0
              auto varInst = _.FindDef(interface);
820
0
              if (inst.id() == get_underlying_type_id(varInst)) {
821
0
                entry_point_interface_id[entry_point] = interface;
822
0
                break;
823
0
              }
824
0
            } else if (inst.id() == interface) {
825
0
              entry_point_interface_id[entry_point] = interface;
826
0
              break;
827
0
            }
828
0
          }
829
0
        }
830
0
      }
831
0
    }
832
0
    return !entry_point_interface_id.empty();
833
0
  }
834
835
  ValidationState_t& _;
836
837
  // Mapping id -> list of rules which validate instruction referencing the
838
  // id. Rules can create new rules and add them to this container.
839
  // Using std::map, and not std::unordered_map to avoid iterator invalidation
840
  // during rehashing.
841
  std::map<uint32_t, std::list<std::function<spv_result_t(const Instruction&)>>>
842
      id_to_at_reference_checks_;
843
844
  // Id of the function we are currently inside. 0 if not inside a function.
845
  uint32_t function_id_ = 0;
846
847
  // Entry points which can (indirectly) call the current function.
848
  // The pointer either points to a vector inside to function_to_entry_points_
849
  // or to no_entry_points_. The pointer is guaranteed to never be null.
850
  const std::vector<uint32_t> no_entry_points;
851
  const std::vector<uint32_t>* entry_points_ = &no_entry_points;
852
853
  // Execution models with which the current function can be called.
854
  std::set<spv::ExecutionModel> execution_models_;
855
856
  // Execution modes with which the current function can be called.
857
  std::set<spv::ExecutionMode> execution_modes_;
858
859
  // For Builtin that can only be declared once in an entry point, keep track if
860
  // the entry point has it already
861
  std::set<uint32_t> cull_primitive_entry_points_;
862
};
863
864
10.4k
void BuiltInsValidator::Update(const Instruction& inst) {
865
10.4k
  const spv::Op opcode = inst.opcode();
866
10.4k
  if (opcode == spv::Op::OpFunction) {
867
    // Entering a function.
868
188
    assert(function_id_ == 0);
869
188
    function_id_ = inst.id();
870
188
    execution_models_.clear();
871
188
    execution_modes_.clear();
872
188
    entry_points_ = &_.FunctionEntryPoints(function_id_);
873
    // Collect execution models from all entry points from which the current
874
    // function can be called.
875
244
    for (const uint32_t entry_point : *entry_points_) {
876
244
      if (const auto* models = _.GetExecutionModels(entry_point)) {
877
244
        execution_models_.insert(models->begin(), models->end());
878
244
      }
879
244
      if (const auto* modes = _.GetExecutionModes(entry_point)) {
880
105
        execution_modes_.insert(modes->begin(), modes->end());
881
105
      }
882
244
    }
883
188
  }
884
885
10.4k
  if (opcode == spv::Op::OpFunctionEnd) {
886
    // Exiting a function.
887
188
    assert(function_id_ != 0);
888
188
    function_id_ = 0;
889
188
    entry_points_ = &no_entry_points;
890
188
    execution_models_.clear();
891
188
    execution_modes_.clear();
892
188
  }
893
10.4k
}
894
895
std::string BuiltInsValidator::GetDefinitionDesc(
896
0
    const Decoration& decoration, const Instruction& inst) const {
897
0
  std::ostringstream ss;
898
0
  if (decoration.struct_member_index() != Decoration::kInvalidMember) {
899
0
    assert(inst.opcode() == spv::Op::OpTypeStruct);
900
0
    ss << "Member #" << decoration.struct_member_index();
901
0
    ss << " of struct ID <" << inst.id() << ">";
902
0
  } else {
903
0
    ss << GetIdDesc(inst);
904
0
  }
905
0
  return ss.str();
906
0
}
907
908
std::string BuiltInsValidator::GetReferenceDesc(
909
    const Decoration& decoration, const Instruction& built_in_inst,
910
    const Instruction& referenced_inst, const Instruction& referenced_from_inst,
911
0
    spv::ExecutionModel execution_model) const {
912
0
  std::ostringstream ss;
913
0
  ss << GetIdDesc(referenced_from_inst) << " is referencing "
914
0
     << GetIdDesc(referenced_inst);
915
0
  if (built_in_inst.id() != referenced_inst.id()) {
916
0
    ss << " which is dependent on " << GetIdDesc(built_in_inst);
917
0
  }
918
919
0
  ss << " which is decorated with BuiltIn ";
920
0
  ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
921
0
                                      (uint32_t)decoration.builtin());
922
0
  if (function_id_) {
923
0
    ss << " in function <" << function_id_ << ">";
924
0
    if (execution_model != spv::ExecutionModel::Max) {
925
0
      ss << " called with execution model ";
926
0
      ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
927
0
                                          uint32_t(execution_model));
928
0
    }
929
0
  }
930
0
  ss << ".";
931
0
  return ss.str();
932
0
}
933
934
std::string BuiltInsValidator::GetStorageClassDesc(
935
0
    const Instruction& inst) const {
936
0
  std::ostringstream ss;
937
0
  ss << GetIdDesc(inst) << " uses storage class ";
938
0
  ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_STORAGE_CLASS,
939
0
                                      uint32_t(GetStorageClass(inst)));
940
0
  ss << ".";
941
0
  return ss.str();
942
0
}
943
944
0
uint64_t BuiltInsValidator::GetArrayLength(uint32_t interface_var_id) {
945
0
  uint32_t underlying_type;
946
0
  spv::StorageClass storage_class;
947
0
  uint64_t array_len = -1;
948
0
  const Instruction* inst = _.FindDef(interface_var_id);
949
0
  if (inst->opcode() != spv::Op::OpVariable) {
950
0
    return -1;
951
0
  }
952
953
0
  if (!_.GetPointerTypeInfo(inst->type_id(), &underlying_type,
954
0
                            &storage_class)) {
955
0
    return 0;
956
0
  }
957
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
958
    // Get the array length
959
0
    const auto length_id = _.FindDef(underlying_type)->word(3u);
960
0
    if (!_.EvalConstantValUint64(length_id, &array_len)) {
961
0
      return 0;
962
0
    }
963
0
  }
964
0
  return array_len;
965
0
}
966
967
spv_result_t BuiltInsValidator::ValidateBool(
968
    const Decoration& decoration, const Instruction& inst,
969
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
970
0
  uint32_t underlying_type = 0;
971
0
  if (spv_result_t error =
972
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
973
0
    return error;
974
0
  }
975
976
0
  if (!_.IsBoolScalarType(underlying_type)) {
977
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
978
0
  }
979
980
0
  return SPV_SUCCESS;
981
0
}
982
983
spv_result_t BuiltInsValidator::ValidateBlockTypeOrArrayedType(
984
    const Decoration& decoration, const Instruction& inst, bool& isBlock,
985
    spv::Op expected_scalar_type,
986
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
987
0
  uint32_t underlying_type = 0;
988
0
  int64_t array_len = -1;
989
0
  isBlock = true;
990
0
  if (spv_result_t error =
991
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
992
0
    return error;
993
0
  }
994
  // Strip the array, if present.
995
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
996
    // Get the array length
997
0
    const auto length_id = _.FindDef(underlying_type)->word(3u);
998
0
    if (!_.EvalConstantValInt64(length_id, &array_len)) {
999
0
      return diag(GetDefinitionDesc(decoration, inst) +
1000
0
                  " Failed to find the array length.");
1001
0
    }
1002
0
    underlying_type = _.FindDef(underlying_type)->word(2u);
1003
0
    isBlock = false;
1004
0
  } else if (!_.HasDecoration(inst.id(), spv::Decoration::Block)) {
1005
    // If not in array, and bool is in a struct, must be in a Block struct
1006
0
    return diag(GetDefinitionDesc(decoration, inst) +
1007
0
                " Scalar boolean must be in a Block.");
1008
0
  }
1009
1010
0
  switch (expected_scalar_type) {
1011
0
    case spv::Op::OpTypeBool:
1012
0
      if (!_.IsBoolScalarType(underlying_type)) {
1013
0
        return diag(GetDefinitionDesc(decoration, inst) +
1014
0
                    " is not a bool scalar.");
1015
0
      }
1016
0
      break;
1017
0
    case spv::Op::OpTypeInt:
1018
0
      if (!_.IsIntScalarType(underlying_type)) {
1019
0
        return diag(GetDefinitionDesc(decoration, inst) +
1020
0
                    " is not an integer scalar.");
1021
0
      }
1022
0
      break;
1023
0
    default:
1024
0
      assert(0 && "Unhandled scalar type");
1025
0
      return diag(GetDefinitionDesc(decoration, inst) +
1026
0
                  " is not a recognized scalar type.");
1027
0
  }
1028
1029
0
  return SPV_SUCCESS;
1030
0
}
1031
1032
spv_result_t BuiltInsValidator::ValidateI(
1033
    const Decoration& decoration, const Instruction& inst,
1034
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1035
0
  uint32_t underlying_type = 0;
1036
0
  if (spv_result_t error =
1037
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1038
0
    return error;
1039
0
  }
1040
1041
0
  if (!_.IsIntScalarType(underlying_type)) {
1042
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
1043
0
  }
1044
1045
0
  return SPV_SUCCESS;
1046
0
}
1047
1048
spv_result_t BuiltInsValidator::ValidateI32(
1049
    const Decoration& decoration, const Instruction& inst,
1050
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1051
0
  uint32_t underlying_type = 0;
1052
0
  if (spv_result_t error =
1053
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1054
0
    return error;
1055
0
  }
1056
1057
0
  return ValidateI32Helper(decoration, inst, diag, underlying_type);
1058
0
}
1059
1060
spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32(
1061
    const Decoration& decoration, const Instruction& inst,
1062
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1063
0
  uint32_t underlying_type = 0;
1064
0
  if (spv_result_t error =
1065
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1066
0
    return error;
1067
0
  }
1068
1069
  // Strip the array, if present.
1070
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
1071
0
    underlying_type = _.FindDef(underlying_type)->word(2u);
1072
0
  }
1073
1074
0
  return ValidateI32Helper(decoration, inst, diag, underlying_type);
1075
0
}
1076
1077
spv_result_t BuiltInsValidator::ValidateI32Helper(
1078
    const Decoration& decoration, const Instruction& inst,
1079
    const std::function<spv_result_t(const std::string& message)>& diag,
1080
0
    uint32_t underlying_type) {
1081
0
  if (!_.IsIntScalarType(underlying_type)) {
1082
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
1083
0
  }
1084
1085
0
  const uint32_t bit_width = _.GetBitWidth(underlying_type);
1086
0
  if (bit_width != 32) {
1087
0
    std::ostringstream ss;
1088
0
    ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
1089
0
       << ".";
1090
0
    return diag(ss.str());
1091
0
  }
1092
1093
0
  return SPV_SUCCESS;
1094
0
}
1095
1096
spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32(
1097
    const Decoration& decoration, const Instruction& inst,
1098
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1099
0
  uint32_t underlying_type = 0;
1100
0
  if (spv_result_t error =
1101
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1102
0
    return error;
1103
0
  }
1104
1105
  // Strip the array, if present.
1106
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
1107
0
    underlying_type = _.FindDef(underlying_type)->word(2u);
1108
0
  }
1109
1110
0
  return ValidateF32Helper(decoration, inst, diag, underlying_type);
1111
0
}
1112
1113
spv_result_t BuiltInsValidator::ValidateF32(
1114
    const Decoration& decoration, const Instruction& inst,
1115
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1116
0
  uint32_t underlying_type = 0;
1117
0
  if (spv_result_t error =
1118
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1119
0
    return error;
1120
0
  }
1121
1122
0
  return ValidateF32Helper(decoration, inst, diag, underlying_type);
1123
0
}
1124
1125
spv_result_t BuiltInsValidator::ValidateF32Helper(
1126
    const Decoration& decoration, const Instruction& inst,
1127
    const std::function<spv_result_t(const std::string& message)>& diag,
1128
0
    uint32_t underlying_type) {
1129
0
  if (!_.IsFloatScalarType(underlying_type)) {
1130
0
    return diag(GetDefinitionDesc(decoration, inst) +
1131
0
                " is not a float scalar.");
1132
0
  }
1133
1134
0
  const uint32_t bit_width = _.GetBitWidth(underlying_type);
1135
0
  if (bit_width != 32) {
1136
0
    std::ostringstream ss;
1137
0
    ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
1138
0
       << ".";
1139
0
    return diag(ss.str());
1140
0
  }
1141
1142
0
  return SPV_SUCCESS;
1143
0
}
1144
1145
spv_result_t BuiltInsValidator::ValidateI32Vec(
1146
    const Decoration& decoration, const Instruction& inst,
1147
    uint32_t num_components,
1148
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1149
0
  uint32_t underlying_type = 0;
1150
0
  if (spv_result_t error =
1151
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1152
0
    return error;
1153
0
  }
1154
1155
0
  if (!_.IsIntVectorType(underlying_type)) {
1156
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
1157
0
  }
1158
1159
0
  const uint32_t actual_num_components = _.GetDimension(underlying_type);
1160
0
  if (_.GetDimension(underlying_type) != num_components) {
1161
0
    std::ostringstream ss;
1162
0
    ss << GetDefinitionDesc(decoration, inst) << " has "
1163
0
       << actual_num_components << " components.";
1164
0
    return diag(ss.str());
1165
0
  }
1166
1167
0
  const uint32_t bit_width = _.GetBitWidth(underlying_type);
1168
0
  if (bit_width != 32) {
1169
0
    std::ostringstream ss;
1170
0
    ss << GetDefinitionDesc(decoration, inst)
1171
0
       << " has components with bit width " << bit_width << ".";
1172
0
    return diag(ss.str());
1173
0
  }
1174
1175
0
  return SPV_SUCCESS;
1176
0
}
1177
1178
spv_result_t BuiltInsValidator::ValidateU32Vec(
1179
    const Decoration& decoration, const Instruction& inst,
1180
    uint32_t num_components,
1181
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1182
0
  uint32_t underlying_type = 0;
1183
0
  if (spv_result_t error =
1184
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1185
0
    return error;
1186
0
  }
1187
1188
0
  if (!_.IsUnsignedIntVectorType(underlying_type)) {
1189
0
    return diag(GetDefinitionDesc(decoration, inst) +
1190
0
                " is not an unsigned int vector.");
1191
0
  }
1192
1193
0
  const uint32_t actual = _.GetDimension(underlying_type);
1194
0
  if (actual != num_components) {
1195
0
    std::ostringstream ss;
1196
0
    ss << GetDefinitionDesc(decoration, inst) << " has " << actual
1197
0
       << " components.";
1198
0
    return diag(ss.str());
1199
0
  }
1200
1201
0
  const uint32_t bit_width = _.GetBitWidth(underlying_type);
1202
0
  if (bit_width != 32) {
1203
0
    std::ostringstream ss;
1204
0
    ss << GetDefinitionDesc(decoration, inst)
1205
0
       << " has components with bit width " << bit_width << ".";
1206
0
    return diag(ss.str());
1207
0
  }
1208
1209
0
  return SPV_SUCCESS;
1210
0
}
1211
1212
spv_result_t BuiltInsValidator::ValidateArrayedI32Vec(
1213
    const Decoration& decoration, const Instruction& inst,
1214
    uint32_t num_components,
1215
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1216
0
  uint32_t underlying_type = 0;
1217
0
  if (spv_result_t error =
1218
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1219
0
    return error;
1220
0
  }
1221
1222
0
  const Instruction* const type_inst = _.FindDef(underlying_type);
1223
0
  if (type_inst->opcode() != spv::Op::OpTypeArray) {
1224
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
1225
0
  }
1226
1227
0
  const uint32_t component_type = type_inst->word(2);
1228
0
  if (!_.IsIntVectorType(component_type)) {
1229
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
1230
0
  }
1231
1232
0
  const uint32_t actual_num_components = _.GetDimension(component_type);
1233
0
  if (_.GetDimension(component_type) != num_components) {
1234
0
    std::ostringstream ss;
1235
0
    ss << GetDefinitionDesc(decoration, inst) << " has "
1236
0
       << actual_num_components << " components.";
1237
0
    return diag(ss.str());
1238
0
  }
1239
1240
0
  const uint32_t bit_width = _.GetBitWidth(component_type);
1241
0
  if (bit_width != 32) {
1242
0
    std::ostringstream ss;
1243
0
    ss << GetDefinitionDesc(decoration, inst)
1244
0
       << " has components with bit width " << bit_width << ".";
1245
0
    return diag(ss.str());
1246
0
  }
1247
1248
0
  return SPV_SUCCESS;
1249
0
}
1250
1251
spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
1252
    const Decoration& decoration, const Instruction& inst,
1253
    uint32_t num_components,
1254
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1255
0
  uint32_t underlying_type = 0;
1256
0
  if (spv_result_t error =
1257
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1258
0
    return error;
1259
0
  }
1260
1261
  // Strip the array, if present.
1262
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
1263
0
    underlying_type = _.FindDef(underlying_type)->word(2u);
1264
0
  }
1265
1266
0
  return ValidateF32VecHelper(decoration, inst, num_components, diag,
1267
0
                              underlying_type);
1268
0
}
1269
1270
spv_result_t BuiltInsValidator::ValidateArrayedF32Vec(
1271
    const Decoration& decoration, const Instruction& inst,
1272
    uint32_t num_components, uint32_t array_length,
1273
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1274
0
  uint32_t underlying_type = 0;
1275
0
  if (spv_result_t error =
1276
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1277
0
    return error;
1278
0
  }
1279
1280
0
  if (_.GetIdOpcode(underlying_type) != spv::Op::OpTypeArray) {
1281
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
1282
0
  }
1283
1284
0
  const uint32_t length_id = _.FindDef(underlying_type)->word(3u);
1285
0
  uint64_t found_length = 0;
1286
0
  if (!_.EvalConstantValUint64(length_id, &found_length)) {
1287
0
    return diag(GetDefinitionDesc(decoration, inst) +
1288
0
                " array has a non constant length.");
1289
0
  }
1290
1291
0
  if (array_length != found_length) {
1292
0
    return diag(GetDefinitionDesc(decoration, inst) + " array length must be " +
1293
0
                std::to_string(array_length));
1294
0
  }
1295
1296
0
  underlying_type = _.FindDef(underlying_type)->word(2u);
1297
1298
0
  return ValidateF32VecHelper(decoration, inst, num_components, diag,
1299
0
                              underlying_type);
1300
0
}
1301
1302
spv_result_t BuiltInsValidator::ValidateF32Vec(
1303
    const Decoration& decoration, const Instruction& inst,
1304
    uint32_t num_components,
1305
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1306
0
  uint32_t underlying_type = 0;
1307
0
  if (spv_result_t error =
1308
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1309
0
    return error;
1310
0
  }
1311
1312
0
  return ValidateF32VecHelper(decoration, inst, num_components, diag,
1313
0
                              underlying_type);
1314
0
}
1315
1316
spv_result_t BuiltInsValidator::ValidateF32VecHelper(
1317
    const Decoration& decoration, const Instruction& inst,
1318
    uint32_t num_components,
1319
    const std::function<spv_result_t(const std::string& message)>& diag,
1320
0
    uint32_t underlying_type) {
1321
0
  if (!_.IsFloatVectorType(underlying_type)) {
1322
0
    return diag(GetDefinitionDesc(decoration, inst) +
1323
0
                " is not a float vector.");
1324
0
  }
1325
1326
0
  const uint32_t actual_num_components = _.GetDimension(underlying_type);
1327
0
  if (_.GetDimension(underlying_type) != num_components) {
1328
0
    std::ostringstream ss;
1329
0
    ss << GetDefinitionDesc(decoration, inst) << " has "
1330
0
       << actual_num_components << " components.";
1331
0
    return diag(ss.str());
1332
0
  }
1333
1334
0
  const uint32_t bit_width = _.GetBitWidth(underlying_type);
1335
0
  if (bit_width != 32) {
1336
0
    std::ostringstream ss;
1337
0
    ss << GetDefinitionDesc(decoration, inst)
1338
0
       << " has components with bit width " << bit_width << ".";
1339
0
    return diag(ss.str());
1340
0
  }
1341
1342
0
  return SPV_SUCCESS;
1343
0
}
1344
1345
spv_result_t BuiltInsValidator::ValidateI32Arr(
1346
    const Decoration& decoration, const Instruction& inst,
1347
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1348
0
  uint32_t underlying_type = 0;
1349
0
  if (spv_result_t error =
1350
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1351
0
    return error;
1352
0
  }
1353
1354
0
  const Instruction* const type_inst = _.FindDef(underlying_type);
1355
0
  if (type_inst->opcode() != spv::Op::OpTypeArray) {
1356
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
1357
0
  }
1358
1359
0
  const uint32_t component_type = type_inst->word(2);
1360
0
  if (!_.IsIntScalarType(component_type)) {
1361
0
    return diag(GetDefinitionDesc(decoration, inst) +
1362
0
                " components are not int scalar.");
1363
0
  }
1364
1365
0
  const uint32_t bit_width = _.GetBitWidth(component_type);
1366
0
  if (bit_width != 32) {
1367
0
    std::ostringstream ss;
1368
0
    ss << GetDefinitionDesc(decoration, inst)
1369
0
       << " has components with bit width " << bit_width << ".";
1370
0
    return diag(ss.str());
1371
0
  }
1372
1373
0
  return SPV_SUCCESS;
1374
0
}
1375
1376
spv_result_t BuiltInsValidator::ValidateF32Arr(
1377
    const Decoration& decoration, const Instruction& inst,
1378
    uint32_t num_components,
1379
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1380
0
  uint32_t underlying_type = 0;
1381
0
  if (spv_result_t error =
1382
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1383
0
    return error;
1384
0
  }
1385
1386
0
  return ValidateF32ArrHelper(decoration, inst, num_components, diag,
1387
0
                              underlying_type);
1388
0
}
1389
1390
spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Arr(
1391
    const Decoration& decoration, const Instruction& inst,
1392
    uint32_t num_components,
1393
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1394
0
  uint32_t underlying_type = 0;
1395
0
  if (spv_result_t error =
1396
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1397
0
    return error;
1398
0
  }
1399
1400
  // Strip an extra layer of arraying if present.
1401
0
  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
1402
0
    uint32_t subtype = _.FindDef(underlying_type)->word(2u);
1403
0
    if (_.GetIdOpcode(subtype) == spv::Op::OpTypeArray) {
1404
0
      underlying_type = subtype;
1405
0
    }
1406
0
  }
1407
1408
0
  return ValidateF32ArrHelper(decoration, inst, num_components, diag,
1409
0
                              underlying_type);
1410
0
}
1411
1412
spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
1413
    const Decoration& decoration, const Instruction& inst,
1414
    uint32_t num_components,
1415
    const std::function<spv_result_t(const std::string& message)>& diag,
1416
0
    uint32_t underlying_type) {
1417
0
  const Instruction* const type_inst = _.FindDef(underlying_type);
1418
0
  if (type_inst->opcode() != spv::Op::OpTypeArray) {
1419
0
    return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
1420
0
  }
1421
1422
0
  const uint32_t component_type = type_inst->word(2);
1423
0
  if (!_.IsFloatScalarType(component_type)) {
1424
0
    return diag(GetDefinitionDesc(decoration, inst) +
1425
0
                " components are not float scalar.");
1426
0
  }
1427
1428
0
  const uint32_t bit_width = _.GetBitWidth(component_type);
1429
0
  if (bit_width != 32) {
1430
0
    std::ostringstream ss;
1431
0
    ss << GetDefinitionDesc(decoration, inst)
1432
0
       << " has components with bit width " << bit_width << ".";
1433
0
    return diag(ss.str());
1434
0
  }
1435
1436
0
  if (num_components != 0) {
1437
0
    uint64_t actual_num_components = 0;
1438
0
    if (!_.EvalConstantValUint64(type_inst->word(3), &actual_num_components)) {
1439
0
      assert(0 && "Array type definition is corrupt");
1440
0
    }
1441
0
    if (actual_num_components != num_components) {
1442
0
      std::ostringstream ss;
1443
0
      ss << GetDefinitionDesc(decoration, inst) << " has "
1444
0
         << actual_num_components << " components.";
1445
0
      return diag(ss.str());
1446
0
    }
1447
0
  }
1448
1449
0
  return SPV_SUCCESS;
1450
0
}
1451
1452
spv_result_t BuiltInsValidator::ValidateF32Mat(
1453
    const Decoration& decoration, const Instruction& inst,
1454
    uint32_t req_num_rows, uint32_t req_num_columns,
1455
0
    const std::function<spv_result_t(const std::string& message)>& diag) {
1456
0
  uint32_t underlying_type = 0;
1457
0
  uint32_t num_rows = 0;
1458
0
  uint32_t num_cols = 0;
1459
0
  uint32_t col_type = 0;
1460
0
  uint32_t component_type = 0;
1461
0
  if (spv_result_t error =
1462
0
          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
1463
0
    return error;
1464
0
  }
1465
0
  if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
1466
0
                           &component_type) ||
1467
0
      num_rows != req_num_rows || num_cols != req_num_columns) {
1468
0
    std::ostringstream ss;
1469
0
    ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
1470
0
       << " and rows " << num_rows << " not equal to expected "
1471
0
       << req_num_columns << "x" << req_num_rows << ".";
1472
0
    return diag(ss.str());
1473
0
  }
1474
1475
0
  return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
1476
0
}
1477
1478
spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
1479
    int vuid, const char* comment, spv::ExecutionModel execution_model,
1480
    const Decoration& decoration, const Instruction& built_in_inst,
1481
    const Instruction& referenced_inst,
1482
0
    const Instruction& referenced_from_inst) {
1483
0
  if (function_id_) {
1484
0
    if (execution_models_.count(execution_model)) {
1485
0
      const char* execution_model_str = _.grammar().lookupOperandName(
1486
0
          SPV_OPERAND_TYPE_EXECUTION_MODEL, uint32_t(execution_model));
1487
0
      const char* built_in_str = _.grammar().lookupOperandName(
1488
0
          SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)decoration.builtin());
1489
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1490
0
             << (vuid < 0 ? std::string("") : _.VkErrorID(vuid)) << comment
1491
0
             << " " << GetIdDesc(referenced_inst) << " depends on "
1492
0
             << GetIdDesc(built_in_inst) << " which is decorated with BuiltIn "
1493
0
             << built_in_str << "."
1494
0
             << " Id <" << referenced_inst.id() << "> is later referenced by "
1495
0
             << GetIdDesc(referenced_from_inst) << " in function <"
1496
0
             << function_id_ << "> which is called with execution model "
1497
0
             << execution_model_str << ".";
1498
0
    }
1499
0
  } else {
1500
    // Propagate this rule to all dependant ids in the global scope.
1501
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1502
0
        std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this,
1503
0
                  vuid, comment, execution_model, decoration, built_in_inst,
1504
0
                  referenced_from_inst, std::placeholders::_1));
1505
0
  }
1506
0
  return SPV_SUCCESS;
1507
0
}
1508
1509
spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtDefinition(
1510
0
    const Decoration& decoration, const Instruction& inst) {
1511
  // Seed at reference checks with this built-in.
1512
0
  return ValidateClipOrCullDistanceAtReference(decoration, inst, inst, inst);
1513
0
}
1514
1515
spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
1516
    const Decoration& decoration, const Instruction& built_in_inst,
1517
    const Instruction& referenced_inst,
1518
0
    const Instruction& referenced_from_inst) {
1519
0
  uint32_t operand = (uint32_t)decoration.builtin();
1520
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1521
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1522
0
    if (storage_class != spv::StorageClass::Max &&
1523
0
        storage_class != spv::StorageClass::Input &&
1524
0
        storage_class != spv::StorageClass::Output) {
1525
0
      uint32_t vuid =
1526
0
          (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4190 : 4199;
1527
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1528
0
             << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
1529
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
1530
0
                                              operand)
1531
0
             << " to be only used for variables with Input or Output storage "
1532
0
                "class. "
1533
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1534
0
                                 referenced_from_inst)
1535
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1536
0
    }
1537
1538
0
    if (storage_class == spv::StorageClass::Input) {
1539
0
      assert(function_id_ == 0);
1540
0
      uint32_t vuid =
1541
0
          (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4188 : 4197;
1542
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1543
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
1544
0
          "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1545
0
          "used for variables with Input storage class if execution model is "
1546
0
          "Vertex.",
1547
0
          spv::ExecutionModel::Vertex, decoration, built_in_inst,
1548
0
          referenced_from_inst, std::placeholders::_1));
1549
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1550
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
1551
0
          "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1552
0
          "used for variables with Input storage class if execution model is "
1553
0
          "MeshNV.",
1554
0
          spv::ExecutionModel::MeshNV, decoration, built_in_inst,
1555
0
          referenced_from_inst, std::placeholders::_1));
1556
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1557
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
1558
0
          "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1559
0
          "used for variables with Input storage class if execution model is "
1560
0
          "MeshEXT.",
1561
0
          spv::ExecutionModel::MeshEXT, decoration, built_in_inst,
1562
0
          referenced_from_inst, std::placeholders::_1));
1563
0
    }
1564
1565
0
    if (storage_class == spv::StorageClass::Output) {
1566
0
      assert(function_id_ == 0);
1567
0
      uint32_t vuid =
1568
0
          (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4189 : 4198;
1569
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1570
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
1571
0
          "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1572
0
          "used for variables with Output storage class if execution model is "
1573
0
          "Fragment.",
1574
0
          spv::ExecutionModel::Fragment, decoration, built_in_inst,
1575
0
          referenced_from_inst, std::placeholders::_1));
1576
0
    }
1577
1578
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1579
0
      switch (execution_model) {
1580
0
        case spv::ExecutionModel::Fragment:
1581
0
        case spv::ExecutionModel::Vertex: {
1582
0
          if (spv_result_t error = ValidateF32Arr(
1583
0
                  decoration, built_in_inst, /* Any number of components */ 0,
1584
0
                  [this, &decoration, &referenced_from_inst](
1585
0
                      const std::string& message) -> spv_result_t {
1586
0
                    uint32_t vuid =
1587
0
                        (decoration.builtin() == spv::BuiltIn::ClipDistance)
1588
0
                            ? 4191
1589
0
                            : 4200;
1590
0
                    return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1591
0
                           << _.VkErrorID(vuid)
1592
0
                           << "According to the Vulkan spec BuiltIn "
1593
0
                           << _.grammar().lookupOperandName(
1594
0
                                  SPV_OPERAND_TYPE_BUILT_IN,
1595
0
                                  (uint32_t)decoration.builtin())
1596
0
                           << " variable needs to be a 32-bit float array. "
1597
0
                           << message;
1598
0
                  })) {
1599
0
            return error;
1600
0
          }
1601
0
          break;
1602
0
        }
1603
0
        case spv::ExecutionModel::TessellationControl:
1604
0
        case spv::ExecutionModel::TessellationEvaluation:
1605
0
        case spv::ExecutionModel::Geometry:
1606
0
        case spv::ExecutionModel::MeshNV:
1607
0
        case spv::ExecutionModel::MeshEXT: {
1608
0
          if (decoration.struct_member_index() != Decoration::kInvalidMember) {
1609
            // The outer level of array is applied on the variable.
1610
0
            if (spv_result_t error = ValidateF32Arr(
1611
0
                    decoration, built_in_inst, /* Any number of components */ 0,
1612
0
                    [this, &decoration, &referenced_from_inst](
1613
0
                        const std::string& message) -> spv_result_t {
1614
0
                      uint32_t vuid =
1615
0
                          (decoration.builtin() == spv::BuiltIn::ClipDistance)
1616
0
                              ? 4191
1617
0
                              : 4200;
1618
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
1619
0
                                    &referenced_from_inst)
1620
0
                             << _.VkErrorID(vuid)
1621
0
                             << "According to the Vulkan spec BuiltIn "
1622
0
                             << _.grammar().lookupOperandName(
1623
0
                                    SPV_OPERAND_TYPE_BUILT_IN,
1624
0
                                    (uint32_t)decoration.builtin())
1625
0
                             << " variable needs to be a 32-bit float array. "
1626
0
                             << message;
1627
0
                    })) {
1628
0
              return error;
1629
0
            }
1630
0
          } else {
1631
0
            if (spv_result_t error = ValidateOptionalArrayedF32Arr(
1632
0
                    decoration, built_in_inst, /* Any number of components */ 0,
1633
0
                    [this, &decoration, &referenced_from_inst](
1634
0
                        const std::string& message) -> spv_result_t {
1635
0
                      uint32_t vuid =
1636
0
                          (decoration.builtin() == spv::BuiltIn::ClipDistance)
1637
0
                              ? 4191
1638
0
                              : 4200;
1639
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
1640
0
                                    &referenced_from_inst)
1641
0
                             << _.VkErrorID(vuid)
1642
0
                             << "According to the Vulkan spec BuiltIn "
1643
0
                             << _.grammar().lookupOperandName(
1644
0
                                    SPV_OPERAND_TYPE_BUILT_IN,
1645
0
                                    (uint32_t)decoration.builtin())
1646
0
                             << " variable needs to be a 32-bit float array. "
1647
0
                             << message;
1648
0
                    })) {
1649
0
              return error;
1650
0
            }
1651
0
          }
1652
0
          break;
1653
0
        }
1654
1655
0
        default: {
1656
0
          uint32_t vuid = (decoration.builtin() == spv::BuiltIn::ClipDistance)
1657
0
                              ? 4187
1658
0
                              : 4196;
1659
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1660
0
                 << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
1661
0
                 << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
1662
0
                                                  operand)
1663
0
                 << " to be used only with Fragment, Vertex, "
1664
0
                    "TessellationControl, TessellationEvaluation or Geometry "
1665
0
                    "execution models. "
1666
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1667
0
                                     referenced_from_inst, execution_model);
1668
0
        }
1669
0
      }
1670
0
    }
1671
0
  }
1672
1673
0
  if (function_id_ == 0) {
1674
    // Propagate this rule to all dependant ids in the global scope.
1675
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1676
0
        std::bind(&BuiltInsValidator::ValidateClipOrCullDistanceAtReference,
1677
0
                  this, decoration, built_in_inst, referenced_from_inst,
1678
0
                  std::placeholders::_1));
1679
0
  }
1680
1681
0
  return SPV_SUCCESS;
1682
0
}
1683
1684
spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
1685
0
    const Decoration& decoration, const Instruction& inst) {
1686
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1687
0
    if (spv_result_t error = ValidateF32Vec(
1688
0
            decoration, inst, 4,
1689
0
            [this, &inst](const std::string& message) -> spv_result_t {
1690
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
1691
0
                     << _.VkErrorID(4212) << "According to the "
1692
0
                     << spvLogStringForEnv(_.context()->target_env)
1693
0
                     << " spec BuiltIn FragCoord "
1694
0
                        "variable needs to be a 4-component 32-bit float "
1695
0
                        "vector. "
1696
0
                     << message;
1697
0
            })) {
1698
0
      return error;
1699
0
    }
1700
0
  }
1701
1702
  // Seed at reference checks with this built-in.
1703
0
  return ValidateFragCoordAtReference(decoration, inst, inst, inst);
1704
0
}
1705
1706
spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
1707
    const Decoration& decoration, const Instruction& built_in_inst,
1708
    const Instruction& referenced_inst,
1709
0
    const Instruction& referenced_from_inst) {
1710
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1711
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1712
0
    if (storage_class != spv::StorageClass::Max &&
1713
0
        storage_class != spv::StorageClass::Input) {
1714
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1715
0
             << _.VkErrorID(4211) << spvLogStringForEnv(_.context()->target_env)
1716
0
             << " spec allows BuiltIn FragCoord to be only used for "
1717
0
                "variables with Input storage class. "
1718
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1719
0
                                 referenced_from_inst)
1720
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1721
0
    }
1722
1723
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1724
0
      if (execution_model != spv::ExecutionModel::Fragment) {
1725
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1726
0
               << _.VkErrorID(4210)
1727
0
               << spvLogStringForEnv(_.context()->target_env)
1728
0
               << " spec allows BuiltIn FragCoord to be used only with "
1729
0
                  "Fragment execution model. "
1730
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1731
0
                                   referenced_from_inst, execution_model);
1732
0
      }
1733
0
    }
1734
0
  }
1735
1736
0
  if (function_id_ == 0) {
1737
    // Propagate this rule to all dependant ids in the global scope.
1738
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1739
0
        &BuiltInsValidator::ValidateFragCoordAtReference, this, decoration,
1740
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
1741
0
  }
1742
1743
0
  return SPV_SUCCESS;
1744
0
}
1745
1746
spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
1747
0
    const Decoration& decoration, const Instruction& inst) {
1748
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1749
0
    if (spv_result_t error = ValidateF32(
1750
0
            decoration, inst,
1751
0
            [this, &inst](const std::string& message) -> spv_result_t {
1752
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
1753
0
                     << _.VkErrorID(4215) << "According to the "
1754
0
                     << spvLogStringForEnv(_.context()->target_env)
1755
0
                     << " spec BuiltIn FragDepth "
1756
0
                        "variable needs to be a 32-bit float scalar. "
1757
0
                     << message;
1758
0
            })) {
1759
0
      return error;
1760
0
    }
1761
0
  }
1762
1763
  // Seed at reference checks with this built-in.
1764
0
  return ValidateFragDepthAtReference(decoration, inst, inst, inst);
1765
0
}
1766
1767
spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
1768
    const Decoration& decoration, const Instruction& built_in_inst,
1769
    const Instruction& referenced_inst,
1770
0
    const Instruction& referenced_from_inst) {
1771
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1772
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1773
0
    if (storage_class != spv::StorageClass::Max &&
1774
0
        storage_class != spv::StorageClass::Output) {
1775
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1776
0
             << _.VkErrorID(4214) << spvLogStringForEnv(_.context()->target_env)
1777
0
             << " spec allows BuiltIn FragDepth to be only used for "
1778
0
                "variables with Output storage class. "
1779
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1780
0
                                 referenced_from_inst)
1781
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1782
0
    }
1783
1784
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1785
0
      if (execution_model != spv::ExecutionModel::Fragment) {
1786
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1787
0
               << _.VkErrorID(4213)
1788
0
               << spvLogStringForEnv(_.context()->target_env)
1789
0
               << " spec allows BuiltIn FragDepth to be used only with "
1790
0
                  "Fragment execution model. "
1791
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1792
0
                                   referenced_from_inst, execution_model);
1793
0
      }
1794
0
    }
1795
1796
0
    for (const uint32_t entry_point : *entry_points_) {
1797
      // Every entry point from which this function is called needs to have
1798
      // Execution Mode DepthReplacing.
1799
0
      const auto* modes = _.GetExecutionModes(entry_point);
1800
0
      if (!modes || !modes->count(spv::ExecutionMode::DepthReplacing)) {
1801
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1802
0
               << _.VkErrorID(4216)
1803
0
               << spvLogStringForEnv(_.context()->target_env)
1804
0
               << " spec requires DepthReplacing execution mode to be "
1805
0
                  "declared when using BuiltIn FragDepth. "
1806
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1807
0
                                   referenced_from_inst);
1808
0
      }
1809
0
    }
1810
0
  }
1811
1812
0
  if (function_id_ == 0) {
1813
    // Propagate this rule to all dependant ids in the global scope.
1814
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1815
0
        &BuiltInsValidator::ValidateFragDepthAtReference, this, decoration,
1816
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
1817
0
  }
1818
1819
0
  return SPV_SUCCESS;
1820
0
}
1821
1822
spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
1823
0
    const Decoration& decoration, const Instruction& inst) {
1824
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1825
0
    if (spv_result_t error = ValidateBool(
1826
0
            decoration, inst,
1827
0
            [this, &inst](const std::string& message) -> spv_result_t {
1828
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
1829
0
                     << _.VkErrorID(4231) << "According to the "
1830
0
                     << spvLogStringForEnv(_.context()->target_env)
1831
0
                     << " spec BuiltIn FrontFacing "
1832
0
                        "variable needs to be a bool scalar. "
1833
0
                     << message;
1834
0
            })) {
1835
0
      return error;
1836
0
    }
1837
0
  }
1838
1839
  // Seed at reference checks with this built-in.
1840
0
  return ValidateFrontFacingAtReference(decoration, inst, inst, inst);
1841
0
}
1842
1843
spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
1844
    const Decoration& decoration, const Instruction& built_in_inst,
1845
    const Instruction& referenced_inst,
1846
0
    const Instruction& referenced_from_inst) {
1847
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1848
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1849
0
    if (storage_class != spv::StorageClass::Max &&
1850
0
        storage_class != spv::StorageClass::Input) {
1851
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1852
0
             << _.VkErrorID(4230) << spvLogStringForEnv(_.context()->target_env)
1853
0
             << " spec allows BuiltIn FrontFacing to be only used for "
1854
0
                "variables with Input storage class. "
1855
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1856
0
                                 referenced_from_inst)
1857
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1858
0
    }
1859
1860
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1861
0
      if (execution_model != spv::ExecutionModel::Fragment) {
1862
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1863
0
               << _.VkErrorID(4229)
1864
0
               << spvLogStringForEnv(_.context()->target_env)
1865
0
               << " spec allows BuiltIn FrontFacing to be used only with "
1866
0
                  "Fragment execution model. "
1867
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1868
0
                                   referenced_from_inst, execution_model);
1869
0
      }
1870
0
    }
1871
0
  }
1872
1873
0
  if (function_id_ == 0) {
1874
    // Propagate this rule to all dependant ids in the global scope.
1875
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1876
0
        &BuiltInsValidator::ValidateFrontFacingAtReference, this, decoration,
1877
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
1878
0
  }
1879
1880
0
  return SPV_SUCCESS;
1881
0
}
1882
1883
spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition(
1884
0
    const Decoration& decoration, const Instruction& inst) {
1885
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1886
0
    if (spv_result_t error = ValidateBool(
1887
0
            decoration, inst,
1888
0
            [this, &inst](const std::string& message) -> spv_result_t {
1889
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
1890
0
                     << _.VkErrorID(4241)
1891
0
                     << "According to the Vulkan spec BuiltIn HelperInvocation "
1892
0
                        "variable needs to be a bool scalar. "
1893
0
                     << message;
1894
0
            })) {
1895
0
      return error;
1896
0
    }
1897
0
  }
1898
1899
  // Seed at reference checks with this built-in.
1900
0
  return ValidateHelperInvocationAtReference(decoration, inst, inst, inst);
1901
0
}
1902
1903
spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference(
1904
    const Decoration& decoration, const Instruction& built_in_inst,
1905
    const Instruction& referenced_inst,
1906
0
    const Instruction& referenced_from_inst) {
1907
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1908
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1909
0
    if (storage_class != spv::StorageClass::Max &&
1910
0
        storage_class != spv::StorageClass::Input) {
1911
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1912
0
             << _.VkErrorID(4240)
1913
0
             << "Vulkan spec allows BuiltIn HelperInvocation to be only used "
1914
0
                "for variables with Input storage class. "
1915
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1916
0
                                 referenced_from_inst)
1917
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1918
0
    }
1919
1920
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1921
0
      if (execution_model != spv::ExecutionModel::Fragment) {
1922
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1923
0
               << _.VkErrorID(4239)
1924
0
               << "Vulkan spec allows BuiltIn HelperInvocation to be used only "
1925
0
                  "with Fragment execution model. "
1926
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1927
0
                                   referenced_from_inst, execution_model);
1928
0
      }
1929
0
    }
1930
0
  }
1931
1932
0
  if (function_id_ == 0) {
1933
    // Propagate this rule to all dependant ids in the global scope.
1934
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1935
0
        std::bind(&BuiltInsValidator::ValidateHelperInvocationAtReference, this,
1936
0
                  decoration, built_in_inst, referenced_from_inst,
1937
0
                  std::placeholders::_1));
1938
0
  }
1939
1940
0
  return SPV_SUCCESS;
1941
0
}
1942
1943
spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition(
1944
0
    const Decoration& decoration, const Instruction& inst) {
1945
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1946
0
    if (spv_result_t error = ValidateI32(
1947
0
            decoration, inst,
1948
0
            [this, &inst](const std::string& message) -> spv_result_t {
1949
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
1950
0
                     << _.VkErrorID(4259)
1951
0
                     << "According to the Vulkan spec BuiltIn InvocationId "
1952
0
                        "variable needs to be a 32-bit int scalar. "
1953
0
                     << message;
1954
0
            })) {
1955
0
      return error;
1956
0
    }
1957
0
  }
1958
1959
  // Seed at reference checks with this built-in.
1960
0
  return ValidateInvocationIdAtReference(decoration, inst, inst, inst);
1961
0
}
1962
1963
spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
1964
    const Decoration& decoration, const Instruction& built_in_inst,
1965
    const Instruction& referenced_inst,
1966
0
    const Instruction& referenced_from_inst) {
1967
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
1968
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
1969
0
    if (storage_class != spv::StorageClass::Max &&
1970
0
        storage_class != spv::StorageClass::Input) {
1971
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1972
0
             << _.VkErrorID(4258)
1973
0
             << "Vulkan spec allows BuiltIn InvocationId to be only used for "
1974
0
                "variables with Input storage class. "
1975
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1976
0
                                 referenced_from_inst)
1977
0
             << " " << GetStorageClassDesc(referenced_from_inst);
1978
0
    }
1979
1980
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
1981
0
      if (execution_model != spv::ExecutionModel::TessellationControl &&
1982
0
          execution_model != spv::ExecutionModel::Geometry) {
1983
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
1984
0
               << _.VkErrorID(4257)
1985
0
               << "Vulkan spec allows BuiltIn InvocationId to be used only "
1986
0
                  "with TessellationControl or Geometry execution models. "
1987
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1988
0
                                   referenced_from_inst, execution_model);
1989
0
      }
1990
0
    }
1991
0
  }
1992
1993
0
  if (function_id_ == 0) {
1994
    // Propagate this rule to all dependant ids in the global scope.
1995
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
1996
0
        &BuiltInsValidator::ValidateInvocationIdAtReference, this, decoration,
1997
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
1998
0
  }
1999
2000
0
  return SPV_SUCCESS;
2001
0
}
2002
2003
spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
2004
0
    const Decoration& decoration, const Instruction& inst) {
2005
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2006
0
    if (spv_result_t error = ValidateI32(
2007
0
            decoration, inst,
2008
0
            [this, &inst](const std::string& message) -> spv_result_t {
2009
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2010
0
                     << _.VkErrorID(4265) << "According to the "
2011
0
                     << spvLogStringForEnv(_.context()->target_env)
2012
0
                     << " spec BuiltIn InstanceIndex "
2013
0
                        "variable needs to be a 32-bit int scalar. "
2014
0
                     << message;
2015
0
            })) {
2016
0
      return error;
2017
0
    }
2018
0
  }
2019
2020
  // Seed at reference checks with this built-in.
2021
0
  return ValidateInstanceIndexAtReference(decoration, inst, inst, inst);
2022
0
}
2023
2024
spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
2025
    const Decoration& decoration, const Instruction& built_in_inst,
2026
    const Instruction& referenced_inst,
2027
0
    const Instruction& referenced_from_inst) {
2028
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2029
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2030
0
    if (storage_class != spv::StorageClass::Max &&
2031
0
        storage_class != spv::StorageClass::Input) {
2032
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2033
0
             << _.VkErrorID(4264) << spvLogStringForEnv(_.context()->target_env)
2034
0
             << " spec allows BuiltIn InstanceIndex to be only used for "
2035
0
                "variables with Input storage class. "
2036
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2037
0
                                 referenced_from_inst)
2038
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2039
0
    }
2040
2041
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2042
0
      if (execution_model != spv::ExecutionModel::Vertex) {
2043
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2044
0
               << _.VkErrorID(4263)
2045
0
               << spvLogStringForEnv(_.context()->target_env)
2046
0
               << " spec allows BuiltIn InstanceIndex to be used only "
2047
0
                  "with Vertex execution model. "
2048
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2049
0
                                   referenced_from_inst, execution_model);
2050
0
      }
2051
0
    }
2052
0
  }
2053
2054
0
  if (function_id_ == 0) {
2055
    // Propagate this rule to all dependant ids in the global scope.
2056
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2057
0
        &BuiltInsValidator::ValidateInstanceIndexAtReference, this, decoration,
2058
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2059
0
  }
2060
2061
0
  return SPV_SUCCESS;
2062
0
}
2063
2064
spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition(
2065
0
    const Decoration& decoration, const Instruction& inst) {
2066
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2067
0
    if (spv_result_t error = ValidateI32(
2068
0
            decoration, inst,
2069
0
            [this, &inst](const std::string& message) -> spv_result_t {
2070
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2071
0
                     << _.VkErrorID(4310)
2072
0
                     << "According to the Vulkan spec BuiltIn PatchVertices "
2073
0
                        "variable needs to be a 32-bit int scalar. "
2074
0
                     << message;
2075
0
            })) {
2076
0
      return error;
2077
0
    }
2078
0
  }
2079
2080
  // Seed at reference checks with this built-in.
2081
0
  return ValidatePatchVerticesAtReference(decoration, inst, inst, inst);
2082
0
}
2083
2084
spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference(
2085
    const Decoration& decoration, const Instruction& built_in_inst,
2086
    const Instruction& referenced_inst,
2087
0
    const Instruction& referenced_from_inst) {
2088
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2089
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2090
0
    if (storage_class != spv::StorageClass::Max &&
2091
0
        storage_class != spv::StorageClass::Input) {
2092
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2093
0
             << _.VkErrorID(4309)
2094
0
             << "Vulkan spec allows BuiltIn PatchVertices to be only used for "
2095
0
                "variables with Input storage class. "
2096
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2097
0
                                 referenced_from_inst)
2098
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2099
0
    }
2100
2101
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2102
0
      if (execution_model != spv::ExecutionModel::TessellationControl &&
2103
0
          execution_model != spv::ExecutionModel::TessellationEvaluation) {
2104
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2105
0
               << _.VkErrorID(4308)
2106
0
               << "Vulkan spec allows BuiltIn PatchVertices to be used only "
2107
0
                  "with TessellationControl or TessellationEvaluation "
2108
0
                  "execution models. "
2109
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2110
0
                                   referenced_from_inst, execution_model);
2111
0
      }
2112
0
    }
2113
0
  }
2114
2115
0
  if (function_id_ == 0) {
2116
    // Propagate this rule to all dependant ids in the global scope.
2117
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2118
0
        &BuiltInsValidator::ValidatePatchVerticesAtReference, this, decoration,
2119
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2120
0
  }
2121
2122
0
  return SPV_SUCCESS;
2123
0
}
2124
2125
spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition(
2126
0
    const Decoration& decoration, const Instruction& inst) {
2127
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2128
0
    if (spv_result_t error = ValidateF32Vec(
2129
0
            decoration, inst, 2,
2130
0
            [this, &inst](const std::string& message) -> spv_result_t {
2131
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2132
0
                     << _.VkErrorID(4313)
2133
0
                     << "According to the Vulkan spec BuiltIn PointCoord "
2134
0
                        "variable needs to be a 2-component 32-bit float "
2135
0
                        "vector. "
2136
0
                     << message;
2137
0
            })) {
2138
0
      return error;
2139
0
    }
2140
0
  }
2141
2142
  // Seed at reference checks with this built-in.
2143
0
  return ValidatePointCoordAtReference(decoration, inst, inst, inst);
2144
0
}
2145
2146
spv_result_t BuiltInsValidator::ValidatePointCoordAtReference(
2147
    const Decoration& decoration, const Instruction& built_in_inst,
2148
    const Instruction& referenced_inst,
2149
0
    const Instruction& referenced_from_inst) {
2150
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2151
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2152
0
    if (storage_class != spv::StorageClass::Max &&
2153
0
        storage_class != spv::StorageClass::Input) {
2154
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2155
0
             << _.VkErrorID(4312)
2156
0
             << "Vulkan spec allows BuiltIn PointCoord to be only used for "
2157
0
                "variables with Input storage class. "
2158
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2159
0
                                 referenced_from_inst)
2160
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2161
0
    }
2162
2163
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2164
0
      if (execution_model != spv::ExecutionModel::Fragment) {
2165
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2166
0
               << _.VkErrorID(4311)
2167
0
               << "Vulkan spec allows BuiltIn PointCoord to be used only with "
2168
0
                  "Fragment execution model. "
2169
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2170
0
                                   referenced_from_inst, execution_model);
2171
0
      }
2172
0
    }
2173
0
  }
2174
2175
0
  if (function_id_ == 0) {
2176
    // Propagate this rule to all dependant ids in the global scope.
2177
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2178
0
        &BuiltInsValidator::ValidatePointCoordAtReference, this, decoration,
2179
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2180
0
  }
2181
2182
0
  return SPV_SUCCESS;
2183
0
}
2184
2185
spv_result_t BuiltInsValidator::ValidatePointSizeAtDefinition(
2186
0
    const Decoration& decoration, const Instruction& inst) {
2187
  // Seed at reference checks with this built-in.
2188
0
  return ValidatePointSizeAtReference(decoration, inst, inst, inst);
2189
0
}
2190
2191
spv_result_t BuiltInsValidator::ValidatePointSizeAtReference(
2192
    const Decoration& decoration, const Instruction& built_in_inst,
2193
    const Instruction& referenced_inst,
2194
0
    const Instruction& referenced_from_inst) {
2195
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2196
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2197
0
    if (storage_class != spv::StorageClass::Max &&
2198
0
        storage_class != spv::StorageClass::Input &&
2199
0
        storage_class != spv::StorageClass::Output) {
2200
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2201
0
             << _.VkErrorID(4316)
2202
0
             << "Vulkan spec allows BuiltIn PointSize to be only used for "
2203
0
                "variables with Input or Output storage class. "
2204
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2205
0
                                 referenced_from_inst)
2206
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2207
0
    }
2208
2209
0
    if (storage_class == spv::StorageClass::Input) {
2210
0
      assert(function_id_ == 0);
2211
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2212
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4315,
2213
0
          "Vulkan spec doesn't allow BuiltIn PointSize to be used for "
2214
0
          "variables with Input storage class if execution model is "
2215
0
          "Vertex.",
2216
0
          spv::ExecutionModel::Vertex, decoration, built_in_inst,
2217
0
          referenced_from_inst, std::placeholders::_1));
2218
0
    }
2219
2220
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2221
0
      switch (execution_model) {
2222
0
        case spv::ExecutionModel::Vertex: {
2223
0
          if (spv_result_t error = ValidateF32(
2224
0
                  decoration, built_in_inst,
2225
0
                  [this, &referenced_from_inst](
2226
0
                      const std::string& message) -> spv_result_t {
2227
0
                    return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2228
0
                           << _.VkErrorID(4317)
2229
0
                           << "According to the Vulkan spec BuiltIn PointSize "
2230
0
                              "variable needs to be a 32-bit float scalar. "
2231
0
                           << message;
2232
0
                  })) {
2233
0
            return error;
2234
0
          }
2235
0
          break;
2236
0
        }
2237
0
        case spv::ExecutionModel::TessellationControl:
2238
0
        case spv::ExecutionModel::TessellationEvaluation:
2239
0
        case spv::ExecutionModel::Geometry:
2240
0
        case spv::ExecutionModel::MeshNV:
2241
0
        case spv::ExecutionModel::MeshEXT: {
2242
          // PointSize can be a per-vertex variable for tessellation control,
2243
          // tessellation evaluation and geometry shader stages. In such cases
2244
          // variables will have an array of 32-bit floats.
2245
0
          if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2246
            // The array is on the variable, so this must be a 32-bit float.
2247
0
            if (spv_result_t error = ValidateF32(
2248
0
                    decoration, built_in_inst,
2249
0
                    [this, &referenced_from_inst](
2250
0
                        const std::string& message) -> spv_result_t {
2251
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
2252
0
                                    &referenced_from_inst)
2253
0
                             << _.VkErrorID(4317)
2254
0
                             << "According to the Vulkan spec BuiltIn "
2255
0
                                "PointSize variable needs to be a 32-bit "
2256
0
                                "float scalar. "
2257
0
                             << message;
2258
0
                    })) {
2259
0
              return error;
2260
0
            }
2261
0
          } else {
2262
0
            if (spv_result_t error = ValidateOptionalArrayedF32(
2263
0
                    decoration, built_in_inst,
2264
0
                    [this, &referenced_from_inst](
2265
0
                        const std::string& message) -> spv_result_t {
2266
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
2267
0
                                    &referenced_from_inst)
2268
0
                             << _.VkErrorID(4317)
2269
0
                             << "According to the Vulkan spec BuiltIn "
2270
0
                                "PointSize variable needs to be a 32-bit "
2271
0
                                "float scalar. "
2272
0
                             << message;
2273
0
                    })) {
2274
0
              return error;
2275
0
            }
2276
0
          }
2277
0
          break;
2278
0
        }
2279
2280
0
        default: {
2281
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2282
0
                 << _.VkErrorID(4314)
2283
0
                 << "Vulkan spec allows BuiltIn PointSize to be used only with "
2284
0
                    "Vertex, TessellationControl, TessellationEvaluation or "
2285
0
                    "Geometry execution models. "
2286
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2287
0
                                     referenced_from_inst, execution_model);
2288
0
        }
2289
0
      }
2290
0
    }
2291
0
  }
2292
2293
0
  if (function_id_ == 0) {
2294
    // Propagate this rule to all dependant ids in the global scope.
2295
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2296
0
        &BuiltInsValidator::ValidatePointSizeAtReference, this, decoration,
2297
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2298
0
  }
2299
2300
0
  return SPV_SUCCESS;
2301
0
}
2302
2303
spv_result_t BuiltInsValidator::ValidatePositionAtDefinition(
2304
0
    const Decoration& decoration, const Instruction& inst) {
2305
  // Seed at reference checks with this built-in.
2306
0
  return ValidatePositionAtReference(decoration, inst, inst, inst);
2307
0
}
2308
2309
spv_result_t BuiltInsValidator::ValidatePositionAtReference(
2310
    const Decoration& decoration, const Instruction& built_in_inst,
2311
    const Instruction& referenced_inst,
2312
0
    const Instruction& referenced_from_inst) {
2313
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2314
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2315
0
    if (storage_class != spv::StorageClass::Max &&
2316
0
        storage_class != spv::StorageClass::Input &&
2317
0
        storage_class != spv::StorageClass::Output) {
2318
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2319
0
             << _.VkErrorID(4320) << "Vulkan spec allows BuiltIn Position to be only used for "
2320
0
                "variables with Input or Output storage class. "
2321
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2322
0
                                 referenced_from_inst)
2323
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2324
0
    }
2325
2326
0
    if (storage_class == spv::StorageClass::Input) {
2327
0
      assert(function_id_ == 0);
2328
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2329
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
2330
0
          "Vulkan spec doesn't allow BuiltIn Position to be used "
2331
0
          "for variables "
2332
0
          "with Input storage class if execution model is Vertex.",
2333
0
          spv::ExecutionModel::Vertex, decoration, built_in_inst,
2334
0
          referenced_from_inst, std::placeholders::_1));
2335
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2336
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
2337
0
          "Vulkan spec doesn't allow BuiltIn Position to be used "
2338
0
          "for variables "
2339
0
          "with Input storage class if execution model is MeshNV.",
2340
0
          spv::ExecutionModel::MeshNV, decoration, built_in_inst,
2341
0
          referenced_from_inst, std::placeholders::_1));
2342
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2343
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4319,
2344
0
          "Vulkan spec doesn't allow BuiltIn Position to be used "
2345
0
          "for variables "
2346
0
          "with Input storage class if execution model is MeshEXT.",
2347
0
          spv::ExecutionModel::MeshEXT, decoration, built_in_inst,
2348
0
          referenced_from_inst, std::placeholders::_1));
2349
0
    }
2350
2351
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2352
0
      switch (execution_model) {
2353
0
        case spv::ExecutionModel::Vertex: {
2354
0
          if (spv_result_t error = ValidateF32Vec(
2355
0
                  decoration, built_in_inst, 4,
2356
0
                  [this, &referenced_from_inst](
2357
0
                      const std::string& message) -> spv_result_t {
2358
0
                    return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2359
0
                           << _.VkErrorID(4321)
2360
0
                           << "According to the Vulkan spec BuiltIn Position "
2361
0
                              "variable needs to be a 4-component 32-bit float "
2362
0
                              "vector. "
2363
0
                           << message;
2364
0
                  })) {
2365
0
            return error;
2366
0
          }
2367
0
          break;
2368
0
        }
2369
0
        case spv::ExecutionModel::Geometry:
2370
0
        case spv::ExecutionModel::TessellationControl:
2371
0
        case spv::ExecutionModel::TessellationEvaluation:
2372
0
        case spv::ExecutionModel::MeshNV:
2373
0
        case spv::ExecutionModel::MeshEXT: {
2374
          // Position can be a per-vertex variable for tessellation control,
2375
          // tessellation evaluation, geometry and mesh shader stages. In such
2376
          // cases variables will have an array of 4-component 32-bit float
2377
          // vectors.
2378
0
          if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2379
            // The array is on the variable, so this must be a 4-component
2380
            // 32-bit float vector.
2381
0
            if (spv_result_t error = ValidateF32Vec(
2382
0
                    decoration, built_in_inst, 4,
2383
0
                    [this, &referenced_from_inst](
2384
0
                        const std::string& message) -> spv_result_t {
2385
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
2386
0
                                    &referenced_from_inst)
2387
0
                             << _.VkErrorID(4321)
2388
0
                             << "According to the Vulkan spec BuiltIn Position "
2389
0
                                "variable needs to be a 4-component 32-bit "
2390
0
                                "float vector. "
2391
0
                             << message;
2392
0
                    })) {
2393
0
              return error;
2394
0
            }
2395
0
          } else {
2396
0
            if (spv_result_t error = ValidateOptionalArrayedF32Vec(
2397
0
                    decoration, built_in_inst, 4,
2398
0
                    [this, &referenced_from_inst](
2399
0
                        const std::string& message) -> spv_result_t {
2400
0
                      return _.diag(SPV_ERROR_INVALID_DATA,
2401
0
                                    &referenced_from_inst)
2402
0
                             << _.VkErrorID(4321)
2403
0
                             << "According to the Vulkan spec BuiltIn Position "
2404
0
                                "variable needs to be a 4-component 32-bit "
2405
0
                                "float vector. "
2406
0
                             << message;
2407
0
                    })) {
2408
0
              return error;
2409
0
            }
2410
0
          }
2411
0
          break;
2412
0
        }
2413
2414
0
        default: {
2415
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2416
0
                 << _.VkErrorID(4318)
2417
0
                 << "Vulkan spec allows BuiltIn Position to be used only "
2418
0
                    "with Vertex, TessellationControl, TessellationEvaluation"
2419
0
                    " or Geometry execution models. "
2420
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2421
0
                                     referenced_from_inst, execution_model);
2422
0
        }
2423
0
      }
2424
0
    }
2425
0
  }
2426
2427
0
  if (function_id_ == 0) {
2428
    // Propagate this rule to all dependant ids in the global scope.
2429
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2430
0
        &BuiltInsValidator::ValidatePositionAtReference, this, decoration,
2431
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2432
0
  }
2433
2434
0
  return SPV_SUCCESS;
2435
0
}
2436
2437
spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
2438
0
    const Decoration& decoration, const Instruction& inst) {
2439
0
  return ValidatePrimitiveIdAtReference(decoration, inst, inst, inst);
2440
0
}
2441
2442
spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
2443
    const Decoration& decoration, const Instruction& built_in_inst,
2444
    const Instruction& referenced_inst,
2445
0
    const Instruction& referenced_from_inst) {
2446
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2447
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2448
0
    if (storage_class != spv::StorageClass::Max &&
2449
0
        storage_class != spv::StorageClass::Input &&
2450
0
        storage_class != spv::StorageClass::Output) {
2451
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2452
0
             << "Vulkan spec allows BuiltIn PrimitiveId to be only used for "
2453
0
                "variables with Input or Output storage class. "
2454
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2455
0
                                 referenced_from_inst)
2456
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2457
0
    }
2458
2459
0
    if (storage_class == spv::StorageClass::Output) {
2460
0
      assert(function_id_ == 0);
2461
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2462
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2463
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2464
0
          "variables with Output storage class if execution model is "
2465
0
          "TessellationControl.",
2466
0
          spv::ExecutionModel::TessellationControl, decoration, built_in_inst,
2467
0
          referenced_from_inst, std::placeholders::_1));
2468
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2469
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2470
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2471
0
          "variables with Output storage class if execution model is "
2472
0
          "TessellationEvaluation.",
2473
0
          spv::ExecutionModel::TessellationEvaluation, decoration, built_in_inst,
2474
0
          referenced_from_inst, std::placeholders::_1));
2475
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2476
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2477
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2478
0
          "variables with Output storage class if execution model is "
2479
0
          "Fragment.",
2480
0
          spv::ExecutionModel::Fragment, decoration, built_in_inst,
2481
0
          referenced_from_inst, std::placeholders::_1));
2482
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2483
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2484
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2485
0
          "variables with Output storage class if execution model is "
2486
0
          "IntersectionKHR.",
2487
0
          spv::ExecutionModel::IntersectionKHR, decoration, built_in_inst,
2488
0
          referenced_from_inst, std::placeholders::_1));
2489
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2490
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2491
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2492
0
          "variables with Output storage class if execution model is "
2493
0
          "AnyHitKHR.",
2494
0
          spv::ExecutionModel::AnyHitKHR, decoration, built_in_inst,
2495
0
          referenced_from_inst, std::placeholders::_1));
2496
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2497
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
2498
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2499
0
          "variables with Output storage class if execution model is "
2500
0
          "ClosestHitKHR.",
2501
0
          spv::ExecutionModel::ClosestHitKHR, decoration, built_in_inst,
2502
0
          referenced_from_inst, std::placeholders::_1));
2503
0
    }
2504
2505
0
    if (!_.HasCapability(spv::Capability::MeshShadingEXT) &&
2506
0
        !_.HasCapability(spv::Capability::MeshShadingNV) &&
2507
0
        !_.HasCapability(spv::Capability::Geometry) &&
2508
0
        !_.HasCapability(spv::Capability::Tessellation)) {
2509
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2510
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4333,
2511
0
          "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2512
0
          "variables in the Fragment execution model unless it declares "
2513
0
          "Geometry, Tessellation, or MeshShader capabilities.",
2514
0
          spv::ExecutionModel::Fragment, decoration, built_in_inst,
2515
0
          referenced_from_inst, std::placeholders::_1));
2516
0
    }
2517
2518
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2519
0
        &BuiltInsValidator::ValidateMeshBuiltinInterfaceRules, this, decoration,
2520
0
        built_in_inst, spv::Op::OpTypeInt, std::placeholders::_1));
2521
2522
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
2523
0
        std::bind(&BuiltInsValidator::ValidateNonMeshInterfaceRules, this,
2524
0
                  decoration, built_in_inst, std::placeholders::_1));
2525
2526
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2527
0
      switch (execution_model) {
2528
0
        case spv::ExecutionModel::Fragment:
2529
0
        case spv::ExecutionModel::TessellationControl:
2530
0
        case spv::ExecutionModel::TessellationEvaluation:
2531
0
        case spv::ExecutionModel::Geometry:
2532
0
        case spv::ExecutionModel::MeshNV:
2533
0
        case spv::ExecutionModel::MeshEXT:
2534
0
        case spv::ExecutionModel::IntersectionKHR:
2535
0
        case spv::ExecutionModel::AnyHitKHR:
2536
0
        case spv::ExecutionModel::ClosestHitKHR: {
2537
          // Ok.
2538
0
          break;
2539
0
        }
2540
2541
0
        default: {
2542
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2543
0
                 << _.VkErrorID(4330)
2544
0
                 << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
2545
0
                    "with Fragment, TessellationControl, "
2546
0
                    "TessellationEvaluation, Geometry, MeshNV, MeshEXT, "
2547
0
                    "IntersectionKHR, AnyHitKHR, and ClosestHitKHR execution models. "
2548
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2549
0
                                     referenced_from_inst, execution_model);
2550
0
        }
2551
0
      }
2552
0
    }
2553
0
  }
2554
2555
0
  if (function_id_ == 0) {
2556
    // Propagate this rule to all dependant ids in the global scope.
2557
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2558
0
        &BuiltInsValidator::ValidatePrimitiveIdAtReference, this, decoration,
2559
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2560
0
  }
2561
2562
0
  return SPV_SUCCESS;
2563
0
}
2564
2565
spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition(
2566
0
    const Decoration& decoration, const Instruction& inst) {
2567
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2568
0
    if (spv_result_t error = ValidateI32(
2569
0
            decoration, inst,
2570
0
            [this, &inst](const std::string& message) -> spv_result_t {
2571
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2572
0
                     << _.VkErrorID(4356)
2573
0
                     << "According to the Vulkan spec BuiltIn SampleId "
2574
0
                        "variable needs to be a 32-bit int scalar. "
2575
0
                     << message;
2576
0
            })) {
2577
0
      return error;
2578
0
    }
2579
0
  }
2580
2581
  // Seed at reference checks with this built-in.
2582
0
  return ValidateSampleIdAtReference(decoration, inst, inst, inst);
2583
0
}
2584
2585
spv_result_t BuiltInsValidator::ValidateSampleIdAtReference(
2586
    const Decoration& decoration, const Instruction& built_in_inst,
2587
    const Instruction& referenced_inst,
2588
0
    const Instruction& referenced_from_inst) {
2589
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2590
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2591
0
    if (storage_class != spv::StorageClass::Max &&
2592
0
        storage_class != spv::StorageClass::Input) {
2593
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2594
0
             << _.VkErrorID(4355)
2595
0
             << "Vulkan spec allows BuiltIn SampleId to be only used for "
2596
0
                "variables with Input storage class. "
2597
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2598
0
                                 referenced_from_inst)
2599
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2600
0
    }
2601
2602
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2603
0
      if (execution_model != spv::ExecutionModel::Fragment) {
2604
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2605
0
               << _.VkErrorID(4354)
2606
0
               << "Vulkan spec allows BuiltIn SampleId to be used only with "
2607
0
                  "Fragment execution model. "
2608
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2609
0
                                   referenced_from_inst, execution_model);
2610
0
      }
2611
0
    }
2612
0
  }
2613
2614
0
  if (function_id_ == 0) {
2615
    // Propagate this rule to all dependant ids in the global scope.
2616
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2617
0
        &BuiltInsValidator::ValidateSampleIdAtReference, this, decoration,
2618
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2619
0
  }
2620
2621
0
  return SPV_SUCCESS;
2622
0
}
2623
2624
spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition(
2625
0
    const Decoration& decoration, const Instruction& inst) {
2626
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2627
0
    if (spv_result_t error = ValidateI32Arr(
2628
0
            decoration, inst,
2629
0
            [this, &inst](const std::string& message) -> spv_result_t {
2630
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2631
0
                     << _.VkErrorID(4359)
2632
0
                     << "According to the Vulkan spec BuiltIn SampleMask "
2633
0
                        "variable needs to be a 32-bit int array. "
2634
0
                     << message;
2635
0
            })) {
2636
0
      return error;
2637
0
    }
2638
0
  }
2639
2640
  // Seed at reference checks with this built-in.
2641
0
  return ValidateSampleMaskAtReference(decoration, inst, inst, inst);
2642
0
}
2643
2644
spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference(
2645
    const Decoration& decoration, const Instruction& built_in_inst,
2646
    const Instruction& referenced_inst,
2647
0
    const Instruction& referenced_from_inst) {
2648
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2649
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2650
0
    if (storage_class != spv::StorageClass::Max &&
2651
0
        storage_class != spv::StorageClass::Input &&
2652
0
        storage_class != spv::StorageClass::Output) {
2653
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2654
0
             << _.VkErrorID(4358)
2655
0
             << "Vulkan spec allows BuiltIn SampleMask to be only used for "
2656
0
                "variables with Input or Output storage class. "
2657
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2658
0
                                 referenced_from_inst)
2659
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2660
0
    }
2661
2662
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2663
0
      if (execution_model != spv::ExecutionModel::Fragment) {
2664
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2665
0
               << _.VkErrorID(4357)
2666
0
               << "Vulkan spec allows BuiltIn SampleMask to be used only "
2667
0
                  "with "
2668
0
                  "Fragment execution model. "
2669
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2670
0
                                   referenced_from_inst, execution_model);
2671
0
      }
2672
0
    }
2673
0
  }
2674
2675
0
  if (function_id_ == 0) {
2676
    // Propagate this rule to all dependant ids in the global scope.
2677
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2678
0
        &BuiltInsValidator::ValidateSampleMaskAtReference, this, decoration,
2679
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2680
0
  }
2681
2682
0
  return SPV_SUCCESS;
2683
0
}
2684
2685
spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition(
2686
0
    const Decoration& decoration, const Instruction& inst) {
2687
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2688
0
    if (spv_result_t error = ValidateF32Vec(
2689
0
            decoration, inst, 2,
2690
0
            [this, &inst](const std::string& message) -> spv_result_t {
2691
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2692
0
                     << _.VkErrorID(4362)
2693
0
                     << "According to the Vulkan spec BuiltIn SamplePosition "
2694
0
                        "variable needs to be a 2-component 32-bit float "
2695
0
                        "vector. "
2696
0
                     << message;
2697
0
            })) {
2698
0
      return error;
2699
0
    }
2700
0
  }
2701
2702
  // Seed at reference checks with this built-in.
2703
0
  return ValidateSamplePositionAtReference(decoration, inst, inst, inst);
2704
0
}
2705
2706
spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference(
2707
    const Decoration& decoration, const Instruction& built_in_inst,
2708
    const Instruction& referenced_inst,
2709
0
    const Instruction& referenced_from_inst) {
2710
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2711
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2712
0
    if (storage_class != spv::StorageClass::Max &&
2713
0
        storage_class != spv::StorageClass::Input) {
2714
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2715
0
             << _.VkErrorID(4361)
2716
0
             << "Vulkan spec allows BuiltIn SamplePosition to be only used "
2717
0
                "for "
2718
0
                "variables with Input storage class. "
2719
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2720
0
                                 referenced_from_inst)
2721
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2722
0
    }
2723
2724
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2725
0
      if (execution_model != spv::ExecutionModel::Fragment) {
2726
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2727
0
               << _.VkErrorID(4360)
2728
0
               << "Vulkan spec allows BuiltIn SamplePosition to be used only "
2729
0
                  "with "
2730
0
                  "Fragment execution model. "
2731
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2732
0
                                   referenced_from_inst, execution_model);
2733
0
      }
2734
0
    }
2735
0
  }
2736
2737
0
  if (function_id_ == 0) {
2738
    // Propagate this rule to all dependant ids in the global scope.
2739
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2740
0
        &BuiltInsValidator::ValidateSamplePositionAtReference, this, decoration,
2741
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2742
0
  }
2743
2744
0
  return SPV_SUCCESS;
2745
0
}
2746
2747
spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition(
2748
0
    const Decoration& decoration, const Instruction& inst) {
2749
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2750
0
    if (spv_result_t error = ValidateF32Vec(
2751
0
            decoration, inst, 3,
2752
0
            [this, &inst](const std::string& message) -> spv_result_t {
2753
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2754
0
                     << _.VkErrorID(4389)
2755
0
                     << "According to the Vulkan spec BuiltIn TessCoord "
2756
0
                        "variable needs to be a 3-component 32-bit float "
2757
0
                        "vector. "
2758
0
                     << message;
2759
0
            })) {
2760
0
      return error;
2761
0
    }
2762
0
  }
2763
2764
  // Seed at reference checks with this built-in.
2765
0
  return ValidateTessCoordAtReference(decoration, inst, inst, inst);
2766
0
}
2767
2768
spv_result_t BuiltInsValidator::ValidateTessCoordAtReference(
2769
    const Decoration& decoration, const Instruction& built_in_inst,
2770
    const Instruction& referenced_inst,
2771
0
    const Instruction& referenced_from_inst) {
2772
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2773
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2774
0
    if (storage_class != spv::StorageClass::Max &&
2775
0
        storage_class != spv::StorageClass::Input) {
2776
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2777
0
             << _.VkErrorID(4388)
2778
0
             << "Vulkan spec allows BuiltIn TessCoord to be only used for "
2779
0
                "variables with Input storage class. "
2780
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2781
0
                                 referenced_from_inst)
2782
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2783
0
    }
2784
2785
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2786
0
      if (execution_model != spv::ExecutionModel::TessellationEvaluation) {
2787
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2788
0
               << _.VkErrorID(4387)
2789
0
               << "Vulkan spec allows BuiltIn TessCoord to be used only with "
2790
0
                  "TessellationEvaluation execution model. "
2791
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2792
0
                                   referenced_from_inst, execution_model);
2793
0
      }
2794
0
    }
2795
0
  }
2796
2797
0
  if (function_id_ == 0) {
2798
    // Propagate this rule to all dependant ids in the global scope.
2799
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2800
0
        &BuiltInsValidator::ValidateTessCoordAtReference, this, decoration,
2801
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2802
0
  }
2803
2804
0
  return SPV_SUCCESS;
2805
0
}
2806
2807
spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
2808
0
    const Decoration& decoration, const Instruction& inst) {
2809
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2810
0
    if (spv_result_t error = ValidateF32Arr(
2811
0
            decoration, inst, 4,
2812
0
            [this, &inst](const std::string& message) -> spv_result_t {
2813
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2814
0
                     << _.VkErrorID(4393)
2815
0
                     << "According to the Vulkan spec BuiltIn TessLevelOuter "
2816
0
                        "variable needs to be a 4-component 32-bit float "
2817
0
                        "array. "
2818
0
                     << message;
2819
0
            })) {
2820
0
      return error;
2821
0
    }
2822
2823
0
    if (!_.HasDecoration(inst.id(), spv::Decoration::Patch)) {
2824
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2825
0
             << _.VkErrorID(10880)
2826
0
             << "BuiltIn TessLevelOuter variable needs to also have a Patch "
2827
0
                "decoration.";
2828
0
    }
2829
0
  }
2830
2831
  // Seed at reference checks with this built-in.
2832
0
  return ValidateTessLevelAtReference(decoration, inst, inst, inst);
2833
0
}
2834
2835
spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
2836
0
    const Decoration& decoration, const Instruction& inst) {
2837
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2838
0
    if (spv_result_t error = ValidateF32Arr(
2839
0
            decoration, inst, 2,
2840
0
            [this, &inst](const std::string& message) -> spv_result_t {
2841
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2842
0
                     << _.VkErrorID(4397)
2843
0
                     << "According to the Vulkan spec BuiltIn TessLevelInner "
2844
0
                        "variable needs to be a 2-component 32-bit float "
2845
0
                        "array. "
2846
0
                     << message;
2847
0
            })) {
2848
0
      return error;
2849
0
    }
2850
2851
0
    if (!_.HasDecoration(inst.id(), spv::Decoration::Patch)) {
2852
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2853
0
             << _.VkErrorID(10880)
2854
0
             << "BuiltIn TessLevelInner variable needs to also have a Patch "
2855
0
                "decoration.";
2856
0
    }
2857
0
  }
2858
2859
  // Seed at reference checks with this built-in.
2860
0
  return ValidateTessLevelAtReference(decoration, inst, inst, inst);
2861
0
}
2862
2863
spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
2864
    const Decoration& decoration, const Instruction& built_in_inst,
2865
    const Instruction& referenced_inst,
2866
0
    const Instruction& referenced_from_inst) {
2867
0
  uint32_t operand = (uint32_t)decoration.builtin();
2868
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2869
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
2870
0
    if (storage_class != spv::StorageClass::Max &&
2871
0
        storage_class != spv::StorageClass::Input &&
2872
0
        storage_class != spv::StorageClass::Output) {
2873
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2874
0
             << "Vulkan spec allows BuiltIn "
2875
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
2876
0
                                              operand)
2877
0
             << " to be only used for variables with Input or Output storage "
2878
0
                "class. "
2879
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2880
0
                                 referenced_from_inst)
2881
0
             << " " << GetStorageClassDesc(referenced_from_inst);
2882
0
    }
2883
2884
0
    if (storage_class == spv::StorageClass::Input) {
2885
0
      assert(function_id_ == 0);
2886
0
      uint32_t vuid =
2887
0
          (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4391 : 4395;
2888
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2889
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
2890
0
          "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
2891
0
          "used "
2892
0
          "for variables with Input storage class if execution model is "
2893
0
          "TessellationControl.",
2894
0
          spv::ExecutionModel::TessellationControl, decoration, built_in_inst,
2895
0
          referenced_from_inst, std::placeholders::_1));
2896
0
    }
2897
2898
0
    if (storage_class == spv::StorageClass::Output) {
2899
0
      assert(function_id_ == 0);
2900
0
      uint32_t vuid =
2901
0
          (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4392 : 4396;
2902
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2903
0
          &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid,
2904
0
          "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
2905
0
          "used "
2906
0
          "for variables with Output storage class if execution model is "
2907
0
          "TessellationEvaluation.",
2908
0
          spv::ExecutionModel::TessellationEvaluation, decoration, built_in_inst,
2909
0
          referenced_from_inst, std::placeholders::_1));
2910
0
    }
2911
2912
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
2913
0
      switch (execution_model) {
2914
0
        case spv::ExecutionModel::TessellationControl:
2915
0
        case spv::ExecutionModel::TessellationEvaluation: {
2916
          // Ok.
2917
0
          break;
2918
0
        }
2919
2920
0
        default: {
2921
0
          uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::TessLevelOuter) ? 4390 : 4394;
2922
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
2923
0
                 << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
2924
0
                 << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
2925
0
                                                  operand)
2926
0
                 << " to be used only with TessellationControl or "
2927
0
                    "TessellationEvaluation execution models. "
2928
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2929
0
                                     referenced_from_inst, execution_model);
2930
0
        }
2931
0
      }
2932
0
    }
2933
0
  }
2934
2935
0
  if (function_id_ == 0) {
2936
    // Propagate this rule to all dependant ids in the global scope.
2937
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
2938
0
        &BuiltInsValidator::ValidateTessLevelAtReference, this, decoration,
2939
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
2940
0
  }
2941
2942
0
  return SPV_SUCCESS;
2943
0
}
2944
2945
spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
2946
0
    const Decoration& decoration, const Instruction& inst) {
2947
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2948
0
    if (spv_result_t error = ValidateI32(
2949
0
            decoration, inst,
2950
0
            [this, &inst](const std::string& message) -> spv_result_t {
2951
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2952
0
                     << _.VkErrorID(4400) << "According to the "
2953
0
                     << spvLogStringForEnv(_.context()->target_env)
2954
0
                     << " spec BuiltIn VertexIndex variable needs to be a "
2955
0
                        "32-bit int scalar. "
2956
0
                     << message;
2957
0
            })) {
2958
0
      return error;
2959
0
    }
2960
0
  }
2961
2962
  // Seed at reference checks with this built-in.
2963
0
  return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
2964
0
}
2965
2966
spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
2967
0
    const Decoration& decoration, const Instruction& inst) {
2968
0
  (void)decoration;
2969
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2970
0
    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2971
0
           << "Vulkan spec doesn't allow BuiltIn VertexId "
2972
0
              "to be used.";
2973
0
  }
2974
2975
0
  return SPV_SUCCESS;
2976
0
}
2977
2978
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
2979
0
    const Decoration& decoration, const Instruction& inst) {
2980
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
2981
0
    if (spv_result_t error = ValidateI32(
2982
0
            decoration, inst,
2983
0
            [this, &inst](const std::string& message) -> spv_result_t {
2984
0
              uint32_t vuid = GetVUIDForBuiltin(
2985
0
                  spv::BuiltIn::LocalInvocationIndex, VUIDErrorType);
2986
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
2987
0
                     << _.VkErrorID(vuid)
2988
0
                     << "According to the Vulkan spec BuiltIn "
2989
0
                        "LocalInvocationIndex variable needs to be a 32-bit "
2990
0
                        "int scalar. "
2991
0
                     << message;
2992
0
            })) {
2993
0
      return error;
2994
0
    }
2995
0
  }
2996
2997
  // Seed at reference checks with this built-in.
2998
0
  return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst);
2999
0
}
3000
3001
spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
3002
    const Decoration& decoration, const Instruction& built_in_inst,
3003
    const Instruction& referenced_inst,
3004
0
    const Instruction& referenced_from_inst) {
3005
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3006
0
    const spv::StorageClass storage_class =
3007
0
        GetStorageClass(referenced_from_inst);
3008
0
    if (storage_class != spv::StorageClass::Max &&
3009
0
        storage_class != spv::StorageClass::Input) {
3010
0
      uint32_t vuid = GetVUIDForBuiltin(spv::BuiltIn::LocalInvocationIndex,
3011
0
                                        VUIDErrorStorageClass);
3012
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3013
0
             << _.VkErrorID(vuid)
3014
0
             << "Vulkan spec allows BuiltIn LocalInvocationIndex to be only "
3015
0
                "used for variables with Input storage class. "
3016
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3017
0
                                 referenced_from_inst)
3018
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3019
0
    }
3020
3021
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3022
0
      bool has_vulkan_model =
3023
0
          execution_model == spv::ExecutionModel::GLCompute ||
3024
0
          execution_model == spv::ExecutionModel::TaskNV ||
3025
0
          execution_model == spv::ExecutionModel::MeshNV ||
3026
0
          execution_model == spv::ExecutionModel::TaskEXT ||
3027
0
          execution_model == spv::ExecutionModel::MeshEXT;
3028
3029
0
      if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
3030
0
        uint32_t vuid = GetVUIDForBuiltin(spv::BuiltIn::LocalInvocationIndex,
3031
0
                                          VUIDErrorExecutionModel);
3032
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3033
0
               << _.VkErrorID(vuid)
3034
0
               << "Vulkan spec allows BuiltIn LocalInvocationIndex to be used "
3035
0
                  "only with GLCompute, MeshNV, TaskNV, MeshEXT or"
3036
0
               << " TaskEXT execution model. "
3037
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3038
0
                                   referenced_from_inst, execution_model);
3039
0
      }
3040
0
    }
3041
0
  }
3042
3043
0
  if (function_id_ == 0) {
3044
    // Propagate this rule to all dependant ids in the global scope.
3045
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3046
0
        std::bind(&BuiltInsValidator::ValidateLocalInvocationIndexAtReference,
3047
0
                  this, decoration, built_in_inst, referenced_from_inst,
3048
0
                  std::placeholders::_1));
3049
0
  }
3050
3051
0
  return SPV_SUCCESS;
3052
0
}
3053
3054
spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
3055
    const Decoration& decoration, const Instruction& built_in_inst,
3056
    const Instruction& referenced_inst,
3057
0
    const Instruction& referenced_from_inst) {
3058
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3059
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
3060
0
    if (storage_class != spv::StorageClass::Max &&
3061
0
        storage_class != spv::StorageClass::Input) {
3062
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3063
0
             << _.VkErrorID(4399) << spvLogStringForEnv(_.context()->target_env)
3064
0
             << " spec allows BuiltIn VertexIndex to be only used for "
3065
0
                "variables with Input storage class. "
3066
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3067
0
                                 referenced_from_inst)
3068
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3069
0
    }
3070
3071
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3072
0
      if (execution_model != spv::ExecutionModel::Vertex) {
3073
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3074
0
               << _.VkErrorID(4398)
3075
0
               << spvLogStringForEnv(_.context()->target_env)
3076
0
               << " spec allows BuiltIn VertexIndex to be used only with "
3077
0
                  "Vertex execution model. "
3078
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3079
0
                                   referenced_from_inst, execution_model);
3080
0
      }
3081
0
    }
3082
0
  }
3083
3084
0
  if (function_id_ == 0) {
3085
    // Propagate this rule to all dependant ids in the global scope.
3086
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
3087
0
        &BuiltInsValidator::ValidateVertexIndexAtReference, this, decoration,
3088
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
3089
0
  }
3090
3091
0
  return SPV_SUCCESS;
3092
0
}
3093
3094
typedef struct {
3095
  uint32_t array_type;
3096
  uint32_t array_size;
3097
  uint32_t block_array_size;
3098
  uint32_t perprim_deco;
3099
} MeshBuiltinVUIDs;
3100
3101
spv_result_t BuiltInsValidator::ValidateMeshBuiltinInterfaceRules(
3102
    const Decoration& decoration, const Instruction& inst, spv::Op scalar_type,
3103
0
    const Instruction& referenced_from_inst) {
3104
0
  if (function_id_) {
3105
0
    if (!execution_models_.count(spv::ExecutionModel::MeshEXT)) {
3106
0
      return SPV_SUCCESS;
3107
0
    }
3108
3109
0
    const spv::BuiltIn builtin = decoration.builtin();
3110
0
    const bool is_topology =
3111
0
        builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT ||
3112
0
        builtin == spv::BuiltIn::PrimitiveLineIndicesEXT ||
3113
0
        builtin == spv::BuiltIn::PrimitivePointIndicesEXT;
3114
3115
    // These builtin have the ability to be an array with MeshEXT
3116
    // When an array, we need to make sure the array size lines up
3117
0
    std::map<uint32_t, uint32_t> entry_interface_id_map;
3118
0
    const bool is_interface_var =
3119
0
        IsMeshInterfaceVar(inst, entry_interface_id_map);
3120
3121
0
    if (!is_topology) {
3122
0
      bool is_block = false;
3123
3124
0
      static const std::unordered_map<spv::BuiltIn, MeshBuiltinVUIDs>
3125
0
          mesh_vuid_map = {{
3126
0
              {spv::BuiltIn::CullPrimitiveEXT, {7036, 10589, 10590, 7038}},
3127
0
              {spv::BuiltIn::PrimitiveId, {10595, 10596, 10597, 7040}},
3128
0
              {spv::BuiltIn::Layer, {10592, 10593, 10594, 7039}},
3129
0
              {spv::BuiltIn::ViewportIndex, {10601, 10602, 10603, 7060}},
3130
0
              {spv::BuiltIn::PrimitiveShadingRateKHR,
3131
0
               {10598, 10599, 10600, 7059}},
3132
0
          }};
3133
0
      const MeshBuiltinVUIDs& vuids = mesh_vuid_map.at(builtin);
3134
0
      if (spv_result_t error = ValidateBlockTypeOrArrayedType(
3135
0
              decoration, inst, is_block, scalar_type,
3136
0
              [this, &inst, &builtin, &scalar_type,
3137
0
               &vuids](const std::string& message) -> spv_result_t {
3138
0
                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3139
0
                       << _.VkErrorID(vuids.array_type)
3140
0
                       << "According to the Vulkan specspec BuiltIn "
3141
0
                       << _.grammar().lookupOperandName(
3142
0
                              SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin)
3143
0
                       << " variable needs to be a either a "
3144
0
                       << spvOpcodeString(scalar_type)
3145
0
                       << " or an "
3146
0
                          "array of "
3147
0
                       << spvOpcodeString(scalar_type) << ". " << message;
3148
0
              })) {
3149
0
        return error;
3150
0
      }
3151
3152
0
      if (!_.HasDecoration(inst.id(), spv::Decoration::PerPrimitiveEXT)) {
3153
0
        return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3154
0
               << _.VkErrorID(vuids.perprim_deco)
3155
0
               << "According to the Vulkan spec the variable decorated with "
3156
0
                  "Builtin "
3157
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3158
0
                                                (uint32_t)builtin)
3159
0
               << " within the MeshEXT Execution Model must also be "
3160
0
               << "decorated with the PerPrimitiveEXT decoration. ";
3161
0
      }
3162
0
      if (is_interface_var) {
3163
0
        for (const auto& id : entry_interface_id_map) {
3164
0
          uint32_t entry_point_id = id.first;
3165
0
          uint32_t interface_var_id = id.second;
3166
3167
0
          const uint64_t interface_size = GetArrayLength(interface_var_id);
3168
0
          const uint32_t output_prim_size =
3169
0
              _.GetOutputPrimitivesEXT(entry_point_id);
3170
0
          if (interface_size != output_prim_size) {
3171
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3172
0
                   << _.VkErrorID(is_block ? vuids.block_array_size
3173
0
                                           : vuids.array_size)
3174
0
                   << " The size of the array decorated with "
3175
0
                   << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3176
0
                                                    (uint32_t)builtin)
3177
0
                   << " (" << interface_size
3178
0
                   << ") must match the value specified by OutputPrimitivesEXT "
3179
0
                      "("
3180
0
                   << output_prim_size << "). ";
3181
0
          }
3182
0
        }
3183
0
      }
3184
0
    }
3185
3186
0
    if (is_interface_var && is_topology) {
3187
0
      for (const auto& id : entry_interface_id_map) {
3188
0
        uint32_t entry_point_id = id.first;
3189
3190
0
        uint64_t max_output_primitives =
3191
0
            _.GetOutputPrimitivesEXT(entry_point_id);
3192
0
        uint32_t underlying_type = 0;
3193
0
        if (spv_result_t error =
3194
0
                GetUnderlyingType(_, decoration, inst, &underlying_type)) {
3195
0
          return error;
3196
0
        }
3197
3198
0
        uint64_t primitive_array_dim = 0;
3199
0
        if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
3200
0
          underlying_type = _.FindDef(underlying_type)->word(3u);
3201
0
          if (!_.EvalConstantValUint64(underlying_type, &primitive_array_dim)) {
3202
0
            assert(0 && "Array type definition is corrupt");
3203
0
          }
3204
0
        }
3205
3206
0
        const auto* modes = _.GetExecutionModes(entry_point_id);
3207
0
        if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) {
3208
0
          if (!modes || !modes->count(spv::ExecutionMode::OutputTrianglesEXT)) {
3209
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3210
0
                   << _.VkErrorID(7054)
3211
0
                   << "The PrimitiveTriangleIndicesEXT decoration must be used "
3212
0
                      "with the OutputTrianglesEXT Execution Mode. ";
3213
0
          }
3214
0
          if (primitive_array_dim &&
3215
0
              primitive_array_dim != max_output_primitives) {
3216
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3217
0
                   << _.VkErrorID(7058)
3218
0
                   << "The size of the array decorated with "
3219
0
                      "PrimitiveTriangleIndicesEXT ("
3220
0
                   << primitive_array_dim
3221
0
                   << ") must match the value specified "
3222
0
                      "by OutputPrimitivesEXT ("
3223
0
                   << max_output_primitives << "). ";
3224
0
          }
3225
0
        } else if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) {
3226
0
          if (!modes || !modes->count(spv::ExecutionMode::OutputLinesEXT)) {
3227
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3228
0
                   << _.VkErrorID(7048)
3229
0
                   << "The PrimitiveLineIndicesEXT decoration must be used "
3230
0
                      "with the OutputLinesEXT Execution Mode. ";
3231
0
          }
3232
0
          if (primitive_array_dim &&
3233
0
              primitive_array_dim != max_output_primitives) {
3234
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3235
0
                   << _.VkErrorID(7052)
3236
0
                   << "The size of the array decorated with "
3237
0
                      "PrimitiveLineIndicesEXT ("
3238
0
                   << primitive_array_dim
3239
0
                   << ") must match the value specified "
3240
0
                      "by OutputPrimitivesEXT ("
3241
0
                   << max_output_primitives << "). ";
3242
0
          }
3243
3244
0
        } else if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) {
3245
0
          if (!modes || !modes->count(spv::ExecutionMode::OutputPoints)) {
3246
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3247
0
                   << _.VkErrorID(7042)
3248
0
                   << "The PrimitivePointIndicesEXT decoration must be used "
3249
0
                      "with the OutputPoints Execution Mode. ";
3250
0
          }
3251
0
          if (primitive_array_dim &&
3252
0
              primitive_array_dim != max_output_primitives) {
3253
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3254
0
                   << _.VkErrorID(7046)
3255
0
                   << "The size of the array decorated with "
3256
0
                      "PrimitivePointIndicesEXT ("
3257
0
                   << primitive_array_dim
3258
0
                   << ") must match the value specified "
3259
0
                      "by OutputPrimitivesEXT ("
3260
0
                   << max_output_primitives << "). ";
3261
0
          }
3262
0
        }
3263
0
      }
3264
0
    }
3265
0
  } else {
3266
    // Propagate this rule to all dependant ids in the global scope.
3267
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3268
0
        std::bind(&BuiltInsValidator::ValidateMeshBuiltinInterfaceRules, this,
3269
0
                  decoration, inst, scalar_type, std::placeholders::_1));
3270
0
  }
3271
0
  return SPV_SUCCESS;
3272
0
}
3273
3274
spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateInterfaceRules(
3275
    const Decoration& decoration, const Instruction& inst,
3276
0
    const Instruction& referenced_from_inst) {
3277
0
  if (function_id_) {
3278
0
    if (!execution_models_.count(spv::ExecutionModel::MeshEXT)) {
3279
0
      if (spv_result_t error = ValidateI32(
3280
0
              decoration, inst,
3281
0
              [this, &inst,
3282
0
               &decoration](const std::string& message) -> spv_result_t {
3283
0
                return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3284
0
                       << _.VkErrorID(4486)
3285
0
                       << "According to the Vulkan spec BuiltIn "
3286
0
                       << _.grammar().lookupOperandName(
3287
0
                              SPV_OPERAND_TYPE_BUILT_IN,
3288
0
                              (uint32_t)decoration.builtin())
3289
0
                       << " variable needs to be a 32-bit int scalar. "
3290
0
                       << message;
3291
0
              })) {
3292
0
        return error;
3293
0
      }
3294
0
    }
3295
0
  } else {
3296
    // Propagate this rule to all dependant ids in the global scope.
3297
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
3298
0
        &BuiltInsValidator::ValidatePrimitiveShadingRateInterfaceRules, this,
3299
0
        decoration, inst, std::placeholders::_1));
3300
0
  }
3301
0
  return SPV_SUCCESS;
3302
0
}
3303
3304
// For Layer, ViewportIndex, and PrimitiveId
3305
spv_result_t BuiltInsValidator::ValidateNonMeshInterfaceRules(
3306
    const Decoration& decoration, const Instruction& inst,
3307
0
    const Instruction& referenced_from_inst) {
3308
0
  if (function_id_) {
3309
    // This can be a per-primitive variable for NV mesh shader stage.
3310
    // In such cases variable will have an array of 32-bit integers.
3311
0
    if (!execution_models_.count(spv::ExecutionModel::MeshEXT)) {
3312
0
      const spv::BuiltIn builtin = decoration.builtin();
3313
0
      const uint32_t vuid = (builtin == spv::BuiltIn::Layer)           ? 4276
3314
0
                            : (builtin == spv::BuiltIn::ViewportIndex) ? 4408
3315
0
                                                                       : 4337;
3316
0
      if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3317
0
        if (spv_result_t error = ValidateI32(
3318
0
                decoration, inst,
3319
0
                [this, &vuid, builtin,
3320
0
                 &inst](const std::string& message) -> spv_result_t {
3321
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3322
0
                         << _.VkErrorID(vuid)
3323
0
                         << "According to the Vulkan spec BuiltIn "
3324
0
                         << _.grammar().lookupOperandName(
3325
0
                                SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin)
3326
0
                         << "variable needs to be a 32-bit int scalar. "
3327
0
                         << message;
3328
0
                })) {
3329
0
          return error;
3330
0
        }
3331
0
      } else if (spv_result_t error = ValidateOptionalArrayedI32(
3332
0
                     decoration, inst,
3333
0
                     [this, &vuid, builtin,
3334
0
                      &inst](const std::string& message) -> spv_result_t {
3335
0
                       return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3336
0
                              << _.VkErrorID(vuid)
3337
0
                              << "According to the Vulkan spec BuiltIn "
3338
0
                              << _.grammar().lookupOperandName(
3339
0
                                     SPV_OPERAND_TYPE_BUILT_IN,
3340
0
                                     (uint32_t)builtin)
3341
0
                              << "variable needs to be a 32-bit int scalar. "
3342
0
                              << message;
3343
0
                     })) {
3344
0
        return error;
3345
0
      }
3346
0
    }
3347
0
  } else {
3348
    // Propagate this rule to all dependant ids in the global scope.
3349
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3350
0
        std::bind(&BuiltInsValidator::ValidateNonMeshInterfaceRules, this,
3351
0
                  decoration, inst, std::placeholders::_1));
3352
0
  }
3353
0
  return SPV_SUCCESS;
3354
0
}
3355
3356
spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
3357
0
    const Decoration& decoration, const Instruction& inst) {
3358
0
  return ValidateLayerOrViewportIndexAtReference(decoration, inst, inst, inst);
3359
0
}
3360
3361
spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
3362
    const Decoration& decoration, const Instruction& built_in_inst,
3363
    const Instruction& referenced_inst,
3364
0
    const Instruction& referenced_from_inst) {
3365
0
  uint32_t operand = (uint32_t)decoration.builtin();
3366
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3367
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
3368
0
    if (storage_class != spv::StorageClass::Max &&
3369
0
        storage_class != spv::StorageClass::Input &&
3370
0
        storage_class != spv::StorageClass::Output) {
3371
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3372
0
             << "Vulkan spec allows BuiltIn "
3373
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3374
0
                                              operand)
3375
0
             << " to be only used for variables with Input or Output storage "
3376
0
                "class. "
3377
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3378
0
                                 referenced_from_inst)
3379
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3380
0
    }
3381
3382
0
    if (storage_class == spv::StorageClass::Input) {
3383
0
      assert(function_id_ == 0);
3384
0
      for (const auto em :
3385
0
           {spv::ExecutionModel::Vertex, spv::ExecutionModel::TessellationEvaluation,
3386
0
            spv::ExecutionModel::Geometry, spv::ExecutionModel::MeshNV,
3387
0
            spv::ExecutionModel::MeshEXT}) {
3388
0
        id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3389
0
            std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
3390
0
                      this, ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4274 : 4406),
3391
0
                      "Vulkan spec doesn't allow BuiltIn Layer and "
3392
0
                      "ViewportIndex to be "
3393
0
                      "used for variables with Input storage class if "
3394
0
                      "execution model is Vertex, TessellationEvaluation, "
3395
0
                      "Geometry, MeshNV or MeshEXT.",
3396
0
                      em, decoration, built_in_inst, referenced_from_inst,
3397
0
                      std::placeholders::_1));
3398
0
      }
3399
0
    }
3400
3401
0
    if (storage_class == spv::StorageClass::Output) {
3402
0
      assert(function_id_ == 0);
3403
0
      id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3404
0
          std::bind(&BuiltInsValidator::ValidateNotCalledWithExecutionModel,
3405
0
                    this, ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4275 : 4407),
3406
0
                    "Vulkan spec doesn't allow BuiltIn Layer and "
3407
0
                    "ViewportIndex to be "
3408
0
                    "used for variables with Output storage class if "
3409
0
                    "execution model is "
3410
0
                    "Fragment.",
3411
0
                    spv::ExecutionModel::Fragment, decoration, built_in_inst,
3412
0
                    referenced_from_inst, std::placeholders::_1));
3413
0
    }
3414
3415
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
3416
0
        &BuiltInsValidator::ValidateMeshBuiltinInterfaceRules, this, decoration,
3417
0
        built_in_inst, spv::Op::OpTypeInt, std::placeholders::_1));
3418
3419
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3420
0
        std::bind(&BuiltInsValidator::ValidateNonMeshInterfaceRules, this,
3421
0
                  decoration, built_in_inst, std::placeholders::_1));
3422
3423
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3424
0
      switch (execution_model) {
3425
0
        case spv::ExecutionModel::Geometry:
3426
0
        case spv::ExecutionModel::Fragment:
3427
0
        case spv::ExecutionModel::MeshNV:
3428
0
        case spv::ExecutionModel::MeshEXT:
3429
          // Ok.
3430
0
          break;
3431
0
        case spv::ExecutionModel::Vertex:
3432
0
        case spv::ExecutionModel::TessellationEvaluation: {
3433
0
          if (!_.HasCapability(spv::Capability::ShaderViewportIndexLayerEXT)) {
3434
0
            if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex &&
3435
0
                _.HasCapability(spv::Capability::ShaderViewportIndex))
3436
0
              break;  // Ok
3437
0
            if (spv::BuiltIn(operand) == spv::BuiltIn::Layer &&
3438
0
                _.HasCapability(spv::Capability::ShaderLayer))
3439
0
              break;  // Ok
3440
3441
0
            const char* capability = "ShaderViewportIndexLayerEXT";
3442
3443
0
            if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex)
3444
0
              capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex";
3445
0
            if (spv::BuiltIn(operand) == spv::BuiltIn::Layer)
3446
0
              capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
3447
3448
0
            uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4273 : 4405;
3449
0
            return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3450
0
                   << _.VkErrorID(vuid) << "Using BuiltIn "
3451
0
                   << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3452
0
                                                    operand)
3453
0
                   << " in Vertex or Tessellation execution model requires the "
3454
0
                   << capability << " capability.";
3455
0
          }
3456
0
          break;
3457
0
        }
3458
0
        default: {
3459
0
          uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4272 : 4404;
3460
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3461
0
                 << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
3462
0
                 << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3463
0
                                                  operand)
3464
0
                 << " to be used only with Vertex, TessellationEvaluation, "
3465
0
                    "Geometry, or Fragment execution models. "
3466
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3467
0
                                     referenced_from_inst, execution_model);
3468
0
        }
3469
0
      }
3470
0
    }
3471
0
  }
3472
3473
0
  if (function_id_ == 0) {
3474
    // Propagate this rule to all dependant ids in the global scope.
3475
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3476
0
        std::bind(&BuiltInsValidator::ValidateLayerOrViewportIndexAtReference,
3477
0
                  this, decoration, built_in_inst, referenced_from_inst,
3478
0
                  std::placeholders::_1));
3479
0
  }
3480
3481
0
  return SPV_SUCCESS;
3482
0
}
3483
3484
spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtDefinition(
3485
0
    const Decoration& decoration, const Instruction& inst) {
3486
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3487
0
    const spv::BuiltIn builtin = decoration.builtin();
3488
0
    if (spv_result_t error = ValidateF32Vec(
3489
0
            decoration, inst, 3,
3490
0
            [this, &inst, builtin](const std::string& message) -> spv_result_t {
3491
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
3492
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3493
0
                     << _.VkErrorID(vuid) << "According to the "
3494
0
                     << spvLogStringForEnv(_.context()->target_env)
3495
0
                     << " spec BuiltIn "
3496
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3497
0
                                                      uint32_t(builtin))
3498
0
                     << " variable needs to be a 3-component 32-bit float "
3499
0
                        "vector. "
3500
0
                     << message;
3501
0
            })) {
3502
0
      return error;
3503
0
    }
3504
0
  }
3505
3506
  // Seed at reference checks with this built-in.
3507
0
  return ValidateFragmentShaderF32Vec3InputAtReference(decoration, inst, inst,
3508
0
                                                      inst);
3509
0
}
3510
3511
spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference(
3512
    const Decoration& decoration, const Instruction& built_in_inst,
3513
    const Instruction& referenced_inst,
3514
0
    const Instruction& referenced_from_inst) {
3515
3516
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3517
0
    const spv::BuiltIn builtin = decoration.builtin();
3518
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
3519
0
    if (storage_class != spv::StorageClass::Max &&
3520
0
        storage_class != spv::StorageClass::Input) {
3521
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
3522
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3523
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
3524
0
             << " spec allows BuiltIn "
3525
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3526
0
             << " to be only used for variables with Input storage class. "
3527
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3528
0
                                 referenced_from_inst)
3529
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3530
0
    }
3531
3532
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3533
0
      if (execution_model != spv::ExecutionModel::Fragment) {
3534
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
3535
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3536
0
               << _.VkErrorID(vuid)
3537
0
               << spvLogStringForEnv(_.context()->target_env)
3538
0
               << " spec allows BuiltIn "
3539
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3540
0
               << " to be used only with Fragment execution model. "
3541
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3542
0
                                   referenced_from_inst, execution_model);
3543
0
      }
3544
0
    }
3545
0
  }
3546
3547
0
  if (function_id_ == 0) {
3548
    // Propagate this rule to all dependant ids in the global scope.
3549
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
3550
0
        &BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference, this,
3551
0
        decoration, built_in_inst, referenced_from_inst,
3552
0
        std::placeholders::_1));
3553
0
  }
3554
3555
0
  return SPV_SUCCESS;
3556
0
}
3557
3558
spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
3559
0
    const Decoration& decoration, const Instruction& inst) {
3560
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3561
0
    const spv::BuiltIn builtin = decoration.builtin();
3562
0
    if (spv_result_t error = ValidateI32Vec(
3563
0
            decoration, inst, 3,
3564
0
            [this, &inst, builtin](const std::string& message) -> spv_result_t {
3565
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
3566
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3567
0
                     << _.VkErrorID(vuid) << "According to the "
3568
0
                     << spvLogStringForEnv(_.context()->target_env)
3569
0
                     << " spec BuiltIn "
3570
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3571
0
                                                      uint32_t(builtin))
3572
0
                     << " variable needs to be a 3-component 32-bit int "
3573
0
                        "vector. "
3574
0
                     << message;
3575
0
            })) {
3576
0
      return error;
3577
0
    }
3578
0
  }
3579
3580
  // Seed at reference checks with this built-in.
3581
0
  return ValidateComputeShaderI32Vec3InputAtReference(decoration, inst, inst,
3582
0
                                                      inst);
3583
0
}
3584
3585
spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
3586
    const Decoration& decoration, const Instruction& built_in_inst,
3587
    const Instruction& referenced_inst,
3588
0
    const Instruction& referenced_from_inst) {
3589
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3590
0
    const spv::BuiltIn builtin = decoration.builtin();
3591
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
3592
0
    if (storage_class != spv::StorageClass::Max &&
3593
0
        storage_class != spv::StorageClass::Input) {
3594
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
3595
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3596
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
3597
0
             << " spec allows BuiltIn "
3598
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3599
0
             << " to be only used for variables with Input storage class. "
3600
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3601
0
                                 referenced_from_inst)
3602
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3603
0
    }
3604
3605
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3606
0
      bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
3607
0
                              execution_model == spv::ExecutionModel::TaskNV ||
3608
0
                              execution_model == spv::ExecutionModel::MeshNV ||
3609
0
                              execution_model == spv::ExecutionModel::TaskEXT ||
3610
0
                              execution_model == spv::ExecutionModel::MeshEXT;
3611
3612
0
      if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
3613
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
3614
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3615
0
               << _.VkErrorID(vuid)
3616
0
               << spvLogStringForEnv(_.context()->target_env)
3617
0
               << " spec allows BuiltIn "
3618
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3619
0
               << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or"
3620
0
               << " TaskEXT execution model. "
3621
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3622
0
                                   referenced_from_inst, execution_model);
3623
0
      }
3624
0
    }
3625
0
  }
3626
3627
0
  if (function_id_ == 0) {
3628
    // Propagate this rule to all dependant ids in the global scope.
3629
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
3630
0
        &BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference, this,
3631
0
        decoration, built_in_inst, referenced_from_inst,
3632
0
        std::placeholders::_1));
3633
0
  }
3634
3635
0
  return SPV_SUCCESS;
3636
0
}
3637
3638
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
3639
0
    const Decoration& decoration, const Instruction& inst) {
3640
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3641
0
    const spv::BuiltIn builtin = decoration.builtin();
3642
0
    if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3643
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3644
0
             << "BuiltIn "
3645
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3646
0
             << " cannot be used as a member decoration ";
3647
0
    }
3648
0
    if (spv_result_t error = ValidateI32(
3649
0
            decoration, inst,
3650
0
            [this, &inst, builtin](const std::string& message) -> spv_result_t {
3651
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
3652
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3653
0
                     << _.VkErrorID(vuid)
3654
0
                     << "According to the "
3655
0
                     << spvLogStringForEnv(_.context()->target_env)
3656
0
                     << " spec BuiltIn "
3657
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3658
0
                     << " variable needs to be a 32-bit int "
3659
0
                        "vector. "
3660
0
                     << message;
3661
0
            })) {
3662
0
      return error;
3663
0
    }
3664
0
  }
3665
3666
  // Seed at reference checks with this built-in.
3667
0
  return ValidateComputeI32InputAtReference(decoration, inst, inst, inst);
3668
0
}
3669
3670
spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
3671
    const Decoration& decoration, const Instruction& built_in_inst,
3672
    const Instruction& referenced_inst,
3673
0
    const Instruction& referenced_from_inst) {
3674
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3675
0
    const spv::BuiltIn builtin = decoration.builtin();
3676
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
3677
0
    if (storage_class != spv::StorageClass::Max &&
3678
0
        storage_class != spv::StorageClass::Input) {
3679
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
3680
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3681
0
             << _.VkErrorID(vuid)
3682
0
             << spvLogStringForEnv(_.context()->target_env)
3683
0
             << " spec allows BuiltIn "
3684
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3685
0
             << " to be only used for variables with Input storage class. "
3686
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3687
0
                                 referenced_from_inst)
3688
0
             << " " << GetStorageClassDesc(referenced_from_inst);
3689
0
    }
3690
3691
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
3692
0
      bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
3693
0
                              execution_model == spv::ExecutionModel::TaskNV ||
3694
0
                              execution_model == spv::ExecutionModel::MeshNV ||
3695
0
                              execution_model == spv::ExecutionModel::TaskEXT ||
3696
0
                              execution_model == spv::ExecutionModel::MeshEXT;
3697
0
      if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) {
3698
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
3699
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
3700
0
               << _.VkErrorID(vuid)
3701
0
               << spvLogStringForEnv(_.context()->target_env)
3702
0
               << " spec allows BuiltIn "
3703
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3704
0
               << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
3705
0
               << "TaskEXT execution model. "
3706
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3707
0
                                   referenced_from_inst, execution_model);
3708
0
      }
3709
0
    }
3710
0
  }
3711
3712
0
  if (function_id_ == 0) {
3713
    // Propagate this rule to all dependant ids in the global scope.
3714
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3715
0
        std::bind(&BuiltInsValidator::ValidateComputeI32InputAtReference, this,
3716
0
                  decoration, built_in_inst, referenced_from_inst,
3717
0
                  std::placeholders::_1));
3718
0
  }
3719
3720
0
  return SPV_SUCCESS;
3721
0
}
3722
3723
spv_result_t BuiltInsValidator::ValidateVolatileLoads(
3724
    const Decoration& decoration, const Instruction& pointer,
3725
0
    spv::ExecutionModel stage) {
3726
0
  for (const auto& use : pointer.uses()) {
3727
0
    const Instruction* user = use.first;
3728
    // Some of these builtins are composite types, so need to trace through to
3729
    // find them
3730
0
    switch (user->opcode()) {
3731
0
      case spv::Op::OpLoad:
3732
0
      case spv::Op::OpAccessChain:
3733
0
      case spv::Op::OpInBoundsAccessChain:
3734
0
      case spv::Op::OpPtrAccessChain:
3735
0
      case spv::Op::OpInBoundsPtrAccessChain:
3736
0
      case spv::Op::OpCopyObject:
3737
0
        if (user->GetOperandAs<uint32_t>(2u) != pointer.id()) continue;
3738
0
        break;
3739
0
      default:
3740
0
        continue;
3741
0
    }
3742
3743
0
    if (user->opcode() != spv::Op::OpLoad) {
3744
0
      if (spv_result_t error =
3745
0
              ValidateVolatileLoads(decoration, *user, stage)) {
3746
0
        return error;
3747
0
      }
3748
0
      continue;
3749
0
    }
3750
3751
0
    const uint32_t mask =
3752
0
        user->operands().size() > 3u ? user->GetOperandAs<uint32_t>(3u) : 0u;
3753
0
    if (!(mask & uint32_t(spv::MemoryAccessMask::Volatile))) {
3754
0
      return _.diag(SPV_ERROR_INVALID_DATA, user)
3755
0
             << _.VkErrorID(4679)
3756
0
             << "With the VulkanMemoryModel capability declared, OpLoad "
3757
0
                "must use a Volatile memory access when it accesses into a "
3758
0
                "variable decorated with BuiltIn "
3759
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3760
0
                                              uint32_t(decoration.builtin()))
3761
0
             << " used in "
3762
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
3763
0
                                              uint32_t(stage));
3764
0
    }
3765
0
  }
3766
3767
0
  return SPV_SUCCESS;
3768
0
}
3769
3770
spv_result_t BuiltInsValidator::ValidateVolatileSemantics(
3771
0
    const Decoration& decoration, const Instruction& inst) {
3772
0
  const spv::BuiltIn builtin = decoration.builtin();
3773
0
  const bool vulkan_memory_model =
3774
0
      _.HasCapability(spv::Capability::VulkanMemoryModel);
3775
3776
0
  auto validate_variable = [&](const Instruction& variable) -> spv_result_t {
3777
0
    if (GetStorageClass(variable) != spv::StorageClass::Input) {
3778
0
      return SPV_SUCCESS;  // Validated elsewhere already
3779
0
    }
3780
3781
0
    spv::ExecutionModel stage = spv::ExecutionModel::Max;
3782
0
    for (uint32_t entry_point : _.EntryPointReferences(variable.id())) {
3783
0
      const auto* models = _.GetExecutionModels(entry_point);
3784
0
      if (!models) continue;
3785
0
      for (const spv::ExecutionModel model : *models) {
3786
0
        if (NeedsVolatileSemantics(builtin, model)) {
3787
0
          stage = model;
3788
0
          break;
3789
0
        }
3790
0
      }
3791
0
      if (stage != spv::ExecutionModel::Max) break;
3792
0
    }
3793
    // The variable is never used in a stage the VUIDs list
3794
0
    if (stage == spv::ExecutionModel::Max) return SPV_SUCCESS;
3795
3796
0
    if (vulkan_memory_model) {
3797
0
      return ValidateVolatileLoads(decoration, variable, stage);
3798
0
    }
3799
3800
0
    if (!_.HasDecoration(variable.id(), spv::Decoration::Volatile)) {
3801
0
      return _.diag(SPV_ERROR_INVALID_DATA, &variable)
3802
0
             << _.VkErrorID(4678)
3803
0
             << "Without the VulkanMemoryModel capability, a variable "
3804
0
                "decorated with BuiltIn "
3805
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3806
0
                                              uint32_t(builtin))
3807
0
             << " must also be decorated with Volatile when used in "
3808
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_EXECUTION_MODEL,
3809
0
                                              uint32_t(stage));
3810
0
    }
3811
0
    return SPV_SUCCESS;
3812
0
  };
3813
3814
0
  if (inst.opcode() != spv::Op::OpTypeStruct) {
3815
0
    return validate_variable(inst);
3816
0
  }
3817
3818
  // The BuiltIn was a Block member, so the decoration is on the struct type,
3819
  // the Volatile decoration rule are applied on the variable declared with it.
3820
0
  for (const auto& struct_use : inst.uses()) {
3821
0
    const Instruction* pointer_type = struct_use.first;
3822
0
    if (pointer_type->opcode() != spv::Op::OpTypePointer) continue;
3823
0
    for (const auto& pointer_use : pointer_type->uses()) {
3824
0
      const Instruction* variable = pointer_use.first;
3825
0
      if (variable->opcode() != spv::Op::OpVariable) continue;
3826
0
      if (spv_result_t error = validate_variable(*variable)) {
3827
0
        return error;
3828
0
      }
3829
0
    }
3830
0
  }
3831
3832
0
  return SPV_SUCCESS;
3833
0
}
3834
3835
spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
3836
0
    const Decoration& decoration, const Instruction& inst) {
3837
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3838
0
    const spv::BuiltIn builtin = decoration.builtin();
3839
0
    if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3840
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3841
0
             << "BuiltIn "
3842
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3843
0
             << " cannot be used as a member decoration ";
3844
0
    }
3845
0
    if (spv_result_t error = ValidateI32(
3846
0
            decoration, inst,
3847
0
            [this, &inst, builtin](const std::string& message) -> spv_result_t {
3848
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
3849
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3850
0
                     << _.VkErrorID(vuid)
3851
0
                     << "According to the "
3852
0
                     << spvLogStringForEnv(_.context()->target_env)
3853
0
                     << " spec BuiltIn "
3854
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3855
0
                     << " variable needs to be a 32-bit int. " << message;
3856
0
            })) {
3857
0
      return error;
3858
0
    }
3859
3860
0
    const spv::StorageClass storage_class = GetStorageClass(inst);
3861
0
    if (storage_class != spv::StorageClass::Max &&
3862
0
        storage_class != spv::StorageClass::Input) {
3863
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
3864
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3865
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
3866
0
             << " spec allows BuiltIn "
3867
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3868
0
                                              uint32_t(builtin))
3869
0
             << " to be only used for variables with Input storage class. "
3870
0
             << GetReferenceDesc(decoration, inst, inst, inst) << " "
3871
0
             << GetStorageClassDesc(inst);
3872
0
    }
3873
0
  }
3874
3875
0
  return SPV_SUCCESS;
3876
0
}
3877
3878
spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
3879
0
    const Decoration& decoration, const Instruction& inst) {
3880
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
3881
0
    const spv::BuiltIn builtin = decoration.builtin();
3882
0
    if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3883
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3884
0
             << "BuiltIn "
3885
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3886
0
             << " cannot be used as a member decoration ";
3887
0
    }
3888
0
    if (spv_result_t error = ValidateI32Vec(
3889
0
            decoration, inst, 4,
3890
0
            [this, &inst, builtin](const std::string& message) -> spv_result_t {
3891
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
3892
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3893
0
                     << _.VkErrorID(vuid)
3894
0
                     << "According to the "
3895
0
                     << spvLogStringForEnv(_.context()->target_env)
3896
0
                     << " spec BuiltIn "
3897
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
3898
0
                     << " variable needs to be a 4-component 32-bit int "
3899
0
                        "vector. "
3900
0
                     << message;
3901
0
            })) {
3902
0
      return error;
3903
0
    }
3904
3905
0
    const spv::StorageClass storage_class = GetStorageClass(inst);
3906
0
    if (storage_class != spv::StorageClass::Max &&
3907
0
        storage_class != spv::StorageClass::Input) {
3908
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
3909
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3910
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
3911
0
             << " spec allows BuiltIn "
3912
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
3913
0
                                              uint32_t(builtin))
3914
0
             << " to be only used for variables with Input storage class. "
3915
0
             << GetReferenceDesc(decoration, inst, inst, inst) << " "
3916
0
             << GetStorageClassDesc(inst);
3917
0
    }
3918
0
  }
3919
3920
0
  return SPV_SUCCESS;
3921
0
}
3922
3923
spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
3924
501
    const Decoration& decoration, const Instruction& inst) {
3925
  // Vulkan requires 32-bit int, but Universal has no restrictions
3926
501
  if (spvIsVulkanEnv(_.context()->target_env)) {
3927
0
    if (spv_result_t error = ValidateI32Vec(
3928
0
            decoration, inst, 3,
3929
0
            [this, &inst](const std::string& message) -> spv_result_t {
3930
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3931
0
                     << _.VkErrorID(4427) << "According to the "
3932
0
                     << spvLogStringForEnv(_.context()->target_env)
3933
0
                     << " spec BuiltIn WorkgroupSize variable needs to be a "
3934
0
                        "3-component 32-bit int vector. "
3935
0
                     << message;
3936
0
            })) {
3937
0
      return error;
3938
0
    }
3939
0
  }
3940
3941
501
  if (!spvOpcodeIsConstant(inst.opcode())) {
3942
308
    if (spvIsVulkanEnv(_.context()->target_env)) {
3943
0
      return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3944
0
             << _.VkErrorID(4426)
3945
0
             << "Vulkan spec requires BuiltIn WorkgroupSize to be a "
3946
0
                "constant. "
3947
0
             << GetIdDesc(inst) << " is not a constant.";
3948
0
    }
3949
308
  } else if (inst.opcode() == spv::Op::OpConstantComposite) {
3950
    // can only validate product if static and not spec constant
3951
113
    if (_.FindDef(inst.word(3))->opcode() == spv::Op::OpConstant &&
3952
113
        _.FindDef(inst.word(4))->opcode() == spv::Op::OpConstant &&
3953
113
        _.FindDef(inst.word(5))->opcode() == spv::Op::OpConstant) {
3954
113
      uint64_t x_size, y_size, z_size;
3955
      // ValidateI32Vec above confirms there will be 3 words to read
3956
113
      bool static_x = _.EvalConstantValUint64(inst.word(3), &x_size);
3957
113
      bool static_y = _.EvalConstantValUint64(inst.word(4), &y_size);
3958
113
      bool static_z = _.EvalConstantValUint64(inst.word(5), &z_size);
3959
113
      if (static_x && static_y && static_z) {
3960
109
        const uint64_t product_size = x_size * y_size * z_size;
3961
109
        if (product_size == 0) {
3962
3
          return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3963
3
                 << "WorkgroupSize decorations must not have a static "
3964
3
                    "product of zero (X = "
3965
3
                 << x_size << ", Y = " << y_size << ", Z = " << z_size << ").";
3966
3
        }
3967
3968
        // If there is a known static workgroup size, all entrypoints with
3969
        // explicit derivative execution modes can be validated. These are only
3970
        // found in execution models that support explicit workgroup sizes
3971
165
        for (const uint32_t entry_point : _.entry_points()) {
3972
165
          const auto* modes = _.GetExecutionModes(entry_point);
3973
165
          if (!modes) continue;
3974
46
          if (modes->count(spv::ExecutionMode::DerivativeGroupQuadsKHR)) {
3975
0
            if (x_size % 2 != 0 || y_size % 2 != 0) {
3976
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3977
0
                     << _.VkErrorID(10151)
3978
0
                     << "WorkgroupSize decorations has a static dimensions of "
3979
0
                        "(X = "
3980
0
                     << x_size << ", Y = " << y_size << ") but Entry Point id "
3981
0
                     << entry_point
3982
0
                     << " has an DerivativeGroupQuadsKHR execution mode, so "
3983
0
                        "both dimensions must be a multiple of 2";
3984
0
            }
3985
0
          }
3986
46
          if (modes->count(spv::ExecutionMode::DerivativeGroupLinearKHR)) {
3987
0
            if (product_size % 4 != 0) {
3988
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
3989
0
                     << _.VkErrorID(10152)
3990
0
                     << "WorkgroupSize decorations has a static dimensions of "
3991
0
                        "(X = "
3992
0
                     << x_size << ", Y = " << y_size << ", Z = " << z_size
3993
0
                     << ") but Entry Point id " << entry_point
3994
0
                     << " has an DerivativeGroupLinearKHR execution mode, so "
3995
0
                        "the product ("
3996
0
                     << product_size << ") must be a multiple of 4";
3997
0
            }
3998
0
          }
3999
46
        }
4000
106
      }
4001
113
    }
4002
113
  }
4003
4004
  // Seed at reference checks with this built-in.
4005
498
  return ValidateWorkgroupSizeAtReference(decoration, inst, inst, inst);
4006
501
}
4007
4008
spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
4009
    const Decoration& decoration, const Instruction& built_in_inst,
4010
    const Instruction& referenced_inst,
4011
4.43k
    const Instruction& referenced_from_inst) {
4012
4.43k
  if (spvIsVulkanEnv(_.context()->target_env)) {
4013
0
    const spv::StorageClass storage_class =
4014
0
        GetStorageClass(referenced_from_inst);
4015
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4016
0
      if (execution_model != spv::ExecutionModel::GLCompute &&
4017
0
          execution_model != spv::ExecutionModel::TaskNV &&
4018
0
          execution_model != spv::ExecutionModel::MeshNV &&
4019
0
          execution_model != spv::ExecutionModel::TaskEXT &&
4020
0
          execution_model != spv::ExecutionModel::MeshEXT) {
4021
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4022
0
               << _.VkErrorID(4425)
4023
0
               << spvLogStringForEnv(_.context()->target_env)
4024
0
               << " spec allows BuiltIn "
4025
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4026
0
                                                (uint32_t)decoration.builtin())
4027
0
               << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
4028
0
               << "TaskEXT execution model. "
4029
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4030
0
                                   referenced_from_inst, execution_model);
4031
0
      }
4032
0
    }
4033
0
    if (execution_modes_.count(spv::ExecutionMode::TileShadingRateQCOM) &&
4034
0
        storage_class != spv::StorageClass::Max &&
4035
0
        storage_class != spv::StorageClass::Input) {
4036
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4037
0
             << _.VkErrorID(10635)
4038
0
             << spvLogStringForEnv(_.context()->target_env)
4039
0
             << " spec allows BuiltIn WorkgroupSize to be only used for "
4040
0
                "variables with Input storage class when "
4041
0
                "TileShadingRateQCOM Execution Mode is used. "
4042
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4043
0
                                 referenced_from_inst)
4044
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4045
0
    }
4046
0
  }
4047
4048
4.43k
  if (function_id_ == 0) {
4049
    // Propagate this rule to all dependant ids in the global scope.
4050
4.36k
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4051
4.36k
        &BuiltInsValidator::ValidateWorkgroupSizeAtReference, this, decoration,
4052
4.36k
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4053
4.36k
  }
4054
4055
4.43k
  return SPV_SUCCESS;
4056
4.43k
}
4057
4058
spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtDefinition(
4059
0
    const Decoration& decoration, const Instruction& inst) {
4060
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4061
0
    if (spv_result_t error = ValidateI32(
4062
0
            decoration, inst,
4063
0
            [this, &inst,
4064
0
             &decoration](const std::string& message) -> spv_result_t {
4065
0
              uint32_t vuid =
4066
0
                  (decoration.builtin() == spv::BuiltIn::BaseInstance) ? 4183
4067
0
                                                                       : 4186;
4068
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4069
0
                     << _.VkErrorID(vuid)
4070
0
                     << "According to the Vulkan spec BuiltIn "
4071
0
                     << _.grammar().lookupOperandName(
4072
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4073
0
                            (uint32_t)decoration.builtin())
4074
0
                     << " variable needs to be a 32-bit int scalar. "
4075
0
                     << message;
4076
0
            })) {
4077
0
      return error;
4078
0
    }
4079
0
  }
4080
4081
0
  return ValidateBaseInstanceOrVertexAtReference(decoration, inst, inst, inst);
4082
0
}
4083
4084
spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference(
4085
    const Decoration& decoration, const Instruction& built_in_inst,
4086
    const Instruction& referenced_inst,
4087
0
    const Instruction& referenced_from_inst) {
4088
0
  uint32_t operand = (uint32_t)decoration.builtin();
4089
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4090
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4091
0
    if (storage_class != spv::StorageClass::Max &&
4092
0
        storage_class != spv::StorageClass::Input) {
4093
0
      uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4182 : 4185;
4094
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4095
0
             << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
4096
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4097
0
                                              operand)
4098
0
             << " to be only used for variables with Input storage class. "
4099
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4100
0
                                 referenced_from_inst)
4101
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4102
0
    }
4103
4104
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4105
0
      if (execution_model != spv::ExecutionModel::Vertex) {
4106
0
        uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4181 : 4184;
4107
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4108
0
               << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
4109
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4110
0
                                                operand)
4111
0
               << " to be used only with Vertex execution model. "
4112
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4113
0
                                   referenced_from_inst, execution_model);
4114
0
      }
4115
0
    }
4116
0
  }
4117
4118
0
  if (function_id_ == 0) {
4119
    // Propagate this rule to all dependant ids in the global scope.
4120
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
4121
0
        std::bind(&BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference,
4122
0
                  this, decoration, built_in_inst, referenced_from_inst,
4123
0
                  std::placeholders::_1));
4124
0
  }
4125
4126
0
  return SPV_SUCCESS;
4127
0
}
4128
4129
spv_result_t BuiltInsValidator::ValidateDrawIndexAtDefinition(
4130
0
    const Decoration& decoration, const Instruction& inst) {
4131
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4132
0
    if (spv_result_t error = ValidateI32(
4133
0
            decoration, inst,
4134
0
            [this, &inst,
4135
0
             &decoration](const std::string& message) -> spv_result_t {
4136
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4137
0
                     << _.VkErrorID(4209)
4138
0
                     << "According to the Vulkan spec BuiltIn "
4139
0
                     << _.grammar().lookupOperandName(
4140
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4141
0
                            (uint32_t)decoration.builtin())
4142
0
                     << " variable needs to be a 32-bit int scalar. "
4143
0
                     << message;
4144
0
            })) {
4145
0
      return error;
4146
0
    }
4147
0
  }
4148
4149
0
  return ValidateDrawIndexAtReference(decoration, inst, inst, inst);
4150
0
}
4151
4152
spv_result_t BuiltInsValidator::ValidateDrawIndexAtReference(
4153
    const Decoration& decoration, const Instruction& built_in_inst,
4154
    const Instruction& referenced_inst,
4155
0
    const Instruction& referenced_from_inst) {
4156
0
  uint32_t operand = (uint32_t)decoration.builtin();
4157
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4158
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4159
0
    if (storage_class != spv::StorageClass::Max &&
4160
0
        storage_class != spv::StorageClass::Input) {
4161
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4162
0
             << _.VkErrorID(4208) << "Vulkan spec allows BuiltIn "
4163
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4164
0
                                              operand)
4165
0
             << " to be only used for variables with Input storage class. "
4166
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4167
0
                                 referenced_from_inst)
4168
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4169
0
    }
4170
4171
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4172
0
      if (execution_model != spv::ExecutionModel::Vertex &&
4173
0
          execution_model != spv::ExecutionModel::MeshNV &&
4174
0
          execution_model != spv::ExecutionModel::TaskNV &&
4175
0
          execution_model != spv::ExecutionModel::MeshEXT &&
4176
0
          execution_model != spv::ExecutionModel::TaskEXT) {
4177
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4178
0
               << _.VkErrorID(4207) << "Vulkan spec allows BuiltIn "
4179
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4180
0
                                                operand)
4181
0
               << " to be used only with Vertex, MeshNV, TaskNV , MeshEXT or"
4182
0
               << " TaskEXT execution "
4183
0
                  "model. "
4184
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4185
0
                                   referenced_from_inst, execution_model);
4186
0
      }
4187
0
    }
4188
0
  }
4189
4190
0
  if (function_id_ == 0) {
4191
    // Propagate this rule to all dependant ids in the global scope.
4192
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4193
0
        &BuiltInsValidator::ValidateDrawIndexAtReference, this, decoration,
4194
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4195
0
  }
4196
4197
0
  return SPV_SUCCESS;
4198
0
}
4199
4200
spv_result_t BuiltInsValidator::ValidateViewIndexAtDefinition(
4201
0
    const Decoration& decoration, const Instruction& inst) {
4202
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4203
0
    if (spv_result_t error = ValidateI32(
4204
0
            decoration, inst,
4205
0
            [this, &inst,
4206
0
             &decoration](const std::string& message) -> spv_result_t {
4207
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4208
0
                     << _.VkErrorID(4403)
4209
0
                     << "According to the Vulkan spec BuiltIn "
4210
0
                     << _.grammar().lookupOperandName(
4211
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4212
0
                            (uint32_t)decoration.builtin())
4213
0
                     << " variable needs to be a 32-bit int scalar. "
4214
0
                     << message;
4215
0
            })) {
4216
0
      return error;
4217
0
    }
4218
0
  }
4219
4220
0
  return ValidateViewIndexAtReference(decoration, inst, inst, inst);
4221
0
}
4222
4223
spv_result_t BuiltInsValidator::ValidateViewIndexAtReference(
4224
    const Decoration& decoration, const Instruction& built_in_inst,
4225
    const Instruction& referenced_inst,
4226
0
    const Instruction& referenced_from_inst) {
4227
0
  uint32_t operand = (uint32_t)decoration.builtin();
4228
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4229
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4230
0
    if (storage_class != spv::StorageClass::Max &&
4231
0
        storage_class != spv::StorageClass::Input) {
4232
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4233
0
             << _.VkErrorID(4402) << "Vulkan spec allows BuiltIn "
4234
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4235
0
                                              operand)
4236
0
             << " to be only used for variables with Input storage class. "
4237
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4238
0
                                 referenced_from_inst)
4239
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4240
0
    }
4241
4242
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4243
0
      if (execution_model == spv::ExecutionModel::GLCompute) {
4244
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4245
0
               << _.VkErrorID(4401) << "Vulkan spec allows BuiltIn "
4246
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4247
0
                                                operand)
4248
0
               << " to be not be used with GLCompute execution model. "
4249
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4250
0
                                   referenced_from_inst, execution_model);
4251
0
      }
4252
0
    }
4253
0
  }
4254
4255
0
  if (function_id_ == 0) {
4256
    // Propagate this rule to all dependant ids in the global scope.
4257
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4258
0
        &BuiltInsValidator::ValidateViewIndexAtReference, this, decoration,
4259
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4260
0
  }
4261
4262
0
  return SPV_SUCCESS;
4263
0
}
4264
4265
spv_result_t BuiltInsValidator::ValidateDeviceIndexAtDefinition(
4266
0
    const Decoration& decoration, const Instruction& inst) {
4267
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4268
0
    if (spv_result_t error = ValidateI32(
4269
0
            decoration, inst,
4270
0
            [this, &inst,
4271
0
             &decoration](const std::string& message) -> spv_result_t {
4272
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4273
0
                     << _.VkErrorID(4206)
4274
0
                     << "According to the Vulkan spec BuiltIn "
4275
0
                     << _.grammar().lookupOperandName(
4276
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4277
0
                            (uint32_t)decoration.builtin())
4278
0
                     << " variable needs to be a 32-bit int scalar. "
4279
0
                     << message;
4280
0
            })) {
4281
0
      return error;
4282
0
    }
4283
0
  }
4284
4285
0
  return ValidateDeviceIndexAtReference(decoration, inst, inst, inst);
4286
0
}
4287
4288
spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference(
4289
    const Decoration& decoration, const Instruction& built_in_inst,
4290
    const Instruction& referenced_inst,
4291
0
    const Instruction& referenced_from_inst) {
4292
0
  uint32_t operand = (uint32_t)decoration.builtin();
4293
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4294
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4295
0
    if (storage_class != spv::StorageClass::Max &&
4296
0
        storage_class != spv::StorageClass::Input) {
4297
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4298
0
             << _.VkErrorID(4205) << "Vulkan spec allows BuiltIn "
4299
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4300
0
                                              operand)
4301
0
             << " to be only used for variables with Input storage class. "
4302
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4303
0
                                 referenced_from_inst)
4304
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4305
0
    }
4306
0
  }
4307
4308
0
  if (function_id_ == 0) {
4309
    // Propagate this rule to all dependant ids in the global scope.
4310
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4311
0
        &BuiltInsValidator::ValidateDeviceIndexAtReference, this, decoration,
4312
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4313
0
  }
4314
4315
0
  return SPV_SUCCESS;
4316
0
}
4317
4318
spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
4319
0
                                            const Instruction& inst) {
4320
4321
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4322
0
    const spv::BuiltIn builtin = decoration.builtin();
4323
0
    if (spv_result_t error = ValidateI32(
4324
0
            decoration, inst,
4325
0
            [this, &inst, &builtin](const std::string& message) -> spv_result_t {
4326
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4327
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4328
0
                     << _.VkErrorID(vuid) << "According to the "
4329
0
                     << spvLogStringForEnv(_.context()->target_env)
4330
0
                     << " spec BuiltIn "
4331
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4332
0
                                                      uint32_t(builtin))
4333
0
                     << " variable needs to be a 32-bit int scalar. "
4334
0
                     << message;
4335
0
            })) {
4336
0
      return error;
4337
0
    }
4338
0
  }
4339
4340
0
  return ValidateFragInvocationCountAtReference(decoration, inst, inst, inst);
4341
0
}
4342
4343
spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference(
4344
    const Decoration& decoration, const Instruction& built_in_inst,
4345
    const Instruction& referenced_inst,
4346
0
    const Instruction& referenced_from_inst) {
4347
4348
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4349
0
    const spv::BuiltIn builtin = decoration.builtin();
4350
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4351
0
    if (storage_class != spv::StorageClass::Max &&
4352
0
        storage_class != spv::StorageClass::Input) {
4353
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
4354
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4355
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
4356
0
             << " spec allows BuiltIn "
4357
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4358
0
             << " to be only used for variables with Input storage class. "
4359
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4360
0
                                 referenced_from_inst)
4361
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4362
0
    }
4363
4364
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4365
0
      if (execution_model != spv::ExecutionModel::Fragment) {
4366
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
4367
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4368
0
               << _.VkErrorID(vuid)
4369
0
               << spvLogStringForEnv(_.context()->target_env)
4370
0
               << " spec allows BuiltIn "
4371
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4372
0
               << " to be used only with Fragment execution model. "
4373
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4374
0
                                   referenced_from_inst, execution_model);
4375
0
      }
4376
0
    }
4377
0
  }
4378
4379
0
  if (function_id_ == 0) {
4380
    // Propagate this rule to all dependant ids in the global scope.
4381
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4382
0
        &BuiltInsValidator::ValidateFragInvocationCountAtReference, this, decoration,
4383
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4384
0
  }
4385
4386
0
  return SPV_SUCCESS;
4387
0
}
4388
4389
spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration,
4390
0
                                            const Instruction& inst) {
4391
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4392
0
    const spv::BuiltIn builtin = decoration.builtin();
4393
0
    if (spv_result_t error = ValidateI32Vec(
4394
0
            decoration, inst, 2,
4395
0
            [this, &inst, &builtin](const std::string& message) -> spv_result_t {
4396
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4397
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4398
0
                     << _.VkErrorID(vuid) << "According to the "
4399
0
                     << spvLogStringForEnv(_.context()->target_env)
4400
0
                     << " spec BuiltIn "
4401
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4402
0
                                                      uint32_t(builtin))
4403
0
                     << " variable needs to be a 2-component 32-bit int vector. "
4404
0
                     << message;
4405
0
            })) {
4406
0
      return error;
4407
0
    }
4408
0
  }
4409
4410
0
  return ValidateFragSizeAtReference(decoration, inst, inst, inst);
4411
0
}
4412
4413
spv_result_t BuiltInsValidator::ValidateFragSizeAtReference(
4414
    const Decoration& decoration, const Instruction& built_in_inst,
4415
    const Instruction& referenced_inst,
4416
0
    const Instruction& referenced_from_inst) {
4417
4418
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4419
0
    const spv::BuiltIn builtin = decoration.builtin();
4420
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4421
0
    if (storage_class != spv::StorageClass::Max &&
4422
0
        storage_class != spv::StorageClass::Input) {
4423
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
4424
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4425
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
4426
0
             << " spec allows BuiltIn "
4427
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4428
0
             << " to be only used for variables with Input storage class. "
4429
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4430
0
                                 referenced_from_inst)
4431
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4432
0
    }
4433
4434
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4435
0
      if (execution_model != spv::ExecutionModel::Fragment) {
4436
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
4437
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4438
0
               << _.VkErrorID(vuid)
4439
0
               << spvLogStringForEnv(_.context()->target_env)
4440
0
               << " spec allows BuiltIn "
4441
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4442
0
               << " to be used only with Fragment execution model. "
4443
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4444
0
                                   referenced_from_inst, execution_model);
4445
0
      }
4446
0
    }
4447
0
  }
4448
4449
0
  if (function_id_ == 0) {
4450
    // Propagate this rule to all dependant ids in the global scope.
4451
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4452
0
        &BuiltInsValidator::ValidateFragSizeAtReference, this, decoration,
4453
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4454
0
  }
4455
4456
0
  return SPV_SUCCESS;
4457
0
}
4458
4459
spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration,
4460
0
                                            const Instruction& inst) {
4461
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4462
0
    const spv::BuiltIn builtin = decoration.builtin();
4463
0
    if (spv_result_t error = ValidateI(
4464
0
            decoration, inst,
4465
0
            [this, &inst, &builtin](const std::string& message) -> spv_result_t {
4466
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4467
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4468
0
                     << _.VkErrorID(vuid) << "According to the "
4469
0
                     << spvLogStringForEnv(_.context()->target_env)
4470
0
                     << " spec BuiltIn "
4471
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4472
0
                                                      uint32_t(builtin))
4473
0
                     << " variable needs to be a int scalar. "
4474
0
                     << message;
4475
0
            })) {
4476
0
      return error;
4477
0
    }
4478
0
  }
4479
4480
0
  return ValidateFragStencilRefAtReference(decoration, inst, inst, inst);
4481
0
}
4482
4483
spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference(
4484
    const Decoration& decoration, const Instruction& built_in_inst,
4485
    const Instruction& referenced_inst,
4486
0
    const Instruction& referenced_from_inst) {
4487
4488
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4489
0
    const spv::BuiltIn builtin = decoration.builtin();
4490
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4491
0
    if (storage_class != spv::StorageClass::Max &&
4492
0
        storage_class != spv::StorageClass::Output) {
4493
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
4494
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4495
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
4496
0
             << " spec allows BuiltIn "
4497
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4498
0
             << " to be only used for variables with Output storage class. "
4499
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4500
0
                                 referenced_from_inst)
4501
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4502
0
    }
4503
4504
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4505
0
      if (execution_model != spv::ExecutionModel::Fragment) {
4506
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
4507
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4508
0
               << _.VkErrorID(vuid)
4509
0
               << spvLogStringForEnv(_.context()->target_env)
4510
0
               << " spec allows BuiltIn "
4511
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4512
0
               << " to be used only with Fragment execution model. "
4513
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4514
0
                                   referenced_from_inst, execution_model);
4515
0
      }
4516
0
    }
4517
0
  }
4518
4519
0
  if (function_id_ == 0) {
4520
    // Propagate this rule to all dependant ids in the global scope.
4521
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4522
0
        &BuiltInsValidator::ValidateFragStencilRefAtReference, this, decoration,
4523
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4524
0
  }
4525
4526
0
  return SPV_SUCCESS;
4527
0
}
4528
4529
spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration,
4530
0
                                               const Instruction& inst) {
4531
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4532
0
    const spv::BuiltIn builtin = decoration.builtin();
4533
0
    if (spv_result_t error = ValidateBool(
4534
0
            decoration, inst,
4535
0
            [this, &inst, &builtin](const std::string& message) -> spv_result_t {
4536
0
              uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4537
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4538
0
                     << _.VkErrorID(vuid) << "According to the "
4539
0
                     << spvLogStringForEnv(_.context()->target_env)
4540
0
                     << " spec BuiltIn "
4541
0
                     << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4542
0
                                                      uint32_t(builtin))
4543
0
                     << " variable needs to be a bool scalar. "
4544
0
                     << message;
4545
0
            })) {
4546
0
      return error;
4547
0
    }
4548
0
  }
4549
4550
0
  return ValidateFullyCoveredAtReference(decoration, inst, inst, inst);
4551
0
}
4552
4553
spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference(
4554
    const Decoration& decoration, const Instruction& built_in_inst,
4555
    const Instruction& referenced_inst,
4556
0
    const Instruction& referenced_from_inst) {
4557
4558
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4559
0
    const spv::BuiltIn builtin = decoration.builtin();
4560
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4561
0
    if (storage_class != spv::StorageClass::Max &&
4562
0
        storage_class != spv::StorageClass::Input) {
4563
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
4564
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4565
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
4566
0
             << " spec allows BuiltIn "
4567
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4568
0
             << " to be only used for variables with Input storage class. "
4569
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4570
0
                                 referenced_from_inst)
4571
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4572
0
    }
4573
4574
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4575
0
      if (execution_model != spv::ExecutionModel::Fragment) {
4576
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
4577
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4578
0
               << _.VkErrorID(vuid)
4579
0
               << spvLogStringForEnv(_.context()->target_env)
4580
0
               << " spec allows BuiltIn "
4581
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4582
0
               << " to be used only with Fragment execution model. "
4583
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4584
0
                                   referenced_from_inst, execution_model);
4585
0
      }
4586
0
    }
4587
0
  }
4588
4589
0
  if (function_id_ == 0) {
4590
    // Propagate this rule to all dependant ids in the global scope.
4591
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4592
0
        &BuiltInsValidator::ValidateFullyCoveredAtReference, this, decoration,
4593
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4594
0
  }
4595
4596
0
  return SPV_SUCCESS;
4597
0
}
4598
4599
spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtDefinition(
4600
0
    const Decoration& decoration, const Instruction& inst) {
4601
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4602
0
    if (spv_result_t error = ValidateI32(
4603
0
            decoration, inst,
4604
0
            [this, &inst,
4605
0
             &decoration](const std::string& message) -> spv_result_t {
4606
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4607
0
                     << "According to the "
4608
0
                     << spvLogStringForEnv(_.context()->target_env)
4609
0
                     << " spec BuiltIn "
4610
0
                     << _.grammar().lookupOperandName(
4611
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4612
0
                            (uint32_t)decoration.builtin())
4613
0
                     << " variable needs to be a 32-bit int scalar. "
4614
0
                     << message;
4615
0
            })) {
4616
0
      return error;
4617
0
    }
4618
0
  }
4619
4620
  // Seed at reference checks with this built-in.
4621
0
  return ValidateNVSMOrARMCoreBuiltinsAtReference(decoration, inst, inst, inst);
4622
0
}
4623
4624
spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference(
4625
    const Decoration& decoration, const Instruction& built_in_inst,
4626
    const Instruction& referenced_inst,
4627
0
    const Instruction& referenced_from_inst) {
4628
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4629
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4630
0
    if (storage_class != spv::StorageClass::Max &&
4631
0
        storage_class != spv::StorageClass::Input) {
4632
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4633
0
             << spvLogStringForEnv(_.context()->target_env)
4634
0
             << " spec allows BuiltIn "
4635
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4636
0
                                              (uint32_t)decoration.builtin())
4637
0
             << " to be only used for "
4638
0
                "variables with Input storage class. "
4639
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4640
0
                                 referenced_from_inst)
4641
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4642
0
    }
4643
0
  }
4644
4645
0
  if (function_id_ == 0) {
4646
    // Propagate this rule to all dependant ids in the global scope.
4647
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4648
0
        &BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference, this, decoration,
4649
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4650
0
  }
4651
4652
0
  return SPV_SUCCESS;
4653
0
}
4654
4655
spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition(
4656
0
    const Decoration& decoration, const Instruction& inst) {
4657
0
  return ValidatePrimitiveShadingRateAtReference(decoration, inst, inst, inst);
4658
0
}
4659
4660
spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference(
4661
    const Decoration& decoration, const Instruction& built_in_inst,
4662
    const Instruction& referenced_inst,
4663
0
    const Instruction& referenced_from_inst) {
4664
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4665
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4666
0
    if (storage_class != spv::StorageClass::Max &&
4667
0
        storage_class != spv::StorageClass::Output) {
4668
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4669
0
             << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn "
4670
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4671
0
                                              (uint32_t)decoration.builtin())
4672
0
             << " to be only used for variables with Output storage class. "
4673
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4674
0
                                 referenced_from_inst)
4675
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4676
0
    }
4677
4678
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4679
0
        &BuiltInsValidator::ValidateMeshBuiltinInterfaceRules, this, decoration,
4680
0
        built_in_inst, spv::Op::OpTypeInt, std::placeholders::_1));
4681
4682
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4683
0
        &BuiltInsValidator::ValidatePrimitiveShadingRateInterfaceRules, this,
4684
0
        decoration, built_in_inst, std::placeholders::_1));
4685
4686
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4687
0
      switch (execution_model) {
4688
0
        case spv::ExecutionModel::Vertex:
4689
0
        case spv::ExecutionModel::Geometry:
4690
0
        case spv::ExecutionModel::MeshNV:
4691
0
        case spv::ExecutionModel::MeshEXT:
4692
0
          break;
4693
0
        default: {
4694
0
          return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4695
0
                 << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn "
4696
0
                 << _.grammar().lookupOperandName(
4697
0
                        SPV_OPERAND_TYPE_BUILT_IN,
4698
0
                        (uint32_t)decoration.builtin())
4699
0
                 << " to be used only with Vertex, Geometry, MeshNV or MeshEXT "
4700
0
                    "execution models. "
4701
0
                 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4702
0
                                     referenced_from_inst, execution_model);
4703
0
        }
4704
0
      }
4705
0
    }
4706
0
  }
4707
4708
0
  if (function_id_ == 0) {
4709
    // Propagate this rule to all dependant ids in the global scope.
4710
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
4711
0
        std::bind(&BuiltInsValidator::ValidatePrimitiveShadingRateAtReference,
4712
0
                  this, decoration, built_in_inst, referenced_from_inst,
4713
0
                  std::placeholders::_1));
4714
0
  }
4715
4716
0
  return SPV_SUCCESS;
4717
0
}
4718
4719
spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition(
4720
0
    const Decoration& decoration, const Instruction& inst) {
4721
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4722
0
    if (spv_result_t error = ValidateI32(
4723
0
            decoration, inst,
4724
0
            [this, &inst,
4725
0
             &decoration](const std::string& message) -> spv_result_t {
4726
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4727
0
                     << _.VkErrorID(4492)
4728
0
                     << "According to the Vulkan spec BuiltIn "
4729
0
                     << _.grammar().lookupOperandName(
4730
0
                            SPV_OPERAND_TYPE_BUILT_IN,
4731
0
                            (uint32_t)decoration.builtin())
4732
0
                     << " variable needs to be a 32-bit int scalar. "
4733
0
                     << message;
4734
0
            })) {
4735
0
      return error;
4736
0
    }
4737
0
  }
4738
4739
  // Seed at reference checks with this built-in.
4740
0
  return ValidateShadingRateAtReference(decoration, inst, inst, inst);
4741
0
}
4742
4743
spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
4744
    const Decoration& decoration, const Instruction& built_in_inst,
4745
    const Instruction& referenced_inst,
4746
0
    const Instruction& referenced_from_inst) {
4747
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4748
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4749
0
    if (storage_class != spv::StorageClass::Max &&
4750
0
        storage_class != spv::StorageClass::Input) {
4751
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4752
0
             << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn "
4753
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4754
0
                                              (uint32_t)decoration.builtin())
4755
0
             << " to be only used for variables with Input storage class. "
4756
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4757
0
                                 referenced_from_inst)
4758
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4759
0
    }
4760
4761
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4762
0
      if (execution_model != spv::ExecutionModel::Fragment) {
4763
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4764
0
               << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn "
4765
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4766
0
                                                (uint32_t)decoration.builtin())
4767
0
               << " to be used only with the Fragment execution model. "
4768
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4769
0
                                   referenced_from_inst, execution_model);
4770
0
      }
4771
0
    }
4772
0
  }
4773
4774
0
  if (function_id_ == 0) {
4775
    // Propagate this rule to all dependant ids in the global scope.
4776
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
4777
0
        &BuiltInsValidator::ValidateShadingRateAtReference, this, decoration,
4778
0
        built_in_inst, referenced_from_inst, std::placeholders::_1));
4779
0
  }
4780
4781
0
  return SPV_SUCCESS;
4782
0
}
4783
4784
spv_result_t BuiltInsValidator::ValidateDescriptorHeapAtDefinition(
4785
0
    const Decoration& decoration, const Instruction& inst) {
4786
0
  if (decoration.struct_member_index() != Decoration::kInvalidMember) {
4787
0
    return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4788
0
           << "BuiltIn "
4789
0
           << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4790
0
                                            (uint32_t)decoration.builtin())
4791
0
           << " cannot be used as a member decoration ";
4792
0
  }
4793
0
  return SPV_SUCCESS;
4794
0
}
4795
4796
spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
4797
0
    const Decoration& decoration, const Instruction& inst) {
4798
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4799
0
    const spv::BuiltIn builtin = decoration.builtin();
4800
0
    switch (builtin) {
4801
0
      case spv::BuiltIn::HitTNV:
4802
0
      case spv::BuiltIn::RayTminKHR:
4803
0
      case spv::BuiltIn::RayTmaxKHR:
4804
        // f32 scalar
4805
0
        if (spv_result_t error = ValidateF32(
4806
0
                decoration, inst,
4807
0
                [this, &inst,
4808
0
                 builtin](const std::string& message) -> spv_result_t {
4809
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4810
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4811
0
                         << _.VkErrorID(vuid)
4812
0
                         << "According to the Vulkan spec BuiltIn "
4813
0
                         << _.grammar().lookupOperandName(
4814
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4815
0
                         << " variable needs to be a 32-bit float scalar. "
4816
0
                         << message;
4817
0
                })) {
4818
0
          return error;
4819
0
        }
4820
0
        break;
4821
0
      case spv::BuiltIn::HitKindKHR:
4822
0
      case spv::BuiltIn::InstanceCustomIndexKHR:
4823
0
      case spv::BuiltIn::InstanceId:
4824
0
      case spv::BuiltIn::RayGeometryIndexKHR:
4825
0
      case spv::BuiltIn::IncomingRayFlagsKHR:
4826
0
      case spv::BuiltIn::CullMaskKHR:
4827
        // i32 scalar
4828
0
        if (spv_result_t error = ValidateI32(
4829
0
                decoration, inst,
4830
0
                [this, &inst,
4831
0
                 builtin](const std::string& message) -> spv_result_t {
4832
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4833
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4834
0
                         << _.VkErrorID(vuid)
4835
0
                         << "According to the Vulkan spec BuiltIn "
4836
0
                         << _.grammar().lookupOperandName(
4837
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4838
0
                         << " variable needs to be a 32-bit int scalar. "
4839
0
                         << message;
4840
0
                })) {
4841
0
          return error;
4842
0
        }
4843
0
        break;
4844
0
      case spv::BuiltIn::ObjectRayDirectionKHR:
4845
0
      case spv::BuiltIn::ObjectRayOriginKHR:
4846
0
      case spv::BuiltIn::WorldRayDirectionKHR:
4847
0
      case spv::BuiltIn::WorldRayOriginKHR:
4848
        // f32 vec3
4849
0
        if (spv_result_t error = ValidateF32Vec(
4850
0
                decoration, inst, 3,
4851
0
                [this, &inst,
4852
0
                 builtin](const std::string& message) -> spv_result_t {
4853
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4854
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4855
0
                         << _.VkErrorID(vuid)
4856
0
                         << "According to the Vulkan spec BuiltIn "
4857
0
                         << _.grammar().lookupOperandName(
4858
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4859
0
                         << " variable needs to be a 3-component 32-bit float "
4860
0
                            "vector. "
4861
0
                         << message;
4862
0
                })) {
4863
0
          return error;
4864
0
        }
4865
0
        break;
4866
0
      case spv::BuiltIn::LaunchIdKHR:
4867
0
      case spv::BuiltIn::LaunchSizeKHR:
4868
        // i32 vec3
4869
0
        if (spv_result_t error = ValidateI32Vec(
4870
0
                decoration, inst, 3,
4871
0
                [this, &inst,
4872
0
                 builtin](const std::string& message) -> spv_result_t {
4873
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4874
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4875
0
                         << _.VkErrorID(vuid)
4876
0
                         << "According to the Vulkan spec BuiltIn "
4877
0
                         << _.grammar().lookupOperandName(
4878
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4879
0
                         << " variable needs to be a 3-component 32-bit int "
4880
0
                            "vector. "
4881
0
                         << message;
4882
0
                })) {
4883
0
          return error;
4884
0
        }
4885
0
        break;
4886
0
      case spv::BuiltIn::ObjectToWorldKHR:
4887
0
      case spv::BuiltIn::WorldToObjectKHR:
4888
        // f32 mat4x3
4889
0
        if (spv_result_t error = ValidateF32Mat(
4890
0
                decoration, inst, 3, 4,
4891
0
                [this, &inst,
4892
0
                 builtin](const std::string& message) -> spv_result_t {
4893
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4894
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4895
0
                         << _.VkErrorID(vuid)
4896
0
                         << "According to the Vulkan spec BuiltIn "
4897
0
                         << _.grammar().lookupOperandName(
4898
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4899
0
                         << " variable needs to be a matrix with"
4900
0
                         << " 4 columns of 3-component vectors of 32-bit "
4901
0
                            "floats. "
4902
0
                         << message;
4903
0
                })) {
4904
0
          return error;
4905
0
        }
4906
0
        break;
4907
0
      case spv::BuiltIn::HitTriangleVertexPositionsKHR:
4908
        // array[3] of f32 vec3
4909
0
        if (spv_result_t error = ValidateArrayedF32Vec(
4910
0
                decoration, inst, 3, 3,
4911
0
                [this, &inst,
4912
0
                 builtin](const std::string& message) -> spv_result_t {
4913
0
                  uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4914
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4915
0
                         << _.VkErrorID(vuid)
4916
0
                         << "According to the Vulkan spec BuiltIn "
4917
0
                         << _.grammar().lookupOperandName(
4918
0
                                SPV_OPERAND_TYPE_BUILT_IN, uint32_t(builtin))
4919
0
                         << " variable needs to be an array of 3, 32-bit float "
4920
0
                            "3-component vectors. "
4921
0
                         << message;
4922
0
                })) {
4923
0
          return error;
4924
0
        }
4925
0
        break;
4926
0
      default:
4927
0
        assert(0 && "Unexpected ray tracing builtin");
4928
0
        break;
4929
0
    }
4930
0
  }
4931
4932
  // Seed at reference checks with this built-in.
4933
0
  return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
4934
0
}
4935
4936
spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
4937
    const Decoration& decoration, const Instruction& built_in_inst,
4938
    const Instruction& referenced_inst,
4939
0
    const Instruction& referenced_from_inst) {
4940
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4941
0
    const spv::BuiltIn builtin = decoration.builtin();
4942
0
    const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst);
4943
0
    if (storage_class != spv::StorageClass::Max &&
4944
0
        storage_class != spv::StorageClass::Input) {
4945
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
4946
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4947
0
             << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
4948
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4949
0
                                              (uint32_t)decoration.builtin())
4950
0
             << " to be only used for variables with Input storage class. "
4951
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4952
0
                                 referenced_from_inst)
4953
0
             << " " << GetStorageClassDesc(referenced_from_inst);
4954
0
    }
4955
4956
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
4957
0
      if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
4958
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
4959
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
4960
0
               << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
4961
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
4962
0
                                                (uint32_t)decoration.builtin())
4963
0
               << " to be used with the execution model "
4964
0
               << _.grammar().lookupOperandName(
4965
0
                      SPV_OPERAND_TYPE_EXECUTION_MODEL,
4966
0
                      uint32_t(execution_model))
4967
0
               << ".\n"
4968
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4969
0
                                   referenced_from_inst, execution_model);
4970
0
      }
4971
0
    }
4972
0
  }
4973
4974
0
  if (function_id_ == 0) {
4975
    // Propagate this rule to all dependant ids in the global scope.
4976
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
4977
0
        std::bind(&BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
4978
0
                  this, decoration, built_in_inst, referenced_from_inst,
4979
0
                  std::placeholders::_1));
4980
0
  }
4981
4982
0
  return SPV_SUCCESS;
4983
0
}
4984
4985
spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition(
4986
0
    const Decoration& decoration, const Instruction& inst) {
4987
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
4988
0
    const spv::BuiltIn builtin = decoration.builtin();
4989
0
    uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
4990
0
    switch (builtin) {
4991
0
      case spv::BuiltIn::PrimitivePointIndicesEXT:
4992
0
        if (spv_result_t error = ValidateI32Arr(
4993
0
                decoration, inst,
4994
0
                [this, &inst, &decoration,
4995
0
                 &vuid](const std::string& message) -> spv_result_t {
4996
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
4997
0
                         << _.VkErrorID(vuid) << "According to the "
4998
0
                         << spvLogStringForEnv(_.context()->target_env)
4999
0
                         << " spec BuiltIn "
5000
0
                         << _.grammar().lookupOperandName(
5001
0
                                SPV_OPERAND_TYPE_BUILT_IN,
5002
0
                                (uint32_t)decoration.builtin())
5003
0
                         << " variable needs to be a 32-bit int array."
5004
0
                         << message;
5005
0
                })) {
5006
0
          return error;
5007
0
        }
5008
0
        break;
5009
0
      case spv::BuiltIn::PrimitiveLineIndicesEXT:
5010
0
        if (spv_result_t error = ValidateArrayedI32Vec(
5011
0
                decoration, inst, 2,
5012
0
                [this, &inst, &decoration,
5013
0
                 &vuid](const std::string& message) -> spv_result_t {
5014
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
5015
0
                         << _.VkErrorID(vuid) << "According to the "
5016
0
                         << spvLogStringForEnv(_.context()->target_env)
5017
0
                         << " spec BuiltIn "
5018
0
                         << _.grammar().lookupOperandName(
5019
0
                                SPV_OPERAND_TYPE_BUILT_IN,
5020
0
                                (uint32_t)decoration.builtin())
5021
0
                         << " variable needs to be a 2-component 32-bit int "
5022
0
                            "array."
5023
0
                         << message;
5024
0
                })) {
5025
0
          return error;
5026
0
        }
5027
0
        break;
5028
0
      case spv::BuiltIn::PrimitiveTriangleIndicesEXT:
5029
0
        if (spv_result_t error = ValidateArrayedI32Vec(
5030
0
                decoration, inst, 3,
5031
0
                [this, &inst, &decoration,
5032
0
                 &vuid](const std::string& message) -> spv_result_t {
5033
0
                  return _.diag(SPV_ERROR_INVALID_DATA, &inst)
5034
0
                         << _.VkErrorID(vuid) << "According to the "
5035
0
                         << spvLogStringForEnv(_.context()->target_env)
5036
0
                         << " spec BuiltIn "
5037
0
                         << _.grammar().lookupOperandName(
5038
0
                                SPV_OPERAND_TYPE_BUILT_IN,
5039
0
                                (uint32_t)decoration.builtin())
5040
0
                         << " variable needs to be a 3-component 32-bit int "
5041
0
                            "array."
5042
0
                         << message;
5043
0
                })) {
5044
0
          return error;
5045
0
        }
5046
0
        break;
5047
0
      case spv::BuiltIn::CullPrimitiveEXT: {
5048
0
        for (const uint32_t entry_point : _.entry_points()) {
5049
0
          auto* models = _.GetExecutionModels(entry_point);
5050
0
          if (models->find(spv::ExecutionModel::MeshEXT) == models->end() &&
5051
0
              models->find(spv::ExecutionModel::MeshNV) == models->end()) {
5052
0
            continue;
5053
0
          }
5054
5055
0
          if (IsBulitinInEntryPoint(inst, entry_point)) {
5056
0
            if (cull_primitive_entry_points_.find(entry_point) !=
5057
0
                cull_primitive_entry_points_.end()) {
5058
0
              return _.diag(SPV_ERROR_INVALID_DATA, &inst)
5059
0
                     << _.VkErrorID(10591)
5060
0
                     << "There must be only one declaration of the "
5061
0
                        "CullPrimitiveEXT associated in entry point's "
5062
0
                        "interface. "
5063
0
                     << GetIdDesc(*_.FindDef(entry_point));
5064
0
            } else {
5065
0
              cull_primitive_entry_points_.insert(entry_point);
5066
0
            }
5067
0
          }
5068
0
        }
5069
5070
0
        break;
5071
0
      }
5072
0
      default:
5073
0
        assert(0 && "Unexpected mesh EXT builtin");
5074
0
    }
5075
5076
    // - We know this only allowed for Mesh Execution Model.
5077
    // - The Scalar type is is boolean for CullPrimitiveEXT, the other 3 builtin
5078
    // (topology) don't need this type.
5079
    // - It is possible to have multiple mesh
5080
    // shaders (https://github.com/KhronosGroup/SPIRV-Tools/issues/6320) and we
5081
    // need to validate these at reference time.
5082
0
    if (spv_result_t error = ValidateMeshBuiltinInterfaceRules(
5083
0
            decoration, inst, spv::Op::OpTypeBool, inst)) {
5084
0
      return error;
5085
0
    }
5086
0
  }
5087
5088
  // Seed at reference checks with this built-in.
5089
0
  return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst,
5090
0
                                                   inst);
5091
0
}
5092
5093
spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference(
5094
    const Decoration& decoration, const Instruction& built_in_inst,
5095
    const Instruction& referenced_inst,
5096
0
    const Instruction& referenced_from_inst) {
5097
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
5098
0
    const spv::BuiltIn builtin = decoration.builtin();
5099
0
    const spv::StorageClass storage_class =
5100
0
        GetStorageClass(referenced_from_inst);
5101
0
    if (storage_class != spv::StorageClass::Max &&
5102
0
        storage_class != spv::StorageClass::Output) {
5103
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
5104
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
5105
0
             << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env)
5106
0
             << " spec allows BuiltIn "
5107
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
5108
0
                                              uint32_t(builtin))
5109
0
             << " to be only used for variables with Output storage class. "
5110
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
5111
0
                                 referenced_from_inst)
5112
0
             << " " << GetStorageClassDesc(referenced_from_inst);
5113
0
    }
5114
0
    for (const spv::ExecutionModel execution_model : execution_models_) {
5115
0
      if (execution_model != spv::ExecutionModel::MeshEXT) {
5116
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
5117
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
5118
0
               << _.VkErrorID(vuid)
5119
0
               << spvLogStringForEnv(_.context()->target_env)
5120
0
               << " spec allows BuiltIn "
5121
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
5122
0
                                                uint32_t(builtin))
5123
0
               << " to be used only with MeshEXT execution model. "
5124
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
5125
0
                                   referenced_from_inst, execution_model);
5126
0
      }
5127
0
    }
5128
0
  }
5129
5130
0
  if (function_id_ == 0) {
5131
    // Propagate this rule to all dependant ids in the global scope.
5132
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
5133
0
        std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference,
5134
0
                  this, decoration, built_in_inst, referenced_from_inst,
5135
0
                  std::placeholders::_1));
5136
0
  }
5137
5138
0
  return SPV_SUCCESS;
5139
0
}
5140
5141
spv_result_t BuiltInsValidator::ValidateTileQCOMBuiltinAtDefinition(
5142
0
    const Decoration& decoration, const Instruction& inst) {
5143
0
  const spv::BuiltIn builtin = decoration.builtin();
5144
0
  const uint32_t num_components =
5145
0
      (builtin == spv::BuiltIn::TileDimensionQCOM) ? 3 : 2;
5146
0
  if (spv_result_t error = ValidateU32Vec(
5147
0
          decoration, inst, num_components,
5148
0
          [this, &inst, builtin,
5149
0
           num_components](const std::string& msg) -> spv_result_t {
5150
0
            uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType);
5151
0
            return _.diag(SPV_ERROR_INVALID_DATA, &inst)
5152
0
                   << _.VkErrorID(vuid)
5153
0
                   << "According to the Vulkan spec BuiltIn "
5154
0
                   << _.grammar().lookupOperandName(
5155
0
                          SPV_OPERAND_TYPE_BUILT_IN,
5156
0
                          static_cast<uint32_t>(builtin))
5157
0
                   << " variable must be a " << num_components
5158
0
                   << "-component 32-bit unsigned int vector. " << msg;
5159
0
          })) {
5160
0
    return error;
5161
0
  }
5162
5163
0
  return ValidateTileQCOMBuiltinAtReference(decoration, inst, inst, inst);
5164
0
}
5165
5166
spv_result_t BuiltInsValidator::ValidateTileQCOMBuiltinAtReference(
5167
    const Decoration& decoration, const Instruction& built_in_inst,
5168
    const Instruction& referenced_inst,
5169
0
    const Instruction& referenced_from_inst) {
5170
0
  if (spvIsVulkanEnv(_.context()->target_env)) {
5171
0
    const spv::BuiltIn builtin = decoration.builtin();
5172
0
    const spv::StorageClass sc = GetStorageClass(referenced_from_inst);
5173
0
    if (sc != spv::StorageClass::Max && sc != spv::StorageClass::Input) {
5174
0
      uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass);
5175
0
      return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
5176
0
             << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
5177
0
             << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
5178
0
                                              static_cast<uint32_t>(builtin))
5179
0
             << " to be only used for variables with Input storage class. "
5180
0
             << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
5181
0
                                 referenced_from_inst)
5182
0
             << " " << GetStorageClassDesc(referenced_from_inst);
5183
0
    }
5184
5185
0
    for (const spv::ExecutionModel model : execution_models_) {
5186
0
      if (model != spv::ExecutionModel::Fragment &&
5187
0
          model != spv::ExecutionModel::GLCompute) {
5188
0
        uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel);
5189
0
        return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
5190
0
               << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
5191
0
               << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
5192
0
                                                static_cast<uint32_t>(builtin))
5193
0
               << " to be used only with Fragment or GLCompute execution "
5194
0
                  "model. "
5195
0
               << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
5196
0
                                   referenced_from_inst, model);
5197
0
      }
5198
0
    }
5199
0
  }
5200
5201
0
  if (function_id_ == 0) {
5202
0
    id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
5203
0
        std::bind(&BuiltInsValidator::ValidateTileQCOMBuiltinAtReference, this,
5204
0
                  decoration, built_in_inst, referenced_from_inst,
5205
0
                  std::placeholders::_1));
5206
0
  }
5207
5208
0
  return SPV_SUCCESS;
5209
0
}
5210
5211
spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
5212
3.54k
    const Decoration& decoration, const Instruction& inst) {
5213
3.54k
  const spv::BuiltIn label = decoration.builtin();
5214
  // Universial checks
5215
3.54k
  if (label == spv::BuiltIn::WorkgroupSize) {
5216
501
    return ValidateWorkgroupSizeAtDefinition(decoration, inst);
5217
501
  }
5218
5219
3.04k
  if (spvIsVulkanEnv(_.context()->target_env)) {
5220
0
    if (spv_result_t error =
5221
0
            ValidateSingleBuiltInAtDefinitionVulkan(decoration, inst, label)) {
5222
0
      return error;
5223
0
    }
5224
5225
0
    if (IsVolatileSemanticsBuiltIn(label)) {
5226
0
      return ValidateVolatileSemantics(decoration, inst);
5227
0
    }
5228
0
  }
5229
3.04k
  return SPV_SUCCESS;
5230
3.04k
}
5231
5232
spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinitionVulkan(
5233
    const Decoration& decoration, const Instruction& inst,
5234
0
    const spv::BuiltIn label) {
5235
  // If you are adding a new BuiltIn enum, please register it here.
5236
  // If the newly added enum has validation rules associated with it
5237
  // consider leaving a TODO and/or creating an issue.
5238
0
  switch (label) {
5239
0
    case spv::BuiltIn::ClipDistance:
5240
0
    case spv::BuiltIn::CullDistance: {
5241
0
      return ValidateClipOrCullDistanceAtDefinition(decoration, inst);
5242
0
    }
5243
0
    case spv::BuiltIn::FragCoord: {
5244
0
      return ValidateFragCoordAtDefinition(decoration, inst);
5245
0
    }
5246
0
    case spv::BuiltIn::FragDepth: {
5247
0
      return ValidateFragDepthAtDefinition(decoration, inst);
5248
0
    }
5249
0
    case spv::BuiltIn::FrontFacing: {
5250
0
      return ValidateFrontFacingAtDefinition(decoration, inst);
5251
0
    }
5252
0
    case spv::BuiltIn::GlobalInvocationId:
5253
0
    case spv::BuiltIn::LocalInvocationId:
5254
0
    case spv::BuiltIn::NumWorkgroups:
5255
0
    case spv::BuiltIn::WorkgroupId: {
5256
0
      return ValidateComputeShaderI32Vec3InputAtDefinition(decoration, inst);
5257
0
    }
5258
0
    case spv::BuiltIn::BaryCoordKHR:
5259
0
    case spv::BuiltIn::BaryCoordNoPerspKHR: {
5260
0
      return ValidateFragmentShaderF32Vec3InputAtDefinition(decoration, inst);
5261
0
    }
5262
0
    case spv::BuiltIn::HelperInvocation: {
5263
0
      return ValidateHelperInvocationAtDefinition(decoration, inst);
5264
0
    }
5265
0
    case spv::BuiltIn::InvocationId: {
5266
0
      return ValidateInvocationIdAtDefinition(decoration, inst);
5267
0
    }
5268
0
    case spv::BuiltIn::InstanceIndex: {
5269
0
      return ValidateInstanceIndexAtDefinition(decoration, inst);
5270
0
    }
5271
0
    case spv::BuiltIn::Layer:
5272
0
    case spv::BuiltIn::ViewportIndex: {
5273
0
      return ValidateLayerOrViewportIndexAtDefinition(decoration, inst);
5274
0
    }
5275
0
    case spv::BuiltIn::PatchVertices: {
5276
0
      return ValidatePatchVerticesAtDefinition(decoration, inst);
5277
0
    }
5278
0
    case spv::BuiltIn::PointCoord: {
5279
0
      return ValidatePointCoordAtDefinition(decoration, inst);
5280
0
    }
5281
0
    case spv::BuiltIn::PointSize: {
5282
0
      return ValidatePointSizeAtDefinition(decoration, inst);
5283
0
    }
5284
0
    case spv::BuiltIn::Position: {
5285
0
      return ValidatePositionAtDefinition(decoration, inst);
5286
0
    }
5287
0
    case spv::BuiltIn::PrimitiveId: {
5288
0
      return ValidatePrimitiveIdAtDefinition(decoration, inst);
5289
0
    }
5290
0
    case spv::BuiltIn::SampleId: {
5291
0
      return ValidateSampleIdAtDefinition(decoration, inst);
5292
0
    }
5293
0
    case spv::BuiltIn::SampleMask: {
5294
0
      return ValidateSampleMaskAtDefinition(decoration, inst);
5295
0
    }
5296
0
    case spv::BuiltIn::SamplePosition: {
5297
0
      return ValidateSamplePositionAtDefinition(decoration, inst);
5298
0
    }
5299
0
    case spv::BuiltIn::SubgroupId:
5300
0
    case spv::BuiltIn::NumSubgroups: {
5301
0
      return ValidateComputeI32InputAtDefinition(decoration, inst);
5302
0
    }
5303
0
    case spv::BuiltIn::SubgroupLocalInvocationId:
5304
0
    case spv::BuiltIn::SubgroupSize: {
5305
0
      return ValidateI32InputAtDefinition(decoration, inst);
5306
0
    }
5307
0
    case spv::BuiltIn::SubgroupEqMask:
5308
0
    case spv::BuiltIn::SubgroupGeMask:
5309
0
    case spv::BuiltIn::SubgroupGtMask:
5310
0
    case spv::BuiltIn::SubgroupLeMask:
5311
0
    case spv::BuiltIn::SubgroupLtMask: {
5312
0
      return ValidateI32Vec4InputAtDefinition(decoration, inst);
5313
0
    }
5314
0
    case spv::BuiltIn::TessCoord: {
5315
0
      return ValidateTessCoordAtDefinition(decoration, inst);
5316
0
    }
5317
0
    case spv::BuiltIn::TessLevelOuter: {
5318
0
      return ValidateTessLevelOuterAtDefinition(decoration, inst);
5319
0
    }
5320
0
    case spv::BuiltIn::TessLevelInner: {
5321
0
      return ValidateTessLevelInnerAtDefinition(decoration, inst);
5322
0
    }
5323
0
    case spv::BuiltIn::VertexIndex: {
5324
0
      return ValidateVertexIndexAtDefinition(decoration, inst);
5325
0
    }
5326
0
    case spv::BuiltIn::VertexId: {
5327
0
      return ValidateVertexIdAtDefinition(decoration, inst);
5328
0
    }
5329
0
    case spv::BuiltIn::LocalInvocationIndex: {
5330
0
      return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
5331
0
    }
5332
0
    case spv::BuiltIn::CoreIDARM:
5333
0
    case spv::BuiltIn::CoreCountARM:
5334
0
    case spv::BuiltIn::CoreMaxIDARM:
5335
0
    case spv::BuiltIn::WarpIDARM:
5336
0
    case spv::BuiltIn::WarpMaxIDARM:
5337
0
    case spv::BuiltIn::WarpsPerSMNV:
5338
0
    case spv::BuiltIn::SMCountNV:
5339
0
    case spv::BuiltIn::WarpIDNV:
5340
0
    case spv::BuiltIn::SMIDNV: {
5341
0
      return ValidateNVSMOrARMCoreBuiltinsAtDefinition(decoration, inst);
5342
0
    }
5343
0
    case spv::BuiltIn::BaseInstance:
5344
0
    case spv::BuiltIn::BaseVertex: {
5345
0
      return ValidateBaseInstanceOrVertexAtDefinition(decoration, inst);
5346
0
    }
5347
0
    case spv::BuiltIn::DrawIndex: {
5348
0
      return ValidateDrawIndexAtDefinition(decoration, inst);
5349
0
    }
5350
0
    case spv::BuiltIn::ViewIndex: {
5351
0
      return ValidateViewIndexAtDefinition(decoration, inst);
5352
0
    }
5353
0
    case spv::BuiltIn::DeviceIndex: {
5354
0
      return ValidateDeviceIndexAtDefinition(decoration, inst);
5355
0
    }
5356
0
    case spv::BuiltIn::FragInvocationCountEXT: {
5357
      // alias spv::BuiltIn::InvocationsPerPixelNV
5358
0
      return ValidateFragInvocationCountAtDefinition(decoration, inst);
5359
0
    }
5360
0
    case spv::BuiltIn::FragSizeEXT: {
5361
      // alias spv::BuiltIn::FragmentSizeNV
5362
0
      return ValidateFragSizeAtDefinition(decoration, inst);
5363
0
    }
5364
0
    case spv::BuiltIn::FragStencilRefEXT: {
5365
0
      return ValidateFragStencilRefAtDefinition(decoration, inst);
5366
0
    }
5367
0
    case spv::BuiltIn::FullyCoveredEXT:{
5368
0
      return ValidateFullyCoveredAtDefinition(decoration, inst);
5369
0
    }
5370
    // Ray tracing builtins
5371
0
    case spv::BuiltIn::HitKindKHR:  // alias HitKindNV
5372
0
    case spv::BuiltIn::HitTNV:      // NOT present in KHR
5373
0
    case spv::BuiltIn::InstanceId:
5374
0
    case spv::BuiltIn::LaunchIdKHR:             // alias LaunchIdNV
5375
0
    case spv::BuiltIn::LaunchSizeKHR:           // alias LaunchSizeNV
5376
0
    case spv::BuiltIn::WorldRayOriginKHR:       // alias WorldRayOriginNV
5377
0
    case spv::BuiltIn::WorldRayDirectionKHR:    // alias WorldRayDirectionNV
5378
0
    case spv::BuiltIn::ObjectRayOriginKHR:      // alias ObjectRayOriginNV
5379
0
    case spv::BuiltIn::ObjectRayDirectionKHR:   // alias ObjectRayDirectionNV
5380
0
    case spv::BuiltIn::RayTminKHR:              // alias RayTminNV
5381
0
    case spv::BuiltIn::RayTmaxKHR:              // alias RayTmaxNV
5382
0
    case spv::BuiltIn::InstanceCustomIndexKHR:  // alias InstanceCustomIndexNV
5383
0
    case spv::BuiltIn::ObjectToWorldKHR:        // alias ObjectToWorldNV
5384
0
    case spv::BuiltIn::WorldToObjectKHR:        // alias WorldToObjectNV
5385
0
    case spv::BuiltIn::IncomingRayFlagsKHR:     // alias IncomingRayFlagsNV
5386
0
    case spv::BuiltIn::RayGeometryIndexKHR:    // NOT present in NV
5387
0
    case spv::BuiltIn::HitTriangleVertexPositionsKHR:
5388
0
    case spv::BuiltIn::CullMaskKHR: {
5389
0
      return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
5390
0
    }
5391
    // These are only for Mesh, not Task execution model
5392
0
    case spv::BuiltIn::CullPrimitiveEXT:
5393
0
    case spv::BuiltIn::PrimitivePointIndicesEXT:
5394
0
    case spv::BuiltIn::PrimitiveLineIndicesEXT:
5395
0
    case spv::BuiltIn::PrimitiveTriangleIndicesEXT: {
5396
0
      return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst);
5397
0
    }
5398
0
    case spv::BuiltIn::PrimitiveShadingRateKHR: {
5399
0
      return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
5400
0
    }
5401
0
    case spv::BuiltIn::ShadingRateKHR: {
5402
0
      return ValidateShadingRateAtDefinition(decoration, inst);
5403
0
    }
5404
0
    case spv::BuiltIn::SamplerHeapEXT:
5405
0
    case spv::BuiltIn::ResourceHeapEXT: {
5406
0
      return ValidateDescriptorHeapAtDefinition(decoration, inst);
5407
0
    }
5408
0
    case spv::BuiltIn::TileOffsetQCOM:
5409
0
    case spv::BuiltIn::TileDimensionQCOM:
5410
0
    case spv::BuiltIn::TileApronSizeQCOM: {
5411
0
      return ValidateTileQCOMBuiltinAtDefinition(decoration, inst);
5412
0
    }
5413
0
    default:
5414
      // No validation rules (for the moment).
5415
0
      break;
5416
0
  }
5417
0
  return SPV_SUCCESS;
5418
0
}
5419
5420
23.5k
spv_result_t BuiltInsValidator::ValidateBuiltInsAtDefinition() {
5421
320k
  for (const auto& kv : _.id_decorations()) {
5422
320k
    const uint32_t id = kv.first;
5423
320k
    const auto& decorations = kv.second;
5424
320k
    if (decorations.empty()) {
5425
229k
      continue;
5426
229k
    }
5427
5428
91.0k
    const Instruction* inst = _.FindDef(id);
5429
91.0k
    assert(inst);
5430
5431
105k
    for (const auto& decoration : kv.second) {
5432
105k
      if (decoration.dec_type() != spv::Decoration::BuiltIn) {
5433
102k
        continue;
5434
102k
      }
5435
5436
3.54k
      if (spv_result_t error =
5437
3.54k
              ValidateSingleBuiltInAtDefinition(decoration, *inst)) {
5438
3
        return error;
5439
3
      }
5440
3.54k
    }
5441
91.0k
  }
5442
5443
23.5k
  return SPV_SUCCESS;
5444
23.5k
}
5445
5446
23.5k
spv_result_t BuiltInsValidator::Run() {
5447
  // First pass: validate all built-ins at definition and seed
5448
  // id_to_at_reference_checks_ with built-ins.
5449
23.5k
  if (auto error = ValidateBuiltInsAtDefinition()) {
5450
3
    return error;
5451
3
  }
5452
5453
23.5k
  if (id_to_at_reference_checks_.empty()) {
5454
    // No validation tasks were seeded. Nothing else to do.
5455
23.2k
    return SPV_SUCCESS;
5456
23.2k
  }
5457
5458
  // Second pass: validate every id reference in the module using
5459
  // rules in id_to_at_reference_checks_.
5460
10.4k
  for (const Instruction& inst : _.ordered_instructions()) {
5461
10.4k
    Update(inst);
5462
5463
10.4k
    std::set<uint32_t> already_checked;
5464
5465
15.0k
    for (const auto& operand : inst.operands()) {
5466
15.0k
      if (!spvIsIdType(operand.type)) {
5467
        // Not id.
5468
5.91k
        continue;
5469
5.91k
      }
5470
5471
9.12k
      const uint32_t id = inst.word(operand.offset);
5472
9.12k
      if (id == inst.id()) {
5473
        // No need to check result id.
5474
2.48k
        continue;
5475
2.48k
      }
5476
5477
6.64k
      if (!already_checked.insert(id).second) {
5478
        // The instruction has already referenced this id.
5479
259
        continue;
5480
259
      }
5481
5482
      // Instruction references the id. Run all checks associated with the id
5483
      // on the instruction. id_to_at_reference_checks_ can be modified in the
5484
      // process, iterators are safe because it's a tree-based map.
5485
6.38k
      const auto it = id_to_at_reference_checks_.find(id);
5486
6.38k
      if (it != id_to_at_reference_checks_.end()) {
5487
3.93k
        for (const auto& check : it->second) {
5488
3.93k
          if (spv_result_t error = check(inst)) {
5489
0
            return error;
5490
0
          }
5491
3.93k
        }
5492
3.87k
      }
5493
6.38k
    }
5494
10.4k
  }
5495
5496
348
  return SPV_SUCCESS;
5497
348
}
5498
5499
}  // namespace
5500
5501
// Validates correctness of built-in variables.
5502
23.5k
spv_result_t ValidateBuiltIns(ValidationState_t& _) {
5503
23.5k
  BuiltInsValidator validator(_);
5504
23.5k
  return validator.Run();
5505
23.5k
}
5506
5507
}  // namespace val
5508
}  // namespace spvtools