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