1 | // Copyright (c) 2015-2020 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 Regsitry. |
44 | struct VendorTool { |
45 | uint32_t value; |
46 | const char* vendor; |
47 | const char* tool; // Might be empty string. |
48 | const char* vendor_tool; // Combiantion 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 SpvOpTypeRayQueryProvisionalKHR: |
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 SpvOpAtomicISub: |
417 | case SpvOpAtomicSMin: |
418 | case SpvOpAtomicUMin: |
419 | case SpvOpAtomicSMax: |
420 | case SpvOpAtomicUMax: |
421 | case SpvOpAtomicAnd: |
422 | case SpvOpAtomicOr: |
423 | case SpvOpAtomicXor: |
424 | case SpvOpAtomicFlagTestAndSet: |
425 | return true; |
426 | default: |
427 | return false; |
428 | } |
429 | } |
430 | |
431 | bool spvOpcodeIsAtomicOp(const SpvOp opcode) { |
432 | return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore || |
433 | opcode == SpvOpAtomicFlagClear); |
434 | } |
435 | |
436 | bool spvOpcodeIsReturn(SpvOp opcode) { |
437 | switch (opcode) { |
438 | case SpvOpReturn: |
439 | case SpvOpReturnValue: |
440 | return true; |
441 | default: |
442 | return false; |
443 | } |
444 | } |
445 | |
446 | bool spvOpcodeIsReturnOrAbort(SpvOp opcode) { |
447 | return spvOpcodeIsReturn(opcode) || opcode == SpvOpKill || |
448 | opcode == SpvOpUnreachable; |
449 | } |
450 | |
451 | bool spvOpcodeIsBlockTerminator(SpvOp opcode) { |
452 | return spvOpcodeIsBranch(opcode) || spvOpcodeIsReturnOrAbort(opcode); |
453 | } |
454 | |
455 | bool spvOpcodeIsBaseOpaqueType(SpvOp opcode) { |
456 | switch (opcode) { |
457 | case SpvOpTypeImage: |
458 | case SpvOpTypeSampler: |
459 | case SpvOpTypeSampledImage: |
460 | case SpvOpTypeOpaque: |
461 | case SpvOpTypeEvent: |
462 | case SpvOpTypeDeviceEvent: |
463 | case SpvOpTypeReserveId: |
464 | case SpvOpTypeQueue: |
465 | case SpvOpTypePipe: |
466 | case SpvOpTypeForwardPointer: |
467 | case SpvOpTypePipeStorage: |
468 | case SpvOpTypeNamedBarrier: |
469 | return true; |
470 | default: |
471 | return false; |
472 | } |
473 | } |
474 | |
475 | bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode) { |
476 | switch (opcode) { |
477 | case SpvOpGroupNonUniformElect: |
478 | case SpvOpGroupNonUniformAll: |
479 | case SpvOpGroupNonUniformAny: |
480 | case SpvOpGroupNonUniformAllEqual: |
481 | case SpvOpGroupNonUniformBroadcast: |
482 | case SpvOpGroupNonUniformBroadcastFirst: |
483 | case SpvOpGroupNonUniformBallot: |
484 | case SpvOpGroupNonUniformInverseBallot: |
485 | case SpvOpGroupNonUniformBallotBitExtract: |
486 | case SpvOpGroupNonUniformBallotBitCount: |
487 | case SpvOpGroupNonUniformBallotFindLSB: |
488 | case SpvOpGroupNonUniformBallotFindMSB: |
489 | case SpvOpGroupNonUniformShuffle: |
490 | case SpvOpGroupNonUniformShuffleXor: |
491 | case SpvOpGroupNonUniformShuffleUp: |
492 | case SpvOpGroupNonUniformShuffleDown: |
493 | case SpvOpGroupNonUniformIAdd: |
494 | case SpvOpGroupNonUniformFAdd: |
495 | case SpvOpGroupNonUniformIMul: |
496 | case SpvOpGroupNonUniformFMul: |
497 | case SpvOpGroupNonUniformSMin: |
498 | case SpvOpGroupNonUniformUMin: |
499 | case SpvOpGroupNonUniformFMin: |
500 | case SpvOpGroupNonUniformSMax: |
501 | case SpvOpGroupNonUniformUMax: |
502 | case SpvOpGroupNonUniformFMax: |
503 | case SpvOpGroupNonUniformBitwiseAnd: |
504 | case SpvOpGroupNonUniformBitwiseOr: |
505 | case SpvOpGroupNonUniformBitwiseXor: |
506 | case SpvOpGroupNonUniformLogicalAnd: |
507 | case SpvOpGroupNonUniformLogicalOr: |
508 | case SpvOpGroupNonUniformLogicalXor: |
509 | case SpvOpGroupNonUniformQuadBroadcast: |
510 | case SpvOpGroupNonUniformQuadSwap: |
511 | return true; |
512 | default: |
513 | return false; |
514 | } |
515 | } |
516 | |
517 | bool spvOpcodeIsScalarizable(SpvOp opcode) { |
518 | switch (opcode) { |
519 | case SpvOpPhi: |
520 | case SpvOpCopyObject: |
521 | case SpvOpConvertFToU: |
522 | case SpvOpConvertFToS: |
523 | case SpvOpConvertSToF: |
524 | case SpvOpConvertUToF: |
525 | case SpvOpUConvert: |
526 | case SpvOpSConvert: |
527 | case SpvOpFConvert: |
528 | case SpvOpQuantizeToF16: |
529 | case SpvOpVectorInsertDynamic: |
530 | case SpvOpSNegate: |
531 | case SpvOpFNegate: |
532 | case SpvOpIAdd: |
533 | case SpvOpFAdd: |
534 | case SpvOpISub: |
535 | case SpvOpFSub: |
536 | case SpvOpIMul: |
537 | case SpvOpFMul: |
538 | case SpvOpUDiv: |
539 | case SpvOpSDiv: |
540 | case SpvOpFDiv: |
541 | case SpvOpUMod: |
542 | case SpvOpSRem: |
543 | case SpvOpSMod: |
544 | case SpvOpFRem: |
545 | case SpvOpFMod: |
546 | case SpvOpVectorTimesScalar: |
547 | case SpvOpIAddCarry: |
548 | case SpvOpISubBorrow: |
549 | case SpvOpUMulExtended: |
550 | case SpvOpSMulExtended: |
551 | case SpvOpShiftRightLogical: |
552 | case SpvOpShiftRightArithmetic: |
553 | case SpvOpShiftLeftLogical: |
554 | case SpvOpBitwiseOr: |
555 | case SpvOpBitwiseAnd: |
556 | case SpvOpNot: |
557 | case SpvOpBitFieldInsert: |
558 | case SpvOpBitFieldSExtract: |
559 | case SpvOpBitFieldUExtract: |
560 | case SpvOpBitReverse: |
561 | case SpvOpBitCount: |
562 | case SpvOpIsNan: |
563 | case SpvOpIsInf: |
564 | case SpvOpIsFinite: |
565 | case SpvOpIsNormal: |
566 | case SpvOpSignBitSet: |
567 | case SpvOpLessOrGreater: |
568 | case SpvOpOrdered: |
569 | case SpvOpUnordered: |
570 | case SpvOpLogicalEqual: |
571 | case SpvOpLogicalNotEqual: |
572 | case SpvOpLogicalOr: |
573 | case SpvOpLogicalAnd: |
574 | case SpvOpLogicalNot: |
575 | case SpvOpSelect: |
576 | case SpvOpIEqual: |
577 | case SpvOpINotEqual: |
578 | case SpvOpUGreaterThan: |
579 | case SpvOpSGreaterThan: |
580 | case SpvOpUGreaterThanEqual: |
581 | case SpvOpSGreaterThanEqual: |
582 | case SpvOpULessThan: |
583 | case SpvOpSLessThan: |
584 | case SpvOpULessThanEqual: |
585 | case SpvOpSLessThanEqual: |
586 | case SpvOpFOrdEqual: |
587 | case SpvOpFUnordEqual: |
588 | case SpvOpFOrdNotEqual: |
589 | case SpvOpFUnordNotEqual: |
590 | case SpvOpFOrdLessThan: |
591 | case SpvOpFUnordLessThan: |
592 | case SpvOpFOrdGreaterThan: |
593 | case SpvOpFUnordGreaterThan: |
594 | case SpvOpFOrdLessThanEqual: |
595 | case SpvOpFUnordLessThanEqual: |
596 | case SpvOpFOrdGreaterThanEqual: |
597 | case SpvOpFUnordGreaterThanEqual: |
598 | return true; |
599 | default: |
600 | return false; |
601 | } |
602 | } |
603 | |
604 | bool spvOpcodeIsDebug(SpvOp opcode) { |
605 | switch (opcode) { |
606 | case SpvOpName: |
607 | case SpvOpMemberName: |
608 | case SpvOpSource: |
609 | case SpvOpSourceContinued: |
610 | case SpvOpSourceExtension: |
611 | case SpvOpString: |
612 | case SpvOpLine: |
613 | case SpvOpNoLine: |
614 | return true; |
615 | default: |
616 | return false; |
617 | } |
618 | } |
619 | |
620 | bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) { |
621 | switch (opcode) { |
622 | case SpvOpPtrEqual: |
623 | case SpvOpPtrNotEqual: |
624 | case SpvOpIAdd: |
625 | case SpvOpFAdd: |
626 | case SpvOpIMul: |
627 | case SpvOpFMul: |
628 | case SpvOpDot: |
629 | case SpvOpIAddCarry: |
630 | case SpvOpUMulExtended: |
631 | case SpvOpSMulExtended: |
632 | case SpvOpBitwiseOr: |
633 | case SpvOpBitwiseXor: |
634 | case SpvOpBitwiseAnd: |
635 | case SpvOpOrdered: |
636 | case SpvOpUnordered: |
637 | case SpvOpLogicalEqual: |
638 | case SpvOpLogicalNotEqual: |
639 | case SpvOpLogicalOr: |
640 | case SpvOpLogicalAnd: |
641 | case SpvOpIEqual: |
642 | case SpvOpINotEqual: |
643 | case SpvOpFOrdEqual: |
644 | case SpvOpFUnordEqual: |
645 | case SpvOpFOrdNotEqual: |
646 | case SpvOpFUnordNotEqual: |
647 | return true; |
648 | default: |
649 | return false; |
650 | } |
651 | } |
652 | |
653 | std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) { |
654 | switch (opcode) { |
655 | case SpvOpMemoryBarrier: |
656 | return {1}; |
657 | case SpvOpAtomicStore: |
658 | case SpvOpControlBarrier: |
659 | case SpvOpAtomicFlagClear: |
660 | case SpvOpMemoryNamedBarrier: |
661 | return {2}; |
662 | case SpvOpAtomicLoad: |
663 | case SpvOpAtomicExchange: |
664 | case SpvOpAtomicIIncrement: |
665 | case SpvOpAtomicIDecrement: |
666 | case SpvOpAtomicIAdd: |
667 | case SpvOpAtomicISub: |
668 | case SpvOpAtomicSMin: |
669 | case SpvOpAtomicUMin: |
670 | case SpvOpAtomicSMax: |
671 | case SpvOpAtomicUMax: |
672 | case SpvOpAtomicAnd: |
673 | case SpvOpAtomicOr: |
674 | case SpvOpAtomicXor: |
675 | case SpvOpAtomicFlagTestAndSet: |
676 | return {4}; |
677 | case SpvOpAtomicCompareExchange: |
678 | case SpvOpAtomicCompareExchangeWeak: |
679 | return {4, 5}; |
680 | default: |
681 | return {}; |
682 | } |
683 | } |
684 | |