xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/source/opcode.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 // Copyright (c) 2015-2022 The Khronos Group Inc.
2 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3 // reserved.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "source/opcode.h"
18 
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.
spvGeneratorStr(uint32_t generator)59 const char* spvGeneratorStr(uint32_t generator) {
60   auto where = std::find_if(
61       std::begin(vendor_tools), std::end(vendor_tools),
62       [generator](const VendorTool& vt) { return generator == vt.value; });
63   if (where != std::end(vendor_tools)) return where->vendor_tool;
64   return "Unknown";
65 }
66 
spvOpcodeMake(uint16_t wordCount,spv::Op opcode)67 uint32_t spvOpcodeMake(uint16_t wordCount, spv::Op opcode) {
68   return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
69 }
70 
spvOpcodeSplit(const uint32_t word,uint16_t * pWordCount,uint16_t * pOpcode)71 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
72                     uint16_t* pOpcode) {
73   if (pWordCount) {
74     *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
75   }
76   if (pOpcode) {
77     *pOpcode = 0x0000ffff & word;
78   }
79 }
80 
spvOpcodeTableGet(spv_opcode_table * pInstTable,spv_target_env)81 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, spv_target_env) {
82   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   *pInstTable = &kOpcodeTable;
88   return SPV_SUCCESS;
89 }
90 
spvOpcodeTableNameLookup(spv_target_env env,const spv_opcode_table table,const char * name,spv_opcode_desc * pEntry)91 spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
92                                       const spv_opcode_table table,
93                                       const char* name,
94                                       spv_opcode_desc* pEntry) {
95   if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
96   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   const size_t nameLength = strlen(name);
102   const auto version = spvVersionForTargetEnv(env);
103   for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
104     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     if ((version >= entry.minVersion && version <= entry.lastVersion) ||
114         entry.numExtensions > 0u || entry.numCapabilities > 0u) {
115       // Exact match case.
116       if (nameLength == strlen(entry.name) &&
117           !strncmp(name, entry.name, nameLength)) {
118         *pEntry = &entry;
119         return SPV_SUCCESS;
120       }
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       if (entry.numAliases > 0) {
130         for (uint32_t aliasIndex = 0; aliasIndex < entry.numAliases;
131              aliasIndex++) {
132           // Skip Op prefix. Should this be encoded in the table instead?
133           const auto alias = entry.aliases[aliasIndex] + 2;
134           const size_t aliasLength = strlen(alias);
135           if (nameLength == aliasLength && !strncmp(name, alias, nameLength)) {
136             *pEntry = &entry;
137             return SPV_SUCCESS;
138           }
139         }
140       }
141     }
142   }
143 
144   return SPV_ERROR_INVALID_LOOKUP;
145 }
146 
spvOpcodeTableValueLookup(spv_target_env env,const spv_opcode_table table,const spv::Op opcode,spv_opcode_desc * pEntry)147 spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
148                                        const spv_opcode_table table,
149                                        const spv::Op opcode,
150                                        spv_opcode_desc* pEntry) {
151   if (!table) return SPV_ERROR_INVALID_TABLE;
152   if (!pEntry) return SPV_ERROR_INVALID_POINTER;
153 
154   const auto beg = table->entries;
155   const auto end = table->entries + table->count;
156 
157   spv_opcode_desc_t needle = {"", opcode, 0,     nullptr, 0,       {},  0,
158                               {}, false,  false, 0,       nullptr, ~0u, ~0u};
159 
160   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
161     return lhs.opcode < rhs.opcode;
162   };
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   const auto version = spvVersionForTargetEnv(env);
170   for (auto it = std::lower_bound(beg, end, needle, comp);
171        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     if ((version >= it->minVersion && version <= it->lastVersion) ||
181         it->numExtensions > 0u || it->numCapabilities > 0u) {
182       *pEntry = it;
183       return SPV_SUCCESS;
184     }
185   }
186 
187   return SPV_ERROR_INVALID_LOOKUP;
188 }
189 
spvInstructionCopy(const uint32_t * words,const spv::Op opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)190 void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
191                         const uint16_t wordCount, const spv_endianness_t endian,
192                         spv_instruction_t* pInst) {
193   pInst->opcode = opcode;
194   pInst->words.resize(wordCount);
195   for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
196     pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
197     if (!wordIndex) {
198       uint16_t thisWordCount;
199       uint16_t thisOpcode;
200       spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
201       assert(opcode == static_cast<spv::Op>(thisOpcode) &&
202              wordCount == thisWordCount && "Endianness failed!");
203     }
204   }
205 }
206 
spvOpcodeString(const uint32_t opcode)207 const char* spvOpcodeString(const uint32_t opcode) {
208   const auto beg = kOpcodeTableEntries;
209   const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
210   spv_opcode_desc_t needle = {"",    static_cast<spv::Op>(opcode),
211                               0,     nullptr,
212                               0,     {},
213                               0,     {},
214                               false, false,
215                               0,     nullptr,
216                               ~0u,   ~0u};
217   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
218     return lhs.opcode < rhs.opcode;
219   };
220   auto it = std::lower_bound(beg, end, needle, comp);
221   if (it != end && it->opcode == spv::Op(opcode)) {
222     return it->name;
223   }
224 
225   assert(0 && "Unreachable!");
226   return "unknown";
227 }
228 
spvOpcodeString(const spv::Op opcode)229 const char* spvOpcodeString(const spv::Op opcode) {
230   return spvOpcodeString(static_cast<uint32_t>(opcode));
231 }
232 
spvOpcodeIsScalarType(const spv::Op opcode)233 int32_t spvOpcodeIsScalarType(const spv::Op opcode) {
234   switch (opcode) {
235     case spv::Op::OpTypeInt:
236     case spv::Op::OpTypeFloat:
237     case spv::Op::OpTypeBool:
238       return true;
239     default:
240       return false;
241   }
242 }
243 
spvOpcodeIsSpecConstant(const spv::Op opcode)244 int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) {
245   switch (opcode) {
246     case spv::Op::OpSpecConstantTrue:
247     case spv::Op::OpSpecConstantFalse:
248     case spv::Op::OpSpecConstant:
249     case spv::Op::OpSpecConstantComposite:
250     case spv::Op::OpSpecConstantCompositeReplicateEXT:
251     case spv::Op::OpSpecConstantOp:
252       return true;
253     default:
254       return false;
255   }
256 }
257 
spvOpcodeIsConstant(const spv::Op opcode)258 int32_t spvOpcodeIsConstant(const spv::Op opcode) {
259   switch (opcode) {
260     case spv::Op::OpConstantTrue:
261     case spv::Op::OpConstantFalse:
262     case spv::Op::OpConstant:
263     case spv::Op::OpConstantComposite:
264     case spv::Op::OpConstantCompositeReplicateEXT:
265     case spv::Op::OpConstantSampler:
266     case spv::Op::OpConstantNull:
267     case spv::Op::OpConstantFunctionPointerINTEL:
268     case spv::Op::OpSpecConstantTrue:
269     case spv::Op::OpSpecConstantFalse:
270     case spv::Op::OpSpecConstant:
271     case spv::Op::OpSpecConstantComposite:
272     case spv::Op::OpSpecConstantCompositeReplicateEXT:
273     case spv::Op::OpSpecConstantOp:
274       return true;
275     default:
276       return false;
277   }
278 }
279 
spvOpcodeIsConstantOrUndef(const spv::Op opcode)280 bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
281   return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
282 }
283 
spvOpcodeIsScalarSpecConstant(const spv::Op opcode)284 bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
285   switch (opcode) {
286     case spv::Op::OpSpecConstantTrue:
287     case spv::Op::OpSpecConstantFalse:
288     case spv::Op::OpSpecConstant:
289       return true;
290     default:
291       return false;
292   }
293 }
294 
spvOpcodeIsComposite(const spv::Op opcode)295 int32_t spvOpcodeIsComposite(const spv::Op opcode) {
296   switch (opcode) {
297     case spv::Op::OpTypeVector:
298     case spv::Op::OpTypeMatrix:
299     case spv::Op::OpTypeArray:
300     case spv::Op::OpTypeStruct:
301     case spv::Op::OpTypeRuntimeArray:
302     case spv::Op::OpTypeCooperativeMatrixNV:
303     case spv::Op::OpTypeCooperativeMatrixKHR:
304       return true;
305     default:
306       return false;
307   }
308 }
309 
spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode)310 bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
311   switch (opcode) {
312     case spv::Op::OpVariable:
313     case spv::Op::OpUntypedVariableKHR:
314     case spv::Op::OpAccessChain:
315     case spv::Op::OpInBoundsAccessChain:
316     case spv::Op::OpUntypedAccessChainKHR:
317     case spv::Op::OpUntypedInBoundsAccessChainKHR:
318     case spv::Op::OpFunctionParameter:
319     case spv::Op::OpImageTexelPointer:
320     case spv::Op::OpCopyObject:
321     case spv::Op::OpSelect:
322     case spv::Op::OpPhi:
323     case spv::Op::OpFunctionCall:
324     case spv::Op::OpPtrAccessChain:
325     case spv::Op::OpUntypedPtrAccessChainKHR:
326     case spv::Op::OpLoad:
327     case spv::Op::OpConstantNull:
328     case spv::Op::OpRawAccessChainNV:
329       return true;
330     default:
331       return false;
332   }
333 }
334 
spvOpcodeReturnsLogicalPointer(const spv::Op opcode)335 int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
336   switch (opcode) {
337     case spv::Op::OpVariable:
338     case spv::Op::OpUntypedVariableKHR:
339     case spv::Op::OpAccessChain:
340     case spv::Op::OpInBoundsAccessChain:
341     case spv::Op::OpUntypedAccessChainKHR:
342     case spv::Op::OpUntypedInBoundsAccessChainKHR:
343     case spv::Op::OpFunctionParameter:
344     case spv::Op::OpImageTexelPointer:
345     case spv::Op::OpCopyObject:
346     case spv::Op::OpRawAccessChainNV:
347       return true;
348     default:
349       return false;
350   }
351 }
352 
spvOpcodeGeneratesType(spv::Op op)353 int32_t spvOpcodeGeneratesType(spv::Op op) {
354   switch (op) {
355     case spv::Op::OpTypeVoid:
356     case spv::Op::OpTypeBool:
357     case spv::Op::OpTypeInt:
358     case spv::Op::OpTypeFloat:
359     case spv::Op::OpTypeVector:
360     case spv::Op::OpTypeMatrix:
361     case spv::Op::OpTypeImage:
362     case spv::Op::OpTypeSampler:
363     case spv::Op::OpTypeSampledImage:
364     case spv::Op::OpTypeArray:
365     case spv::Op::OpTypeRuntimeArray:
366     case spv::Op::OpTypeStruct:
367     case spv::Op::OpTypeOpaque:
368     case spv::Op::OpTypePointer:
369     case spv::Op::OpTypeFunction:
370     case spv::Op::OpTypeEvent:
371     case spv::Op::OpTypeDeviceEvent:
372     case spv::Op::OpTypeReserveId:
373     case spv::Op::OpTypeQueue:
374     case spv::Op::OpTypePipe:
375     case spv::Op::OpTypePipeStorage:
376     case spv::Op::OpTypeNamedBarrier:
377     case spv::Op::OpTypeAccelerationStructureNV:
378     case spv::Op::OpTypeCooperativeMatrixNV:
379     case spv::Op::OpTypeCooperativeMatrixKHR:
380     // case spv::Op::OpTypeAccelerationStructureKHR: covered by
381     // spv::Op::OpTypeAccelerationStructureNV
382     case spv::Op::OpTypeRayQueryKHR:
383     case spv::Op::OpTypeHitObjectNV:
384     case spv::Op::OpTypeUntypedPointerKHR:
385     case spv::Op::OpTypeTensorLayoutNV:
386     case spv::Op::OpTypeTensorViewNV:
387       return true;
388     default:
389       // In particular, OpTypeForwardPointer does not generate a type,
390       // but declares a storage class for a pointer type generated
391       // by a different instruction.
392       break;
393   }
394   return 0;
395 }
396 
spvOpcodeIsDecoration(const spv::Op opcode)397 bool spvOpcodeIsDecoration(const spv::Op opcode) {
398   switch (opcode) {
399     case spv::Op::OpDecorate:
400     case spv::Op::OpDecorateId:
401     case spv::Op::OpMemberDecorate:
402     case spv::Op::OpGroupDecorate:
403     case spv::Op::OpGroupMemberDecorate:
404     case spv::Op::OpDecorateStringGOOGLE:
405     case spv::Op::OpMemberDecorateStringGOOGLE:
406       return true;
407     default:
408       break;
409   }
410   return false;
411 }
412 
spvOpcodeIsLoad(const spv::Op opcode)413 bool spvOpcodeIsLoad(const spv::Op opcode) {
414   switch (opcode) {
415     case spv::Op::OpLoad:
416     case spv::Op::OpImageSampleExplicitLod:
417     case spv::Op::OpImageSampleImplicitLod:
418     case spv::Op::OpImageSampleDrefImplicitLod:
419     case spv::Op::OpImageSampleDrefExplicitLod:
420     case spv::Op::OpImageSampleProjImplicitLod:
421     case spv::Op::OpImageSampleProjExplicitLod:
422     case spv::Op::OpImageSampleProjDrefImplicitLod:
423     case spv::Op::OpImageSampleProjDrefExplicitLod:
424     case spv::Op::OpImageFetch:
425     case spv::Op::OpImageGather:
426     case spv::Op::OpImageDrefGather:
427     case spv::Op::OpImageRead:
428     case spv::Op::OpImageSparseSampleImplicitLod:
429     case spv::Op::OpImageSparseSampleExplicitLod:
430     case spv::Op::OpImageSparseSampleDrefExplicitLod:
431     case spv::Op::OpImageSparseSampleDrefImplicitLod:
432     case spv::Op::OpImageSparseFetch:
433     case spv::Op::OpImageSparseGather:
434     case spv::Op::OpImageSparseDrefGather:
435     case spv::Op::OpImageSparseRead:
436       return true;
437     default:
438       return false;
439   }
440 }
441 
spvOpcodeIsBranch(spv::Op opcode)442 bool spvOpcodeIsBranch(spv::Op opcode) {
443   switch (opcode) {
444     case spv::Op::OpBranch:
445     case spv::Op::OpBranchConditional:
446     case spv::Op::OpSwitch:
447       return true;
448     default:
449       return false;
450   }
451 }
452 
spvOpcodeIsAtomicWithLoad(const spv::Op opcode)453 bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
454   switch (opcode) {
455     case spv::Op::OpAtomicLoad:
456     case spv::Op::OpAtomicExchange:
457     case spv::Op::OpAtomicCompareExchange:
458     case spv::Op::OpAtomicCompareExchangeWeak:
459     case spv::Op::OpAtomicIIncrement:
460     case spv::Op::OpAtomicIDecrement:
461     case spv::Op::OpAtomicIAdd:
462     case spv::Op::OpAtomicFAddEXT:
463     case spv::Op::OpAtomicISub:
464     case spv::Op::OpAtomicSMin:
465     case spv::Op::OpAtomicUMin:
466     case spv::Op::OpAtomicFMinEXT:
467     case spv::Op::OpAtomicSMax:
468     case spv::Op::OpAtomicUMax:
469     case spv::Op::OpAtomicFMaxEXT:
470     case spv::Op::OpAtomicAnd:
471     case spv::Op::OpAtomicOr:
472     case spv::Op::OpAtomicXor:
473     case spv::Op::OpAtomicFlagTestAndSet:
474       return true;
475     default:
476       return false;
477   }
478 }
479 
spvOpcodeIsAtomicOp(const spv::Op opcode)480 bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
481   return (spvOpcodeIsAtomicWithLoad(opcode) ||
482           opcode == spv::Op::OpAtomicStore ||
483           opcode == spv::Op::OpAtomicFlagClear);
484 }
485 
spvOpcodeIsReturn(spv::Op opcode)486 bool spvOpcodeIsReturn(spv::Op opcode) {
487   switch (opcode) {
488     case spv::Op::OpReturn:
489     case spv::Op::OpReturnValue:
490       return true;
491     default:
492       return false;
493   }
494 }
495 
spvOpcodeIsAbort(spv::Op opcode)496 bool spvOpcodeIsAbort(spv::Op opcode) {
497   switch (opcode) {
498     case spv::Op::OpKill:
499     case spv::Op::OpUnreachable:
500     case spv::Op::OpTerminateInvocation:
501     case spv::Op::OpTerminateRayKHR:
502     case spv::Op::OpIgnoreIntersectionKHR:
503     case spv::Op::OpEmitMeshTasksEXT:
504       return true;
505     default:
506       return false;
507   }
508 }
509 
spvOpcodeIsReturnOrAbort(spv::Op opcode)510 bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
511   return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
512 }
513 
spvOpcodeIsBlockTerminator(spv::Op opcode)514 bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
515   return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
516 }
517 
spvOpcodeIsBaseOpaqueType(spv::Op opcode)518 bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
519   switch (opcode) {
520     case spv::Op::OpTypeImage:
521     case spv::Op::OpTypeSampler:
522     case spv::Op::OpTypeSampledImage:
523     case spv::Op::OpTypeOpaque:
524     case spv::Op::OpTypeEvent:
525     case spv::Op::OpTypeDeviceEvent:
526     case spv::Op::OpTypeReserveId:
527     case spv::Op::OpTypeQueue:
528     case spv::Op::OpTypePipe:
529     case spv::Op::OpTypeForwardPointer:
530     case spv::Op::OpTypePipeStorage:
531     case spv::Op::OpTypeNamedBarrier:
532       return true;
533     default:
534       return false;
535   }
536 }
537 
spvOpcodeIsNonUniformGroupOperation(spv::Op opcode)538 bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
539   switch (opcode) {
540     case spv::Op::OpGroupNonUniformElect:
541     case spv::Op::OpGroupNonUniformAll:
542     case spv::Op::OpGroupNonUniformAny:
543     case spv::Op::OpGroupNonUniformAllEqual:
544     case spv::Op::OpGroupNonUniformBroadcast:
545     case spv::Op::OpGroupNonUniformBroadcastFirst:
546     case spv::Op::OpGroupNonUniformBallot:
547     case spv::Op::OpGroupNonUniformInverseBallot:
548     case spv::Op::OpGroupNonUniformBallotBitExtract:
549     case spv::Op::OpGroupNonUniformBallotBitCount:
550     case spv::Op::OpGroupNonUniformBallotFindLSB:
551     case spv::Op::OpGroupNonUniformBallotFindMSB:
552     case spv::Op::OpGroupNonUniformShuffle:
553     case spv::Op::OpGroupNonUniformShuffleXor:
554     case spv::Op::OpGroupNonUniformShuffleUp:
555     case spv::Op::OpGroupNonUniformShuffleDown:
556     case spv::Op::OpGroupNonUniformIAdd:
557     case spv::Op::OpGroupNonUniformFAdd:
558     case spv::Op::OpGroupNonUniformIMul:
559     case spv::Op::OpGroupNonUniformFMul:
560     case spv::Op::OpGroupNonUniformSMin:
561     case spv::Op::OpGroupNonUniformUMin:
562     case spv::Op::OpGroupNonUniformFMin:
563     case spv::Op::OpGroupNonUniformSMax:
564     case spv::Op::OpGroupNonUniformUMax:
565     case spv::Op::OpGroupNonUniformFMax:
566     case spv::Op::OpGroupNonUniformBitwiseAnd:
567     case spv::Op::OpGroupNonUniformBitwiseOr:
568     case spv::Op::OpGroupNonUniformBitwiseXor:
569     case spv::Op::OpGroupNonUniformLogicalAnd:
570     case spv::Op::OpGroupNonUniformLogicalOr:
571     case spv::Op::OpGroupNonUniformLogicalXor:
572     case spv::Op::OpGroupNonUniformQuadBroadcast:
573     case spv::Op::OpGroupNonUniformQuadSwap:
574     case spv::Op::OpGroupNonUniformRotateKHR:
575     case spv::Op::OpGroupNonUniformQuadAllKHR:
576     case spv::Op::OpGroupNonUniformQuadAnyKHR:
577       return true;
578     default:
579       return false;
580   }
581 }
582 
spvOpcodeIsScalarizable(spv::Op opcode)583 bool spvOpcodeIsScalarizable(spv::Op opcode) {
584   switch (opcode) {
585     case spv::Op::OpPhi:
586     case spv::Op::OpCopyObject:
587     case spv::Op::OpConvertFToU:
588     case spv::Op::OpConvertFToS:
589     case spv::Op::OpConvertSToF:
590     case spv::Op::OpConvertUToF:
591     case spv::Op::OpUConvert:
592     case spv::Op::OpSConvert:
593     case spv::Op::OpFConvert:
594     case spv::Op::OpQuantizeToF16:
595     case spv::Op::OpVectorInsertDynamic:
596     case spv::Op::OpSNegate:
597     case spv::Op::OpFNegate:
598     case spv::Op::OpIAdd:
599     case spv::Op::OpFAdd:
600     case spv::Op::OpISub:
601     case spv::Op::OpFSub:
602     case spv::Op::OpIMul:
603     case spv::Op::OpFMul:
604     case spv::Op::OpUDiv:
605     case spv::Op::OpSDiv:
606     case spv::Op::OpFDiv:
607     case spv::Op::OpUMod:
608     case spv::Op::OpSRem:
609     case spv::Op::OpSMod:
610     case spv::Op::OpFRem:
611     case spv::Op::OpFMod:
612     case spv::Op::OpVectorTimesScalar:
613     case spv::Op::OpIAddCarry:
614     case spv::Op::OpISubBorrow:
615     case spv::Op::OpUMulExtended:
616     case spv::Op::OpSMulExtended:
617     case spv::Op::OpShiftRightLogical:
618     case spv::Op::OpShiftRightArithmetic:
619     case spv::Op::OpShiftLeftLogical:
620     case spv::Op::OpBitwiseOr:
621     case spv::Op::OpBitwiseAnd:
622     case spv::Op::OpNot:
623     case spv::Op::OpBitFieldInsert:
624     case spv::Op::OpBitFieldSExtract:
625     case spv::Op::OpBitFieldUExtract:
626     case spv::Op::OpBitReverse:
627     case spv::Op::OpBitCount:
628     case spv::Op::OpIsNan:
629     case spv::Op::OpIsInf:
630     case spv::Op::OpIsFinite:
631     case spv::Op::OpIsNormal:
632     case spv::Op::OpSignBitSet:
633     case spv::Op::OpLessOrGreater:
634     case spv::Op::OpOrdered:
635     case spv::Op::OpUnordered:
636     case spv::Op::OpLogicalEqual:
637     case spv::Op::OpLogicalNotEqual:
638     case spv::Op::OpLogicalOr:
639     case spv::Op::OpLogicalAnd:
640     case spv::Op::OpLogicalNot:
641     case spv::Op::OpSelect:
642     case spv::Op::OpIEqual:
643     case spv::Op::OpINotEqual:
644     case spv::Op::OpUGreaterThan:
645     case spv::Op::OpSGreaterThan:
646     case spv::Op::OpUGreaterThanEqual:
647     case spv::Op::OpSGreaterThanEqual:
648     case spv::Op::OpULessThan:
649     case spv::Op::OpSLessThan:
650     case spv::Op::OpULessThanEqual:
651     case spv::Op::OpSLessThanEqual:
652     case spv::Op::OpFOrdEqual:
653     case spv::Op::OpFUnordEqual:
654     case spv::Op::OpFOrdNotEqual:
655     case spv::Op::OpFUnordNotEqual:
656     case spv::Op::OpFOrdLessThan:
657     case spv::Op::OpFUnordLessThan:
658     case spv::Op::OpFOrdGreaterThan:
659     case spv::Op::OpFUnordGreaterThan:
660     case spv::Op::OpFOrdLessThanEqual:
661     case spv::Op::OpFUnordLessThanEqual:
662     case spv::Op::OpFOrdGreaterThanEqual:
663     case spv::Op::OpFUnordGreaterThanEqual:
664       return true;
665     default:
666       return false;
667   }
668 }
669 
spvOpcodeIsDebug(spv::Op opcode)670 bool spvOpcodeIsDebug(spv::Op opcode) {
671   switch (opcode) {
672     case spv::Op::OpName:
673     case spv::Op::OpMemberName:
674     case spv::Op::OpSource:
675     case spv::Op::OpSourceContinued:
676     case spv::Op::OpSourceExtension:
677     case spv::Op::OpString:
678     case spv::Op::OpLine:
679     case spv::Op::OpNoLine:
680     case spv::Op::OpModuleProcessed:
681       return true;
682     default:
683       return false;
684   }
685 }
686 
spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode)687 bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
688   switch (opcode) {
689     case spv::Op::OpPtrEqual:
690     case spv::Op::OpPtrNotEqual:
691     case spv::Op::OpIAdd:
692     case spv::Op::OpFAdd:
693     case spv::Op::OpIMul:
694     case spv::Op::OpFMul:
695     case spv::Op::OpDot:
696     case spv::Op::OpIAddCarry:
697     case spv::Op::OpUMulExtended:
698     case spv::Op::OpSMulExtended:
699     case spv::Op::OpBitwiseOr:
700     case spv::Op::OpBitwiseXor:
701     case spv::Op::OpBitwiseAnd:
702     case spv::Op::OpOrdered:
703     case spv::Op::OpUnordered:
704     case spv::Op::OpLogicalEqual:
705     case spv::Op::OpLogicalNotEqual:
706     case spv::Op::OpLogicalOr:
707     case spv::Op::OpLogicalAnd:
708     case spv::Op::OpIEqual:
709     case spv::Op::OpINotEqual:
710     case spv::Op::OpFOrdEqual:
711     case spv::Op::OpFUnordEqual:
712     case spv::Op::OpFOrdNotEqual:
713     case spv::Op::OpFUnordNotEqual:
714       return true;
715     default:
716       return false;
717   }
718 }
719 
spvOpcodeIsLinearAlgebra(spv::Op opcode)720 bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
721   switch (opcode) {
722     case spv::Op::OpTranspose:
723     case spv::Op::OpVectorTimesScalar:
724     case spv::Op::OpMatrixTimesScalar:
725     case spv::Op::OpVectorTimesMatrix:
726     case spv::Op::OpMatrixTimesVector:
727     case spv::Op::OpMatrixTimesMatrix:
728     case spv::Op::OpOuterProduct:
729     case spv::Op::OpDot:
730       return true;
731     default:
732       return false;
733   }
734 }
735 
spvOpcodeIsImageSample(const spv::Op opcode)736 bool spvOpcodeIsImageSample(const spv::Op opcode) {
737   switch (opcode) {
738     case spv::Op::OpImageSampleImplicitLod:
739     case spv::Op::OpImageSampleExplicitLod:
740     case spv::Op::OpImageSampleDrefImplicitLod:
741     case spv::Op::OpImageSampleDrefExplicitLod:
742     case spv::Op::OpImageSampleProjImplicitLod:
743     case spv::Op::OpImageSampleProjExplicitLod:
744     case spv::Op::OpImageSampleProjDrefImplicitLod:
745     case spv::Op::OpImageSampleProjDrefExplicitLod:
746     case spv::Op::OpImageSparseSampleImplicitLod:
747     case spv::Op::OpImageSparseSampleExplicitLod:
748     case spv::Op::OpImageSparseSampleDrefImplicitLod:
749     case spv::Op::OpImageSparseSampleDrefExplicitLod:
750       return true;
751     default:
752       return false;
753   }
754 }
755 
spvIsExtendedInstruction(const spv::Op opcode)756 bool spvIsExtendedInstruction(const spv::Op opcode) {
757   switch (opcode) {
758     case spv::Op::OpExtInst:
759     case spv::Op::OpExtInstWithForwardRefsKHR:
760       return true;
761     default:
762       return false;
763   }
764 }
765 
spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode)766 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
767   switch (opcode) {
768     case spv::Op::OpMemoryBarrier:
769       return {1};
770     case spv::Op::OpAtomicStore:
771     case spv::Op::OpControlBarrier:
772     case spv::Op::OpAtomicFlagClear:
773     case spv::Op::OpMemoryNamedBarrier:
774       return {2};
775     case spv::Op::OpAtomicLoad:
776     case spv::Op::OpAtomicExchange:
777     case spv::Op::OpAtomicIIncrement:
778     case spv::Op::OpAtomicIDecrement:
779     case spv::Op::OpAtomicIAdd:
780     case spv::Op::OpAtomicFAddEXT:
781     case spv::Op::OpAtomicISub:
782     case spv::Op::OpAtomicSMin:
783     case spv::Op::OpAtomicUMin:
784     case spv::Op::OpAtomicSMax:
785     case spv::Op::OpAtomicUMax:
786     case spv::Op::OpAtomicAnd:
787     case spv::Op::OpAtomicOr:
788     case spv::Op::OpAtomicXor:
789     case spv::Op::OpAtomicFlagTestAndSet:
790       return {4};
791     case spv::Op::OpAtomicCompareExchange:
792     case spv::Op::OpAtomicCompareExchangeWeak:
793       return {4, 5};
794     default:
795       return {};
796   }
797 }
798 
spvOpcodeIsAccessChain(spv::Op opcode)799 bool spvOpcodeIsAccessChain(spv::Op opcode) {
800   switch (opcode) {
801     case spv::Op::OpAccessChain:
802     case spv::Op::OpInBoundsAccessChain:
803     case spv::Op::OpPtrAccessChain:
804     case spv::Op::OpInBoundsPtrAccessChain:
805     case spv::Op::OpRawAccessChainNV:
806       return true;
807     default:
808       return false;
809   }
810 }
811 
spvOpcodeIsBit(spv::Op opcode)812 bool spvOpcodeIsBit(spv::Op opcode) {
813   switch (opcode) {
814     case spv::Op::OpShiftRightLogical:
815     case spv::Op::OpShiftRightArithmetic:
816     case spv::Op::OpShiftLeftLogical:
817     case spv::Op::OpBitwiseOr:
818     case spv::Op::OpBitwiseXor:
819     case spv::Op::OpBitwiseAnd:
820     case spv::Op::OpNot:
821     case spv::Op::OpBitReverse:
822     case spv::Op::OpBitCount:
823       return true;
824     default:
825       return false;
826   }
827 }
828 
spvOpcodeGeneratesUntypedPointer(spv::Op opcode)829 bool spvOpcodeGeneratesUntypedPointer(spv::Op opcode) {
830   switch (opcode) {
831     case spv::Op::OpUntypedVariableKHR:
832     case spv::Op::OpUntypedAccessChainKHR:
833     case spv::Op::OpUntypedInBoundsAccessChainKHR:
834     case spv::Op::OpUntypedPtrAccessChainKHR:
835     case spv::Op::OpUntypedInBoundsPtrAccessChainKHR:
836       return true;
837     default:
838       return false;
839   }
840 }
841