Coverage Report

Created: 2025-06-13 06:48

/src/shaderc/third_party/spirv-tools/source/opcode.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2015-2022 The Khronos Group Inc.
2
// Modifications Copyright (C) 2020-2024 Advanced Micro Devices, Inc. All
3
// rights reserved.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
//     http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
17
#include "source/opcode.h"
18
19
#include <assert.h>
20
#include <string.h>
21
22
#include <algorithm>
23
#include <cstdlib>
24
25
#include "source/instruction.h"
26
#include "source/macro.h"
27
#include "source/spirv_constant.h"
28
#include "source/spirv_endian.h"
29
#include "source/spirv_target_env.h"
30
#include "spirv-tools/libspirv.h"
31
32
namespace {
33
struct OpcodeDescPtrLen {
34
  const spv_opcode_desc_t* ptr;
35
  uint32_t len;
36
};
37
38
#include "core.insts-unified1.inc"
39
40
static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
41
                                                kOpcodeTableEntries};
42
43
// Represents a vendor tool entry in the SPIR-V XML Registry.
44
struct VendorTool {
45
  uint32_t value;
46
  const char* vendor;
47
  const char* tool;         // Might be empty string.
48
  const char* vendor_tool;  // Combination of vendor and tool.
49
};
50
51
const VendorTool vendor_tools[] = {
52
#include "generators.inc"
53
};
54
55
}  // anonymous namespace
56
57
// TODO(dneto): Move this to another file.  It doesn't belong with opcode
58
// processing.
59
977
const char* spvGeneratorStr(uint32_t generator) {
60
977
  auto where = std::find_if(
61
977
      std::begin(vendor_tools), std::end(vendor_tools),
62
13.6k
      [generator](const VendorTool& vt) { return generator == vt.value; });
63
977
  if (where != std::end(vendor_tools)) return where->vendor_tool;
64
0
  return "Unknown";
65
977
}
66
67
0
uint32_t spvOpcodeMake(uint16_t wordCount, spv::Op opcode) {
68
0
  return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
69
0
}
70
71
void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
72
954k
                    uint16_t* pOpcode) {
73
954k
  if (pWordCount) {
74
954k
    *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
75
954k
  }
76
954k
  if (pOpcode) {
77
954k
    *pOpcode = 0x0000ffff & word;
78
954k
  }
79
954k
}
80
81
6.00k
spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, spv_target_env) {
82
6.00k
  if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
83
84
  // Descriptions of each opcode.  Each entry describes the format of the
85
  // instruction that follows a particular opcode.
86
87
6.00k
  *pInstTable = &kOpcodeTable;
88
6.00k
  return SPV_SUCCESS;
89
6.00k
}
90
91
spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
92
                                      const spv_opcode_table table,
93
                                      const char* name,
94
0
                                      spv_opcode_desc* pEntry) {
95
0
  if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
96
0
  if (!table) return SPV_ERROR_INVALID_TABLE;
97
98
  // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
99
  // preferable but the table requires sorting on the Opcode name, but it's
100
  // static const initialized and matches the order of the spec.
101
0
  const size_t nameLength = strlen(name);
102
0
  const auto version = spvVersionForTargetEnv(env);
103
0
  for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
104
0
    const spv_opcode_desc_t& entry = table->entries[opcodeIndex];
105
    // We consider the current opcode as available as long as
106
    // 1. The target environment satisfies the minimal requirement of the
107
    //    opcode; or
108
    // 2. There is at least one extension enabling this opcode.
109
    //
110
    // Note that the second rule assumes the extension enabling this instruction
111
    // is indeed requested in the SPIR-V code; checking that should be
112
    // validator's work.
113
0
    if ((version >= entry.minVersion && version <= entry.lastVersion) ||
114
0
        entry.numExtensions > 0u || entry.numCapabilities > 0u) {
115
      // Exact match case.
116
0
      if (nameLength == strlen(entry.name) &&
117
0
          !strncmp(name, entry.name, nameLength)) {
118
0
        *pEntry = &entry;
119
0
        return SPV_SUCCESS;
120
0
      }
121
      // Lack of binary search really hurts here. There isn't an easy filter to
122
      // apply before checking aliases since we need to handle promotion from
123
      // vendor to KHR/EXT and KHR/EXT to core. It would require a sure-fire way
124
      // of dropping suffices. Fortunately, most lookup are based on token
125
      // value.
126
      //
127
      // If this was a binary search we could iterate between the lower and
128
      // upper bounds.
129
0
      if (entry.numAliases > 0) {
130
0
        for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
131
0
             aliasIndex++) {
132
          // Skip Op prefix. Should this be encoded in the table instead?
133
0
          const auto alias = entry.aliases[aliasIndex] + 2;
134
0
          const size_t aliasLength = strlen(alias);
135
0
          if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
136
0
            *pEntry = &entry;
137
0
            return SPV_SUCCESS;
138
0
          }
139
0
        }
140
0
      }
141
0
    }
142
0
  }
143
144
0
  return SPV_ERROR_INVALID_LOOKUP;
145
0
}
146
147
spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
148
                                       const spv_opcode_table table,
149
                                       const spv::Op opcode,
150
1.44M
                                       spv_opcode_desc* pEntry) {
151
1.44M
  if (!table) return SPV_ERROR_INVALID_TABLE;
152
1.44M
  if (!pEntry) return SPV_ERROR_INVALID_POINTER;
153
154
1.44M
  const auto beg = table->entries;
155
1.44M
  const auto end = table->entries + table->count;
156
157
1.44M
  spv_opcode_desc_t needle = {"", opcode, 0,     nullptr, 0,       {},  0,
158
1.44M
                              {}, false,  false, 0,       nullptr, ~0u, ~0u};
159
160
14.2M
  auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
161
14.2M
    return lhs.opcode < rhs.opcode;
162
14.2M
  };
163
164
  // We need to loop here because there can exist multiple symbols for the same
165
  // opcode value, and they can be introduced in different target environments,
166
  // which means they can have different minimal version requirements.
167
  // Assumes the underlying table is already sorted ascendingly according to
168
  // opcode value.
169
1.44M
  const auto version = spvVersionForTargetEnv(env);
170
1.44M
  for (auto it = std::lower_bound(beg, end, needle, comp);
171
1.44M
       it != end && it->opcode == opcode; ++it) {
172
    // We considers the current opcode as available as long as
173
    // 1. The target environment satisfies the minimal requirement of the
174
    //    opcode; or
175
    // 2. There is at least one extension enabling this opcode.
176
    //
177
    // Note that the second rule assumes the extension enabling this instruction
178
    // is indeed requested in the SPIR-V code; checking that should be
179
    // validator's work.
180
1.44M
    if ((version >= it->minVersion && version <= it->lastVersion) ||
181
1.44M
        it->numExtensions > 0u || it->numCapabilities > 0u) {
182
1.44M
      *pEntry = it;
183
1.44M
      return SPV_SUCCESS;
184
1.44M
    }
185
1.44M
  }
186
187
0
  return SPV_ERROR_INVALID_LOOKUP;
188
1.44M
}
189
190
void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
191
                        const uint16_t wordCount, const spv_endianness_t endian,
192
0
                        spv_instruction_t* pInst) {
193
0
  pInst->opcode = opcode;
194
0
  pInst->words.resize(wordCount);
195
0
  for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
196
0
    pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
197
0
    if (!wordIndex) {
198
0
      uint16_t thisWordCount;
199
0
      uint16_t thisOpcode;
200
0
      spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
201
0
      assert(opcode == static_cast<spv::Op>(thisOpcode) &&
202
0
             wordCount == thisWordCount && "Endianness failed!");
203
0
    }
204
0
  }
205
0
}
206
207
99.7k
const char* spvOpcodeString(const uint32_t opcode) {
208
99.7k
  const auto beg = kOpcodeTableEntries;
209
99.7k
  const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
210
99.7k
  spv_opcode_desc_t needle = {"",    static_cast<spv::Op>(opcode),
211
99.7k
                              0,     nullptr,
212
99.7k
                              0,     {},
213
99.7k
                              0,     {},
214
99.7k
                              false, false,
215
99.7k
                              0,     nullptr,
216
99.7k
                              ~0u,   ~0u};
217
980k
  auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
218
980k
    return lhs.opcode < rhs.opcode;
219
980k
  };
220
99.7k
  auto it = std::lower_bound(beg, end, needle, comp);
221
99.7k
  if (it != end && it->opcode == spv::Op(opcode)) {
222
99.7k
    return it->name;
223
99.7k
  }
224
225
0
  assert(0 && "Unreachable!");
226
0
  return "unknown";
227
99.7k
}
228
229
99.7k
const char* spvOpcodeString(const spv::Op opcode) {
230
99.7k
  return spvOpcodeString(static_cast<uint32_t>(opcode));
231
99.7k
}
232
233
4.96k
int32_t spvOpcodeIsScalarType(const spv::Op opcode) {
234
4.96k
  switch (opcode) {
235
1.79k
    case spv::Op::OpTypeInt:
236
3.87k
    case spv::Op::OpTypeFloat:
237
4.81k
    case spv::Op::OpTypeBool:
238
4.81k
      return true;
239
152
    default:
240
152
      return false;
241
4.96k
  }
242
4.96k
}
243
244
11.5k
int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) {
245
11.5k
  switch (opcode) {
246
2
    case spv::Op::OpSpecConstantTrue:
247
2
    case spv::Op::OpSpecConstantFalse:
248
28
    case spv::Op::OpSpecConstant:
249
34
    case spv::Op::OpSpecConstantComposite:
250
34
    case spv::Op::OpSpecConstantCompositeReplicateEXT:
251
34
    case spv::Op::OpSpecConstantOp:
252
34
      return true;
253
11.4k
    default:
254
11.4k
      return false;
255
11.5k
  }
256
11.5k
}
257
258
910k
int32_t spvOpcodeIsConstant(const spv::Op opcode) {
259
910k
  switch (opcode) {
260
1.75k
    case spv::Op::OpConstantTrue:
261
3.20k
    case spv::Op::OpConstantFalse:
262
76.0k
    case spv::Op::OpConstant:
263
87.1k
    case spv::Op::OpConstantComposite:
264
87.1k
    case spv::Op::OpConstantCompositeReplicateEXT:
265
87.1k
    case spv::Op::OpConstantSampler:
266
87.1k
    case spv::Op::OpConstantNull:
267
87.1k
    case spv::Op::OpConstantFunctionPointerINTEL:
268
87.1k
    case spv::Op::OpConstantStringAMDX:
269
87.1k
    case spv::Op::OpSpecConstantTrue:
270
87.1k
    case spv::Op::OpSpecConstantFalse:
271
87.5k
    case spv::Op::OpSpecConstant:
272
87.6k
    case spv::Op::OpSpecConstantComposite:
273
87.6k
    case spv::Op::OpSpecConstantCompositeReplicateEXT:
274
87.7k
    case spv::Op::OpSpecConstantOp:
275
87.7k
    case spv::Op::OpSpecConstantStringAMDX:
276
87.7k
      return true;
277
822k
    default:
278
822k
      return false;
279
910k
  }
280
910k
}
281
282
4.73k
bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
283
4.73k
  return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
284
4.73k
}
285
286
110
bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
287
110
  switch (opcode) {
288
12
    case spv::Op::OpSpecConstantTrue:
289
12
    case spv::Op::OpSpecConstantFalse:
290
104
    case spv::Op::OpSpecConstant:
291
104
      return true;
292
6
    default:
293
6
      return false;
294
110
  }
295
110
}
296
297
5.91k
int32_t spvOpcodeIsComposite(const spv::Op opcode) {
298
5.91k
  switch (opcode) {
299
2.09k
    case spv::Op::OpTypeVector:
300
2.45k
    case spv::Op::OpTypeMatrix:
301
2.50k
    case spv::Op::OpTypeArray:
302
2.50k
    case spv::Op::OpTypeStruct:
303
2.50k
    case spv::Op::OpTypeRuntimeArray:
304
2.50k
    case spv::Op::OpTypeCooperativeMatrixNV:
305
2.50k
    case spv::Op::OpTypeCooperativeMatrixKHR:
306
2.50k
    case spv::Op::OpTypeCooperativeVectorNV:
307
2.50k
      return true;
308
3.41k
    default:
309
3.41k
      return false;
310
5.91k
  }
311
5.91k
}
312
313
0
bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
314
0
  switch (opcode) {
315
0
    case spv::Op::OpVariable:
316
0
    case spv::Op::OpUntypedVariableKHR:
317
0
    case spv::Op::OpAccessChain:
318
0
    case spv::Op::OpInBoundsAccessChain:
319
0
    case spv::Op::OpUntypedAccessChainKHR:
320
0
    case spv::Op::OpUntypedInBoundsAccessChainKHR:
321
0
    case spv::Op::OpFunctionParameter:
322
0
    case spv::Op::OpImageTexelPointer:
323
0
    case spv::Op::OpCopyObject:
324
0
    case spv::Op::OpAllocateNodePayloadsAMDX:
325
0
    case spv::Op::OpSelect:
326
0
    case spv::Op::OpPhi:
327
0
    case spv::Op::OpFunctionCall:
328
0
    case spv::Op::OpPtrAccessChain:
329
0
    case spv::Op::OpUntypedPtrAccessChainKHR:
330
0
    case spv::Op::OpLoad:
331
0
    case spv::Op::OpConstantNull:
332
0
    case spv::Op::OpRawAccessChainNV:
333
0
      return true;
334
0
    default:
335
0
      return false;
336
0
  }
337
0
}
338
339
46.2k
int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
340
46.2k
  switch (opcode) {
341
35.9k
    case spv::Op::OpVariable:
342
35.9k
    case spv::Op::OpUntypedVariableKHR:
343
44.8k
    case spv::Op::OpAccessChain:
344
44.8k
    case spv::Op::OpInBoundsAccessChain:
345
44.8k
    case spv::Op::OpUntypedAccessChainKHR:
346
44.8k
    case spv::Op::OpUntypedInBoundsAccessChainKHR:
347
46.2k
    case spv::Op::OpFunctionParameter:
348
46.2k
    case spv::Op::OpImageTexelPointer:
349
46.2k
    case spv::Op::OpCopyObject:
350
46.2k
    case spv::Op::OpRawAccessChainNV:
351
46.2k
    case spv::Op::OpAllocateNodePayloadsAMDX:
352
46.2k
      return true;
353
0
    default:
354
0
      return false;
355
46.2k
  }
356
46.2k
}
357
358
2.99M
int32_t spvOpcodeGeneratesType(spv::Op op) {
359
2.99M
  switch (op) {
360
38.0k
    case spv::Op::OpTypeVoid:
361
56.7k
    case spv::Op::OpTypeBool:
362
113k
    case spv::Op::OpTypeInt:
363
155k
    case spv::Op::OpTypeFloat:
364
254k
    case spv::Op::OpTypeVector:
365
265k
    case spv::Op::OpTypeMatrix:
366
285k
    case spv::Op::OpTypeImage:
367
287k
    case spv::Op::OpTypeSampler:
368
297k
    case spv::Op::OpTypeSampledImage:
369
311k
    case spv::Op::OpTypeArray:
370
312k
    case spv::Op::OpTypeRuntimeArray:
371
343k
    case spv::Op::OpTypeStruct:
372
343k
    case spv::Op::OpTypeOpaque:
373
525k
    case spv::Op::OpTypePointer:
374
569k
    case spv::Op::OpTypeFunction:
375
569k
    case spv::Op::OpTypeEvent:
376
569k
    case spv::Op::OpTypeDeviceEvent:
377
569k
    case spv::Op::OpTypeReserveId:
378
569k
    case spv::Op::OpTypeQueue:
379
569k
    case spv::Op::OpTypePipe:
380
569k
    case spv::Op::OpTypePipeStorage:
381
569k
    case spv::Op::OpTypeNamedBarrier:
382
570k
    case spv::Op::OpTypeAccelerationStructureNV:
383
570k
    case spv::Op::OpTypeCooperativeMatrixNV:
384
570k
    case spv::Op::OpTypeCooperativeMatrixKHR:
385
570k
    case spv::Op::OpTypeCooperativeVectorNV:
386
    // case spv::Op::OpTypeAccelerationStructureKHR: covered by
387
    // spv::Op::OpTypeAccelerationStructureNV
388
572k
    case spv::Op::OpTypeRayQueryKHR:
389
572k
    case spv::Op::OpTypeHitObjectNV:
390
572k
    case spv::Op::OpTypeUntypedPointerKHR:
391
572k
    case spv::Op::OpTypeNodePayloadArrayAMDX:
392
572k
    case spv::Op::OpTypeTensorLayoutNV:
393
572k
    case spv::Op::OpTypeTensorViewNV:
394
572k
      return true;
395
2.42M
    default:
396
      // In particular, OpTypeForwardPointer does not generate a type,
397
      // but declares a storage class for a pointer type generated
398
      // by a different instruction.
399
2.42M
      break;
400
2.99M
  }
401
2.42M
  return 0;
402
2.99M
}
403
404
305k
bool spvOpcodeIsDecoration(const spv::Op opcode) {
405
305k
  switch (opcode) {
406
476
    case spv::Op::OpDecorate:
407
476
    case spv::Op::OpDecorateId:
408
530
    case spv::Op::OpMemberDecorate:
409
530
    case spv::Op::OpGroupDecorate:
410
530
    case spv::Op::OpGroupMemberDecorate:
411
530
    case spv::Op::OpDecorateStringGOOGLE:
412
530
    case spv::Op::OpMemberDecorateStringGOOGLE:
413
530
      return true;
414
304k
    default:
415
304k
      break;
416
305k
  }
417
304k
  return false;
418
305k
}
419
420
421k
bool spvOpcodeIsLoad(const spv::Op opcode) {
421
421k
  switch (opcode) {
422
36.7k
    case spv::Op::OpLoad:
423
43.7k
    case spv::Op::OpImageSampleExplicitLod:
424
43.7k
    case spv::Op::OpImageSampleImplicitLod:
425
43.7k
    case spv::Op::OpImageSampleDrefImplicitLod:
426
43.7k
    case spv::Op::OpImageSampleDrefExplicitLod:
427
43.7k
    case spv::Op::OpImageSampleProjImplicitLod:
428
43.7k
    case spv::Op::OpImageSampleProjExplicitLod:
429
43.7k
    case spv::Op::OpImageSampleProjDrefImplicitLod:
430
43.7k
    case spv::Op::OpImageSampleProjDrefExplicitLod:
431
43.7k
    case spv::Op::OpImageSampleFootprintNV:
432
43.7k
    case spv::Op::OpImageFetch:
433
43.7k
    case spv::Op::OpImageGather:
434
43.7k
    case spv::Op::OpImageDrefGather:
435
44.0k
    case spv::Op::OpImageRead:
436
44.0k
    case spv::Op::OpImageSparseSampleImplicitLod:
437
44.0k
    case spv::Op::OpImageSparseSampleExplicitLod:
438
44.0k
    case spv::Op::OpImageSparseSampleDrefExplicitLod:
439
44.0k
    case spv::Op::OpImageSparseSampleDrefImplicitLod:
440
44.0k
    case spv::Op::OpImageSparseFetch:
441
44.0k
    case spv::Op::OpImageSparseGather:
442
44.0k
    case spv::Op::OpImageSparseDrefGather:
443
44.2k
    case spv::Op::OpImageSparseRead:
444
44.2k
      return true;
445
377k
    default:
446
377k
      return false;
447
421k
  }
448
421k
}
449
450
1.55M
bool spvOpcodeIsBranch(spv::Op opcode) {
451
1.55M
  switch (opcode) {
452
148k
    case spv::Op::OpBranch:
453
233k
    case spv::Op::OpBranchConditional:
454
241k
    case spv::Op::OpSwitch:
455
241k
      return true;
456
1.31M
    default:
457
1.31M
      return false;
458
1.55M
  }
459
1.55M
}
460
461
994k
bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
462
994k
  switch (opcode) {
463
0
    case spv::Op::OpAtomicLoad:
464
0
    case spv::Op::OpAtomicExchange:
465
0
    case spv::Op::OpAtomicCompareExchange:
466
0
    case spv::Op::OpAtomicCompareExchangeWeak:
467
0
    case spv::Op::OpAtomicIIncrement:
468
0
    case spv::Op::OpAtomicIDecrement:
469
0
    case spv::Op::OpAtomicIAdd:
470
0
    case spv::Op::OpAtomicFAddEXT:
471
0
    case spv::Op::OpAtomicISub:
472
0
    case spv::Op::OpAtomicSMin:
473
0
    case spv::Op::OpAtomicUMin:
474
0
    case spv::Op::OpAtomicFMinEXT:
475
0
    case spv::Op::OpAtomicSMax:
476
0
    case spv::Op::OpAtomicUMax:
477
0
    case spv::Op::OpAtomicFMaxEXT:
478
0
    case spv::Op::OpAtomicAnd:
479
0
    case spv::Op::OpAtomicOr:
480
0
    case spv::Op::OpAtomicXor:
481
0
    case spv::Op::OpAtomicFlagTestAndSet:
482
0
      return true;
483
994k
    default:
484
994k
      return false;
485
994k
  }
486
994k
}
487
488
0
bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
489
0
  return (spvOpcodeIsAtomicWithLoad(opcode) ||
490
0
          opcode == spv::Op::OpAtomicStore ||
491
0
          opcode == spv::Op::OpAtomicFlagClear);
492
0
}
493
494
589k
bool spvOpcodeIsReturn(spv::Op opcode) {
495
589k
  switch (opcode) {
496
13.2k
    case spv::Op::OpReturn:
497
15.7k
    case spv::Op::OpReturnValue:
498
15.7k
      return true;
499
574k
    default:
500
574k
      return false;
501
589k
  }
502
589k
}
503
504
560k
bool spvOpcodeIsAbort(spv::Op opcode) {
505
560k
  switch (opcode) {
506
0
    case spv::Op::OpKill:
507
2
    case spv::Op::OpUnreachable:
508
2
    case spv::Op::OpTerminateInvocation:
509
2
    case spv::Op::OpTerminateRayKHR:
510
2
    case spv::Op::OpIgnoreIntersectionKHR:
511
2
    case spv::Op::OpEmitMeshTasksEXT:
512
2
      return true;
513
560k
    default:
514
560k
      return false;
515
560k
  }
516
560k
}
517
518
561k
bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
519
561k
  return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
520
561k
}
521
522
586k
bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
523
586k
  return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
524
586k
}
525
526
0
bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
527
0
  switch (opcode) {
528
0
    case spv::Op::OpTypeImage:
529
0
    case spv::Op::OpTypeSampler:
530
0
    case spv::Op::OpTypeSampledImage:
531
0
    case spv::Op::OpTypeOpaque:
532
0
    case spv::Op::OpTypeEvent:
533
0
    case spv::Op::OpTypeDeviceEvent:
534
0
    case spv::Op::OpTypeReserveId:
535
0
    case spv::Op::OpTypeQueue:
536
0
    case spv::Op::OpTypePipe:
537
0
    case spv::Op::OpTypeForwardPointer:
538
0
    case spv::Op::OpTypePipeStorage:
539
0
    case spv::Op::OpTypeNamedBarrier:
540
0
      return true;
541
0
    default:
542
0
      return false;
543
0
  }
544
0
}
545
546
243k
bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
547
243k
  switch (opcode) {
548
0
    case spv::Op::OpGroupNonUniformElect:
549
0
    case spv::Op::OpGroupNonUniformAll:
550
0
    case spv::Op::OpGroupNonUniformAny:
551
0
    case spv::Op::OpGroupNonUniformAllEqual:
552
0
    case spv::Op::OpGroupNonUniformBroadcast:
553
0
    case spv::Op::OpGroupNonUniformBroadcastFirst:
554
0
    case spv::Op::OpGroupNonUniformBallot:
555
0
    case spv::Op::OpGroupNonUniformInverseBallot:
556
0
    case spv::Op::OpGroupNonUniformBallotBitExtract:
557
0
    case spv::Op::OpGroupNonUniformBallotBitCount:
558
0
    case spv::Op::OpGroupNonUniformBallotFindLSB:
559
0
    case spv::Op::OpGroupNonUniformBallotFindMSB:
560
0
    case spv::Op::OpGroupNonUniformShuffle:
561
0
    case spv::Op::OpGroupNonUniformShuffleXor:
562
0
    case spv::Op::OpGroupNonUniformShuffleUp:
563
0
    case spv::Op::OpGroupNonUniformShuffleDown:
564
0
    case spv::Op::OpGroupNonUniformIAdd:
565
0
    case spv::Op::OpGroupNonUniformFAdd:
566
0
    case spv::Op::OpGroupNonUniformIMul:
567
0
    case spv::Op::OpGroupNonUniformFMul:
568
0
    case spv::Op::OpGroupNonUniformSMin:
569
0
    case spv::Op::OpGroupNonUniformUMin:
570
0
    case spv::Op::OpGroupNonUniformFMin:
571
0
    case spv::Op::OpGroupNonUniformSMax:
572
0
    case spv::Op::OpGroupNonUniformUMax:
573
0
    case spv::Op::OpGroupNonUniformFMax:
574
0
    case spv::Op::OpGroupNonUniformBitwiseAnd:
575
0
    case spv::Op::OpGroupNonUniformBitwiseOr:
576
0
    case spv::Op::OpGroupNonUniformBitwiseXor:
577
0
    case spv::Op::OpGroupNonUniformLogicalAnd:
578
0
    case spv::Op::OpGroupNonUniformLogicalOr:
579
0
    case spv::Op::OpGroupNonUniformLogicalXor:
580
0
    case spv::Op::OpGroupNonUniformQuadBroadcast:
581
0
    case spv::Op::OpGroupNonUniformQuadSwap:
582
0
    case spv::Op::OpGroupNonUniformRotateKHR:
583
0
    case spv::Op::OpGroupNonUniformQuadAllKHR:
584
0
    case spv::Op::OpGroupNonUniformQuadAnyKHR:
585
0
      return true;
586
243k
    default:
587
243k
      return false;
588
243k
  }
589
243k
}
590
591
42.4k
bool spvOpcodeIsScalarizable(spv::Op opcode) {
592
42.4k
  switch (opcode) {
593
5.23k
    case spv::Op::OpPhi:
594
5.23k
    case spv::Op::OpCopyObject:
595
5.41k
    case spv::Op::OpConvertFToU:
596
5.44k
    case spv::Op::OpConvertFToS:
597
7.17k
    case spv::Op::OpConvertSToF:
598
7.17k
    case spv::Op::OpConvertUToF:
599
7.18k
    case spv::Op::OpUConvert:
600
7.20k
    case spv::Op::OpSConvert:
601
7.20k
    case spv::Op::OpFConvert:
602
7.20k
    case spv::Op::OpQuantizeToF16:
603
7.20k
    case spv::Op::OpVectorInsertDynamic:
604
7.20k
    case spv::Op::OpSNegate:
605
7.35k
    case spv::Op::OpFNegate:
606
8.88k
    case spv::Op::OpIAdd:
607
12.1k
    case spv::Op::OpFAdd:
608
12.1k
    case spv::Op::OpISub:
609
12.6k
    case spv::Op::OpFSub:
610
12.6k
    case spv::Op::OpIMul:
611
14.7k
    case spv::Op::OpFMul:
612
14.7k
    case spv::Op::OpUDiv:
613
14.7k
    case spv::Op::OpSDiv:
614
16.7k
    case spv::Op::OpFDiv:
615
16.7k
    case spv::Op::OpUMod:
616
16.7k
    case spv::Op::OpSRem:
617
16.7k
    case spv::Op::OpSMod:
618
16.7k
    case spv::Op::OpFRem:
619
16.7k
    case spv::Op::OpFMod:
620
19.7k
    case spv::Op::OpVectorTimesScalar:
621
19.7k
    case spv::Op::OpIAddCarry:
622
19.7k
    case spv::Op::OpISubBorrow:
623
19.7k
    case spv::Op::OpUMulExtended:
624
19.7k
    case spv::Op::OpSMulExtended:
625
19.7k
    case spv::Op::OpShiftRightLogical:
626
19.7k
    case spv::Op::OpShiftRightArithmetic:
627
19.7k
    case spv::Op::OpShiftLeftLogical:
628
19.7k
    case spv::Op::OpBitwiseOr:
629
19.7k
    case spv::Op::OpBitwiseAnd:
630
19.7k
    case spv::Op::OpNot:
631
19.7k
    case spv::Op::OpBitFieldInsert:
632
19.7k
    case spv::Op::OpBitFieldSExtract:
633
19.7k
    case spv::Op::OpBitFieldUExtract:
634
19.7k
    case spv::Op::OpBitReverse:
635
19.7k
    case spv::Op::OpBitCount:
636
19.7k
    case spv::Op::OpIsNan:
637
19.7k
    case spv::Op::OpIsInf:
638
19.7k
    case spv::Op::OpIsFinite:
639
19.7k
    case spv::Op::OpIsNormal:
640
19.7k
    case spv::Op::OpSignBitSet:
641
19.7k
    case spv::Op::OpLessOrGreater:
642
19.7k
    case spv::Op::OpOrdered:
643
19.7k
    case spv::Op::OpUnordered:
644
19.7k
    case spv::Op::OpLogicalEqual:
645
19.7k
    case spv::Op::OpLogicalNotEqual:
646
19.7k
    case spv::Op::OpLogicalOr:
647
19.7k
    case spv::Op::OpLogicalAnd:
648
19.7k
    case spv::Op::OpLogicalNot:
649
19.8k
    case spv::Op::OpSelect:
650
19.8k
    case spv::Op::OpIEqual:
651
20.0k
    case spv::Op::OpINotEqual:
652
20.2k
    case spv::Op::OpUGreaterThan:
653
20.8k
    case spv::Op::OpSGreaterThan:
654
20.8k
    case spv::Op::OpUGreaterThanEqual:
655
20.8k
    case spv::Op::OpSGreaterThanEqual:
656
20.8k
    case spv::Op::OpULessThan:
657
21.3k
    case spv::Op::OpSLessThan:
658
21.3k
    case spv::Op::OpULessThanEqual:
659
21.8k
    case spv::Op::OpSLessThanEqual:
660
22.1k
    case spv::Op::OpFOrdEqual:
661
22.1k
    case spv::Op::OpFUnordEqual:
662
22.1k
    case spv::Op::OpFOrdNotEqual:
663
22.1k
    case spv::Op::OpFUnordNotEqual:
664
22.7k
    case spv::Op::OpFOrdLessThan:
665
22.7k
    case spv::Op::OpFUnordLessThan:
666
23.7k
    case spv::Op::OpFOrdGreaterThan:
667
23.7k
    case spv::Op::OpFUnordGreaterThan:
668
23.7k
    case spv::Op::OpFOrdLessThanEqual:
669
23.7k
    case spv::Op::OpFUnordLessThanEqual:
670
23.7k
    case spv::Op::OpFOrdGreaterThanEqual:
671
23.7k
    case spv::Op::OpFUnordGreaterThanEqual:
672
23.7k
      return true;
673
18.7k
    default:
674
18.7k
      return false;
675
42.4k
  }
676
42.4k
}
677
678
10.2k
bool spvOpcodeIsDebug(spv::Op opcode) {
679
10.2k
  switch (opcode) {
680
0
    case spv::Op::OpName:
681
0
    case spv::Op::OpMemberName:
682
0
    case spv::Op::OpSource:
683
0
    case spv::Op::OpSourceContinued:
684
0
    case spv::Op::OpSourceExtension:
685
0
    case spv::Op::OpString:
686
0
    case spv::Op::OpLine:
687
0
    case spv::Op::OpNoLine:
688
0
    case spv::Op::OpModuleProcessed:
689
0
      return true;
690
10.2k
    default:
691
10.2k
      return false;
692
10.2k
  }
693
10.2k
}
694
695
0
bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
696
0
  switch (opcode) {
697
0
    case spv::Op::OpPtrEqual:
698
0
    case spv::Op::OpPtrNotEqual:
699
0
    case spv::Op::OpIAdd:
700
0
    case spv::Op::OpFAdd:
701
0
    case spv::Op::OpIMul:
702
0
    case spv::Op::OpFMul:
703
0
    case spv::Op::OpDot:
704
0
    case spv::Op::OpIAddCarry:
705
0
    case spv::Op::OpUMulExtended:
706
0
    case spv::Op::OpSMulExtended:
707
0
    case spv::Op::OpBitwiseOr:
708
0
    case spv::Op::OpBitwiseXor:
709
0
    case spv::Op::OpBitwiseAnd:
710
0
    case spv::Op::OpOrdered:
711
0
    case spv::Op::OpUnordered:
712
0
    case spv::Op::OpLogicalEqual:
713
0
    case spv::Op::OpLogicalNotEqual:
714
0
    case spv::Op::OpLogicalOr:
715
0
    case spv::Op::OpLogicalAnd:
716
0
    case spv::Op::OpIEqual:
717
0
    case spv::Op::OpINotEqual:
718
0
    case spv::Op::OpFOrdEqual:
719
0
    case spv::Op::OpFUnordEqual:
720
0
    case spv::Op::OpFOrdNotEqual:
721
0
    case spv::Op::OpFUnordNotEqual:
722
0
      return true;
723
0
    default:
724
0
      return false;
725
0
  }
726
0
}
727
728
0
bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
729
0
  switch (opcode) {
730
0
    case spv::Op::OpTranspose:
731
0
    case spv::Op::OpVectorTimesScalar:
732
0
    case spv::Op::OpMatrixTimesScalar:
733
0
    case spv::Op::OpVectorTimesMatrix:
734
0
    case spv::Op::OpMatrixTimesVector:
735
0
    case spv::Op::OpMatrixTimesMatrix:
736
0
    case spv::Op::OpOuterProduct:
737
0
    case spv::Op::OpDot:
738
0
      return true;
739
0
    default:
740
0
      return false;
741
0
  }
742
0
}
743
744
0
bool spvOpcodeIsImageSample(const spv::Op opcode) {
745
0
  switch (opcode) {
746
0
    case spv::Op::OpImageSampleImplicitLod:
747
0
    case spv::Op::OpImageSampleExplicitLod:
748
0
    case spv::Op::OpImageSampleDrefImplicitLod:
749
0
    case spv::Op::OpImageSampleDrefExplicitLod:
750
0
    case spv::Op::OpImageSampleProjImplicitLod:
751
0
    case spv::Op::OpImageSampleProjExplicitLod:
752
0
    case spv::Op::OpImageSampleProjDrefImplicitLod:
753
0
    case spv::Op::OpImageSampleProjDrefExplicitLod:
754
0
    case spv::Op::OpImageSparseSampleImplicitLod:
755
0
    case spv::Op::OpImageSparseSampleExplicitLod:
756
0
    case spv::Op::OpImageSparseSampleDrefImplicitLod:
757
0
    case spv::Op::OpImageSparseSampleDrefExplicitLod:
758
0
    case spv::Op::OpImageSampleFootprintNV:
759
0
      return true;
760
0
    default:
761
0
      return false;
762
0
  }
763
0
}
764
765
2.38M
bool spvIsExtendedInstruction(const spv::Op opcode) {
766
2.38M
  switch (opcode) {
767
34.7k
    case spv::Op::OpExtInst:
768
34.7k
    case spv::Op::OpExtInstWithForwardRefsKHR:
769
34.7k
      return true;
770
2.34M
    default:
771
2.34M
      return false;
772
2.38M
  }
773
2.38M
}
774
775
0
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
776
0
  switch (opcode) {
777
0
    case spv::Op::OpMemoryBarrier:
778
0
      return {1};
779
0
    case spv::Op::OpAtomicStore:
780
0
    case spv::Op::OpControlBarrier:
781
0
    case spv::Op::OpAtomicFlagClear:
782
0
    case spv::Op::OpMemoryNamedBarrier:
783
0
      return {2};
784
0
    case spv::Op::OpAtomicLoad:
785
0
    case spv::Op::OpAtomicExchange:
786
0
    case spv::Op::OpAtomicIIncrement:
787
0
    case spv::Op::OpAtomicIDecrement:
788
0
    case spv::Op::OpAtomicIAdd:
789
0
    case spv::Op::OpAtomicFAddEXT:
790
0
    case spv::Op::OpAtomicISub:
791
0
    case spv::Op::OpAtomicSMin:
792
0
    case spv::Op::OpAtomicUMin:
793
0
    case spv::Op::OpAtomicSMax:
794
0
    case spv::Op::OpAtomicUMax:
795
0
    case spv::Op::OpAtomicAnd:
796
0
    case spv::Op::OpAtomicOr:
797
0
    case spv::Op::OpAtomicXor:
798
0
    case spv::Op::OpAtomicFlagTestAndSet:
799
0
      return {4};
800
0
    case spv::Op::OpAtomicCompareExchange:
801
0
    case spv::Op::OpAtomicCompareExchangeWeak:
802
0
      return {4, 5};
803
0
    default:
804
0
      return {};
805
0
  }
806
0
}
807
808
0
bool spvOpcodeIsAccessChain(spv::Op opcode) {
809
0
  switch (opcode) {
810
0
    case spv::Op::OpAccessChain:
811
0
    case spv::Op::OpInBoundsAccessChain:
812
0
    case spv::Op::OpPtrAccessChain:
813
0
    case spv::Op::OpInBoundsPtrAccessChain:
814
0
    case spv::Op::OpRawAccessChainNV:
815
0
      return true;
816
0
    default:
817
0
      return false;
818
0
  }
819
0
}
820
821
0
bool spvOpcodeIsBit(spv::Op opcode) {
822
0
  switch (opcode) {
823
0
    case spv::Op::OpShiftRightLogical:
824
0
    case spv::Op::OpShiftRightArithmetic:
825
0
    case spv::Op::OpShiftLeftLogical:
826
0
    case spv::Op::OpBitwiseOr:
827
0
    case spv::Op::OpBitwiseXor:
828
0
    case spv::Op::OpBitwiseAnd:
829
0
    case spv::Op::OpNot:
830
0
    case spv::Op::OpBitReverse:
831
0
    case spv::Op::OpBitCount:
832
0
      return true;
833
0
    default:
834
0
      return false;
835
0
  }
836
0
}
837
838
9.34k
bool spvOpcodeGeneratesUntypedPointer(spv::Op opcode) {
839
9.34k
  switch (opcode) {
840
0
    case spv::Op::OpUntypedVariableKHR:
841
0
    case spv::Op::OpUntypedAccessChainKHR:
842
0
    case spv::Op::OpUntypedInBoundsAccessChainKHR:
843
0
    case spv::Op::OpUntypedPtrAccessChainKHR:
844
0
    case spv::Op::OpUntypedInBoundsPtrAccessChainKHR:
845
0
      return true;
846
9.34k
    default:
847
9.34k
      return false;
848
9.34k
  }
849
9.34k
}