1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/opcode.h"
16 
17 #include <assert.h>
18 #include <string.h>
19 
20 #include <algorithm>
21 #include <cstdlib>
22 
23 #include "source/instruction.h"
24 #include "source/macro.h"
25 #include "source/spirv_constant.h"
26 #include "source/spirv_endian.h"
27 #include "source/spirv_target_env.h"
28 #include "spirv-tools/libspirv.h"
29 
30 namespace {
31 struct OpcodeDescPtrLen {
32   const spv_opcode_desc_t* ptr;
33   uint32_t len;
34 };
35 
36 #include "core.insts-unified1.inc"
37 
38 static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
39                                                 kOpcodeTableEntries};
40 
41 // Represents a vendor tool entry in the SPIR-V XML Regsitry.
42 struct VendorTool {
43   uint32_t value;
44   const char* vendor;
45   const char* tool;         // Might be empty string.
46   const char* vendor_tool;  // Combiantion of vendor and tool.
47 };
48 
49 const VendorTool vendor_tools[] = {
50 #include "generators.inc"
51 };
52 
53 }  // anonymous namespace
54 
55 // TODO(dneto): Move this to another file.  It doesn't belong with opcode
56 // processing.
spvGeneratorStr(uint32_t generator)57 const char* spvGeneratorStr(uint32_t generator) {
58   auto where = std::find_if(
59       std::begin(vendor_tools), std::end(vendor_tools),
60       [generator](const VendorTool& vt) { return generator == vt.value; });
61   if (where != std::end(vendor_tools)) return where->vendor_tool;
62   return "Unknown";
63 }
64 
spvOpcodeMake(uint16_t wordCount,SpvOp opcode)65 uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) {
66   return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
67 }
68 
spvOpcodeSplit(const uint32_t word,uint16_t * pWordCount,uint16_t * pOpcode)69 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
70                     uint16_t* pOpcode) {
71   if (pWordCount) {
72     *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
73   }
74   if (pOpcode) {
75     *pOpcode = 0x0000ffff & word;
76   }
77 }
78 
spvOpcodeTableGet(spv_opcode_table * pInstTable,spv_target_env)79 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, spv_target_env) {
80   if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
81 
82   // Descriptions of each opcode.  Each entry describes the format of the
83   // instruction that follows a particular opcode.
84 
85   *pInstTable = &kOpcodeTable;
86   return SPV_SUCCESS;
87 }
88 
spvOpcodeTableNameLookup(spv_target_env env,const spv_opcode_table table,const char * name,spv_opcode_desc * pEntry)89 spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
90                                       const spv_opcode_table table,
91                                       const char* name,
92                                       spv_opcode_desc* pEntry) {
93   if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
94   if (!table) return SPV_ERROR_INVALID_TABLE;
95 
96   // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
97   // preferable but the table requires sorting on the Opcode name, but it's
98   // static const initialized and matches the order of the spec.
99   const size_t nameLength = strlen(name);
100   const auto version = spvVersionForTargetEnv(env);
101   for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
102     const spv_opcode_desc_t& entry = table->entries[opcodeIndex];
103     // We considers the current opcode as available as long as
104     // 1. The target environment satisfies the minimal requirement of the
105     //    opcode; or
106     // 2. There is at least one extension enabling this opcode.
107     //
108     // Note that the second rule assumes the extension enabling this instruction
109     // is indeed requested in the SPIR-V code; checking that should be
110     // validator's work.
111     if (((version >= entry.minVersion && version <= entry.lastVersion) ||
112          entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
113         nameLength == strlen(entry.name) &&
114         !strncmp(name, entry.name, nameLength)) {
115       // NOTE: Found out Opcode!
116       *pEntry = &entry;
117       return SPV_SUCCESS;
118     }
119   }
120 
121   return SPV_ERROR_INVALID_LOOKUP;
122 }
123 
spvOpcodeTableValueLookup(spv_target_env env,const spv_opcode_table table,const SpvOp opcode,spv_opcode_desc * pEntry)124 spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
125                                        const spv_opcode_table table,
126                                        const SpvOp opcode,
127                                        spv_opcode_desc* pEntry) {
128   if (!table) return SPV_ERROR_INVALID_TABLE;
129   if (!pEntry) return SPV_ERROR_INVALID_POINTER;
130 
131   const auto beg = table->entries;
132   const auto end = table->entries + table->count;
133 
134   spv_opcode_desc_t needle = {"",    opcode, 0, nullptr, 0,   {},
135                               false, false,  0, nullptr, ~0u, ~0u};
136 
137   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
138     return lhs.opcode < rhs.opcode;
139   };
140 
141   // We need to loop here because there can exist multiple symbols for the same
142   // opcode value, and they can be introduced in different target environments,
143   // which means they can have different minimal version requirements.
144   // Assumes the underlying table is already sorted ascendingly according to
145   // opcode value.
146   const auto version = spvVersionForTargetEnv(env);
147   for (auto it = std::lower_bound(beg, end, needle, comp);
148        it != end && it->opcode == opcode; ++it) {
149     // We considers the current opcode as available as long as
150     // 1. The target environment satisfies the minimal requirement of the
151     //    opcode; or
152     // 2. There is at least one extension enabling this opcode.
153     //
154     // Note that the second rule assumes the extension enabling this instruction
155     // is indeed requested in the SPIR-V code; checking that should be
156     // validator's work.
157     if ((version >= it->minVersion && version <= it->lastVersion) ||
158         it->numExtensions > 0u || it->numCapabilities > 0u) {
159       *pEntry = it;
160       return SPV_SUCCESS;
161     }
162   }
163 
164   return SPV_ERROR_INVALID_LOOKUP;
165 }
166 
spvInstructionCopy(const uint32_t * words,const SpvOp opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)167 void spvInstructionCopy(const uint32_t* words, const SpvOp opcode,
168                         const uint16_t wordCount, const spv_endianness_t endian,
169                         spv_instruction_t* pInst) {
170   pInst->opcode = opcode;
171   pInst->words.resize(wordCount);
172   for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
173     pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
174     if (!wordIndex) {
175       uint16_t thisWordCount;
176       uint16_t thisOpcode;
177       spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
178       assert(opcode == static_cast<SpvOp>(thisOpcode) &&
179              wordCount == thisWordCount && "Endianness failed!");
180     }
181   }
182 }
183 
spvOpcodeString(const SpvOp opcode)184 const char* spvOpcodeString(const SpvOp opcode) {
185   const auto beg = kOpcodeTableEntries;
186   const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
187   spv_opcode_desc_t needle = {"",    opcode, 0, nullptr, 0,   {},
188                               false, false,  0, nullptr, ~0u, ~0u};
189   auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
190     return lhs.opcode < rhs.opcode;
191   };
192   auto it = std::lower_bound(beg, end, needle, comp);
193   if (it != end && it->opcode == opcode) {
194     return it->name;
195   }
196 
197   assert(0 && "Unreachable!");
198   return "unknown";
199 }
200 
spvOpcodeIsScalarType(const SpvOp opcode)201 int32_t spvOpcodeIsScalarType(const SpvOp opcode) {
202   switch (opcode) {
203     case SpvOpTypeInt:
204     case SpvOpTypeFloat:
205     case SpvOpTypeBool:
206       return true;
207     default:
208       return false;
209   }
210 }
211 
spvOpcodeIsSpecConstant(const SpvOp opcode)212 int32_t spvOpcodeIsSpecConstant(const SpvOp opcode) {
213   switch (opcode) {
214     case SpvOpSpecConstantTrue:
215     case SpvOpSpecConstantFalse:
216     case SpvOpSpecConstant:
217     case SpvOpSpecConstantComposite:
218     case SpvOpSpecConstantOp:
219       return true;
220     default:
221       return false;
222   }
223 }
224 
spvOpcodeIsConstant(const SpvOp opcode)225 int32_t spvOpcodeIsConstant(const SpvOp opcode) {
226   switch (opcode) {
227     case SpvOpConstantTrue:
228     case SpvOpConstantFalse:
229     case SpvOpConstant:
230     case SpvOpConstantComposite:
231     case SpvOpConstantSampler:
232     case SpvOpConstantNull:
233     case SpvOpSpecConstantTrue:
234     case SpvOpSpecConstantFalse:
235     case SpvOpSpecConstant:
236     case SpvOpSpecConstantComposite:
237     case SpvOpSpecConstantOp:
238       return true;
239     default:
240       return false;
241   }
242 }
243 
spvOpcodeIsConstantOrUndef(const SpvOp opcode)244 bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) {
245   return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode);
246 }
247 
spvOpcodeIsScalarSpecConstant(const SpvOp opcode)248 bool spvOpcodeIsScalarSpecConstant(const SpvOp opcode) {
249   switch (opcode) {
250     case SpvOpSpecConstantTrue:
251     case SpvOpSpecConstantFalse:
252     case SpvOpSpecConstant:
253       return true;
254     default:
255       return false;
256   }
257 }
258 
spvOpcodeIsComposite(const SpvOp opcode)259 int32_t spvOpcodeIsComposite(const SpvOp opcode) {
260   switch (opcode) {
261     case SpvOpTypeVector:
262     case SpvOpTypeMatrix:
263     case SpvOpTypeArray:
264     case SpvOpTypeStruct:
265     case SpvOpTypeCooperativeMatrixNV:
266       return true;
267     default:
268       return false;
269   }
270 }
271 
spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode)272 bool spvOpcodeReturnsLogicalVariablePointer(const SpvOp opcode) {
273   switch (opcode) {
274     case SpvOpVariable:
275     case SpvOpAccessChain:
276     case SpvOpInBoundsAccessChain:
277     case SpvOpFunctionParameter:
278     case SpvOpImageTexelPointer:
279     case SpvOpCopyObject:
280     case SpvOpSelect:
281     case SpvOpPhi:
282     case SpvOpFunctionCall:
283     case SpvOpPtrAccessChain:
284     case SpvOpLoad:
285     case SpvOpConstantNull:
286       return true;
287     default:
288       return false;
289   }
290 }
291 
spvOpcodeReturnsLogicalPointer(const SpvOp opcode)292 int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) {
293   switch (opcode) {
294     case SpvOpVariable:
295     case SpvOpAccessChain:
296     case SpvOpInBoundsAccessChain:
297     case SpvOpFunctionParameter:
298     case SpvOpImageTexelPointer:
299     case SpvOpCopyObject:
300       return true;
301     default:
302       return false;
303   }
304 }
305 
spvOpcodeGeneratesType(SpvOp op)306 int32_t spvOpcodeGeneratesType(SpvOp op) {
307   switch (op) {
308     case SpvOpTypeVoid:
309     case SpvOpTypeBool:
310     case SpvOpTypeInt:
311     case SpvOpTypeFloat:
312     case SpvOpTypeVector:
313     case SpvOpTypeMatrix:
314     case SpvOpTypeImage:
315     case SpvOpTypeSampler:
316     case SpvOpTypeSampledImage:
317     case SpvOpTypeArray:
318     case SpvOpTypeRuntimeArray:
319     case SpvOpTypeStruct:
320     case SpvOpTypeOpaque:
321     case SpvOpTypePointer:
322     case SpvOpTypeFunction:
323     case SpvOpTypeEvent:
324     case SpvOpTypeDeviceEvent:
325     case SpvOpTypeReserveId:
326     case SpvOpTypeQueue:
327     case SpvOpTypePipe:
328     case SpvOpTypePipeStorage:
329     case SpvOpTypeNamedBarrier:
330     case SpvOpTypeAccelerationStructureNV:
331     case SpvOpTypeCooperativeMatrixNV:
332       return true;
333     default:
334       // In particular, OpTypeForwardPointer does not generate a type,
335       // but declares a storage class for a pointer type generated
336       // by a different instruction.
337       break;
338   }
339   return 0;
340 }
341 
spvOpcodeIsDecoration(const SpvOp opcode)342 bool spvOpcodeIsDecoration(const SpvOp opcode) {
343   switch (opcode) {
344     case SpvOpDecorate:
345     case SpvOpDecorateId:
346     case SpvOpMemberDecorate:
347     case SpvOpGroupDecorate:
348     case SpvOpGroupMemberDecorate:
349     case SpvOpDecorateStringGOOGLE:
350     case SpvOpMemberDecorateStringGOOGLE:
351       return true;
352     default:
353       break;
354   }
355   return false;
356 }
357 
spvOpcodeIsLoad(const SpvOp opcode)358 bool spvOpcodeIsLoad(const SpvOp opcode) {
359   switch (opcode) {
360     case SpvOpLoad:
361     case SpvOpImageSampleExplicitLod:
362     case SpvOpImageSampleImplicitLod:
363     case SpvOpImageSampleDrefImplicitLod:
364     case SpvOpImageSampleDrefExplicitLod:
365     case SpvOpImageSampleProjImplicitLod:
366     case SpvOpImageSampleProjExplicitLod:
367     case SpvOpImageSampleProjDrefImplicitLod:
368     case SpvOpImageSampleProjDrefExplicitLod:
369     case SpvOpImageFetch:
370     case SpvOpImageGather:
371     case SpvOpImageDrefGather:
372     case SpvOpImageRead:
373     case SpvOpImageSparseSampleImplicitLod:
374     case SpvOpImageSparseSampleExplicitLod:
375     case SpvOpImageSparseSampleDrefExplicitLod:
376     case SpvOpImageSparseSampleDrefImplicitLod:
377     case SpvOpImageSparseFetch:
378     case SpvOpImageSparseGather:
379     case SpvOpImageSparseDrefGather:
380     case SpvOpImageSparseRead:
381       return true;
382     default:
383       return false;
384   }
385 }
386 
spvOpcodeIsBranch(SpvOp opcode)387 bool spvOpcodeIsBranch(SpvOp opcode) {
388   switch (opcode) {
389     case SpvOpBranch:
390     case SpvOpBranchConditional:
391     case SpvOpSwitch:
392       return true;
393     default:
394       return false;
395   }
396 }
397 
spvOpcodeIsAtomicWithLoad(const SpvOp opcode)398 bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) {
399   switch (opcode) {
400     case SpvOpAtomicLoad:
401     case SpvOpAtomicExchange:
402     case SpvOpAtomicCompareExchange:
403     case SpvOpAtomicCompareExchangeWeak:
404     case SpvOpAtomicIIncrement:
405     case SpvOpAtomicIDecrement:
406     case SpvOpAtomicIAdd:
407     case SpvOpAtomicISub:
408     case SpvOpAtomicSMin:
409     case SpvOpAtomicUMin:
410     case SpvOpAtomicSMax:
411     case SpvOpAtomicUMax:
412     case SpvOpAtomicAnd:
413     case SpvOpAtomicOr:
414     case SpvOpAtomicXor:
415     case SpvOpAtomicFlagTestAndSet:
416       return true;
417     default:
418       return false;
419   }
420 }
421 
spvOpcodeIsAtomicOp(const SpvOp opcode)422 bool spvOpcodeIsAtomicOp(const SpvOp opcode) {
423   return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore ||
424           opcode == SpvOpAtomicFlagClear);
425 }
426 
spvOpcodeIsReturn(SpvOp opcode)427 bool spvOpcodeIsReturn(SpvOp opcode) {
428   switch (opcode) {
429     case SpvOpReturn:
430     case SpvOpReturnValue:
431       return true;
432     default:
433       return false;
434   }
435 }
436 
spvOpcodeIsReturnOrAbort(SpvOp opcode)437 bool spvOpcodeIsReturnOrAbort(SpvOp opcode) {
438   return spvOpcodeIsReturn(opcode) || opcode == SpvOpKill ||
439          opcode == SpvOpUnreachable;
440 }
441 
spvOpcodeIsBlockTerminator(SpvOp opcode)442 bool spvOpcodeIsBlockTerminator(SpvOp opcode) {
443   return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
444 }
445 
spvOpcodeIsBaseOpaqueType(SpvOp opcode)446 bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) {
447   switch (opcode) {
448     case SpvOpTypeImage:
449     case SpvOpTypeSampler:
450     case SpvOpTypeSampledImage:
451     case SpvOpTypeOpaque:
452     case SpvOpTypeEvent:
453     case SpvOpTypeDeviceEvent:
454     case SpvOpTypeReserveId:
455     case SpvOpTypeQueue:
456     case SpvOpTypePipe:
457     case SpvOpTypeForwardPointer:
458     case SpvOpTypePipeStorage:
459     case SpvOpTypeNamedBarrier:
460       return true;
461     default:
462       return false;
463   }
464 }
465 
spvOpcodeIsNonUniformGroupOperation(SpvOp opcode)466 bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) {
467   switch (opcode) {
468     case SpvOpGroupNonUniformElect:
469     case SpvOpGroupNonUniformAll:
470     case SpvOpGroupNonUniformAny:
471     case SpvOpGroupNonUniformAllEqual:
472     case SpvOpGroupNonUniformBroadcast:
473     case SpvOpGroupNonUniformBroadcastFirst:
474     case SpvOpGroupNonUniformBallot:
475     case SpvOpGroupNonUniformInverseBallot:
476     case SpvOpGroupNonUniformBallotBitExtract:
477     case SpvOpGroupNonUniformBallotBitCount:
478     case SpvOpGroupNonUniformBallotFindLSB:
479     case SpvOpGroupNonUniformBallotFindMSB:
480     case SpvOpGroupNonUniformShuffle:
481     case SpvOpGroupNonUniformShuffleXor:
482     case SpvOpGroupNonUniformShuffleUp:
483     case SpvOpGroupNonUniformShuffleDown:
484     case SpvOpGroupNonUniformIAdd:
485     case SpvOpGroupNonUniformFAdd:
486     case SpvOpGroupNonUniformIMul:
487     case SpvOpGroupNonUniformFMul:
488     case SpvOpGroupNonUniformSMin:
489     case SpvOpGroupNonUniformUMin:
490     case SpvOpGroupNonUniformFMin:
491     case SpvOpGroupNonUniformSMax:
492     case SpvOpGroupNonUniformUMax:
493     case SpvOpGroupNonUniformFMax:
494     case SpvOpGroupNonUniformBitwiseAnd:
495     case SpvOpGroupNonUniformBitwiseOr:
496     case SpvOpGroupNonUniformBitwiseXor:
497     case SpvOpGroupNonUniformLogicalAnd:
498     case SpvOpGroupNonUniformLogicalOr:
499     case SpvOpGroupNonUniformLogicalXor:
500     case SpvOpGroupNonUniformQuadBroadcast:
501     case SpvOpGroupNonUniformQuadSwap:
502       return true;
503     default:
504       return false;
505   }
506 }
507 
spvOpcodeIsScalarizable(SpvOp opcode)508 bool spvOpcodeIsScalarizable(SpvOp opcode) {
509   switch (opcode) {
510     case SpvOpPhi:
511     case SpvOpCopyObject:
512     case SpvOpConvertFToU:
513     case SpvOpConvertFToS:
514     case SpvOpConvertSToF:
515     case SpvOpConvertUToF:
516     case SpvOpUConvert:
517     case SpvOpSConvert:
518     case SpvOpFConvert:
519     case SpvOpQuantizeToF16:
520     case SpvOpVectorInsertDynamic:
521     case SpvOpSNegate:
522     case SpvOpFNegate:
523     case SpvOpIAdd:
524     case SpvOpFAdd:
525     case SpvOpISub:
526     case SpvOpFSub:
527     case SpvOpIMul:
528     case SpvOpFMul:
529     case SpvOpUDiv:
530     case SpvOpSDiv:
531     case SpvOpFDiv:
532     case SpvOpUMod:
533     case SpvOpSRem:
534     case SpvOpSMod:
535     case SpvOpFRem:
536     case SpvOpFMod:
537     case SpvOpVectorTimesScalar:
538     case SpvOpIAddCarry:
539     case SpvOpISubBorrow:
540     case SpvOpUMulExtended:
541     case SpvOpSMulExtended:
542     case SpvOpShiftRightLogical:
543     case SpvOpShiftRightArithmetic:
544     case SpvOpShiftLeftLogical:
545     case SpvOpBitwiseOr:
546     case SpvOpBitwiseAnd:
547     case SpvOpNot:
548     case SpvOpBitFieldInsert:
549     case SpvOpBitFieldSExtract:
550     case SpvOpBitFieldUExtract:
551     case SpvOpBitReverse:
552     case SpvOpBitCount:
553     case SpvOpIsNan:
554     case SpvOpIsInf:
555     case SpvOpIsFinite:
556     case SpvOpIsNormal:
557     case SpvOpSignBitSet:
558     case SpvOpLessOrGreater:
559     case SpvOpOrdered:
560     case SpvOpUnordered:
561     case SpvOpLogicalEqual:
562     case SpvOpLogicalNotEqual:
563     case SpvOpLogicalOr:
564     case SpvOpLogicalAnd:
565     case SpvOpLogicalNot:
566     case SpvOpSelect:
567     case SpvOpIEqual:
568     case SpvOpINotEqual:
569     case SpvOpUGreaterThan:
570     case SpvOpSGreaterThan:
571     case SpvOpUGreaterThanEqual:
572     case SpvOpSGreaterThanEqual:
573     case SpvOpULessThan:
574     case SpvOpSLessThan:
575     case SpvOpULessThanEqual:
576     case SpvOpSLessThanEqual:
577     case SpvOpFOrdEqual:
578     case SpvOpFUnordEqual:
579     case SpvOpFOrdNotEqual:
580     case SpvOpFUnordNotEqual:
581     case SpvOpFOrdLessThan:
582     case SpvOpFUnordLessThan:
583     case SpvOpFOrdGreaterThan:
584     case SpvOpFUnordGreaterThan:
585     case SpvOpFOrdLessThanEqual:
586     case SpvOpFUnordLessThanEqual:
587     case SpvOpFOrdGreaterThanEqual:
588     case SpvOpFUnordGreaterThanEqual:
589       return true;
590     default:
591       return false;
592   }
593 }
594 
spvOpcodeIsDebug(SpvOp opcode)595 bool spvOpcodeIsDebug(SpvOp opcode) {
596   switch (opcode) {
597     case SpvOpName:
598     case SpvOpMemberName:
599     case SpvOpSource:
600     case SpvOpSourceContinued:
601     case SpvOpSourceExtension:
602     case SpvOpString:
603     case SpvOpLine:
604     case SpvOpNoLine:
605       return true;
606     default:
607       return false;
608   }
609 }
610 
spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode)611 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
612   switch (opcode) {
613     case SpvOpMemoryBarrier:
614       return {1};
615     case SpvOpAtomicStore:
616     case SpvOpControlBarrier:
617     case SpvOpAtomicFlagClear:
618     case SpvOpMemoryNamedBarrier:
619       return {2};
620     case SpvOpAtomicLoad:
621     case SpvOpAtomicExchange:
622     case SpvOpAtomicIIncrement:
623     case SpvOpAtomicIDecrement:
624     case SpvOpAtomicIAdd:
625     case SpvOpAtomicISub:
626     case SpvOpAtomicSMin:
627     case SpvOpAtomicUMin:
628     case SpvOpAtomicSMax:
629     case SpvOpAtomicUMax:
630     case SpvOpAtomicAnd:
631     case SpvOpAtomicOr:
632     case SpvOpAtomicXor:
633     case SpvOpAtomicFlagTestAndSet:
634       return {4};
635     case SpvOpAtomicCompareExchange:
636     case SpvOpAtomicCompareExchangeWeak:
637       return {4, 5};
638     default:
639       return {};
640   }
641 }
642