• 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,SpvOp opcode)67 uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp 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 SpvOp opcode,spv_opcode_desc * pEntry)126 spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
127                                        const spv_opcode_table table,
128                                        const SpvOp 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 SpvOp opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)169 void spvInstructionCopy(const uint32_t* words, const SpvOp 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<SpvOp>(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<SpvOp>(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 == opcode) {
200     return it->name;
201   }
202 
203   assert(0 && "Unreachable!");
204   return "unknown";
205 }
206 
spvOpcodeIsScalarType(const SpvOp opcode)207 int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
208   switch (opcode) {
209     case SpvOpTypeInt:
210     case SpvOpTypeFloat:
211     case SpvOpTypeBool:
212       return true;
213     default:
214       return false;
215   }
216 }
217 
spvOpcodeIsSpecConstant(const SpvOp opcode)218 int32_t spvOpcodeIsSpecConstant(const SpvOp opcode) {
219   switch (opcode) {
220     case SpvOpSpecConstantTrue:
221     case SpvOpSpecConstantFalse:
222     case SpvOpSpecConstant:
223     case SpvOpSpecConstantComposite:
224     case SpvOpSpecConstantOp:
225       return true;
226     default:
227       return false;
228   }
229 }
230 
spvOpcodeIsConstant(const SpvOp opcode)231 int32_t spvOpcodeIsConstant(const SpvOp opcode) {
232   switch (opcode) {
233     case SpvOpConstantTrue:
234     case SpvOpConstantFalse:
235     case SpvOpConstant:
236     case SpvOpConstantComposite:
237     case SpvOpConstantSampler:
238     case SpvOpConstantNull:
239     case SpvOpSpecConstantTrue:
240     case SpvOpSpecConstantFalse:
241     case SpvOpSpecConstant:
242     case SpvOpSpecConstantComposite:
243     case SpvOpSpecConstantOp:
244       return true;
245     default:
246       return false;
247   }
248 }
249 
spvOpcodeIsConstantOrUndef(const SpvOp opcode)250 bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) {
251   return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode);
252 }
253 
spvOpcodeIsScalarSpecConstant(const SpvOp opcode)254 bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) {
255   switch (opcode) {
256     case SpvOpSpecConstantTrue:
257     case SpvOpSpecConstantFalse:
258     case SpvOpSpecConstant:
259       return true;
260     default:
261       return false;
262   }
263 }
264 
spvOpcodeIsComposite(const SpvOp opcode)265 int32_t spvOpcodeIsComposite(const SpvOp opcode) {
266   switch (opcode) {
267     case SpvOpTypeVector:
268     case SpvOpTypeMatrix:
269     case SpvOpTypeArray:
270     case SpvOpTypeStruct:
271     case SpvOpTypeCooperativeMatrixNV:
272       return true;
273     default:
274       return false;
275   }
276 }
277 
spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode)278 bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode) {
279   switch (opcode) {
280     case SpvOpVariable:
281     case SpvOpAccessChain:
282     case SpvOpInBoundsAccessChain:
283     case SpvOpFunctionParameter:
284     case SpvOpImageTexelPointer:
285     case SpvOpCopyObject:
286     case SpvOpSelect:
287     case SpvOpPhi:
288     case SpvOpFunctionCall:
289     case SpvOpPtrAccessChain:
290     case SpvOpLoad:
291     case SpvOpConstantNull:
292       return true;
293     default:
294       return false;
295   }
296 }
297 
spvOpcodeReturnsLogicalPointer(const SpvOp opcode)298 int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) {
299   switch (opcode) {
300     case SpvOpVariable:
301     case SpvOpAccessChain:
302     case SpvOpInBoundsAccessChain:
303     case SpvOpFunctionParameter:
304     case SpvOpImageTexelPointer:
305     case SpvOpCopyObject:
306       return true;
307     default:
308       return false;
309   }
310 }
311 
spvOpcodeGeneratesType(SpvOp op)312 int32_t spvOpcodeGeneratesType(SpvOp op) {
313   switch (op) {
314     case SpvOpTypeVoid:
315     case SpvOpTypeBool:
316     case SpvOpTypeInt:
317     case SpvOpTypeFloat:
318     case SpvOpTypeVector:
319     case SpvOpTypeMatrix:
320     case SpvOpTypeImage:
321     case SpvOpTypeSampler:
322     case SpvOpTypeSampledImage:
323     case SpvOpTypeArray:
324     case SpvOpTypeRuntimeArray:
325     case SpvOpTypeStruct:
326     case SpvOpTypeOpaque:
327     case SpvOpTypePointer:
328     case SpvOpTypeFunction:
329     case SpvOpTypeEvent:
330     case SpvOpTypeDeviceEvent:
331     case SpvOpTypeReserveId:
332     case SpvOpTypeQueue:
333     case SpvOpTypePipe:
334     case SpvOpTypePipeStorage:
335     case SpvOpTypeNamedBarrier:
336     case SpvOpTypeAccelerationStructureNV:
337     case SpvOpTypeCooperativeMatrixNV:
338     // case SpvOpTypeAccelerationStructureKHR: covered by
339     // SpvOpTypeAccelerationStructureNV
340     case SpvOpTypeRayQueryKHR:
341       return true;
342     default:
343       // In particular, OpTypeForwardPointer does not generate a type,
344       // but declares a storage class for a pointer type generated
345       // by a different instruction.
346       break;
347   }
348   return 0;
349 }
350 
spvOpcodeIsDecoration(const SpvOp opcode)351 bool spvOpcodeIsDecoration(const SpvOp opcode) {
352   switch (opcode) {
353     case SpvOpDecorate:
354     case SpvOpDecorateId:
355     case SpvOpMemberDecorate:
356     case SpvOpGroupDecorate:
357     case SpvOpGroupMemberDecorate:
358     case SpvOpDecorateStringGOOGLE:
359     case SpvOpMemberDecorateStringGOOGLE:
360       return true;
361     default:
362       break;
363   }
364   return false;
365 }
366 
spvOpcodeIsLoad(const SpvOp opcode)367 bool spvOpcodeIsLoad(const SpvOp opcode) {
368   switch (opcode) {
369     case SpvOpLoad:
370     case SpvOpImageSampleExplicitLod:
371     case SpvOpImageSampleImplicitLod:
372     case SpvOpImageSampleDrefImplicitLod:
373     case SpvOpImageSampleDrefExplicitLod:
374     case SpvOpImageSampleProjImplicitLod:
375     case SpvOpImageSampleProjExplicitLod:
376     case SpvOpImageSampleProjDrefImplicitLod:
377     case SpvOpImageSampleProjDrefExplicitLod:
378     case SpvOpImageFetch:
379     case SpvOpImageGather:
380     case SpvOpImageDrefGather:
381     case SpvOpImageRead:
382     case SpvOpImageSparseSampleImplicitLod:
383     case SpvOpImageSparseSampleExplicitLod:
384     case SpvOpImageSparseSampleDrefExplicitLod:
385     case SpvOpImageSparseSampleDrefImplicitLod:
386     case SpvOpImageSparseFetch:
387     case SpvOpImageSparseGather:
388     case SpvOpImageSparseDrefGather:
389     case SpvOpImageSparseRead:
390       return true;
391     default:
392       return false;
393   }
394 }
395 
spvOpcodeIsBranch(SpvOp opcode)396 bool spvOpcodeIsBranch(SpvOp opcode) {
397   switch (opcode) {
398     case SpvOpBranch:
399     case SpvOpBranchConditional:
400     case SpvOpSwitch:
401       return true;
402     default:
403       return false;
404   }
405 }
406 
spvOpcodeIsAtomicWithLoad(const SpvOp opcode)407 bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) {
408   switch (opcode) {
409     case SpvOpAtomicLoad:
410     case SpvOpAtomicExchange:
411     case SpvOpAtomicCompareExchange:
412     case SpvOpAtomicCompareExchangeWeak:
413     case SpvOpAtomicIIncrement:
414     case SpvOpAtomicIDecrement:
415     case SpvOpAtomicIAdd:
416     case SpvOpAtomicFAddEXT:
417     case SpvOpAtomicISub:
418     case SpvOpAtomicSMin:
419     case SpvOpAtomicUMin:
420     case SpvOpAtomicFMinEXT:
421     case SpvOpAtomicSMax:
422     case SpvOpAtomicUMax:
423     case SpvOpAtomicFMaxEXT:
424     case SpvOpAtomicAnd:
425     case SpvOpAtomicOr:
426     case SpvOpAtomicXor:
427     case SpvOpAtomicFlagTestAndSet:
428       return true;
429     default:
430       return false;
431   }
432 }
433 
spvOpcodeIsAtomicOp(const SpvOp opcode)434 bool spvOpcodeIsAtomicOp(const SpvOp opcode) {
435   return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore ||
436           opcode == SpvOpAtomicFlagClear);
437 }
438 
spvOpcodeIsReturn(SpvOp opcode)439 bool spvOpcodeIsReturn(SpvOp opcode) {
440   switch (opcode) {
441     case SpvOpReturn:
442     case SpvOpReturnValue:
443       return true;
444     default:
445       return false;
446   }
447 }
448 
spvOpcodeIsAbort(SpvOp opcode)449 bool spvOpcodeIsAbort(SpvOp opcode) {
450   switch (opcode) {
451     case SpvOpKill:
452     case SpvOpUnreachable:
453     case SpvOpTerminateInvocation:
454     case SpvOpTerminateRayKHR:
455     case SpvOpIgnoreIntersectionKHR:
456     case SpvOpEmitMeshTasksEXT:
457       return true;
458     default:
459       return false;
460   }
461 }
462 
spvOpcodeIsReturnOrAbort(SpvOp opcode)463 bool spvOpcodeIsReturnOrAbort(SpvOp opcode) {
464   return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
465 }
466 
spvOpcodeIsBlockTerminator(SpvOp opcode)467 bool spvOpcodeIsBlockTerminator(SpvOp opcode) {
468   return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
469 }
470 
spvOpcodeIsBaseOpaqueType(SpvOp opcode)471 bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) {
472   switch (opcode) {
473     case SpvOpTypeImage:
474     case SpvOpTypeSampler:
475     case SpvOpTypeSampledImage:
476     case SpvOpTypeOpaque:
477     case SpvOpTypeEvent:
478     case SpvOpTypeDeviceEvent:
479     case SpvOpTypeReserveId:
480     case SpvOpTypeQueue:
481     case SpvOpTypePipe:
482     case SpvOpTypeForwardPointer:
483     case SpvOpTypePipeStorage:
484     case SpvOpTypeNamedBarrier:
485       return true;
486     default:
487       return false;
488   }
489 }
490 
spvOpcodeIsNonUniformGroupOperation(SpvOp opcode)491 bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) {
492   switch (opcode) {
493     case SpvOpGroupNonUniformElect:
494     case SpvOpGroupNonUniformAll:
495     case SpvOpGroupNonUniformAny:
496     case SpvOpGroupNonUniformAllEqual:
497     case SpvOpGroupNonUniformBroadcast:
498     case SpvOpGroupNonUniformBroadcastFirst:
499     case SpvOpGroupNonUniformBallot:
500     case SpvOpGroupNonUniformInverseBallot:
501     case SpvOpGroupNonUniformBallotBitExtract:
502     case SpvOpGroupNonUniformBallotBitCount:
503     case SpvOpGroupNonUniformBallotFindLSB:
504     case SpvOpGroupNonUniformBallotFindMSB:
505     case SpvOpGroupNonUniformShuffle:
506     case SpvOpGroupNonUniformShuffleXor:
507     case SpvOpGroupNonUniformShuffleUp:
508     case SpvOpGroupNonUniformShuffleDown:
509     case SpvOpGroupNonUniformIAdd:
510     case SpvOpGroupNonUniformFAdd:
511     case SpvOpGroupNonUniformIMul:
512     case SpvOpGroupNonUniformFMul:
513     case SpvOpGroupNonUniformSMin:
514     case SpvOpGroupNonUniformUMin:
515     case SpvOpGroupNonUniformFMin:
516     case SpvOpGroupNonUniformSMax:
517     case SpvOpGroupNonUniformUMax:
518     case SpvOpGroupNonUniformFMax:
519     case SpvOpGroupNonUniformBitwiseAnd:
520     case SpvOpGroupNonUniformBitwiseOr:
521     case SpvOpGroupNonUniformBitwiseXor:
522     case SpvOpGroupNonUniformLogicalAnd:
523     case SpvOpGroupNonUniformLogicalOr:
524     case SpvOpGroupNonUniformLogicalXor:
525     case SpvOpGroupNonUniformQuadBroadcast:
526     case SpvOpGroupNonUniformQuadSwap:
527     case SpvOpGroupNonUniformRotateKHR:
528       return true;
529     default:
530       return false;
531   }
532 }
533 
spvOpcodeIsScalarizable(SpvOp opcode)534 bool spvOpcodeIsScalarizable(SpvOp opcode) {
535   switch (opcode) {
536     case SpvOpPhi:
537     case SpvOpCopyObject:
538     case SpvOpConvertFToU:
539     case SpvOpConvertFToS:
540     case SpvOpConvertSToF:
541     case SpvOpConvertUToF:
542     case SpvOpUConvert:
543     case SpvOpSConvert:
544     case SpvOpFConvert:
545     case SpvOpQuantizeToF16:
546     case SpvOpVectorInsertDynamic:
547     case SpvOpSNegate:
548     case SpvOpFNegate:
549     case SpvOpIAdd:
550     case SpvOpFAdd:
551     case SpvOpISub:
552     case SpvOpFSub:
553     case SpvOpIMul:
554     case SpvOpFMul:
555     case SpvOpUDiv:
556     case SpvOpSDiv:
557     case SpvOpFDiv:
558     case SpvOpUMod:
559     case SpvOpSRem:
560     case SpvOpSMod:
561     case SpvOpFRem:
562     case SpvOpFMod:
563     case SpvOpVectorTimesScalar:
564     case SpvOpIAddCarry:
565     case SpvOpISubBorrow:
566     case SpvOpUMulExtended:
567     case SpvOpSMulExtended:
568     case SpvOpShiftRightLogical:
569     case SpvOpShiftRightArithmetic:
570     case SpvOpShiftLeftLogical:
571     case SpvOpBitwiseOr:
572     case SpvOpBitwiseAnd:
573     case SpvOpNot:
574     case SpvOpBitFieldInsert:
575     case SpvOpBitFieldSExtract:
576     case SpvOpBitFieldUExtract:
577     case SpvOpBitReverse:
578     case SpvOpBitCount:
579     case SpvOpIsNan:
580     case SpvOpIsInf:
581     case SpvOpIsFinite:
582     case SpvOpIsNormal:
583     case SpvOpSignBitSet:
584     case SpvOpLessOrGreater:
585     case SpvOpOrdered:
586     case SpvOpUnordered:
587     case SpvOpLogicalEqual:
588     case SpvOpLogicalNotEqual:
589     case SpvOpLogicalOr:
590     case SpvOpLogicalAnd:
591     case SpvOpLogicalNot:
592     case SpvOpSelect:
593     case SpvOpIEqual:
594     case SpvOpINotEqual:
595     case SpvOpUGreaterThan:
596     case SpvOpSGreaterThan:
597     case SpvOpUGreaterThanEqual:
598     case SpvOpSGreaterThanEqual:
599     case SpvOpULessThan:
600     case SpvOpSLessThan:
601     case SpvOpULessThanEqual:
602     case SpvOpSLessThanEqual:
603     case SpvOpFOrdEqual:
604     case SpvOpFUnordEqual:
605     case SpvOpFOrdNotEqual:
606     case SpvOpFUnordNotEqual:
607     case SpvOpFOrdLessThan:
608     case SpvOpFUnordLessThan:
609     case SpvOpFOrdGreaterThan:
610     case SpvOpFUnordGreaterThan:
611     case SpvOpFOrdLessThanEqual:
612     case SpvOpFUnordLessThanEqual:
613     case SpvOpFOrdGreaterThanEqual:
614     case SpvOpFUnordGreaterThanEqual:
615       return true;
616     default:
617       return false;
618   }
619 }
620 
spvOpcodeIsDebug(SpvOp opcode)621 bool spvOpcodeIsDebug(SpvOp opcode) {
622   switch (opcode) {
623     case SpvOpName:
624     case SpvOpMemberName:
625     case SpvOpSource:
626     case SpvOpSourceContinued:
627     case SpvOpSourceExtension:
628     case SpvOpString:
629     case SpvOpLine:
630     case SpvOpNoLine:
631     case SpvOpModuleProcessed:
632       return true;
633     default:
634       return false;
635   }
636 }
637 
spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode)638 bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) {
639   switch (opcode) {
640     case SpvOpPtrEqual:
641     case SpvOpPtrNotEqual:
642     case SpvOpIAdd:
643     case SpvOpFAdd:
644     case SpvOpIMul:
645     case SpvOpFMul:
646     case SpvOpDot:
647     case SpvOpIAddCarry:
648     case SpvOpUMulExtended:
649     case SpvOpSMulExtended:
650     case SpvOpBitwiseOr:
651     case SpvOpBitwiseXor:
652     case SpvOpBitwiseAnd:
653     case SpvOpOrdered:
654     case SpvOpUnordered:
655     case SpvOpLogicalEqual:
656     case SpvOpLogicalNotEqual:
657     case SpvOpLogicalOr:
658     case SpvOpLogicalAnd:
659     case SpvOpIEqual:
660     case SpvOpINotEqual:
661     case SpvOpFOrdEqual:
662     case SpvOpFUnordEqual:
663     case SpvOpFOrdNotEqual:
664     case SpvOpFUnordNotEqual:
665       return true;
666     default:
667       return false;
668   }
669 }
670 
spvOpcodeIsLinearAlgebra(SpvOp opcode)671 bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
672   switch (opcode) {
673     case SpvOpTranspose:
674     case SpvOpVectorTimesScalar:
675     case SpvOpMatrixTimesScalar:
676     case SpvOpVectorTimesMatrix:
677     case SpvOpMatrixTimesVector:
678     case SpvOpMatrixTimesMatrix:
679     case SpvOpOuterProduct:
680     case SpvOpDot:
681       return true;
682     default:
683       return false;
684   }
685 }
686 
spvOpcodeIsImageSample(const SpvOp opcode)687 bool spvOpcodeIsImageSample(const SpvOp opcode) {
688   switch (opcode) {
689     case SpvOpImageSampleImplicitLod:
690     case SpvOpImageSampleExplicitLod:
691     case SpvOpImageSampleDrefImplicitLod:
692     case SpvOpImageSampleDrefExplicitLod:
693     case SpvOpImageSampleProjImplicitLod:
694     case SpvOpImageSampleProjExplicitLod:
695     case SpvOpImageSampleProjDrefImplicitLod:
696     case SpvOpImageSampleProjDrefExplicitLod:
697     case SpvOpImageSparseSampleImplicitLod:
698     case SpvOpImageSparseSampleExplicitLod:
699     case SpvOpImageSparseSampleDrefImplicitLod:
700     case SpvOpImageSparseSampleDrefExplicitLod:
701       return true;
702     default:
703       return false;
704   }
705 }
706 
spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode)707 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
708   switch (opcode) {
709     case SpvOpMemoryBarrier:
710       return {1};
711     case SpvOpAtomicStore:
712     case SpvOpControlBarrier:
713     case SpvOpAtomicFlagClear:
714     case SpvOpMemoryNamedBarrier:
715       return {2};
716     case SpvOpAtomicLoad:
717     case SpvOpAtomicExchange:
718     case SpvOpAtomicIIncrement:
719     case SpvOpAtomicIDecrement:
720     case SpvOpAtomicIAdd:
721     case SpvOpAtomicFAddEXT:
722     case SpvOpAtomicISub:
723     case SpvOpAtomicSMin:
724     case SpvOpAtomicUMin:
725     case SpvOpAtomicSMax:
726     case SpvOpAtomicUMax:
727     case SpvOpAtomicAnd:
728     case SpvOpAtomicOr:
729     case SpvOpAtomicXor:
730     case SpvOpAtomicFlagTestAndSet:
731       return {4};
732     case SpvOpAtomicCompareExchange:
733     case SpvOpAtomicCompareExchangeWeak:
734       return {4, 5};
735     default:
736       return {};
737   }
738 }
739 
spvOpcodeIsAccessChain(SpvOp opcode)740 bool spvOpcodeIsAccessChain(SpvOp opcode) {
741   switch (opcode) {
742     case SpvOpAccessChain:
743     case SpvOpInBoundsAccessChain:
744     case SpvOpPtrAccessChain:
745     case SpvOpInBoundsPtrAccessChain:
746       return true;
747     default:
748       return false;
749   }
750 }
751 
spvOpcodeIsBit(SpvOp opcode)752 bool spvOpcodeIsBit(SpvOp opcode) {
753   switch (opcode) {
754     case SpvOpShiftRightLogical:
755     case SpvOpShiftRightArithmetic:
756     case SpvOpShiftLeftLogical:
757     case SpvOpBitwiseOr:
758     case SpvOpBitwiseXor:
759     case SpvOpBitwiseAnd:
760     case SpvOpNot:
761     case SpvOpBitReverse:
762     case SpvOpBitCount:
763       return true;
764     default:
765       return false;
766   }
767 }
768