• 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::OpSpecConstantCompositeReplicateEXT:
229     case spv::Op::OpSpecConstantOp:
230       return true;
231     default:
232       return false;
233   }
234 }
235 
spvOpcodeIsConstant(const spv::Op opcode)236 int32_t spvOpcodeIsConstant(const spv::Op opcode) {
237   switch (opcode) {
238     case spv::Op::OpConstantTrue:
239     case spv::Op::OpConstantFalse:
240     case spv::Op::OpConstant:
241     case spv::Op::OpConstantComposite:
242     case spv::Op::OpConstantCompositeReplicateEXT:
243     case spv::Op::OpConstantSampler:
244     case spv::Op::OpConstantNull:
245     case spv::Op::OpConstantFunctionPointerINTEL:
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 
spvOpcodeIsConstantOrUndef(const spv::Op opcode)258 bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
259   return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
260 }
261 
spvOpcodeIsScalarSpecConstant(const spv::Op opcode)262 bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
263   switch (opcode) {
264     case spv::Op::OpSpecConstantTrue:
265     case spv::Op::OpSpecConstantFalse:
266     case spv::Op::OpSpecConstant:
267       return true;
268     default:
269       return false;
270   }
271 }
272 
spvOpcodeIsComposite(const spv::Op opcode)273 int32_t spvOpcodeIsComposite(const spv::Op opcode) {
274   switch (opcode) {
275     case spv::Op::OpTypeVector:
276     case spv::Op::OpTypeMatrix:
277     case spv::Op::OpTypeArray:
278     case spv::Op::OpTypeStruct:
279     case spv::Op::OpTypeCooperativeMatrixNV:
280     case spv::Op::OpTypeCooperativeMatrixKHR:
281       return true;
282     default:
283       return false;
284   }
285 }
286 
spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode)287 bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
288   switch (opcode) {
289     case spv::Op::OpVariable:
290     case spv::Op::OpAccessChain:
291     case spv::Op::OpInBoundsAccessChain:
292     case spv::Op::OpFunctionParameter:
293     case spv::Op::OpImageTexelPointer:
294     case spv::Op::OpCopyObject:
295     case spv::Op::OpSelect:
296     case spv::Op::OpPhi:
297     case spv::Op::OpFunctionCall:
298     case spv::Op::OpPtrAccessChain:
299     case spv::Op::OpLoad:
300     case spv::Op::OpConstantNull:
301     case spv::Op::OpRawAccessChainNV:
302       return true;
303     default:
304       return false;
305   }
306 }
307 
spvOpcodeReturnsLogicalPointer(const spv::Op opcode)308 int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
309   switch (opcode) {
310     case spv::Op::OpVariable:
311     case spv::Op::OpAccessChain:
312     case spv::Op::OpInBoundsAccessChain:
313     case spv::Op::OpFunctionParameter:
314     case spv::Op::OpImageTexelPointer:
315     case spv::Op::OpCopyObject:
316     case spv::Op::OpRawAccessChainNV:
317       return true;
318     default:
319       return false;
320   }
321 }
322 
spvOpcodeGeneratesType(spv::Op op)323 int32_t spvOpcodeGeneratesType(spv::Op op) {
324   switch (op) {
325     case spv::Op::OpTypeVoid:
326     case spv::Op::OpTypeBool:
327     case spv::Op::OpTypeInt:
328     case spv::Op::OpTypeFloat:
329     case spv::Op::OpTypeVector:
330     case spv::Op::OpTypeMatrix:
331     case spv::Op::OpTypeImage:
332     case spv::Op::OpTypeSampler:
333     case spv::Op::OpTypeSampledImage:
334     case spv::Op::OpTypeArray:
335     case spv::Op::OpTypeRuntimeArray:
336     case spv::Op::OpTypeStruct:
337     case spv::Op::OpTypeOpaque:
338     case spv::Op::OpTypePointer:
339     case spv::Op::OpTypeFunction:
340     case spv::Op::OpTypeEvent:
341     case spv::Op::OpTypeDeviceEvent:
342     case spv::Op::OpTypeReserveId:
343     case spv::Op::OpTypeQueue:
344     case spv::Op::OpTypePipe:
345     case spv::Op::OpTypePipeStorage:
346     case spv::Op::OpTypeNamedBarrier:
347     case spv::Op::OpTypeAccelerationStructureNV:
348     case spv::Op::OpTypeCooperativeMatrixNV:
349     case spv::Op::OpTypeCooperativeMatrixKHR:
350     // case spv::Op::OpTypeAccelerationStructureKHR: covered by
351     // spv::Op::OpTypeAccelerationStructureNV
352     case spv::Op::OpTypeRayQueryKHR:
353     case spv::Op::OpTypeHitObjectNV:
354       return true;
355     default:
356       // In particular, OpTypeForwardPointer does not generate a type,
357       // but declares a storage class for a pointer type generated
358       // by a different instruction.
359       break;
360   }
361   return 0;
362 }
363 
spvOpcodeIsDecoration(const spv::Op opcode)364 bool spvOpcodeIsDecoration(const spv::Op opcode) {
365   switch (opcode) {
366     case spv::Op::OpDecorate:
367     case spv::Op::OpDecorateId:
368     case spv::Op::OpMemberDecorate:
369     case spv::Op::OpGroupDecorate:
370     case spv::Op::OpGroupMemberDecorate:
371     case spv::Op::OpDecorateStringGOOGLE:
372     case spv::Op::OpMemberDecorateStringGOOGLE:
373       return true;
374     default:
375       break;
376   }
377   return false;
378 }
379 
spvOpcodeIsLoad(const spv::Op opcode)380 bool spvOpcodeIsLoad(const spv::Op opcode) {
381   switch (opcode) {
382     case spv::Op::OpLoad:
383     case spv::Op::OpImageSampleExplicitLod:
384     case spv::Op::OpImageSampleImplicitLod:
385     case spv::Op::OpImageSampleDrefImplicitLod:
386     case spv::Op::OpImageSampleDrefExplicitLod:
387     case spv::Op::OpImageSampleProjImplicitLod:
388     case spv::Op::OpImageSampleProjExplicitLod:
389     case spv::Op::OpImageSampleProjDrefImplicitLod:
390     case spv::Op::OpImageSampleProjDrefExplicitLod:
391     case spv::Op::OpImageFetch:
392     case spv::Op::OpImageGather:
393     case spv::Op::OpImageDrefGather:
394     case spv::Op::OpImageRead:
395     case spv::Op::OpImageSparseSampleImplicitLod:
396     case spv::Op::OpImageSparseSampleExplicitLod:
397     case spv::Op::OpImageSparseSampleDrefExplicitLod:
398     case spv::Op::OpImageSparseSampleDrefImplicitLod:
399     case spv::Op::OpImageSparseFetch:
400     case spv::Op::OpImageSparseGather:
401     case spv::Op::OpImageSparseDrefGather:
402     case spv::Op::OpImageSparseRead:
403       return true;
404     default:
405       return false;
406   }
407 }
408 
spvOpcodeIsBranch(spv::Op opcode)409 bool spvOpcodeIsBranch(spv::Op opcode) {
410   switch (opcode) {
411     case spv::Op::OpBranch:
412     case spv::Op::OpBranchConditional:
413     case spv::Op::OpSwitch:
414       return true;
415     default:
416       return false;
417   }
418 }
419 
spvOpcodeIsAtomicWithLoad(const spv::Op opcode)420 bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
421   switch (opcode) {
422     case spv::Op::OpAtomicLoad:
423     case spv::Op::OpAtomicExchange:
424     case spv::Op::OpAtomicCompareExchange:
425     case spv::Op::OpAtomicCompareExchangeWeak:
426     case spv::Op::OpAtomicIIncrement:
427     case spv::Op::OpAtomicIDecrement:
428     case spv::Op::OpAtomicIAdd:
429     case spv::Op::OpAtomicFAddEXT:
430     case spv::Op::OpAtomicISub:
431     case spv::Op::OpAtomicSMin:
432     case spv::Op::OpAtomicUMin:
433     case spv::Op::OpAtomicFMinEXT:
434     case spv::Op::OpAtomicSMax:
435     case spv::Op::OpAtomicUMax:
436     case spv::Op::OpAtomicFMaxEXT:
437     case spv::Op::OpAtomicAnd:
438     case spv::Op::OpAtomicOr:
439     case spv::Op::OpAtomicXor:
440     case spv::Op::OpAtomicFlagTestAndSet:
441       return true;
442     default:
443       return false;
444   }
445 }
446 
spvOpcodeIsAtomicOp(const spv::Op opcode)447 bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
448   return (spvOpcodeIsAtomicWithLoad(opcode) ||
449           opcode == spv::Op::OpAtomicStore ||
450           opcode == spv::Op::OpAtomicFlagClear);
451 }
452 
spvOpcodeIsReturn(spv::Op opcode)453 bool spvOpcodeIsReturn(spv::Op opcode) {
454   switch (opcode) {
455     case spv::Op::OpReturn:
456     case spv::Op::OpReturnValue:
457       return true;
458     default:
459       return false;
460   }
461 }
462 
spvOpcodeIsAbort(spv::Op opcode)463 bool spvOpcodeIsAbort(spv::Op opcode) {
464   switch (opcode) {
465     case spv::Op::OpKill:
466     case spv::Op::OpUnreachable:
467     case spv::Op::OpTerminateInvocation:
468     case spv::Op::OpTerminateRayKHR:
469     case spv::Op::OpIgnoreIntersectionKHR:
470     case spv::Op::OpEmitMeshTasksEXT:
471       return true;
472     default:
473       return false;
474   }
475 }
476 
spvOpcodeIsReturnOrAbort(spv::Op opcode)477 bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
478   return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
479 }
480 
spvOpcodeIsBlockTerminator(spv::Op opcode)481 bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
482   return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
483 }
484 
spvOpcodeIsBaseOpaqueType(spv::Op opcode)485 bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
486   switch (opcode) {
487     case spv::Op::OpTypeImage:
488     case spv::Op::OpTypeSampler:
489     case spv::Op::OpTypeSampledImage:
490     case spv::Op::OpTypeOpaque:
491     case spv::Op::OpTypeEvent:
492     case spv::Op::OpTypeDeviceEvent:
493     case spv::Op::OpTypeReserveId:
494     case spv::Op::OpTypeQueue:
495     case spv::Op::OpTypePipe:
496     case spv::Op::OpTypeForwardPointer:
497     case spv::Op::OpTypePipeStorage:
498     case spv::Op::OpTypeNamedBarrier:
499       return true;
500     default:
501       return false;
502   }
503 }
504 
spvOpcodeIsNonUniformGroupOperation(spv::Op opcode)505 bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
506   switch (opcode) {
507     case spv::Op::OpGroupNonUniformElect:
508     case spv::Op::OpGroupNonUniformAll:
509     case spv::Op::OpGroupNonUniformAny:
510     case spv::Op::OpGroupNonUniformAllEqual:
511     case spv::Op::OpGroupNonUniformBroadcast:
512     case spv::Op::OpGroupNonUniformBroadcastFirst:
513     case spv::Op::OpGroupNonUniformBallot:
514     case spv::Op::OpGroupNonUniformInverseBallot:
515     case spv::Op::OpGroupNonUniformBallotBitExtract:
516     case spv::Op::OpGroupNonUniformBallotBitCount:
517     case spv::Op::OpGroupNonUniformBallotFindLSB:
518     case spv::Op::OpGroupNonUniformBallotFindMSB:
519     case spv::Op::OpGroupNonUniformShuffle:
520     case spv::Op::OpGroupNonUniformShuffleXor:
521     case spv::Op::OpGroupNonUniformShuffleUp:
522     case spv::Op::OpGroupNonUniformShuffleDown:
523     case spv::Op::OpGroupNonUniformIAdd:
524     case spv::Op::OpGroupNonUniformFAdd:
525     case spv::Op::OpGroupNonUniformIMul:
526     case spv::Op::OpGroupNonUniformFMul:
527     case spv::Op::OpGroupNonUniformSMin:
528     case spv::Op::OpGroupNonUniformUMin:
529     case spv::Op::OpGroupNonUniformFMin:
530     case spv::Op::OpGroupNonUniformSMax:
531     case spv::Op::OpGroupNonUniformUMax:
532     case spv::Op::OpGroupNonUniformFMax:
533     case spv::Op::OpGroupNonUniformBitwiseAnd:
534     case spv::Op::OpGroupNonUniformBitwiseOr:
535     case spv::Op::OpGroupNonUniformBitwiseXor:
536     case spv::Op::OpGroupNonUniformLogicalAnd:
537     case spv::Op::OpGroupNonUniformLogicalOr:
538     case spv::Op::OpGroupNonUniformLogicalXor:
539     case spv::Op::OpGroupNonUniformQuadBroadcast:
540     case spv::Op::OpGroupNonUniformQuadSwap:
541     case spv::Op::OpGroupNonUniformRotateKHR:
542     case spv::Op::OpGroupNonUniformQuadAllKHR:
543     case spv::Op::OpGroupNonUniformQuadAnyKHR:
544       return true;
545     default:
546       return false;
547   }
548 }
549 
spvOpcodeIsScalarizable(spv::Op opcode)550 bool spvOpcodeIsScalarizable(spv::Op opcode) {
551   switch (opcode) {
552     case spv::Op::OpPhi:
553     case spv::Op::OpCopyObject:
554     case spv::Op::OpConvertFToU:
555     case spv::Op::OpConvertFToS:
556     case spv::Op::OpConvertSToF:
557     case spv::Op::OpConvertUToF:
558     case spv::Op::OpUConvert:
559     case spv::Op::OpSConvert:
560     case spv::Op::OpFConvert:
561     case spv::Op::OpQuantizeToF16:
562     case spv::Op::OpVectorInsertDynamic:
563     case spv::Op::OpSNegate:
564     case spv::Op::OpFNegate:
565     case spv::Op::OpIAdd:
566     case spv::Op::OpFAdd:
567     case spv::Op::OpISub:
568     case spv::Op::OpFSub:
569     case spv::Op::OpIMul:
570     case spv::Op::OpFMul:
571     case spv::Op::OpUDiv:
572     case spv::Op::OpSDiv:
573     case spv::Op::OpFDiv:
574     case spv::Op::OpUMod:
575     case spv::Op::OpSRem:
576     case spv::Op::OpSMod:
577     case spv::Op::OpFRem:
578     case spv::Op::OpFMod:
579     case spv::Op::OpVectorTimesScalar:
580     case spv::Op::OpIAddCarry:
581     case spv::Op::OpISubBorrow:
582     case spv::Op::OpUMulExtended:
583     case spv::Op::OpSMulExtended:
584     case spv::Op::OpShiftRightLogical:
585     case spv::Op::OpShiftRightArithmetic:
586     case spv::Op::OpShiftLeftLogical:
587     case spv::Op::OpBitwiseOr:
588     case spv::Op::OpBitwiseAnd:
589     case spv::Op::OpNot:
590     case spv::Op::OpBitFieldInsert:
591     case spv::Op::OpBitFieldSExtract:
592     case spv::Op::OpBitFieldUExtract:
593     case spv::Op::OpBitReverse:
594     case spv::Op::OpBitCount:
595     case spv::Op::OpIsNan:
596     case spv::Op::OpIsInf:
597     case spv::Op::OpIsFinite:
598     case spv::Op::OpIsNormal:
599     case spv::Op::OpSignBitSet:
600     case spv::Op::OpLessOrGreater:
601     case spv::Op::OpOrdered:
602     case spv::Op::OpUnordered:
603     case spv::Op::OpLogicalEqual:
604     case spv::Op::OpLogicalNotEqual:
605     case spv::Op::OpLogicalOr:
606     case spv::Op::OpLogicalAnd:
607     case spv::Op::OpLogicalNot:
608     case spv::Op::OpSelect:
609     case spv::Op::OpIEqual:
610     case spv::Op::OpINotEqual:
611     case spv::Op::OpUGreaterThan:
612     case spv::Op::OpSGreaterThan:
613     case spv::Op::OpUGreaterThanEqual:
614     case spv::Op::OpSGreaterThanEqual:
615     case spv::Op::OpULessThan:
616     case spv::Op::OpSLessThan:
617     case spv::Op::OpULessThanEqual:
618     case spv::Op::OpSLessThanEqual:
619     case spv::Op::OpFOrdEqual:
620     case spv::Op::OpFUnordEqual:
621     case spv::Op::OpFOrdNotEqual:
622     case spv::Op::OpFUnordNotEqual:
623     case spv::Op::OpFOrdLessThan:
624     case spv::Op::OpFUnordLessThan:
625     case spv::Op::OpFOrdGreaterThan:
626     case spv::Op::OpFUnordGreaterThan:
627     case spv::Op::OpFOrdLessThanEqual:
628     case spv::Op::OpFUnordLessThanEqual:
629     case spv::Op::OpFOrdGreaterThanEqual:
630     case spv::Op::OpFUnordGreaterThanEqual:
631       return true;
632     default:
633       return false;
634   }
635 }
636 
spvOpcodeIsDebug(spv::Op opcode)637 bool spvOpcodeIsDebug(spv::Op opcode) {
638   switch (opcode) {
639     case spv::Op::OpName:
640     case spv::Op::OpMemberName:
641     case spv::Op::OpSource:
642     case spv::Op::OpSourceContinued:
643     case spv::Op::OpSourceExtension:
644     case spv::Op::OpString:
645     case spv::Op::OpLine:
646     case spv::Op::OpNoLine:
647     case spv::Op::OpModuleProcessed:
648       return true;
649     default:
650       return false;
651   }
652 }
653 
spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode)654 bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
655   switch (opcode) {
656     case spv::Op::OpPtrEqual:
657     case spv::Op::OpPtrNotEqual:
658     case spv::Op::OpIAdd:
659     case spv::Op::OpFAdd:
660     case spv::Op::OpIMul:
661     case spv::Op::OpFMul:
662     case spv::Op::OpDot:
663     case spv::Op::OpIAddCarry:
664     case spv::Op::OpUMulExtended:
665     case spv::Op::OpSMulExtended:
666     case spv::Op::OpBitwiseOr:
667     case spv::Op::OpBitwiseXor:
668     case spv::Op::OpBitwiseAnd:
669     case spv::Op::OpOrdered:
670     case spv::Op::OpUnordered:
671     case spv::Op::OpLogicalEqual:
672     case spv::Op::OpLogicalNotEqual:
673     case spv::Op::OpLogicalOr:
674     case spv::Op::OpLogicalAnd:
675     case spv::Op::OpIEqual:
676     case spv::Op::OpINotEqual:
677     case spv::Op::OpFOrdEqual:
678     case spv::Op::OpFUnordEqual:
679     case spv::Op::OpFOrdNotEqual:
680     case spv::Op::OpFUnordNotEqual:
681       return true;
682     default:
683       return false;
684   }
685 }
686 
spvOpcodeIsLinearAlgebra(spv::Op opcode)687 bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
688   switch (opcode) {
689     case spv::Op::OpTranspose:
690     case spv::Op::OpVectorTimesScalar:
691     case spv::Op::OpMatrixTimesScalar:
692     case spv::Op::OpVectorTimesMatrix:
693     case spv::Op::OpMatrixTimesVector:
694     case spv::Op::OpMatrixTimesMatrix:
695     case spv::Op::OpOuterProduct:
696     case spv::Op::OpDot:
697       return true;
698     default:
699       return false;
700   }
701 }
702 
spvOpcodeIsImageSample(const spv::Op opcode)703 bool spvOpcodeIsImageSample(const spv::Op opcode) {
704   switch (opcode) {
705     case spv::Op::OpImageSampleImplicitLod:
706     case spv::Op::OpImageSampleExplicitLod:
707     case spv::Op::OpImageSampleDrefImplicitLod:
708     case spv::Op::OpImageSampleDrefExplicitLod:
709     case spv::Op::OpImageSampleProjImplicitLod:
710     case spv::Op::OpImageSampleProjExplicitLod:
711     case spv::Op::OpImageSampleProjDrefImplicitLod:
712     case spv::Op::OpImageSampleProjDrefExplicitLod:
713     case spv::Op::OpImageSparseSampleImplicitLod:
714     case spv::Op::OpImageSparseSampleExplicitLod:
715     case spv::Op::OpImageSparseSampleDrefImplicitLod:
716     case spv::Op::OpImageSparseSampleDrefExplicitLod:
717       return true;
718     default:
719       return false;
720   }
721 }
722 
spvIsExtendedInstruction(const spv::Op opcode)723 bool spvIsExtendedInstruction(const spv::Op opcode) {
724   switch (opcode) {
725     case spv::Op::OpExtInst:
726     case spv::Op::OpExtInstWithForwardRefsKHR:
727       return true;
728     default:
729       return false;
730   }
731 }
732 
spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode)733 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
734   switch (opcode) {
735     case spv::Op::OpMemoryBarrier:
736       return {1};
737     case spv::Op::OpAtomicStore:
738     case spv::Op::OpControlBarrier:
739     case spv::Op::OpAtomicFlagClear:
740     case spv::Op::OpMemoryNamedBarrier:
741       return {2};
742     case spv::Op::OpAtomicLoad:
743     case spv::Op::OpAtomicExchange:
744     case spv::Op::OpAtomicIIncrement:
745     case spv::Op::OpAtomicIDecrement:
746     case spv::Op::OpAtomicIAdd:
747     case spv::Op::OpAtomicFAddEXT:
748     case spv::Op::OpAtomicISub:
749     case spv::Op::OpAtomicSMin:
750     case spv::Op::OpAtomicUMin:
751     case spv::Op::OpAtomicSMax:
752     case spv::Op::OpAtomicUMax:
753     case spv::Op::OpAtomicAnd:
754     case spv::Op::OpAtomicOr:
755     case spv::Op::OpAtomicXor:
756     case spv::Op::OpAtomicFlagTestAndSet:
757       return {4};
758     case spv::Op::OpAtomicCompareExchange:
759     case spv::Op::OpAtomicCompareExchangeWeak:
760       return {4, 5};
761     default:
762       return {};
763   }
764 }
765 
spvOpcodeIsAccessChain(spv::Op opcode)766 bool spvOpcodeIsAccessChain(spv::Op opcode) {
767   switch (opcode) {
768     case spv::Op::OpAccessChain:
769     case spv::Op::OpInBoundsAccessChain:
770     case spv::Op::OpPtrAccessChain:
771     case spv::Op::OpInBoundsPtrAccessChain:
772     case spv::Op::OpRawAccessChainNV:
773       return true;
774     default:
775       return false;
776   }
777 }
778 
spvOpcodeIsBit(spv::Op opcode)779 bool spvOpcodeIsBit(spv::Op opcode) {
780   switch (opcode) {
781     case spv::Op::OpShiftRightLogical:
782     case spv::Op::OpShiftRightArithmetic:
783     case spv::Op::OpShiftLeftLogical:
784     case spv::Op::OpBitwiseOr:
785     case spv::Op::OpBitwiseXor:
786     case spv::Op::OpBitwiseAnd:
787     case spv::Op::OpNot:
788     case spv::Op::OpBitReverse:
789     case spv::Op::OpBitCount:
790       return true;
791     default:
792       return false;
793   }
794 }
795