• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 considers 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         nameLength == strlen(entry.name) &&
116         !strncmp(name, entry.name, nameLength)) {
117       // NOTE: Found out Opcode!
118       *pEntry = &entry;
119       return SPV_SUCCESS;
120     }
121   }
122 
123   return SPV_ERROR_INVALID_LOOKUP;
124 }
125 
spvOpcodeTableValueLookup(spv_target_env env,const spv_opcode_table table,const spv::Op opcode,spv_opcode_desc * pEntry)126 spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
127                                        const spv_opcode_table table,
128                                        const spv::Op opcode,
129                                        spv_opcode_desc* pEntry) {
130   if (!table) return SPV_ERROR_INVALID_TABLE;
131   if (!pEntry) return SPV_ERROR_INVALID_POINTER;
132 
133   const auto beg = table->entries;
134   const auto end = table->entries + table->count;
135 
136   spv_opcode_desc_t needle = {"",    opcode, 0, nullptr, 0,   {},
137                               false, false,  0, nullptr, ~0u, ~0u};
138 
139   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
140     return lhs.opcode < rhs.opcode;
141   };
142 
143   // We need to loop here because there can exist multiple symbols for the same
144   // opcode value, and they can be introduced in different target environments,
145   // which means they can have different minimal version requirements.
146   // Assumes the underlying table is already sorted ascendingly according to
147   // opcode value.
148   const auto version = spvVersionForTargetEnv(env);
149   for (auto it = std::lower_bound(beg, end, needle, comp);
150        it != end && it->opcode == opcode; ++it) {
151     // We considers the current opcode as available as long as
152     // 1. The target environment satisfies the minimal requirement of the
153     //    opcode; or
154     // 2. There is at least one extension enabling this opcode.
155     //
156     // Note that the second rule assumes the extension enabling this instruction
157     // is indeed requested in the SPIR-V code; checking that should be
158     // validator's work.
159     if ((version >= it->minVersion && version <= it->lastVersion) ||
160         it->numExtensions > 0u || it->numCapabilities > 0u) {
161       *pEntry = it;
162       return SPV_SUCCESS;
163     }
164   }
165 
166   return SPV_ERROR_INVALID_LOOKUP;
167 }
168 
spvInstructionCopy(const uint32_t * words,const spv::Op opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)169 void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
170                         const uint16_t wordCount, const spv_endianness_t endian,
171                         spv_instruction_t* pInst) {
172   pInst->opcode = opcode;
173   pInst->words.resize(wordCount);
174   for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
175     pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
176     if (!wordIndex) {
177       uint16_t thisWordCount;
178       uint16_t thisOpcode;
179       spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
180       assert(opcode == static_cast<spv::Op>(thisOpcode) &&
181              wordCount == thisWordCount && "Endianness failed!");
182     }
183   }
184 }
185 
spvOpcodeString(const uint32_t opcode)186 const char* spvOpcodeString(const uint32_t opcode) {
187   const auto beg = kOpcodeTableEntries;
188   const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
189   spv_opcode_desc_t needle = {"",    static_cast<spv::Op>(opcode),
190                               0,     nullptr,
191                               0,     {},
192                               false, false,
193                               0,     nullptr,
194                               ~0u,   ~0u};
195   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
196     return lhs.opcode < rhs.opcode;
197   };
198   auto it = std::lower_bound(beg, end, needle, comp);
199   if (it != end && it->opcode == spv::Op(opcode)) {
200     return it->name;
201   }
202 
203   assert(0 && "Unreachable!");
204   return "unknown";
205 }
206 
spvOpcodeString(const spv::Op opcode)207 const char* spvOpcodeString(const spv::Op opcode) {
208   return spvOpcodeString(static_cast<uint32_t>(opcode));
209 }
210 
spvOpcodeIsScalarType(const spv::Op opcode)211 int32_t spvOpcodeIsScalarType(const spv::Op opcode) {
212   switch (opcode) {
213     case spv::Op::OpTypeInt:
214     case spv::Op::OpTypeFloat:
215     case spv::Op::OpTypeBool:
216       return true;
217     default:
218       return false;
219   }
220 }
221 
spvOpcodeIsSpecConstant(const spv::Op opcode)222 int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) {
223   switch (opcode) {
224     case spv::Op::OpSpecConstantTrue:
225     case spv::Op::OpSpecConstantFalse:
226     case spv::Op::OpSpecConstant:
227     case spv::Op::OpSpecConstantComposite:
228     case spv::Op::OpSpecConstantOp:
229       return true;
230     default:
231       return false;
232   }
233 }
234 
spvOpcodeIsConstant(const spv::Op opcode)235 int32_t spvOpcodeIsConstant(const spv::Op opcode) {
236   switch (opcode) {
237     case spv::Op::OpConstantTrue:
238     case spv::Op::OpConstantFalse:
239     case spv::Op::OpConstant:
240     case spv::Op::OpConstantComposite:
241     case spv::Op::OpConstantSampler:
242     case spv::Op::OpConstantNull:
243     case spv::Op::OpConstantFunctionPointerINTEL:
244     case spv::Op::OpSpecConstantTrue:
245     case spv::Op::OpSpecConstantFalse:
246     case spv::Op::OpSpecConstant:
247     case spv::Op::OpSpecConstantComposite:
248     case spv::Op::OpSpecConstantOp:
249       return true;
250     default:
251       return false;
252   }
253 }
254 
spvOpcodeIsConstantOrUndef(const spv::Op opcode)255 bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
256   return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
257 }
258 
spvOpcodeIsScalarSpecConstant(const spv::Op opcode)259 bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
260   switch (opcode) {
261     case spv::Op::OpSpecConstantTrue:
262     case spv::Op::OpSpecConstantFalse:
263     case spv::Op::OpSpecConstant:
264       return true;
265     default:
266       return false;
267   }
268 }
269 
spvOpcodeIsComposite(const spv::Op opcode)270 int32_t spvOpcodeIsComposite(const spv::Op opcode) {
271   switch (opcode) {
272     case spv::Op::OpTypeVector:
273     case spv::Op::OpTypeMatrix:
274     case spv::Op::OpTypeArray:
275     case spv::Op::OpTypeStruct:
276     case spv::Op::OpTypeCooperativeMatrixNV:
277     case spv::Op::OpTypeCooperativeMatrixKHR:
278       return true;
279     default:
280       return false;
281   }
282 }
283 
spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode)284 bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
285   switch (opcode) {
286     case spv::Op::OpVariable:
287     case spv::Op::OpAccessChain:
288     case spv::Op::OpInBoundsAccessChain:
289     case spv::Op::OpFunctionParameter:
290     case spv::Op::OpImageTexelPointer:
291     case spv::Op::OpCopyObject:
292     case spv::Op::OpSelect:
293     case spv::Op::OpPhi:
294     case spv::Op::OpFunctionCall:
295     case spv::Op::OpPtrAccessChain:
296     case spv::Op::OpLoad:
297     case spv::Op::OpConstantNull:
298     case spv::Op::OpRawAccessChainNV:
299       return true;
300     default:
301       return false;
302   }
303 }
304 
spvOpcodeReturnsLogicalPointer(const spv::Op opcode)305 int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
306   switch (opcode) {
307     case spv::Op::OpVariable:
308     case spv::Op::OpAccessChain:
309     case spv::Op::OpInBoundsAccessChain:
310     case spv::Op::OpFunctionParameter:
311     case spv::Op::OpImageTexelPointer:
312     case spv::Op::OpCopyObject:
313     case spv::Op::OpRawAccessChainNV:
314       return true;
315     default:
316       return false;
317   }
318 }
319 
spvOpcodeGeneratesType(spv::Op op)320 int32_t spvOpcodeGeneratesType(spv::Op op) {
321   switch (op) {
322     case spv::Op::OpTypeVoid:
323     case spv::Op::OpTypeBool:
324     case spv::Op::OpTypeInt:
325     case spv::Op::OpTypeFloat:
326     case spv::Op::OpTypeVector:
327     case spv::Op::OpTypeMatrix:
328     case spv::Op::OpTypeImage:
329     case spv::Op::OpTypeSampler:
330     case spv::Op::OpTypeSampledImage:
331     case spv::Op::OpTypeArray:
332     case spv::Op::OpTypeRuntimeArray:
333     case spv::Op::OpTypeStruct:
334     case spv::Op::OpTypeOpaque:
335     case spv::Op::OpTypePointer:
336     case spv::Op::OpTypeFunction:
337     case spv::Op::OpTypeEvent:
338     case spv::Op::OpTypeDeviceEvent:
339     case spv::Op::OpTypeReserveId:
340     case spv::Op::OpTypeQueue:
341     case spv::Op::OpTypePipe:
342     case spv::Op::OpTypePipeStorage:
343     case spv::Op::OpTypeNamedBarrier:
344     case spv::Op::OpTypeAccelerationStructureNV:
345     case spv::Op::OpTypeCooperativeMatrixNV:
346     case spv::Op::OpTypeCooperativeMatrixKHR:
347     // case spv::Op::OpTypeAccelerationStructureKHR: covered by
348     // spv::Op::OpTypeAccelerationStructureNV
349     case spv::Op::OpTypeRayQueryKHR:
350     case spv::Op::OpTypeHitObjectNV:
351       return true;
352     default:
353       // In particular, OpTypeForwardPointer does not generate a type,
354       // but declares a storage class for a pointer type generated
355       // by a different instruction.
356       break;
357   }
358   return 0;
359 }
360 
spvOpcodeIsDecoration(const spv::Op opcode)361 bool spvOpcodeIsDecoration(const spv::Op opcode) {
362   switch (opcode) {
363     case spv::Op::OpDecorate:
364     case spv::Op::OpDecorateId:
365     case spv::Op::OpMemberDecorate:
366     case spv::Op::OpGroupDecorate:
367     case spv::Op::OpGroupMemberDecorate:
368     case spv::Op::OpDecorateStringGOOGLE:
369     case spv::Op::OpMemberDecorateStringGOOGLE:
370       return true;
371     default:
372       break;
373   }
374   return false;
375 }
376 
spvOpcodeIsLoad(const spv::Op opcode)377 bool spvOpcodeIsLoad(const spv::Op opcode) {
378   switch (opcode) {
379     case spv::Op::OpLoad:
380     case spv::Op::OpImageSampleExplicitLod:
381     case spv::Op::OpImageSampleImplicitLod:
382     case spv::Op::OpImageSampleDrefImplicitLod:
383     case spv::Op::OpImageSampleDrefExplicitLod:
384     case spv::Op::OpImageSampleProjImplicitLod:
385     case spv::Op::OpImageSampleProjExplicitLod:
386     case spv::Op::OpImageSampleProjDrefImplicitLod:
387     case spv::Op::OpImageSampleProjDrefExplicitLod:
388     case spv::Op::OpImageFetch:
389     case spv::Op::OpImageGather:
390     case spv::Op::OpImageDrefGather:
391     case spv::Op::OpImageRead:
392     case spv::Op::OpImageSparseSampleImplicitLod:
393     case spv::Op::OpImageSparseSampleExplicitLod:
394     case spv::Op::OpImageSparseSampleDrefExplicitLod:
395     case spv::Op::OpImageSparseSampleDrefImplicitLod:
396     case spv::Op::OpImageSparseFetch:
397     case spv::Op::OpImageSparseGather:
398     case spv::Op::OpImageSparseDrefGather:
399     case spv::Op::OpImageSparseRead:
400       return true;
401     default:
402       return false;
403   }
404 }
405 
spvOpcodeIsBranch(spv::Op opcode)406 bool spvOpcodeIsBranch(spv::Op opcode) {
407   switch (opcode) {
408     case spv::Op::OpBranch:
409     case spv::Op::OpBranchConditional:
410     case spv::Op::OpSwitch:
411       return true;
412     default:
413       return false;
414   }
415 }
416 
spvOpcodeIsAtomicWithLoad(const spv::Op opcode)417 bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
418   switch (opcode) {
419     case spv::Op::OpAtomicLoad:
420     case spv::Op::OpAtomicExchange:
421     case spv::Op::OpAtomicCompareExchange:
422     case spv::Op::OpAtomicCompareExchangeWeak:
423     case spv::Op::OpAtomicIIncrement:
424     case spv::Op::OpAtomicIDecrement:
425     case spv::Op::OpAtomicIAdd:
426     case spv::Op::OpAtomicFAddEXT:
427     case spv::Op::OpAtomicISub:
428     case spv::Op::OpAtomicSMin:
429     case spv::Op::OpAtomicUMin:
430     case spv::Op::OpAtomicFMinEXT:
431     case spv::Op::OpAtomicSMax:
432     case spv::Op::OpAtomicUMax:
433     case spv::Op::OpAtomicFMaxEXT:
434     case spv::Op::OpAtomicAnd:
435     case spv::Op::OpAtomicOr:
436     case spv::Op::OpAtomicXor:
437     case spv::Op::OpAtomicFlagTestAndSet:
438       return true;
439     default:
440       return false;
441   }
442 }
443 
spvOpcodeIsAtomicOp(const spv::Op opcode)444 bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
445   return (spvOpcodeIsAtomicWithLoad(opcode) ||
446           opcode == spv::Op::OpAtomicStore ||
447           opcode == spv::Op::OpAtomicFlagClear);
448 }
449 
spvOpcodeIsReturn(spv::Op opcode)450 bool spvOpcodeIsReturn(spv::Op opcode) {
451   switch (opcode) {
452     case spv::Op::OpReturn:
453     case spv::Op::OpReturnValue:
454       return true;
455     default:
456       return false;
457   }
458 }
459 
spvOpcodeIsAbort(spv::Op opcode)460 bool spvOpcodeIsAbort(spv::Op opcode) {
461   switch (opcode) {
462     case spv::Op::OpKill:
463     case spv::Op::OpUnreachable:
464     case spv::Op::OpTerminateInvocation:
465     case spv::Op::OpTerminateRayKHR:
466     case spv::Op::OpIgnoreIntersectionKHR:
467     case spv::Op::OpEmitMeshTasksEXT:
468       return true;
469     default:
470       return false;
471   }
472 }
473 
spvOpcodeIsReturnOrAbort(spv::Op opcode)474 bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
475   return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
476 }
477 
spvOpcodeIsBlockTerminator(spv::Op opcode)478 bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
479   return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
480 }
481 
spvOpcodeIsBaseOpaqueType(spv::Op opcode)482 bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
483   switch (opcode) {
484     case spv::Op::OpTypeImage:
485     case spv::Op::OpTypeSampler:
486     case spv::Op::OpTypeSampledImage:
487     case spv::Op::OpTypeOpaque:
488     case spv::Op::OpTypeEvent:
489     case spv::Op::OpTypeDeviceEvent:
490     case spv::Op::OpTypeReserveId:
491     case spv::Op::OpTypeQueue:
492     case spv::Op::OpTypePipe:
493     case spv::Op::OpTypeForwardPointer:
494     case spv::Op::OpTypePipeStorage:
495     case spv::Op::OpTypeNamedBarrier:
496       return true;
497     default:
498       return false;
499   }
500 }
501 
spvOpcodeIsNonUniformGroupOperation(spv::Op opcode)502 bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
503   switch (opcode) {
504     case spv::Op::OpGroupNonUniformElect:
505     case spv::Op::OpGroupNonUniformAll:
506     case spv::Op::OpGroupNonUniformAny:
507     case spv::Op::OpGroupNonUniformAllEqual:
508     case spv::Op::OpGroupNonUniformBroadcast:
509     case spv::Op::OpGroupNonUniformBroadcastFirst:
510     case spv::Op::OpGroupNonUniformBallot:
511     case spv::Op::OpGroupNonUniformInverseBallot:
512     case spv::Op::OpGroupNonUniformBallotBitExtract:
513     case spv::Op::OpGroupNonUniformBallotBitCount:
514     case spv::Op::OpGroupNonUniformBallotFindLSB:
515     case spv::Op::OpGroupNonUniformBallotFindMSB:
516     case spv::Op::OpGroupNonUniformShuffle:
517     case spv::Op::OpGroupNonUniformShuffleXor:
518     case spv::Op::OpGroupNonUniformShuffleUp:
519     case spv::Op::OpGroupNonUniformShuffleDown:
520     case spv::Op::OpGroupNonUniformIAdd:
521     case spv::Op::OpGroupNonUniformFAdd:
522     case spv::Op::OpGroupNonUniformIMul:
523     case spv::Op::OpGroupNonUniformFMul:
524     case spv::Op::OpGroupNonUniformSMin:
525     case spv::Op::OpGroupNonUniformUMin:
526     case spv::Op::OpGroupNonUniformFMin:
527     case spv::Op::OpGroupNonUniformSMax:
528     case spv::Op::OpGroupNonUniformUMax:
529     case spv::Op::OpGroupNonUniformFMax:
530     case spv::Op::OpGroupNonUniformBitwiseAnd:
531     case spv::Op::OpGroupNonUniformBitwiseOr:
532     case spv::Op::OpGroupNonUniformBitwiseXor:
533     case spv::Op::OpGroupNonUniformLogicalAnd:
534     case spv::Op::OpGroupNonUniformLogicalOr:
535     case spv::Op::OpGroupNonUniformLogicalXor:
536     case spv::Op::OpGroupNonUniformQuadBroadcast:
537     case spv::Op::OpGroupNonUniformQuadSwap:
538     case spv::Op::OpGroupNonUniformRotateKHR:
539     case spv::Op::OpGroupNonUniformQuadAllKHR:
540     case spv::Op::OpGroupNonUniformQuadAnyKHR:
541       return true;
542     default:
543       return false;
544   }
545 }
546 
spvOpcodeIsScalarizable(spv::Op opcode)547 bool spvOpcodeIsScalarizable(spv::Op opcode) {
548   switch (opcode) {
549     case spv::Op::OpPhi:
550     case spv::Op::OpCopyObject:
551     case spv::Op::OpConvertFToU:
552     case spv::Op::OpConvertFToS:
553     case spv::Op::OpConvertSToF:
554     case spv::Op::OpConvertUToF:
555     case spv::Op::OpUConvert:
556     case spv::Op::OpSConvert:
557     case spv::Op::OpFConvert:
558     case spv::Op::OpQuantizeToF16:
559     case spv::Op::OpVectorInsertDynamic:
560     case spv::Op::OpSNegate:
561     case spv::Op::OpFNegate:
562     case spv::Op::OpIAdd:
563     case spv::Op::OpFAdd:
564     case spv::Op::OpISub:
565     case spv::Op::OpFSub:
566     case spv::Op::OpIMul:
567     case spv::Op::OpFMul:
568     case spv::Op::OpUDiv:
569     case spv::Op::OpSDiv:
570     case spv::Op::OpFDiv:
571     case spv::Op::OpUMod:
572     case spv::Op::OpSRem:
573     case spv::Op::OpSMod:
574     case spv::Op::OpFRem:
575     case spv::Op::OpFMod:
576     case spv::Op::OpVectorTimesScalar:
577     case spv::Op::OpIAddCarry:
578     case spv::Op::OpISubBorrow:
579     case spv::Op::OpUMulExtended:
580     case spv::Op::OpSMulExtended:
581     case spv::Op::OpShiftRightLogical:
582     case spv::Op::OpShiftRightArithmetic:
583     case spv::Op::OpShiftLeftLogical:
584     case spv::Op::OpBitwiseOr:
585     case spv::Op::OpBitwiseAnd:
586     case spv::Op::OpNot:
587     case spv::Op::OpBitFieldInsert:
588     case spv::Op::OpBitFieldSExtract:
589     case spv::Op::OpBitFieldUExtract:
590     case spv::Op::OpBitReverse:
591     case spv::Op::OpBitCount:
592     case spv::Op::OpIsNan:
593     case spv::Op::OpIsInf:
594     case spv::Op::OpIsFinite:
595     case spv::Op::OpIsNormal:
596     case spv::Op::OpSignBitSet:
597     case spv::Op::OpLessOrGreater:
598     case spv::Op::OpOrdered:
599     case spv::Op::OpUnordered:
600     case spv::Op::OpLogicalEqual:
601     case spv::Op::OpLogicalNotEqual:
602     case spv::Op::OpLogicalOr:
603     case spv::Op::OpLogicalAnd:
604     case spv::Op::OpLogicalNot:
605     case spv::Op::OpSelect:
606     case spv::Op::OpIEqual:
607     case spv::Op::OpINotEqual:
608     case spv::Op::OpUGreaterThan:
609     case spv::Op::OpSGreaterThan:
610     case spv::Op::OpUGreaterThanEqual:
611     case spv::Op::OpSGreaterThanEqual:
612     case spv::Op::OpULessThan:
613     case spv::Op::OpSLessThan:
614     case spv::Op::OpULessThanEqual:
615     case spv::Op::OpSLessThanEqual:
616     case spv::Op::OpFOrdEqual:
617     case spv::Op::OpFUnordEqual:
618     case spv::Op::OpFOrdNotEqual:
619     case spv::Op::OpFUnordNotEqual:
620     case spv::Op::OpFOrdLessThan:
621     case spv::Op::OpFUnordLessThan:
622     case spv::Op::OpFOrdGreaterThan:
623     case spv::Op::OpFUnordGreaterThan:
624     case spv::Op::OpFOrdLessThanEqual:
625     case spv::Op::OpFUnordLessThanEqual:
626     case spv::Op::OpFOrdGreaterThanEqual:
627     case spv::Op::OpFUnordGreaterThanEqual:
628       return true;
629     default:
630       return false;
631   }
632 }
633 
spvOpcodeIsDebug(spv::Op opcode)634 bool spvOpcodeIsDebug(spv::Op opcode) {
635   switch (opcode) {
636     case spv::Op::OpName:
637     case spv::Op::OpMemberName:
638     case spv::Op::OpSource:
639     case spv::Op::OpSourceContinued:
640     case spv::Op::OpSourceExtension:
641     case spv::Op::OpString:
642     case spv::Op::OpLine:
643     case spv::Op::OpNoLine:
644     case spv::Op::OpModuleProcessed:
645       return true;
646     default:
647       return false;
648   }
649 }
650 
spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode)651 bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
652   switch (opcode) {
653     case spv::Op::OpPtrEqual:
654     case spv::Op::OpPtrNotEqual:
655     case spv::Op::OpIAdd:
656     case spv::Op::OpFAdd:
657     case spv::Op::OpIMul:
658     case spv::Op::OpFMul:
659     case spv::Op::OpDot:
660     case spv::Op::OpIAddCarry:
661     case spv::Op::OpUMulExtended:
662     case spv::Op::OpSMulExtended:
663     case spv::Op::OpBitwiseOr:
664     case spv::Op::OpBitwiseXor:
665     case spv::Op::OpBitwiseAnd:
666     case spv::Op::OpOrdered:
667     case spv::Op::OpUnordered:
668     case spv::Op::OpLogicalEqual:
669     case spv::Op::OpLogicalNotEqual:
670     case spv::Op::OpLogicalOr:
671     case spv::Op::OpLogicalAnd:
672     case spv::Op::OpIEqual:
673     case spv::Op::OpINotEqual:
674     case spv::Op::OpFOrdEqual:
675     case spv::Op::OpFUnordEqual:
676     case spv::Op::OpFOrdNotEqual:
677     case spv::Op::OpFUnordNotEqual:
678       return true;
679     default:
680       return false;
681   }
682 }
683 
spvOpcodeIsLinearAlgebra(spv::Op opcode)684 bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
685   switch (opcode) {
686     case spv::Op::OpTranspose:
687     case spv::Op::OpVectorTimesScalar:
688     case spv::Op::OpMatrixTimesScalar:
689     case spv::Op::OpVectorTimesMatrix:
690     case spv::Op::OpMatrixTimesVector:
691     case spv::Op::OpMatrixTimesMatrix:
692     case spv::Op::OpOuterProduct:
693     case spv::Op::OpDot:
694       return true;
695     default:
696       return false;
697   }
698 }
699 
spvOpcodeIsImageSample(const spv::Op opcode)700 bool spvOpcodeIsImageSample(const spv::Op opcode) {
701   switch (opcode) {
702     case spv::Op::OpImageSampleImplicitLod:
703     case spv::Op::OpImageSampleExplicitLod:
704     case spv::Op::OpImageSampleDrefImplicitLod:
705     case spv::Op::OpImageSampleDrefExplicitLod:
706     case spv::Op::OpImageSampleProjImplicitLod:
707     case spv::Op::OpImageSampleProjExplicitLod:
708     case spv::Op::OpImageSampleProjDrefImplicitLod:
709     case spv::Op::OpImageSampleProjDrefExplicitLod:
710     case spv::Op::OpImageSparseSampleImplicitLod:
711     case spv::Op::OpImageSparseSampleExplicitLod:
712     case spv::Op::OpImageSparseSampleDrefImplicitLod:
713     case spv::Op::OpImageSparseSampleDrefExplicitLod:
714       return true;
715     default:
716       return false;
717   }
718 }
719 
spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode)720 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
721   switch (opcode) {
722     case spv::Op::OpMemoryBarrier:
723       return {1};
724     case spv::Op::OpAtomicStore:
725     case spv::Op::OpControlBarrier:
726     case spv::Op::OpAtomicFlagClear:
727     case spv::Op::OpMemoryNamedBarrier:
728       return {2};
729     case spv::Op::OpAtomicLoad:
730     case spv::Op::OpAtomicExchange:
731     case spv::Op::OpAtomicIIncrement:
732     case spv::Op::OpAtomicIDecrement:
733     case spv::Op::OpAtomicIAdd:
734     case spv::Op::OpAtomicFAddEXT:
735     case spv::Op::OpAtomicISub:
736     case spv::Op::OpAtomicSMin:
737     case spv::Op::OpAtomicUMin:
738     case spv::Op::OpAtomicSMax:
739     case spv::Op::OpAtomicUMax:
740     case spv::Op::OpAtomicAnd:
741     case spv::Op::OpAtomicOr:
742     case spv::Op::OpAtomicXor:
743     case spv::Op::OpAtomicFlagTestAndSet:
744       return {4};
745     case spv::Op::OpAtomicCompareExchange:
746     case spv::Op::OpAtomicCompareExchangeWeak:
747       return {4, 5};
748     default:
749       return {};
750   }
751 }
752 
spvOpcodeIsAccessChain(spv::Op opcode)753 bool spvOpcodeIsAccessChain(spv::Op opcode) {
754   switch (opcode) {
755     case spv::Op::OpAccessChain:
756     case spv::Op::OpInBoundsAccessChain:
757     case spv::Op::OpPtrAccessChain:
758     case spv::Op::OpInBoundsPtrAccessChain:
759     case spv::Op::OpRawAccessChainNV:
760       return true;
761     default:
762       return false;
763   }
764 }
765 
spvOpcodeIsBit(spv::Op opcode)766 bool spvOpcodeIsBit(spv::Op opcode) {
767   switch (opcode) {
768     case spv::Op::OpShiftRightLogical:
769     case spv::Op::OpShiftRightArithmetic:
770     case spv::Op::OpShiftLeftLogical:
771     case spv::Op::OpBitwiseOr:
772     case spv::Op::OpBitwiseXor:
773     case spv::Op::OpBitwiseAnd:
774     case spv::Op::OpNot:
775     case spv::Op::OpBitReverse:
776     case spv::Op::OpBitCount:
777       return true;
778     default:
779       return false;
780   }
781 }
782