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