| //===-- SPIRVAtomicOps.td - MLIR SPIR-V Atomic Ops ---------*- tablegen -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains atomic ops for the SPIR-V dialect. It corresponds to |
| // "3.32.18. Atomic Instructions" of the SPIR-V specification. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS |
| #define MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS |
| |
| class SPV_AtomicUpdateOp<string mnemonic, list<OpTrait> traits = []> : |
| SPV_Op<mnemonic, traits> { |
| let parser = [{ return ::parseAtomicUpdateOp(parser, result, false); }]; |
| let printer = [{ return ::printAtomicUpdateOp(getOperation(), p); }]; |
| let verifier = [{ return ::verifyAtomicUpdateOp<IntegerType>(getOperation()); }]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$semantics |
| ); |
| |
| let results = (outs |
| SPV_Integer:$result |
| ); |
| } |
| |
| class SPV_AtomicUpdateWithValueOp<string mnemonic, list<OpTrait> traits = []> : |
| SPV_Op<mnemonic, traits> { |
| let parser = [{ return ::parseAtomicUpdateOp(parser, result, true); }]; |
| let printer = [{ return ::printAtomicUpdateOp(getOperation(), p); }]; |
| let verifier = [{ return ::verifyAtomicUpdateOp<IntegerType>(getOperation()); }]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$semantics, |
| SPV_Integer:$value |
| ); |
| |
| let results = (outs |
| SPV_Integer:$result |
| ); |
| |
| let builders = [ |
| OpBuilder<(ins "Value":$pointer, "::mlir::spirv::Scope":$scope, |
| "::mlir::spirv::MemorySemantics":$memory, "Value":$value), |
| [{build($_builder, $_state, value.getType(), pointer, scope, memory, value);}]> |
| ]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicAndOp : SPV_AtomicUpdateWithValueOp<"AtomicAnd", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by the bitwise AND of Original Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| scope ::= `"CrossDevice"` | `"Device"` | `"Workgroup"` | ... |
| |
| memory-semantics ::= `"None"` | `"Acquire"` | "Release"` | ... |
| |
| atomic-and-op ::= |
| `spv.AtomicAnd` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicAnd "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicCompareExchangeOp : SPV_Op<"AtomicCompareExchange", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value from Value only if Original Value equals Comparator, |
| and |
| |
| 3) store the New Value back through Pointer'only if 'Original Value |
| equaled Comparator. |
| |
| The instruction's result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| Use Equal for the memory semantics of this instruction when Value and |
| Original Value compare equal. |
| |
| Use Unequal for the memory semantics of this instruction when Value and |
| Original Value compare unequal. Unequal must not be set to Release or |
| Acquire and Release. In addition, Unequal cannot be set to a stronger |
| memory-order then Equal. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. This type |
| must also match the type of Comparator. |
| |
| Memory is a memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-compare-exchange-op ::= |
| `spv.AtomicCompareExchange` scope memory-semantics memory-semantics |
| ssa-use `,` ssa-use `,` ssa-use |
| `:` spv-pointer-type |
| ```mlir |
| |
| #### Example: |
| |
| ``` |
| %0 = spv.AtomicCompareExchange "Workgroup" "Acquire" "None" |
| %pointer, %value, %comparator |
| : !spv.ptr<i32, WorkGroup> |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$equal_semantics, |
| SPV_MemorySemanticsAttr:$unequal_semantics, |
| SPV_Integer:$value, |
| SPV_Integer:$comparator |
| ); |
| |
| let results = (outs |
| SPV_Integer:$result |
| ); |
| |
| let parser = [{ return ::parseAtomicCompareExchangeImpl(parser, result); }]; |
| let printer = [{ return ::printAtomicCompareExchangeImpl(*this, p); }]; |
| let verifier = [{ return ::verifyAtomicCompareExchangeImpl(*this); }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicCompareExchangeWeakOp : SPV_Op<"AtomicCompareExchangeWeak", []> { |
| let summary = "Deprecated (use OpAtomicCompareExchange)."; |
| |
| let description = [{ |
| Has the same semantics as OpAtomicCompareExchange. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-compare-exchange-weak-op ::= |
| `spv.AtomicCompareExchangeWeak` scope memory-semantics memory-semantics |
| ssa-use `,` ssa-use `,` ssa-use |
| `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicCompareExchangeWeak "Workgroup" "Acquire" "None" |
| %pointer, %value, %comparator |
| : !spv.ptr<i32, WorkGroup> |
| ``` |
| }]; |
| |
| let availability = [ |
| MinVersion<SPV_V_1_0>, |
| MaxVersion<SPV_V_1_3>, |
| Extension<[]>, |
| Capability<[SPV_C_Kernel]> |
| ]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$equal_semantics, |
| SPV_MemorySemanticsAttr:$unequal_semantics, |
| SPV_Integer:$value, |
| SPV_Integer:$comparator |
| ); |
| |
| let results = (outs |
| SPV_Integer:$result |
| ); |
| |
| let parser = [{ return ::parseAtomicCompareExchangeImpl(parser, result); }]; |
| let printer = [{ return ::printAtomicCompareExchangeImpl(*this, p); }]; |
| let verifier = [{ return ::verifyAtomicCompareExchangeImpl(*this); }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicExchangeOp : SPV_Op<"AtomicExchange", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value from copying Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction's result is the Original Value. |
| |
| Result Type must be a scalar of integer type or floating-point type. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory is a memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-exchange-op ::= |
| `spv.AtomicCompareExchange` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ```mlir |
| |
| #### Example: |
| |
| ``` |
| %0 = spv.AtomicExchange "Workgroup" "Acquire" %pointer, %value, |
| : !spv.ptr<i32, WorkGroup> |
| ``` |
| }]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$semantics, |
| SPV_Numerical:$value |
| ); |
| |
| let results = (outs |
| SPV_Numerical:$result |
| ); |
| } |
| |
| // ----- |
| |
| def SPV_AtomicFAddEXTOp : SPV_Op<"AtomicFAddEXT", []> { |
| let summary = "TBD"; |
| |
| let description = [{ |
| |
| |
| <!-- End of AutoGen section --> |
| |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by float addition of Original Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be a floating-point type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the value |
| pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| ``` |
| atomic-fadd-op ::= |
| `spv.AtomicFAddEXT` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicFAddEXT "Device" "None" %pointer, %value : |
| !spv.ptr<f32, StorageBuffer> |
| ```mlir |
| }]; |
| |
| let availability = [ |
| MinVersion<SPV_V_1_0>, |
| MaxVersion<SPV_V_1_5>, |
| Extension<[SPV_EXT_shader_atomic_float_add]>, |
| Capability<[SPV_C_AtomicFloat16AddEXT, SPV_C_AtomicFloat32AddEXT, SPV_C_AtomicFloat64AddEXT]> |
| ]; |
| |
| let arguments = (ins |
| SPV_AnyPtr:$pointer, |
| SPV_ScopeAttr:$memory_scope, |
| SPV_MemorySemanticsAttr:$semantics, |
| SPV_Float:$value |
| ); |
| |
| let results = (outs |
| SPV_Float:$result |
| ); |
| |
| let parser = [{ return ::parseAtomicUpdateOp(parser, result, true); }]; |
| let printer = [{ return ::printAtomicUpdateOp(getOperation(), p); }]; |
| let verifier = [{ return ::verifyAtomicUpdateOp<FloatType>(getOperation()); }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicIAddOp : SPV_AtomicUpdateWithValueOp<"AtomicIAdd", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by integer addition of Original Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-iadd-op ::= |
| `spv.AtomicIAdd` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicIAdd "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicIDecrementOp : SPV_AtomicUpdateOp<"AtomicIDecrement", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value through integer subtraction of 1 from Original Value, |
| and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. The type of the value |
| pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-idecrement-op ::= |
| `spv.AtomicIDecrement` scope memory-semantics ssa-use |
| `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicIDecrement "Device" "None" %pointer : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicIIncrementOp : SPV_AtomicUpdateOp<"AtomicIIncrement", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value through integer addition of 1 to Original Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. The type of the value |
| pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-iincrement-op ::= |
| `spv.AtomicIIncrement` scope memory-semantics ssa-use |
| `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicIncrement "Device" "None" %pointer : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicISubOp : SPV_AtomicUpdateWithValueOp<"AtomicISub", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by integer subtraction of Value from Original Value, |
| and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-isub-op ::= |
| `spv.AtomicISub` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicISub "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicOrOp : SPV_AtomicUpdateWithValueOp<"AtomicOr", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by the bitwise OR of Original Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-or-op ::= |
| `spv.AtomicOr` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicOr "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicSMaxOp : SPV_AtomicUpdateWithValueOp<"AtomicSMax", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by finding the largest signed integer of Original |
| Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-smax-op ::= |
| `spv.AtomicSMax` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicSMax "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicSMinOp : SPV_AtomicUpdateWithValueOp<"AtomicSMin", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by finding the smallest signed integer of Original |
| Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-smin-op ::= |
| `spv.AtomicSMin` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicSMin "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicUMaxOp : SPV_AtomicUpdateWithValueOp<"AtomicUMax", [UnsignedOp]> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by finding the largest unsigned integer of Original |
| Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-umax-op ::= |
| `spv.AtomicUMax` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicUMax "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicUMinOp : SPV_AtomicUpdateWithValueOp<"AtomicUMin", [UnsignedOp]> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by finding the smallest unsigned integer of Original |
| Value and Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-umin-op ::= |
| `spv.AtomicUMin` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicUMin "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| def SPV_AtomicXorOp : SPV_AtomicUpdateWithValueOp<"AtomicXor", []> { |
| let summary = [{ |
| Perform the following steps atomically with respect to any other atomic |
| accesses within Scope to the same location: |
| }]; |
| |
| let description = [{ |
| 1) load through Pointer to get an Original Value, |
| |
| 2) get a New Value by the bitwise exclusive OR of Original Value and |
| Value, and |
| |
| 3) store the New Value back through Pointer. |
| |
| The instruction’s result is the Original Value. |
| |
| Result Type must be an integer type scalar. |
| |
| The type of Value must be the same as Result Type. The type of the |
| value pointed to by Pointer must be the same as Result Type. |
| |
| Memory must be a valid memory Scope. |
| |
| <!-- End of AutoGen section --> |
| |
| ``` |
| atomic-xor-op ::= |
| `spv.AtomicXor` scope memory-semantics |
| ssa-use `,` ssa-use `:` spv-pointer-type |
| ``` |
| |
| #### Example: |
| |
| ```mlir |
| %0 = spv.AtomicXor "Device" "None" %pointer, %value : |
| !spv.ptr<i32, StorageBuffer> |
| ``` |
| }]; |
| } |
| |
| // ----- |
| |
| #endif // MLIR_DIALECT_SPIRV_IR_ATOMIC_OPS |