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. |
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 | |
67 | uint32_t spvOpcodeMake(uint16_t wordCount, SpvOp opcode) { |
68 | return ((uint32_t)opcode) | (((uint32_t)wordCount) << 16); |
69 | } |
70 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
250 | bool spvOpcodeIsConstantOrUndef(const SpvOp opcode) { |
251 | return opcode == SpvOpUndef || spvOpcodeIsConstant(opcode); |
252 | } |
253 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
434 | bool spvOpcodeIsAtomicOp(const SpvOp opcode) { |
435 | return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore || |
436 | opcode == SpvOpAtomicFlagClear); |
437 | } |
438 | |
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 | |
449 | bool spvOpcodeIsAbort(SpvOp opcode) { |
450 | switch (opcode) { |
451 | case SpvOpKill: |
452 | case SpvOpUnreachable: |
453 | case SpvOpTerminateInvocation: |
454 | case SpvOpTerminateRayKHR: |
455 | case SpvOpIgnoreIntersectionKHR: |
456 | return true; |
457 | default: |
458 | return false; |
459 | } |
460 | } |
461 | |
462 | bool spvOpcodeIsReturnOrAbort(SpvOp opcode) { |
463 | return spvOpcodeIsReturn(opcode) || spvOpcodeIsAbort(opcode); |
464 | } |
465 | |
466 | bool spvOpcodeIsBlockTerminator(SpvOp opcode) { |
467 | return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode); |
468 | } |
469 | |
470 | bool spvOpcodeTerminatesExecution(SpvOp opcode) { |
471 | return opcode == SpvOpKill || opcode == SpvOpTerminateInvocation || |
472 | opcode == SpvOpTerminateRayKHR || opcode == SpvOpIgnoreIntersectionKHR; |
473 | } |
474 | |
475 | bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) { |
476 | switch (opcode) { |
477 | case SpvOpTypeImage: |
478 | case SpvOpTypeSampler: |
479 | case SpvOpTypeSampledImage: |
480 | case SpvOpTypeOpaque: |
481 | case SpvOpTypeEvent: |
482 | case SpvOpTypeDeviceEvent: |
483 | case SpvOpTypeReserveId: |
484 | case SpvOpTypeQueue: |
485 | case SpvOpTypePipe: |
486 | case SpvOpTypeForwardPointer: |
487 | case SpvOpTypePipeStorage: |
488 | case SpvOpTypeNamedBarrier: |
489 | return true; |
490 | default: |
491 | return false; |
492 | } |
493 | } |
494 | |
495 | bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) { |
496 | switch (opcode) { |
497 | case SpvOpGroupNonUniformElect: |
498 | case SpvOpGroupNonUniformAll: |
499 | case SpvOpGroupNonUniformAny: |
500 | case SpvOpGroupNonUniformAllEqual: |
501 | case SpvOpGroupNonUniformBroadcast: |
502 | case SpvOpGroupNonUniformBroadcastFirst: |
503 | case SpvOpGroupNonUniformBallot: |
504 | case SpvOpGroupNonUniformInverseBallot: |
505 | case SpvOpGroupNonUniformBallotBitExtract: |
506 | case SpvOpGroupNonUniformBallotBitCount: |
507 | case SpvOpGroupNonUniformBallotFindLSB: |
508 | case SpvOpGroupNonUniformBallotFindMSB: |
509 | case SpvOpGroupNonUniformShuffle: |
510 | case SpvOpGroupNonUniformShuffleXor: |
511 | case SpvOpGroupNonUniformShuffleUp: |
512 | case SpvOpGroupNonUniformShuffleDown: |
513 | case SpvOpGroupNonUniformIAdd: |
514 | case SpvOpGroupNonUniformFAdd: |
515 | case SpvOpGroupNonUniformIMul: |
516 | case SpvOpGroupNonUniformFMul: |
517 | case SpvOpGroupNonUniformSMin: |
518 | case SpvOpGroupNonUniformUMin: |
519 | case SpvOpGroupNonUniformFMin: |
520 | case SpvOpGroupNonUniformSMax: |
521 | case SpvOpGroupNonUniformUMax: |
522 | case SpvOpGroupNonUniformFMax: |
523 | case SpvOpGroupNonUniformBitwiseAnd: |
524 | case SpvOpGroupNonUniformBitwiseOr: |
525 | case SpvOpGroupNonUniformBitwiseXor: |
526 | case SpvOpGroupNonUniformLogicalAnd: |
527 | case SpvOpGroupNonUniformLogicalOr: |
528 | case SpvOpGroupNonUniformLogicalXor: |
529 | case SpvOpGroupNonUniformQuadBroadcast: |
530 | case SpvOpGroupNonUniformQuadSwap: |
531 | case SpvOpGroupNonUniformRotateKHR: |
532 | return true; |
533 | default: |
534 | return false; |
535 | } |
536 | } |
537 | |
538 | bool spvOpcodeIsScalarizable(SpvOp opcode) { |
539 | switch (opcode) { |
540 | case SpvOpPhi: |
541 | case SpvOpCopyObject: |
542 | case SpvOpConvertFToU: |
543 | case SpvOpConvertFToS: |
544 | case SpvOpConvertSToF: |
545 | case SpvOpConvertUToF: |
546 | case SpvOpUConvert: |
547 | case SpvOpSConvert: |
548 | case SpvOpFConvert: |
549 | case SpvOpQuantizeToF16: |
550 | case SpvOpVectorInsertDynamic: |
551 | case SpvOpSNegate: |
552 | case SpvOpFNegate: |
553 | case SpvOpIAdd: |
554 | case SpvOpFAdd: |
555 | case SpvOpISub: |
556 | case SpvOpFSub: |
557 | case SpvOpIMul: |
558 | case SpvOpFMul: |
559 | case SpvOpUDiv: |
560 | case SpvOpSDiv: |
561 | case SpvOpFDiv: |
562 | case SpvOpUMod: |
563 | case SpvOpSRem: |
564 | case SpvOpSMod: |
565 | case SpvOpFRem: |
566 | case SpvOpFMod: |
567 | case SpvOpVectorTimesScalar: |
568 | case SpvOpIAddCarry: |
569 | case SpvOpISubBorrow: |
570 | case SpvOpUMulExtended: |
571 | case SpvOpSMulExtended: |
572 | case SpvOpShiftRightLogical: |
573 | case SpvOpShiftRightArithmetic: |
574 | case SpvOpShiftLeftLogical: |
575 | case SpvOpBitwiseOr: |
576 | case SpvOpBitwiseAnd: |
577 | case SpvOpNot: |
578 | case SpvOpBitFieldInsert: |
579 | case SpvOpBitFieldSExtract: |
580 | case SpvOpBitFieldUExtract: |
581 | case SpvOpBitReverse: |
582 | case SpvOpBitCount: |
583 | case SpvOpIsNan: |
584 | case SpvOpIsInf: |
585 | case SpvOpIsFinite: |
586 | case SpvOpIsNormal: |
587 | case SpvOpSignBitSet: |
588 | case SpvOpLessOrGreater: |
589 | case SpvOpOrdered: |
590 | case SpvOpUnordered: |
591 | case SpvOpLogicalEqual: |
592 | case SpvOpLogicalNotEqual: |
593 | case SpvOpLogicalOr: |
594 | case SpvOpLogicalAnd: |
595 | case SpvOpLogicalNot: |
596 | case SpvOpSelect: |
597 | case SpvOpIEqual: |
598 | case SpvOpINotEqual: |
599 | case SpvOpUGreaterThan: |
600 | case SpvOpSGreaterThan: |
601 | case SpvOpUGreaterThanEqual: |
602 | case SpvOpSGreaterThanEqual: |
603 | case SpvOpULessThan: |
604 | case SpvOpSLessThan: |
605 | case SpvOpULessThanEqual: |
606 | case SpvOpSLessThanEqual: |
607 | case SpvOpFOrdEqual: |
608 | case SpvOpFUnordEqual: |
609 | case SpvOpFOrdNotEqual: |
610 | case SpvOpFUnordNotEqual: |
611 | case SpvOpFOrdLessThan: |
612 | case SpvOpFUnordLessThan: |
613 | case SpvOpFOrdGreaterThan: |
614 | case SpvOpFUnordGreaterThan: |
615 | case SpvOpFOrdLessThanEqual: |
616 | case SpvOpFUnordLessThanEqual: |
617 | case SpvOpFOrdGreaterThanEqual: |
618 | case SpvOpFUnordGreaterThanEqual: |
619 | return true; |
620 | default: |
621 | return false; |
622 | } |
623 | } |
624 | |
625 | bool spvOpcodeIsDebug(SpvOp opcode) { |
626 | switch (opcode) { |
627 | case SpvOpName: |
628 | case SpvOpMemberName: |
629 | case SpvOpSource: |
630 | case SpvOpSourceContinued: |
631 | case SpvOpSourceExtension: |
632 | case SpvOpString: |
633 | case SpvOpLine: |
634 | case SpvOpNoLine: |
635 | case SpvOpModuleProcessed: |
636 | return true; |
637 | default: |
638 | return false; |
639 | } |
640 | } |
641 | |
642 | bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) { |
643 | switch (opcode) { |
644 | case SpvOpPtrEqual: |
645 | case SpvOpPtrNotEqual: |
646 | case SpvOpIAdd: |
647 | case SpvOpFAdd: |
648 | case SpvOpIMul: |
649 | case SpvOpFMul: |
650 | case SpvOpDot: |
651 | case SpvOpIAddCarry: |
652 | case SpvOpUMulExtended: |
653 | case SpvOpSMulExtended: |
654 | case SpvOpBitwiseOr: |
655 | case SpvOpBitwiseXor: |
656 | case SpvOpBitwiseAnd: |
657 | case SpvOpOrdered: |
658 | case SpvOpUnordered: |
659 | case SpvOpLogicalEqual: |
660 | case SpvOpLogicalNotEqual: |
661 | case SpvOpLogicalOr: |
662 | case SpvOpLogicalAnd: |
663 | case SpvOpIEqual: |
664 | case SpvOpINotEqual: |
665 | case SpvOpFOrdEqual: |
666 | case SpvOpFUnordEqual: |
667 | case SpvOpFOrdNotEqual: |
668 | case SpvOpFUnordNotEqual: |
669 | return true; |
670 | default: |
671 | return false; |
672 | } |
673 | } |
674 | |
675 | bool spvOpcodeIsLinearAlgebra(SpvOp opcode) { |
676 | switch (opcode) { |
677 | case SpvOpTranspose: |
678 | case SpvOpVectorTimesScalar: |
679 | case SpvOpMatrixTimesScalar: |
680 | case SpvOpVectorTimesMatrix: |
681 | case SpvOpMatrixTimesVector: |
682 | case SpvOpMatrixTimesMatrix: |
683 | case SpvOpOuterProduct: |
684 | case SpvOpDot: |
685 | return true; |
686 | default: |
687 | return false; |
688 | } |
689 | } |
690 | |
691 | bool spvOpcodeIsImageSample(const SpvOp opcode) { |
692 | switch (opcode) { |
693 | case SpvOpImageSampleImplicitLod: |
694 | case SpvOpImageSampleExplicitLod: |
695 | case SpvOpImageSampleDrefImplicitLod: |
696 | case SpvOpImageSampleDrefExplicitLod: |
697 | case SpvOpImageSampleProjImplicitLod: |
698 | case SpvOpImageSampleProjExplicitLod: |
699 | case SpvOpImageSampleProjDrefImplicitLod: |
700 | case SpvOpImageSampleProjDrefExplicitLod: |
701 | case SpvOpImageSparseSampleImplicitLod: |
702 | case SpvOpImageSparseSampleExplicitLod: |
703 | case SpvOpImageSparseSampleDrefImplicitLod: |
704 | case SpvOpImageSparseSampleDrefExplicitLod: |
705 | return true; |
706 | default: |
707 | return false; |
708 | } |
709 | } |
710 | |
711 | std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) { |
712 | switch (opcode) { |
713 | case SpvOpMemoryBarrier: |
714 | return {1}; |
715 | case SpvOpAtomicStore: |
716 | case SpvOpControlBarrier: |
717 | case SpvOpAtomicFlagClear: |
718 | case SpvOpMemoryNamedBarrier: |
719 | return {2}; |
720 | case SpvOpAtomicLoad: |
721 | case SpvOpAtomicExchange: |
722 | case SpvOpAtomicIIncrement: |
723 | case SpvOpAtomicIDecrement: |
724 | case SpvOpAtomicIAdd: |
725 | case SpvOpAtomicFAddEXT: |
726 | case SpvOpAtomicISub: |
727 | case SpvOpAtomicSMin: |
728 | case SpvOpAtomicUMin: |
729 | case SpvOpAtomicSMax: |
730 | case SpvOpAtomicUMax: |
731 | case SpvOpAtomicAnd: |
732 | case SpvOpAtomicOr: |
733 | case SpvOpAtomicXor: |
734 | case SpvOpAtomicFlagTestAndSet: |
735 | return {4}; |
736 | case SpvOpAtomicCompareExchange: |
737 | case SpvOpAtomicCompareExchangeWeak: |
738 | return {4, 5}; |
739 | default: |
740 | return {}; |
741 | } |
742 | } |
743 | |
744 | bool spvOpcodeIsAccessChain(SpvOp opcode) { |
745 | switch (opcode) { |
746 | case SpvOpAccessChain: |
747 | case SpvOpInBoundsAccessChain: |
748 | case SpvOpPtrAccessChain: |
749 | case SpvOpInBoundsPtrAccessChain: |
750 | return true; |
751 | default: |
752 | return false; |
753 | } |
754 | } |
755 | |
756 | bool spvOpcodeIsBit(SpvOp opcode) { |
757 | switch (opcode) { |
758 | case SpvOpShiftRightLogical: |
759 | case SpvOpShiftRightArithmetic: |
760 | case SpvOpShiftLeftLogical: |
761 | case SpvOpBitwiseOr: |
762 | case SpvOpBitwiseXor: |
763 | case SpvOpBitwiseAnd: |
764 | case SpvOpNot: |
765 | case SpvOpBitReverse: |
766 | case SpvOpBitCount: |
767 | return true; |
768 | default: |
769 | return false; |
770 | } |
771 | } |
772 | |