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