[Mlir-commits] [mlir] e6c20ad - [mlir][gpu][math] Fix assertion in OpToFuncCallLowering on vector results (#215317)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Aug 31 02:08:26 PDT 2026


Author: SeongJaePark
Date: 2026-08-31T11:08:22+02:00
New Revision: e6c20ada052d34166da21bdb40f79a4e177bc115

URL: https://github.com/llvm/llvm-project/commit/e6c20ada052d34166da21bdb40f79a4e177bc115
DIFF: https://github.com/llvm/llvm-project/commit/e6c20ada052d34166da21bdb40f79a4e177bc115.diff

LOG: [mlir][gpu][math] Fix assertion in OpToFuncCallLowering on vector results (#215317)

`OpToFuncCallLowering` asserts that operand and result types match, with
an escape hatch for scalar `i1` results. Math vector FP classification ops
return `vector<...xi1>`, which the escape hatch does not cover, so they trigger
the assertion.

Reject non-scalar results before the assertion, allowing
`ScalarizeVectorOpLowering` to lower them element-wise. This preserves
the existing behavior in non-assert builds, where `OpToFuncCallLowering`
already failed to match vector types. Add regression coverage for vector and
scalar FP classification ops.

Fixes #210855

Assisted-by: Claude (Anthropic)

Added: 
    mlir/test/Conversion/MathToNVVM/math-to-nvvm.mlir

Modified: 
    mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h b/mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h
index cb9b6da071839..ea6d7c9f2da1d 100644
--- a/mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h
+++ b/mlir/lib/Conversion/GPUCommon/OpToFuncCallLowering.h
@@ -72,7 +72,15 @@ struct OpToFuncCallLowering : public ConvertOpToLLVMPattern<SourceOp> {
         std::is_base_of<OpTrait::OneResult<SourceOp>, SourceOp>::value,
         "expected single result op");
 
-    bool isResultBool = op->getResultTypes().front().isInteger(1);
+    // This pattern only handles scalar ops. Ops with shaped (e.g. vector)
+    // result types, such as `math.isinf` on `vector<Nxf32>`, are expected to be
+    // scalarized first by `ScalarizeVectorOpLowering`, which is co-registered
+    // for these ops; bail out so that pattern can take over.
+    Type opResultType = op->getResultTypes().front();
+    if (!opResultType.isIntOrIndexOrFloat())
+      return rewriter.notifyMatchFailure(op, "expected scalar result type");
+
+    bool isResultBool = opResultType.isInteger(1);
     if constexpr (!std::is_base_of<OpTrait::SameOperandsAndResultType<SourceOp>,
                                    SourceOp>::value) {
       assert(op->getNumOperands() > 0 &&

diff  --git a/mlir/test/Conversion/MathToNVVM/math-to-nvvm.mlir b/mlir/test/Conversion/MathToNVVM/math-to-nvvm.mlir
new file mode 100644
index 0000000000000..ac14ab15fd80c
--- /dev/null
+++ b/mlir/test/Conversion/MathToNVVM/math-to-nvvm.mlir
@@ -0,0 +1,29 @@
+// RUN: mlir-opt %s -convert-math-to-nvvm | FileCheck %s
+
+// Classification ops return a bool, so their operand and result types 
diff er.
+// On shaped operands `OpToFuncCallLowering` bails out and `ScalarizeVectorOpLowering`
+// unrolls them element-wise, lowering each element to a libdevice call.
+
+// CHECK-LABEL:   func.func @fpclass_vector(
+// CHECK-SAME:                              %[[ARG:.*]]: vector<2xf32>)
+func.func @fpclass_vector(%arg: vector<2xf32>) -> (vector<2xi1>, vector<2xi1>, vector<2xi1>) {
+  // CHECK-COUNT-2: llvm.call @__nv_isinff({{.*}}) : (f32) -> i32
+  %inf = math.isinf %arg : vector<2xf32>
+  // CHECK-COUNT-2: llvm.call @__nv_finitef({{.*}}) : (f32) -> i32
+  %finite = math.isfinite %arg : vector<2xf32>
+  // CHECK-COUNT-2: llvm.call @__nv_isnanf({{.*}}) : (f32) -> i32
+  %nan = math.isnan %arg : vector<2xf32>
+  return %inf, %finite, %nan : vector<2xi1>, vector<2xi1>, vector<2xi1>
+}
+
+// CHECK-LABEL:   func.func @fpclass_scalar(
+func.func @fpclass_scalar(%arg: f32) -> (i1, i1, i1) {
+  // CHECK: %[[INF:.*]] = llvm.call @__nv_isinff({{.*}}) : (f32) -> i32
+  // CHECK: llvm.icmp "ne" %[[INF]], {{.*}} : i32
+  %inf = math.isinf %arg : f32
+  // CHECK: llvm.call @__nv_finitef({{.*}}) : (f32) -> i32
+  %finite = math.isfinite %arg : f32
+  // CHECK: llvm.call @__nv_isnanf({{.*}}) : (f32) -> i32
+  %nan = math.isnan %arg : f32
+  return %inf, %finite, %nan : i1, i1, i1
+}


        


More information about the Mlir-commits mailing list