diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td index 252d9319fccc5..27c82811aa007 100644 --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td @@ -4512,6 +4512,8 @@ def SPIRV_OC_OpAssumeTrueKHR : I32EnumAttrCase<"OpAssumeTrueKHR", def SPIRV_OC_OpAtomicFAddEXT : I32EnumAttrCase<"OpAtomicFAddEXT", 6035>; def SPIRV_OC_OpConvertFToBF16INTEL : I32EnumAttrCase<"OpConvertFToBF16INTEL", 6116>; def SPIRV_OC_OpConvertBF16ToFINTEL : I32EnumAttrCase<"OpConvertBF16ToFINTEL", 6117>; +def SPIRV_OC_OpControlBarrierArriveINTEL : I32EnumAttrCase<"OpControlBarrierArriveINTEL", 6142>; +def SPIRV_OC_OpControlBarrierWaitINTEL : I32EnumAttrCase<"OpControlBarrierWaitINTEL", 6143>; def SPIRV_OC_OpGroupIMulKHR : I32EnumAttrCase<"OpGroupIMulKHR", 6401>; def SPIRV_OC_OpGroupFMulKHR : I32EnumAttrCase<"OpGroupFMulKHR", 6402>; @@ -4602,7 +4604,9 @@ def SPIRV_OpcodeAttr : SPIRV_OC_OpCooperativeMatrixLengthKHR, SPIRV_OC_OpSubgroupBlockReadINTEL, SPIRV_OC_OpSubgroupBlockWriteINTEL, SPIRV_OC_OpAssumeTrueKHR, SPIRV_OC_OpAtomicFAddEXT, SPIRV_OC_OpConvertFToBF16INTEL, - SPIRV_OC_OpConvertBF16ToFINTEL, SPIRV_OC_OpGroupIMulKHR, + SPIRV_OC_OpConvertBF16ToFINTEL, + SPIRV_OC_OpControlBarrierArriveINTEL, SPIRV_OC_OpControlBarrierWaitINTEL, + SPIRV_OC_OpGroupIMulKHR, SPIRV_OC_OpGroupFMulKHR ]>; diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVIntelExtOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVIntelExtOps.td index 97c61ddd64829..8ff7d0d63469f 100644 --- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVIntelExtOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVIntelExtOps.td @@ -111,6 +111,95 @@ def SPIRV_INTELConvertBF16ToFOp : SPIRV_IntelVendorOp<"ConvertBF16ToF", []> { } +// ----- + +class SPIRV_IntelSplitBarrierOp + : SPIRV_IntelVendorOp { + let availability = [ + MinVersion, + MaxVersion, + Extension<[SPV_INTEL_split_barrier]>, + Capability<[SPIRV_C_SplitBarrierINTEL]> + ]; + + let arguments = (ins + SPIRV_ScopeAttr:$execution_scope, + SPIRV_ScopeAttr:$memory_scope, + SPIRV_MemorySemanticsAttr:$memory_semantics + ); + + let results = (outs); + + let assemblyFormat = [{ + $execution_scope `,` $memory_scope `,` $memory_semantics attr-dict + }]; + + let hasVerifier = 0; +} + +def SPIRV_INTELControlBarrierArriveOp + : SPIRV_IntelSplitBarrierOp<"ControlBarrierArrive"> { + let summary = "See extension SPV_INTEL_split_barrier"; + + let description = [{ + Indicates that an invocation has arrived at a split control barrier. This + may allow other invocations waiting on the split control barrier to continue + executing. + + When `Execution` is `Workgroup` or larger, behavior is undefined unless all + invocations within `Execution` execute the same dynamic instance of this + instruction. When `Execution` is `Subgroup` or `Invocation`, the behavior of + this instruction in non-uniform control flow is defined by the client API. + + If `Semantics` is not `None`, this instruction also serves as the start of a + memory barrier similar to an `OpMemoryBarrier` instruction with the same + `Memory` and `Semantics` operands. This allows atomically specifying both a + control barrier and a memory barrier (that is, without needing two + instructions). If `Semantics` is `None`, `Memory` is ignored. + + #### Example: + + ```mlir + spirv.ControlBarrierArrive , , + ``` + }]; +} + + +// ----- + +def SPIRV_INTELControlBarrierWaitOp + : SPIRV_IntelSplitBarrierOp<"ControlBarrierWait"> { + let summary = "See extension SPV_INTEL_split_barrier"; + + let description = [{ + Waits for other invocations of this module to arrive at a split control + barrier. + + When `Execution` is `Workgroup` or larger, behavior is undefined unless all + invocations within `Execution` execute the same dynamic instance of this + instruction. When `Execution` is `Subgroup` or `Invocation`, the behavior of + this instruction in non-uniform control flow is defined by the client API. + + If `Semantics` is not `None`, this instruction also serves as the end of a + memory barrier similar to an `OpMemoryBarrier` instruction with the same + `Memory` and `Semantics` operands. This ensures that memory accesses issued + before arriving at the split barrier are observed before memory accesses + issued after this instruction. This control is ensured only for memory + accesses issued by this invocation and observed by another invocation + executing within `Memory` scope. This allows atomically specifying both a + control barrier and a memory barrier (that is, without needing two + instructions). If `Semantics` is `None`, `Memory` is ignored. + + #### Example: + + ```mlir + spirv.ControlBarrierWait , , + ``` + }]; +} + + // ----- #endif // MLIR_DIALECT_SPIRV_IR_INTEL_EXT_OPS diff --git a/mlir/test/Dialect/SPIRV/IR/intel-ext-ops.mlir b/mlir/test/Dialect/SPIRV/IR/intel-ext-ops.mlir index 66c70e816d413..6dd0353d9374a 100644 --- a/mlir/test/Dialect/SPIRV/IR/intel-ext-ops.mlir +++ b/mlir/test/Dialect/SPIRV/IR/intel-ext-ops.mlir @@ -72,6 +72,20 @@ spirv.func @bf16_to_f32_vec_unsupported(%arg0 : vector<2xi16>) "None" { // ----- +//===----------------------------------------------------------------------===// +// spirv.INTEL.SplitBarrier +//===----------------------------------------------------------------------===// + +spirv.func @split_barrier() "None" { + // CHECK: spirv.INTEL.ControlBarrierArrive , , + spirv.INTEL.ControlBarrierArrive , , + // CHECK: spirv.INTEL.ControlBarrierWait , , + spirv.INTEL.ControlBarrierWait , , + spirv.Return +} + +// ----- + //===----------------------------------------------------------------------===// // spirv.INTEL.CacheControls //===----------------------------------------------------------------------===// diff --git a/mlir/test/Target/SPIRV/intel-ext-ops.mlir b/mlir/test/Target/SPIRV/intel-ext-ops.mlir index fe86fd2b7be25..8c50501cf7409 100644 --- a/mlir/test/Target/SPIRV/intel-ext-ops.mlir +++ b/mlir/test/Target/SPIRV/intel-ext-ops.mlir @@ -29,3 +29,21 @@ spirv.module Logical GLSL450 requires #spirv.vce +spirv.module Logical GLSL450 requires #spirv.vce { + // CHECK-LABEL: @split_barrier + spirv.func @split_barrier() "None" { + // CHECK: spirv.INTEL.ControlBarrierArrive , , + spirv.INTEL.ControlBarrierArrive , , + // CHECK: spirv.INTEL.ControlBarrierWait , , + spirv.INTEL.ControlBarrierWait , , + spirv.Return + } +}