1 // Copyright (c) 2015-2022 The Khronos Group Inc.
2 // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3 // reserved.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 #include "source/opcode.h"
18
19 #include <assert.h>
20 #include <string.h>
21
22 #include <algorithm>
23 #include <cstdlib>
24
25 #include "source/instruction.h"
26 #include "source/macro.h"
27 #include "source/spirv_constant.h"
28 #include "source/spirv_endian.h"
29 #include "source/spirv_target_env.h"
30 #include "spirv-tools/libspirv.h"
31
32 namespace {
33 struct OpcodeDescPtrLen {
34 const spv_opcode_desc_t* ptr;
35 uint32_t len;
36 };
37
38 #include "core.insts-unified1.inc"
39
40 static const spv_opcode_table_t kOpcodeTable = {ARRAY_SIZE(kOpcodeTableEntries),
41 kOpcodeTableEntries};
42
43 // Represents a vendor tool entry in the SPIR-V XML Registry.
44 struct VendorTool {
45 uint32_t value;
46 const char* vendor;
47 const char* tool; // Might be empty string.
48 const char* vendor_tool; // Combination of vendor and tool.
49 };
50
51 const VendorTool vendor_tools[] = {
52 #include "generators.inc"
53 };
54
55 } // anonymous namespace
56
57 // TODO(dneto): Move this to another file. It doesn't belong with opcode
58 // processing.
spvGeneratorStr(uint32_t generator)59 const char* spvGeneratorStr(uint32_t generator) {
60 auto where = std::find_if(
61 std::begin(vendor_tools), std::end(vendor_tools),
62 [generator](const VendorTool& vt) { return generator == vt.value; });
63 if (where != std::end(vendor_tools)) return where->vendor_tool;
64 return "Unknown";
65 }
66
spvOpcodeMake(uint16_t wordCount,spv::Op opcode)67 uint32_t spvOpcodeMake(uint16_t wordCount, spv::Op opcode) {
68 return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16);
69 }
70
spvOpcodeSplit(const uint32_t word,uint16_t * pWordCount,uint16_t * pOpcode)71 void spvOpcodeSplit(const uint32_t word, uint16_t* pWordCount,
72 uint16_t* pOpcode) {
73 if (pWordCount) {
74 *pWordCount = (uint16_t)((0xffff0000 & word) >> 16);
75 }
76 if (pOpcode) {
77 *pOpcode = 0x0000ffff & word;
78 }
79 }
80
spvOpcodeTableGet(spv_opcode_table * pInstTable,spv_target_env)81 spv_result_t spvOpcodeTableGet(spv_opcode_table* pInstTable, spv_target_env) {
82 if (!pInstTable) return SPV_ERROR_INVALID_POINTER;
83
84 // Descriptions of each opcode. Each entry describes the format of the
85 // instruction that follows a particular opcode.
86
87 *pInstTable = &kOpcodeTable;
88 return SPV_SUCCESS;
89 }
90
spvOpcodeTableNameLookup(spv_target_env env,const spv_opcode_table table,const char * name,spv_opcode_desc * pEntry)91 spv_result_t spvOpcodeTableNameLookup(spv_target_env env,
92 const spv_opcode_table table,
93 const char* name,
94 spv_opcode_desc* pEntry) {
95 if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER;
96 if (!table) return SPV_ERROR_INVALID_TABLE;
97
98 // TODO: This lookup of the Opcode table is suboptimal! Binary sort would be
99 // preferable but the table requires sorting on the Opcode name, but it's
100 // static const initialized and matches the order of the spec.
101 const size_t nameLength = strlen(name);
102 const auto version = spvVersionForTargetEnv(env);
103 for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) {
104 const spv_opcode_desc_t& entry = table->entries[opcodeIndex];
105 // We considers the current opcode as available as long as
106 // 1. The target environment satisfies the minimal requirement of the
107 // opcode; or
108 // 2. There is at least one extension enabling this opcode.
109 //
110 // Note that the second rule assumes the extension enabling this instruction
111 // is indeed requested in the SPIR-V code; checking that should be
112 // validator's work.
113 if (((version >= entry.minVersion && version <= entry.lastVersion) ||
114 entry.numExtensions > 0u || entry.numCapabilities > 0u) &&
115 nameLength == strlen(entry.name) &&
116 !strncmp(name, entry.name, nameLength)) {
117 // NOTE: Found out Opcode!
118 *pEntry = &entry;
119 return SPV_SUCCESS;
120 }
121 }
122
123 return SPV_ERROR_INVALID_LOOKUP;
124 }
125
spvOpcodeTableValueLookup(spv_target_env env,const spv_opcode_table table,const spv::Op opcode,spv_opcode_desc * pEntry)126 spv_result_t spvOpcodeTableValueLookup(spv_target_env env,
127 const spv_opcode_table table,
128 const spv::Op opcode,
129 spv_opcode_desc* pEntry) {
130 if (!table) return SPV_ERROR_INVALID_TABLE;
131 if (!pEntry) return SPV_ERROR_INVALID_POINTER;
132
133 const auto beg = table->entries;
134 const auto end = table->entries + table->count;
135
136 spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {},
137 false, false, 0, nullptr, ~0u, ~0u};
138
139 auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
140 return lhs.opcode < rhs.opcode;
141 };
142
143 // We need to loop here because there can exist multiple symbols for the same
144 // opcode value, and they can be introduced in different target environments,
145 // which means they can have different minimal version requirements.
146 // Assumes the underlying table is already sorted ascendingly according to
147 // opcode value.
148 const auto version = spvVersionForTargetEnv(env);
149 for (auto it = std::lower_bound(beg, end, needle, comp);
150 it != end && it->opcode == opcode; ++it) {
151 // We considers the current opcode as available as long as
152 // 1. The target environment satisfies the minimal requirement of the
153 // opcode; or
154 // 2. There is at least one extension enabling this opcode.
155 //
156 // Note that the second rule assumes the extension enabling this instruction
157 // is indeed requested in the SPIR-V code; checking that should be
158 // validator's work.
159 if ((version >= it->minVersion && version <= it->lastVersion) ||
160 it->numExtensions > 0u || it->numCapabilities > 0u) {
161 *pEntry = it;
162 return SPV_SUCCESS;
163 }
164 }
165
166 return SPV_ERROR_INVALID_LOOKUP;
167 }
168
spvInstructionCopy(const uint32_t * words,const spv::Op opcode,const uint16_t wordCount,const spv_endianness_t endian,spv_instruction_t * pInst)169 void spvInstructionCopy(const uint32_t* words, const spv::Op opcode,
170 const uint16_t wordCount, const spv_endianness_t endian,
171 spv_instruction_t* pInst) {
172 pInst->opcode = opcode;
173 pInst->words.resize(wordCount);
174 for (uint16_t wordIndex = 0; wordIndex < wordCount; ++wordIndex) {
175 pInst->words[wordIndex] = spvFixWord(words[wordIndex], endian);
176 if (!wordIndex) {
177 uint16_t thisWordCount;
178 uint16_t thisOpcode;
179 spvOpcodeSplit(pInst->words[wordIndex], &thisWordCount, &thisOpcode);
180 assert(opcode == static_cast<spv::Op>(thisOpcode) &&
181 wordCount == thisWordCount && "Endianness failed!");
182 }
183 }
184 }
185
spvOpcodeString(const uint32_t opcode)186 const char* spvOpcodeString(const uint32_t opcode) {
187 const auto beg = kOpcodeTableEntries;
188 const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries);
189 spv_opcode_desc_t needle = {"", static_cast<spv::Op>(opcode),
190 0, nullptr,
191 0, {},
192 false, false,
193 0, nullptr,
194 ~0u, ~0u};
195 auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) {
196 return lhs.opcode < rhs.opcode;
197 };
198 auto it = std::lower_bound(beg, end, needle, comp);
199 if (it != end && it->opcode == spv::Op(opcode)) {
200 return it->name;
201 }
202
203 assert(0 && "Unreachable!");
204 return "unknown";
205 }
206
spvOpcodeString(const spv::Op opcode)207 const char* spvOpcodeString(const spv::Op opcode) {
208 return spvOpcodeString(static_cast<uint32_t>(opcode));
209 }
210
spvOpcodeIsScalarType(const spv::Op opcode)211 int32_t spvOpcodeIsScalarType(const spv::Op opcode) {
212 switch (opcode) {
213 case spv::Op::OpTypeInt:
214 case spv::Op::OpTypeFloat:
215 case spv::Op::OpTypeBool:
216 return true;
217 default:
218 return false;
219 }
220 }
221
spvOpcodeIsSpecConstant(const spv::Op opcode)222 int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) {
223 switch (opcode) {
224 case spv::Op::OpSpecConstantTrue:
225 case spv::Op::OpSpecConstantFalse:
226 case spv::Op::OpSpecConstant:
227 case spv::Op::OpSpecConstantComposite:
228 case spv::Op::OpSpecConstantCompositeReplicateEXT:
229 case spv::Op::OpSpecConstantOp:
230 return true;
231 default:
232 return false;
233 }
234 }
235
spvOpcodeIsConstant(const spv::Op opcode)236 int32_t spvOpcodeIsConstant(const spv::Op opcode) {
237 switch (opcode) {
238 case spv::Op::OpConstantTrue:
239 case spv::Op::OpConstantFalse:
240 case spv::Op::OpConstant:
241 case spv::Op::OpConstantComposite:
242 case spv::Op::OpConstantCompositeReplicateEXT:
243 case spv::Op::OpConstantSampler:
244 case spv::Op::OpConstantNull:
245 case spv::Op::OpConstantFunctionPointerINTEL:
246 case spv::Op::OpSpecConstantTrue:
247 case spv::Op::OpSpecConstantFalse:
248 case spv::Op::OpSpecConstant:
249 case spv::Op::OpSpecConstantComposite:
250 case spv::Op::OpSpecConstantCompositeReplicateEXT:
251 case spv::Op::OpSpecConstantOp:
252 return true;
253 default:
254 return false;
255 }
256 }
257
spvOpcodeIsConstantOrUndef(const spv::Op opcode)258 bool spvOpcodeIsConstantOrUndef(const spv::Op opcode) {
259 return opcode == spv::Op::OpUndef || spvOpcodeIsConstant(opcode);
260 }
261
spvOpcodeIsScalarSpecConstant(const spv::Op opcode)262 bool spvOpcodeIsScalarSpecConstant(const spv::Op opcode) {
263 switch (opcode) {
264 case spv::Op::OpSpecConstantTrue:
265 case spv::Op::OpSpecConstantFalse:
266 case spv::Op::OpSpecConstant:
267 return true;
268 default:
269 return false;
270 }
271 }
272
spvOpcodeIsComposite(const spv::Op opcode)273 int32_t spvOpcodeIsComposite(const spv::Op opcode) {
274 switch (opcode) {
275 case spv::Op::OpTypeVector:
276 case spv::Op::OpTypeMatrix:
277 case spv::Op::OpTypeArray:
278 case spv::Op::OpTypeStruct:
279 case spv::Op::OpTypeCooperativeMatrixNV:
280 case spv::Op::OpTypeCooperativeMatrixKHR:
281 return true;
282 default:
283 return false;
284 }
285 }
286
spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode)287 bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
288 switch (opcode) {
289 case spv::Op::OpVariable:
290 case spv::Op::OpAccessChain:
291 case spv::Op::OpInBoundsAccessChain:
292 case spv::Op::OpFunctionParameter:
293 case spv::Op::OpImageTexelPointer:
294 case spv::Op::OpCopyObject:
295 case spv::Op::OpSelect:
296 case spv::Op::OpPhi:
297 case spv::Op::OpFunctionCall:
298 case spv::Op::OpPtrAccessChain:
299 case spv::Op::OpLoad:
300 case spv::Op::OpConstantNull:
301 case spv::Op::OpRawAccessChainNV:
302 return true;
303 default:
304 return false;
305 }
306 }
307
spvOpcodeReturnsLogicalPointer(const spv::Op opcode)308 int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
309 switch (opcode) {
310 case spv::Op::OpVariable:
311 case spv::Op::OpAccessChain:
312 case spv::Op::OpInBoundsAccessChain:
313 case spv::Op::OpFunctionParameter:
314 case spv::Op::OpImageTexelPointer:
315 case spv::Op::OpCopyObject:
316 case spv::Op::OpRawAccessChainNV:
317 return true;
318 default:
319 return false;
320 }
321 }
322
spvOpcodeGeneratesType(spv::Op op)323 int32_t spvOpcodeGeneratesType(spv::Op op) {
324 switch (op) {
325 case spv::Op::OpTypeVoid:
326 case spv::Op::OpTypeBool:
327 case spv::Op::OpTypeInt:
328 case spv::Op::OpTypeFloat:
329 case spv::Op::OpTypeVector:
330 case spv::Op::OpTypeMatrix:
331 case spv::Op::OpTypeImage:
332 case spv::Op::OpTypeSampler:
333 case spv::Op::OpTypeSampledImage:
334 case spv::Op::OpTypeArray:
335 case spv::Op::OpTypeRuntimeArray:
336 case spv::Op::OpTypeStruct:
337 case spv::Op::OpTypeOpaque:
338 case spv::Op::OpTypePointer:
339 case spv::Op::OpTypeFunction:
340 case spv::Op::OpTypeEvent:
341 case spv::Op::OpTypeDeviceEvent:
342 case spv::Op::OpTypeReserveId:
343 case spv::Op::OpTypeQueue:
344 case spv::Op::OpTypePipe:
345 case spv::Op::OpTypePipeStorage:
346 case spv::Op::OpTypeNamedBarrier:
347 case spv::Op::OpTypeAccelerationStructureNV:
348 case spv::Op::OpTypeCooperativeMatrixNV:
349 case spv::Op::OpTypeCooperativeMatrixKHR:
350 // case spv::Op::OpTypeAccelerationStructureKHR: covered by
351 // spv::Op::OpTypeAccelerationStructureNV
352 case spv::Op::OpTypeRayQueryKHR:
353 case spv::Op::OpTypeHitObjectNV:
354 return true;
355 default:
356 // In particular, OpTypeForwardPointer does not generate a type,
357 // but declares a storage class for a pointer type generated
358 // by a different instruction.
359 break;
360 }
361 return 0;
362 }
363
spvOpcodeIsDecoration(const spv::Op opcode)364 bool spvOpcodeIsDecoration(const spv::Op opcode) {
365 switch (opcode) {
366 case spv::Op::OpDecorate:
367 case spv::Op::OpDecorateId:
368 case spv::Op::OpMemberDecorate:
369 case spv::Op::OpGroupDecorate:
370 case spv::Op::OpGroupMemberDecorate:
371 case spv::Op::OpDecorateStringGOOGLE:
372 case spv::Op::OpMemberDecorateStringGOOGLE:
373 return true;
374 default:
375 break;
376 }
377 return false;
378 }
379
spvOpcodeIsLoad(const spv::Op opcode)380 bool spvOpcodeIsLoad(const spv::Op opcode) {
381 switch (opcode) {
382 case spv::Op::OpLoad:
383 case spv::Op::OpImageSampleExplicitLod:
384 case spv::Op::OpImageSampleImplicitLod:
385 case spv::Op::OpImageSampleDrefImplicitLod:
386 case spv::Op::OpImageSampleDrefExplicitLod:
387 case spv::Op::OpImageSampleProjImplicitLod:
388 case spv::Op::OpImageSampleProjExplicitLod:
389 case spv::Op::OpImageSampleProjDrefImplicitLod:
390 case spv::Op::OpImageSampleProjDrefExplicitLod:
391 case spv::Op::OpImageFetch:
392 case spv::Op::OpImageGather:
393 case spv::Op::OpImageDrefGather:
394 case spv::Op::OpImageRead:
395 case spv::Op::OpImageSparseSampleImplicitLod:
396 case spv::Op::OpImageSparseSampleExplicitLod:
397 case spv::Op::OpImageSparseSampleDrefExplicitLod:
398 case spv::Op::OpImageSparseSampleDrefImplicitLod:
399 case spv::Op::OpImageSparseFetch:
400 case spv::Op::OpImageSparseGather:
401 case spv::Op::OpImageSparseDrefGather:
402 case spv::Op::OpImageSparseRead:
403 return true;
404 default:
405 return false;
406 }
407 }
408
spvOpcodeIsBranch(spv::Op opcode)409 bool spvOpcodeIsBranch(spv::Op opcode) {
410 switch (opcode) {
411 case spv::Op::OpBranch:
412 case spv::Op::OpBranchConditional:
413 case spv::Op::OpSwitch:
414 return true;
415 default:
416 return false;
417 }
418 }
419
spvOpcodeIsAtomicWithLoad(const spv::Op opcode)420 bool spvOpcodeIsAtomicWithLoad(const spv::Op opcode) {
421 switch (opcode) {
422 case spv::Op::OpAtomicLoad:
423 case spv::Op::OpAtomicExchange:
424 case spv::Op::OpAtomicCompareExchange:
425 case spv::Op::OpAtomicCompareExchangeWeak:
426 case spv::Op::OpAtomicIIncrement:
427 case spv::Op::OpAtomicIDecrement:
428 case spv::Op::OpAtomicIAdd:
429 case spv::Op::OpAtomicFAddEXT:
430 case spv::Op::OpAtomicISub:
431 case spv::Op::OpAtomicSMin:
432 case spv::Op::OpAtomicUMin:
433 case spv::Op::OpAtomicFMinEXT:
434 case spv::Op::OpAtomicSMax:
435 case spv::Op::OpAtomicUMax:
436 case spv::Op::OpAtomicFMaxEXT:
437 case spv::Op::OpAtomicAnd:
438 case spv::Op::OpAtomicOr:
439 case spv::Op::OpAtomicXor:
440 case spv::Op::OpAtomicFlagTestAndSet:
441 return true;
442 default:
443 return false;
444 }
445 }
446
spvOpcodeIsAtomicOp(const spv::Op opcode)447 bool spvOpcodeIsAtomicOp(const spv::Op opcode) {
448 return (spvOpcodeIsAtomicWithLoad(opcode) ||
449 opcode == spv::Op::OpAtomicStore ||
450 opcode == spv::Op::OpAtomicFlagClear);
451 }
452
spvOpcodeIsReturn(spv::Op opcode)453 bool spvOpcodeIsReturn(spv::Op opcode) {
454 switch (opcode) {
455 case spv::Op::OpReturn:
456 case spv::Op::OpReturnValue:
457 return true;
458 default:
459 return false;
460 }
461 }
462
spvOpcodeIsAbort(spv::Op opcode)463 bool spvOpcodeIsAbort(spv::Op opcode) {
464 switch (opcode) {
465 case spv::Op::OpKill:
466 case spv::Op::OpUnreachable:
467 case spv::Op::OpTerminateInvocation:
468 case spv::Op::OpTerminateRayKHR:
469 case spv::Op::OpIgnoreIntersectionKHR:
470 case spv::Op::OpEmitMeshTasksEXT:
471 return true;
472 default:
473 return false;
474 }
475 }
476
spvOpcodeIsReturnOrAbort(spv::Op opcode)477 bool spvOpcodeIsReturnOrAbort(spv::Op opcode) {
478 return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode);
479 }
480
spvOpcodeIsBlockTerminator(spv::Op opcode)481 bool spvOpcodeIsBlockTerminator(spv::Op opcode) {
482 return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode);
483 }
484
spvOpcodeIsBaseOpaqueType(spv::Op opcode)485 bool spvOpcodeIsBaseOpaqueType(spv::Op opcode) {
486 switch (opcode) {
487 case spv::Op::OpTypeImage:
488 case spv::Op::OpTypeSampler:
489 case spv::Op::OpTypeSampledImage:
490 case spv::Op::OpTypeOpaque:
491 case spv::Op::OpTypeEvent:
492 case spv::Op::OpTypeDeviceEvent:
493 case spv::Op::OpTypeReserveId:
494 case spv::Op::OpTypeQueue:
495 case spv::Op::OpTypePipe:
496 case spv::Op::OpTypeForwardPointer:
497 case spv::Op::OpTypePipeStorage:
498 case spv::Op::OpTypeNamedBarrier:
499 return true;
500 default:
501 return false;
502 }
503 }
504
spvOpcodeIsNonUniformGroupOperation(spv::Op opcode)505 bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) {
506 switch (opcode) {
507 case spv::Op::OpGroupNonUniformElect:
508 case spv::Op::OpGroupNonUniformAll:
509 case spv::Op::OpGroupNonUniformAny:
510 case spv::Op::OpGroupNonUniformAllEqual:
511 case spv::Op::OpGroupNonUniformBroadcast:
512 case spv::Op::OpGroupNonUniformBroadcastFirst:
513 case spv::Op::OpGroupNonUniformBallot:
514 case spv::Op::OpGroupNonUniformInverseBallot:
515 case spv::Op::OpGroupNonUniformBallotBitExtract:
516 case spv::Op::OpGroupNonUniformBallotBitCount:
517 case spv::Op::OpGroupNonUniformBallotFindLSB:
518 case spv::Op::OpGroupNonUniformBallotFindMSB:
519 case spv::Op::OpGroupNonUniformShuffle:
520 case spv::Op::OpGroupNonUniformShuffleXor:
521 case spv::Op::OpGroupNonUniformShuffleUp:
522 case spv::Op::OpGroupNonUniformShuffleDown:
523 case spv::Op::OpGroupNonUniformIAdd:
524 case spv::Op::OpGroupNonUniformFAdd:
525 case spv::Op::OpGroupNonUniformIMul:
526 case spv::Op::OpGroupNonUniformFMul:
527 case spv::Op::OpGroupNonUniformSMin:
528 case spv::Op::OpGroupNonUniformUMin:
529 case spv::Op::OpGroupNonUniformFMin:
530 case spv::Op::OpGroupNonUniformSMax:
531 case spv::Op::OpGroupNonUniformUMax:
532 case spv::Op::OpGroupNonUniformFMax:
533 case spv::Op::OpGroupNonUniformBitwiseAnd:
534 case spv::Op::OpGroupNonUniformBitwiseOr:
535 case spv::Op::OpGroupNonUniformBitwiseXor:
536 case spv::Op::OpGroupNonUniformLogicalAnd:
537 case spv::Op::OpGroupNonUniformLogicalOr:
538 case spv::Op::OpGroupNonUniformLogicalXor:
539 case spv::Op::OpGroupNonUniformQuadBroadcast:
540 case spv::Op::OpGroupNonUniformQuadSwap:
541 case spv::Op::OpGroupNonUniformRotateKHR:
542 case spv::Op::OpGroupNonUniformQuadAllKHR:
543 case spv::Op::OpGroupNonUniformQuadAnyKHR:
544 return true;
545 default:
546 return false;
547 }
548 }
549
spvOpcodeIsScalarizable(spv::Op opcode)550 bool spvOpcodeIsScalarizable(spv::Op opcode) {
551 switch (opcode) {
552 case spv::Op::OpPhi:
553 case spv::Op::OpCopyObject:
554 case spv::Op::OpConvertFToU:
555 case spv::Op::OpConvertFToS:
556 case spv::Op::OpConvertSToF:
557 case spv::Op::OpConvertUToF:
558 case spv::Op::OpUConvert:
559 case spv::Op::OpSConvert:
560 case spv::Op::OpFConvert:
561 case spv::Op::OpQuantizeToF16:
562 case spv::Op::OpVectorInsertDynamic:
563 case spv::Op::OpSNegate:
564 case spv::Op::OpFNegate:
565 case spv::Op::OpIAdd:
566 case spv::Op::OpFAdd:
567 case spv::Op::OpISub:
568 case spv::Op::OpFSub:
569 case spv::Op::OpIMul:
570 case spv::Op::OpFMul:
571 case spv::Op::OpUDiv:
572 case spv::Op::OpSDiv:
573 case spv::Op::OpFDiv:
574 case spv::Op::OpUMod:
575 case spv::Op::OpSRem:
576 case spv::Op::OpSMod:
577 case spv::Op::OpFRem:
578 case spv::Op::OpFMod:
579 case spv::Op::OpVectorTimesScalar:
580 case spv::Op::OpIAddCarry:
581 case spv::Op::OpISubBorrow:
582 case spv::Op::OpUMulExtended:
583 case spv::Op::OpSMulExtended:
584 case spv::Op::OpShiftRightLogical:
585 case spv::Op::OpShiftRightArithmetic:
586 case spv::Op::OpShiftLeftLogical:
587 case spv::Op::OpBitwiseOr:
588 case spv::Op::OpBitwiseAnd:
589 case spv::Op::OpNot:
590 case spv::Op::OpBitFieldInsert:
591 case spv::Op::OpBitFieldSExtract:
592 case spv::Op::OpBitFieldUExtract:
593 case spv::Op::OpBitReverse:
594 case spv::Op::OpBitCount:
595 case spv::Op::OpIsNan:
596 case spv::Op::OpIsInf:
597 case spv::Op::OpIsFinite:
598 case spv::Op::OpIsNormal:
599 case spv::Op::OpSignBitSet:
600 case spv::Op::OpLessOrGreater:
601 case spv::Op::OpOrdered:
602 case spv::Op::OpUnordered:
603 case spv::Op::OpLogicalEqual:
604 case spv::Op::OpLogicalNotEqual:
605 case spv::Op::OpLogicalOr:
606 case spv::Op::OpLogicalAnd:
607 case spv::Op::OpLogicalNot:
608 case spv::Op::OpSelect:
609 case spv::Op::OpIEqual:
610 case spv::Op::OpINotEqual:
611 case spv::Op::OpUGreaterThan:
612 case spv::Op::OpSGreaterThan:
613 case spv::Op::OpUGreaterThanEqual:
614 case spv::Op::OpSGreaterThanEqual:
615 case spv::Op::OpULessThan:
616 case spv::Op::OpSLessThan:
617 case spv::Op::OpULessThanEqual:
618 case spv::Op::OpSLessThanEqual:
619 case spv::Op::OpFOrdEqual:
620 case spv::Op::OpFUnordEqual:
621 case spv::Op::OpFOrdNotEqual:
622 case spv::Op::OpFUnordNotEqual:
623 case spv::Op::OpFOrdLessThan:
624 case spv::Op::OpFUnordLessThan:
625 case spv::Op::OpFOrdGreaterThan:
626 case spv::Op::OpFUnordGreaterThan:
627 case spv::Op::OpFOrdLessThanEqual:
628 case spv::Op::OpFUnordLessThanEqual:
629 case spv::Op::OpFOrdGreaterThanEqual:
630 case spv::Op::OpFUnordGreaterThanEqual:
631 return true;
632 default:
633 return false;
634 }
635 }
636
spvOpcodeIsDebug(spv::Op opcode)637 bool spvOpcodeIsDebug(spv::Op opcode) {
638 switch (opcode) {
639 case spv::Op::OpName:
640 case spv::Op::OpMemberName:
641 case spv::Op::OpSource:
642 case spv::Op::OpSourceContinued:
643 case spv::Op::OpSourceExtension:
644 case spv::Op::OpString:
645 case spv::Op::OpLine:
646 case spv::Op::OpNoLine:
647 case spv::Op::OpModuleProcessed:
648 return true;
649 default:
650 return false;
651 }
652 }
653
spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode)654 bool spvOpcodeIsCommutativeBinaryOperator(spv::Op opcode) {
655 switch (opcode) {
656 case spv::Op::OpPtrEqual:
657 case spv::Op::OpPtrNotEqual:
658 case spv::Op::OpIAdd:
659 case spv::Op::OpFAdd:
660 case spv::Op::OpIMul:
661 case spv::Op::OpFMul:
662 case spv::Op::OpDot:
663 case spv::Op::OpIAddCarry:
664 case spv::Op::OpUMulExtended:
665 case spv::Op::OpSMulExtended:
666 case spv::Op::OpBitwiseOr:
667 case spv::Op::OpBitwiseXor:
668 case spv::Op::OpBitwiseAnd:
669 case spv::Op::OpOrdered:
670 case spv::Op::OpUnordered:
671 case spv::Op::OpLogicalEqual:
672 case spv::Op::OpLogicalNotEqual:
673 case spv::Op::OpLogicalOr:
674 case spv::Op::OpLogicalAnd:
675 case spv::Op::OpIEqual:
676 case spv::Op::OpINotEqual:
677 case spv::Op::OpFOrdEqual:
678 case spv::Op::OpFUnordEqual:
679 case spv::Op::OpFOrdNotEqual:
680 case spv::Op::OpFUnordNotEqual:
681 return true;
682 default:
683 return false;
684 }
685 }
686
spvOpcodeIsLinearAlgebra(spv::Op opcode)687 bool spvOpcodeIsLinearAlgebra(spv::Op opcode) {
688 switch (opcode) {
689 case spv::Op::OpTranspose:
690 case spv::Op::OpVectorTimesScalar:
691 case spv::Op::OpMatrixTimesScalar:
692 case spv::Op::OpVectorTimesMatrix:
693 case spv::Op::OpMatrixTimesVector:
694 case spv::Op::OpMatrixTimesMatrix:
695 case spv::Op::OpOuterProduct:
696 case spv::Op::OpDot:
697 return true;
698 default:
699 return false;
700 }
701 }
702
spvOpcodeIsImageSample(const spv::Op opcode)703 bool spvOpcodeIsImageSample(const spv::Op opcode) {
704 switch (opcode) {
705 case spv::Op::OpImageSampleImplicitLod:
706 case spv::Op::OpImageSampleExplicitLod:
707 case spv::Op::OpImageSampleDrefImplicitLod:
708 case spv::Op::OpImageSampleDrefExplicitLod:
709 case spv::Op::OpImageSampleProjImplicitLod:
710 case spv::Op::OpImageSampleProjExplicitLod:
711 case spv::Op::OpImageSampleProjDrefImplicitLod:
712 case spv::Op::OpImageSampleProjDrefExplicitLod:
713 case spv::Op::OpImageSparseSampleImplicitLod:
714 case spv::Op::OpImageSparseSampleExplicitLod:
715 case spv::Op::OpImageSparseSampleDrefImplicitLod:
716 case spv::Op::OpImageSparseSampleDrefExplicitLod:
717 return true;
718 default:
719 return false;
720 }
721 }
722
spvIsExtendedInstruction(const spv::Op opcode)723 bool spvIsExtendedInstruction(const spv::Op opcode) {
724 switch (opcode) {
725 case spv::Op::OpExtInst:
726 case spv::Op::OpExtInstWithForwardRefsKHR:
727 return true;
728 default:
729 return false;
730 }
731 }
732
spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode)733 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) {
734 switch (opcode) {
735 case spv::Op::OpMemoryBarrier:
736 return {1};
737 case spv::Op::OpAtomicStore:
738 case spv::Op::OpControlBarrier:
739 case spv::Op::OpAtomicFlagClear:
740 case spv::Op::OpMemoryNamedBarrier:
741 return {2};
742 case spv::Op::OpAtomicLoad:
743 case spv::Op::OpAtomicExchange:
744 case spv::Op::OpAtomicIIncrement:
745 case spv::Op::OpAtomicIDecrement:
746 case spv::Op::OpAtomicIAdd:
747 case spv::Op::OpAtomicFAddEXT:
748 case spv::Op::OpAtomicISub:
749 case spv::Op::OpAtomicSMin:
750 case spv::Op::OpAtomicUMin:
751 case spv::Op::OpAtomicSMax:
752 case spv::Op::OpAtomicUMax:
753 case spv::Op::OpAtomicAnd:
754 case spv::Op::OpAtomicOr:
755 case spv::Op::OpAtomicXor:
756 case spv::Op::OpAtomicFlagTestAndSet:
757 return {4};
758 case spv::Op::OpAtomicCompareExchange:
759 case spv::Op::OpAtomicCompareExchangeWeak:
760 return {4, 5};
761 default:
762 return {};
763 }
764 }
765
spvOpcodeIsAccessChain(spv::Op opcode)766 bool spvOpcodeIsAccessChain(spv::Op opcode) {
767 switch (opcode) {
768 case spv::Op::OpAccessChain:
769 case spv::Op::OpInBoundsAccessChain:
770 case spv::Op::OpPtrAccessChain:
771 case spv::Op::OpInBoundsPtrAccessChain:
772 case spv::Op::OpRawAccessChainNV:
773 return true;
774 default:
775 return false;
776 }
777 }
778
spvOpcodeIsBit(spv::Op opcode)779 bool spvOpcodeIsBit(spv::Op opcode) {
780 switch (opcode) {
781 case spv::Op::OpShiftRightLogical:
782 case spv::Op::OpShiftRightArithmetic:
783 case spv::Op::OpShiftLeftLogical:
784 case spv::Op::OpBitwiseOr:
785 case spv::Op::OpBitwiseXor:
786 case spv::Op::OpBitwiseAnd:
787 case spv::Op::OpNot:
788 case spv::Op::OpBitReverse:
789 case spv::Op::OpBitCount:
790 return true;
791 default:
792 return false;
793 }
794 }
795