//===-- SPIRVGroupOps.td - MLIR SPIR-V (Sub)Group 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 group and subgroup ops for the SPIR-V dialect. It // corresponds to "3.32.21. Group and Subgroup Instructions" of the SPIR-V // specification. // //===----------------------------------------------------------------------===// #ifndef MLIR_DIALECT_SPIRV_IR_GROUP_OPS #define MLIR_DIALECT_SPIRV_IR_GROUP_OPS // ----- def SPIRV_GroupFMulKHROp : SPIRV_KhrVendorOp<"GroupFMul", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A floating-point multiplication group operation specified for all values of 'X' specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within 'Execution' reach this point of execution. Behavior is undefined unless all invocations within 'Execution' execute the same dynamic instance of this instruction. 'Result Type' must be a scalar or vector of floating-point type. 'Execution' is a Scope. It must be either Workgroup or Subgroup. The identity I for 'Operation' is 1. The type of 'X' must be the same as 'Result Type'. #### Example: ```mlir %0 = spirv.KHR.GroupFMul %value : f32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_GroupUniformArithmeticKHR]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupBroadcastOp : SPIRV_Op<"GroupBroadcast", [Pure, AllTypesMatch<["value", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ Broadcast the Value of the invocation identified by the local id LocalId to the result of all invocations in the group. }]; let description = [{ All invocations of this module within Execution must reach this point of execution. Behavior is undefined if this instruction is used in control flow that is non-uniform within Execution. Result Type must be a scalar or vector of floating-point type, integer type, or Boolean type. Execution must be Workgroup or Subgroup Scope. The type of Value must be the same as Result Type. LocalId must be an integer datatype. It can be a scalar, or a vector with 2 components or a vector with 3 components. LocalId must be the same for all invocations in the group. #### Example: ```mlir %scalar_value = ... : f32 %vector_value = ... : vector<4xf32> %scalar_localid = ... : i32 %vector_localid = ... : vector<3xi32> %0 = spirv.GroupBroadcast %scalar_value, %scalar_localid : f32, i32 %1 = spirv.GroupBroadcast %vector_value, %vector_localid : vector<4xf32>, vector<3xi32> ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_ScalarOrVector:$value, SPIRV_ScalarOrVectorOf:$localid ); let results = (outs SPIRV_ScalarOrVector:$result ); let assemblyFormat = [{ $execution_scope operands attr-dict `:` type($value) `,` type($localid) }]; } // ----- def SPIRV_GroupFAddOp : SPIRV_Op<"GroupFAdd", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A floating-point add group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of floating-point type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is 0. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupFAdd %value : f32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupFMaxOp : SPIRV_Op<"GroupFMax", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A floating-point maximum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of floating-point type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is -INF. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupFMax %value : f32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupFMinOp : SPIRV_Op<"GroupFMin", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A floating-point minimum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of floating-point type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is +INF. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupFMin %value : f32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupIAddOp : SPIRV_Op<"GroupIAdd", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ An integer add group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of integer type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is 0. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupIAdd %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupIMulKHROp : SPIRV_KhrVendorOp<"GroupIMul", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ An integer multiplication group operation specified for all values of 'X' specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within 'Execution' reach this point of execution. Behavior is undefined unless all invocations within 'Execution' execute the same dynamic instance of this instruction. 'Result Type' must be a scalar or vector of integer type. 'Execution' is a Scope. It must be either Workgroup or Subgroup. The identity I for 'Operation' is 1. The type of 'X' must be the same as 'Result Type'. #### Example: ```mlir %0 = spirv.KHR.GroupIMul %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_GroupUniformArithmeticKHR]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupSMaxOp : SPIRV_Op<"GroupSMax", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A signed integer maximum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of integer type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is INT_MIN when X is 32 bits wide and LONG_MIN when X is 64 bits wide. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupSMax %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupSMinOp : SPIRV_Op<"GroupSMin", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ A signed integer minimum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of integer type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is INT_MAX when X is 32 bits wide and LONG_MAX when X is 64 bits wide. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupSMin %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupUMaxOp : SPIRV_Op<"GroupUMax", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ An unsigned integer maximum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of integer type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is 0. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupUMax %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_GroupUMinOp : SPIRV_Op<"GroupUMin", [Pure, AllTypesMatch<["x", "result"]>, SPIRV_ExecutionScopeAttrIs<"execution_scope", ["Workgroup", "Subgroup"]>]> { let summary = [{ An unsigned integer minimum group operation specified for all values of X specified by invocations in the group. }]; let description = [{ Behavior is undefined if not all invocations of this module within Execution reach this point of execution. Behavior is undefined unless all invocations within Execution execute the same dynamic instance of this instruction. Result Type must be a scalar or vector of integer type. Execution is a Scope. It must be either Workgroup or Subgroup. The identity I for Operation is UINT_MAX when X is 32 bits wide and ULONG_MAX when X is 64 bits wide. The type of X must be the same as Result Type. #### Example: ```mlir %0 = spirv.GroupUMin %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[]>, Capability<[SPIRV_C_Groups]> ]; let arguments = (ins SPIRV_ScopeAttr:$execution_scope, SPIRV_GroupOperationAttr:$group_operation, SPIRV_ScalarOrVectorOf:$x ); let results = (outs SPIRV_ScalarOrVectorOf:$result ); let assemblyFormat = [{ $execution_scope $group_operation operands attr-dict `:` type($x) }]; let hasVerifier = 0; } // ----- def SPIRV_INTELSubgroupBlockReadOp : SPIRV_IntelVendorOp<"SubgroupBlockRead", []> { let summary = "See extension SPV_INTEL_subgroups"; let description = [{ Reads one or more components of Result data for each invocation in the subgroup from the specified Ptr as a block operation. The data is read strided, so the first value read is: Ptr[ SubgroupLocalInvocationId ] and the second value read is: Ptr[ SubgroupLocalInvocationId + SubgroupMaxSize ] etc. Result Type may be a scalar or vector type, and its component type must be equal to the type pointed to by Ptr. The type of Ptr must be a pointer type, and must point to a scalar type. ``` subgroup-block-read-INTEL-op ::= ssa-id `=` `spirv.INTEL.SubgroupBlockRead` storage-class ssa_use `:` spirv-element-type ``` #### Example: ```mlir %0 = spirv.INTEL.SubgroupBlockRead "StorageBuffer" %ptr : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[SPV_INTEL_subgroups]>, Capability<[SPIRV_C_SubgroupBufferBlockIOINTEL]> ]; let arguments = (ins SPIRV_AnyPtr:$ptr ); let results = (outs SPIRV_Type:$value ); let hasCustomAssemblyFormat = 0; let assemblyFormat = [{ $ptr attr-dict `:` type($ptr) `->` type($value) }]; } // ----- def SPIRV_INTELSubgroupBlockWriteOp : SPIRV_IntelVendorOp<"SubgroupBlockWrite", []> { let summary = "See extension SPV_INTEL_subgroups"; let description = [{ Writes one or more components of Data for each invocation in the subgroup from the specified Ptr as a block operation. The data is written strided, so the first value is written to: Ptr[ SubgroupLocalInvocationId ] and the second value written is: Ptr[ SubgroupLocalInvocationId + SubgroupMaxSize ] etc. The type of Ptr must be a pointer type, and must point to a scalar type. The component type of Data must be equal to the type pointed to by Ptr. ``` subgroup-block-write-INTEL-op ::= ssa-id `=` `spirv.INTEL.SubgroupBlockWrite` storage-class ssa_use `,` ssa-use `:` spirv-element-type ``` #### Example: ```mlir spirv.INTEL.SubgroupBlockWrite "StorageBuffer" %ptr, %value : i32 ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[SPV_INTEL_subgroups]>, Capability<[SPIRV_C_SubgroupBufferBlockIOINTEL]> ]; let arguments = (ins SPIRV_AnyPtr:$ptr, SPIRV_Type:$value ); let results = (outs); } // ----- def SPIRV_KHRSubgroupBallotOp : SPIRV_KhrVendorOp<"SubgroupBallot", []> { let summary = "See extension SPV_KHR_shader_ballot"; let description = [{ Computes a bitfield value combining the Predicate value from all invocations in the current Subgroup that execute the same dynamic instance of this instruction. The bit is set to one if the corresponding invocation is active and the predicate is evaluated to true; otherwise, it is set to zero. Predicate must be a Boolean type. Result Type must be a 4 component vector of 32 bit integer types. Result is a set of bitfields where the first invocation is represented in bit 0 of the first vector component and the last (up to SubgroupSize) is the higher bit number of the last bitmask needed to represent all bits of the subgroup invocations. ``` subgroup-ballot-op ::= ssa-id `=` `spirv.KHR.SubgroupBallot` ssa-use `:` `vector` `<` 4 `x` `i32` `>` ``` #### Example: ```mlir %0 = spirv.KHR.SubgroupBallot %predicate : vector<4xi32> ``` }]; let availability = [ MinVersion, MaxVersion, Extension<[SPV_KHR_shader_ballot]>, Capability<[SPIRV_C_SubgroupBallotKHR]> ]; let arguments = (ins SPIRV_Bool:$predicate ); let results = (outs SPIRV_Int32Vec4:$result ); let hasVerifier = 0; let assemblyFormat = "$predicate attr-dict `:` type($result)"; } // ----- #endif // MLIR_DIALECT_SPIRV_IR_GROUP_OPS