[Mlir-commits] [mlir] [mlir][gpu] Support `minimumnumf` and `maximumnumf` in GPU dialect (PR #226897)
Artem Gindinson
llvmlistbot at llvm.org
Sun Sep 27 23:57:34 PDT 2026
https://github.com/AGindinson updated https://github.com/llvm/llvm-project/pull/226897
>From 383ca456e8dd2ba07df2214cdbaa66e481d3bdcb Mon Sep 17 00:00:00 2001
From: Artem Gindinson <gindinson at roofline.ai>
Date: Fri, 25 Sep 2026 15:24:44 +0000
Subject: [PATCH] [mlir][gpu] Support `minimumnumf` and `maximumnumf` in GPU
dialect
Follow up on #221658. Add mirroring GPU reduction kinds and lower
through appropriate arith ops.
Assisted-by: Codex
---
mlir/include/mlir/Dialect/GPU/IR/GPUOps.td | 12 +++++--
.../GPUToNVVM/LowerGpuOpsToNVVMOps.cpp | 2 ++
mlir/lib/Dialect/GPU/IR/GPUDialect.cpp | 3 +-
mlir/lib/Dialect/GPU/Utils/Utils.cpp | 2 ++
.../Dialect/GPU/all-reduce-minmaxnumf.mlir | 21 ++++++++++++
mlir/test/Dialect/GPU/invalid.mlir | 32 +++++++++++++++++++
.../Dialect/GPU/subgroup-reduce-lowering.mlir | 24 ++++++++++++++
7 files changed, 92 insertions(+), 4 deletions(-)
create mode 100644 mlir/test/Dialect/GPU/all-reduce-minmaxnumf.mlir
diff --git a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
index 2aa5219e904040..1b6c4ec26ab685 100644
--- a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
+++ b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
@@ -1151,6 +1151,10 @@ def GPU_AllReduceOpXor : I32EnumAttrCase<"XOR", 10, "xor">;
def GPU_AllReduceOpMinimumF : I32EnumAttrCase<"MINIMUMF", 11, "minimumf">;
// Follows the `arith.maximumf` semantics.
def GPU_AllReduceOpMaximumF : I32EnumAttrCase<"MAXIMUMF", 12, "maximumf">;
+// Follows the `arith.minimumnumf` semantics.
+def GPU_AllReduceOpMinimumNumF : I32EnumAttrCase<"MINIMUMNUMF", 13, "minimumnumf">;
+// Follows the `arith.maximumnumf` semantics.
+def GPU_AllReduceOpMaximumNumF : I32EnumAttrCase<"MAXIMUMNUMF", 14, "maximumnumf">;
def GPU_AllReduceOperation : I32EnumAttr<"AllReduceOperation",
"built-in reduction operations supported by gpu.allreduce.",
@@ -1167,7 +1171,9 @@ def GPU_AllReduceOperation : I32EnumAttr<"AllReduceOperation",
GPU_AllReduceOpOr,
GPU_AllReduceOpXor,
GPU_AllReduceOpMinimumF,
- GPU_AllReduceOpMaximumF
+ GPU_AllReduceOpMaximumF,
+ GPU_AllReduceOpMinimumNumF,
+ GPU_AllReduceOpMaximumNumF
]>{
let genSpecializedAttr = 0;
let cppNamespace = "::mlir::gpu";
@@ -1202,7 +1208,7 @@ def GPU_AllReduceOp : GPU_Op<"all_reduce",
* Integer types: `add`, `mul`, `minui`, `minsi`, `maxui`, `maxsi`, `and`,
`or`, `xor`
* Floating point types: `add`, `mul`, `minnumf`, `maxnumf`, `minimumf`,
- `maximumf`
+ `maximumf`, `minimumnumf`, `maximumnumf`
If `uniform` flag is set either none or all work items of a workgroup
need to execute this op in convergence.
@@ -1259,7 +1265,7 @@ def GPU_SubgroupReduceOp : GPU_Op<"subgroup_reduce", [SameOperandsAndResultType,
* Integer types: `add`, `mul`, `minui`, `minsi`, `maxui`, `maxsi`, `and`,
`or`, `xor`
* Floating point types: `add`, `mul`, `minnumf`, `maxnumf`, `minimumf`,
- `maximumf`
+ `maximumf`, `minimumnumf`, `maximumnumf`
}];
let arguments = (ins
diff --git a/mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp b/mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp
index 10de345eb67128..ea776000d8190e 100644
--- a/mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp
+++ b/mlir/lib/Conversion/GPUToNVVM/LowerGpuOpsToNVVMOps.cpp
@@ -91,6 +91,8 @@ convertToNVVMReductionKind(gpu::AllReduceOperation mode) {
return NVVM::ReductionKind::XOR;
case gpu::AllReduceOperation::MINIMUMF:
case gpu::AllReduceOperation::MAXIMUMF:
+ case gpu::AllReduceOperation::MINIMUMNUMF:
+ case gpu::AllReduceOperation::MAXIMUMNUMF:
return std::nullopt;
}
return std::nullopt;
diff --git a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
index a39b43c9803eb9..4c29801c34220c 100644
--- a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
+++ b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
@@ -540,7 +540,8 @@ static LogicalResult verifyReduceOpAndType(gpu::AllReduceOperation opName,
Type resType) {
using Kind = gpu::AllReduceOperation;
if (llvm::is_contained(
- {Kind::MINNUMF, Kind::MAXNUMF, Kind::MINIMUMF, Kind::MAXIMUMF},
+ {Kind::MINNUMF, Kind::MAXNUMF, Kind::MINIMUMF, Kind::MAXIMUMF,
+ Kind::MINIMUMNUMF, Kind::MAXIMUMNUMF},
opName)) {
if (!isa<FloatType>(resType))
return failure();
diff --git a/mlir/lib/Dialect/GPU/Utils/Utils.cpp b/mlir/lib/Dialect/GPU/Utils/Utils.cpp
index 1f09875b3e2732..8edd1ae904b6b9 100644
--- a/mlir/lib/Dialect/GPU/Utils/Utils.cpp
+++ b/mlir/lib/Dialect/GPU/Utils/Utils.cpp
@@ -34,6 +34,8 @@ vector::CombiningKind convertReductionKind(gpu::AllReduceOperation mode) {
MAP_CASE(XOR);
MAP_CASE(MINIMUMF);
MAP_CASE(MAXIMUMF);
+ MAP_CASE(MINIMUMNUMF);
+ MAP_CASE(MAXIMUMNUMF);
#undef MAP_CASE
}
diff --git a/mlir/test/Dialect/GPU/all-reduce-minmaxnumf.mlir b/mlir/test/Dialect/GPU/all-reduce-minmaxnumf.mlir
new file mode 100644
index 00000000000000..7ee88d38ffd4fa
--- /dev/null
+++ b/mlir/test/Dialect/GPU/all-reduce-minmaxnumf.mlir
@@ -0,0 +1,21 @@
+// RUN: mlir-opt --convert-gpu-to-nvvm %s | FileCheck %s
+
+gpu.module @kernels {
+ // CHECK-LABEL: llvm.func @minimum_number
+ // CHECK: llvm.intr.minimumnum
+ // CHECK: llvm.return
+ gpu.func @minimum_number(%arg0 : f32, %out : memref<f32>) kernel {
+ %result = gpu.all_reduce minimumnumf %arg0 uniform {} : (f32) -> f32
+ memref.store %result, %out[] : memref<f32>
+ gpu.return
+ }
+
+ // CHECK-LABEL: llvm.func @maximum_number
+ // CHECK: llvm.intr.maximumnum
+ // CHECK: llvm.return
+ gpu.func @maximum_number(%arg0 : f32, %out : memref<f32>) kernel {
+ %result = gpu.all_reduce maximumnumf %arg0 uniform {} : (f32) -> f32
+ memref.store %result, %out[] : memref<f32>
+ gpu.return
+ }
+}
diff --git a/mlir/test/Dialect/GPU/invalid.mlir b/mlir/test/Dialect/GPU/invalid.mlir
index 1b6d3a41d2bd09..7d352506209ffa 100644
--- a/mlir/test/Dialect/GPU/invalid.mlir
+++ b/mlir/test/Dialect/GPU/invalid.mlir
@@ -473,6 +473,22 @@ func.func @reduce_invalid_op_type_minimumf(%arg0 : i32) {
// -----
+func.func @reduce_invalid_op_type_minimumnumf(%arg0 : i32) {
+ // expected-error at +1 {{`minimumnumf` reduction operation is not compatible with type 'i32'}}
+ %res = gpu.all_reduce minimumnumf %arg0 {} : (i32) -> (i32)
+ return
+}
+
+// -----
+
+func.func @reduce_invalid_op_type_maximumnumf(%arg0 : i32) {
+ // expected-error at +1 {{`maximumnumf` reduction operation is not compatible with type 'i32'}}
+ %res = gpu.all_reduce maximumnumf %arg0 {} : (i32) -> (i32)
+ return
+}
+
+// -----
+
func.func @reduce_invalid_op_type_maximumf(%arg0 : i32) {
// expected-error at +1 {{`maximumf` reduction operation is not compatible with type 'i32'}}
%res = gpu.all_reduce maximumf %arg0 {} : (i32) -> (i32)
@@ -546,6 +562,22 @@ func.func @subgroup_reduce_invalid_op_type_maxnumf(%arg0 : i32) {
// -----
+func.func @subgroup_reduce_invalid_op_type_minimumnumf(%arg0 : i32) {
+ // expected-error at +1 {{`minimumnumf` reduction operation is not compatible with type 'i32'}}
+ %res = gpu.subgroup_reduce minimumnumf %arg0 : (i32) -> (i32)
+ return
+}
+
+// -----
+
+func.func @subgroup_reduce_invalid_op_type_maximumnumf(%arg0 : vector<2xi32>) {
+ // expected-error at +1 {{`maximumnumf` reduction operation is not compatible with type 'vector<2xi32>'}}
+ %res = gpu.subgroup_reduce maximumnumf %arg0 : (vector<2xi32>) -> vector<2xi32>
+ return
+}
+
+// -----
+
func.func @reduce_incorrect_region_arguments(%arg0 : f32) {
// expected-error at +1 {{expected two region arguments}}
%res = gpu.all_reduce %arg0 {
diff --git a/mlir/test/Dialect/GPU/subgroup-reduce-lowering.mlir b/mlir/test/Dialect/GPU/subgroup-reduce-lowering.mlir
index ed69a60de85bc2..4d9fa23c3c2e1b 100644
--- a/mlir/test/Dialect/GPU/subgroup-reduce-lowering.mlir
+++ b/mlir/test/Dialect/GPU/subgroup-reduce-lowering.mlir
@@ -20,6 +20,30 @@
// CHECK-GFX10: gpu.module @kernels {
gpu.module @kernels {
+ // CHECK-SUB-LABEL: gpu.func @minimum_number
+ // CHECK-SUB: gpu.subgroup_reduce minimumnumf
+ // CHECK-SHFL-LABEL: gpu.func @minimum_number
+ // CHECK-SHFL: arith.minimumnumf
+ // CHECK-GFX-LABEL: gpu.func @minimum_number
+ // CHECK-GFX: arith.minimumnumf
+ gpu.func @minimum_number(%arg0: f32) kernel {
+ %result = gpu.subgroup_reduce minimumnumf %arg0 : (f32) -> f32
+ "test.consume"(%result) : (f32) -> ()
+ gpu.return
+ }
+
+ // CHECK-SUB-LABEL: gpu.func @maximum_number
+ // CHECK-SUB: gpu.subgroup_reduce maximumnumf
+ // CHECK-SHFL-LABEL: gpu.func @maximum_number
+ // CHECK-SHFL: arith.maximumnumf
+ // CHECK-GFX-LABEL: gpu.func @maximum_number
+ // CHECK-GFX: arith.maximumnumf
+ gpu.func @maximum_number(%arg0: vector<2xf32>) kernel {
+ %result = gpu.subgroup_reduce maximumnumf %arg0 : (vector<2xf32>) -> vector<2xf32>
+ "test.consume"(%result) : (vector<2xf32>) -> ()
+ gpu.return
+ }
+
// CHECK-SUB-LABEL: gpu.func @kernel0(
// CHECK-SUB-SAME: %[[ARG0:.+]]: vector<5xf16>)
//
More information about the Mlir-commits
mailing list