[Mlir-commits] [mlir] [mlir][arith] Fix crash when constant-folding truncf of inf to FiniteOnly float type (PR #186191)

Mehdi Amini llvmlistbot at llvm.org
Thu Mar 12 10:24:27 PDT 2026


https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/186191

When arith.truncf constant-folding converts a value such as infinity to a type with fltNonfiniteBehavior::FiniteOnly (e.g. f4E2M1FN), APFloat::convert hits an llvm_unreachable("semantics don't support inf\!").

The fix adds early-exit guards in convertFloatValue() to return failure() before calling APFloat::convert() when the source value is infinity or NaN and the target type cannot represent it. This makes the fold a no-op for unrepresentable special values, matching the existing behavior for lossy ordinary conversions.

Fixes #185351

Assisted-by: Claude Code

>From 493df390f96e946e53915e25b48cc88f361b62b3 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Mon, 9 Mar 2026 04:21:17 -0700
Subject: [PATCH] [mlir][arith] Fix crash when constant-folding truncf of inf
 to FiniteOnly float type

When arith.truncf constant-folding converts a value such as infinity
to a type with fltNonfiniteBehavior::FiniteOnly (e.g. f4E2M1FN),
APFloat::convert hits an llvm_unreachable("semantics don't support inf\!").

The fix adds early-exit guards in convertFloatValue() to return failure()
before calling APFloat::convert() when the source value is infinity or NaN
and the target type cannot represent it. This makes the fold a no-op for
unrepresentable special values, matching the existing behavior for lossy
ordinary conversions.

Fixes #185351

Assisted-by: Claude Code
---
 mlir/lib/Dialect/Arith/IR/ArithOps.cpp    | 11 ++++++++++
 mlir/test/Dialect/Arith/canonicalize.mlir | 26 +++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
index 6f368604df65a..d6a98a667da32 100644
--- a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
@@ -1451,6 +1451,17 @@ static bool checkWidthChangeCast(TypeRange inputs, TypeRange outputs) {
 static FailureOr<APFloat> convertFloatValue(
     APFloat sourceValue, const llvm::fltSemantics &targetSemantics,
     llvm::RoundingMode roundingMode = llvm::RoundingMode::NearestTiesToEven) {
+  // Reject special values that are not representable in the target type before
+  // calling APFloat::convert, which would llvm_unreachable on them.
+  using fltNonfiniteBehavior = llvm::fltNonfiniteBehavior;
+  if (sourceValue.isInfinity() &&
+      (targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::NanOnly ||
+       targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly))
+    return failure();
+  if (sourceValue.isNaN() &&
+      targetSemantics.nonFiniteBehavior == fltNonfiniteBehavior::FiniteOnly)
+    return failure();
+
   bool losesInfo = false;
   auto status = sourceValue.convert(targetSemantics, roundingMode, &losesInfo);
   if (losesInfo || status != APFloat::opOK)
diff --git a/mlir/test/Dialect/Arith/canonicalize.mlir b/mlir/test/Dialect/Arith/canonicalize.mlir
index 26b04e4209a43..643e4e076e7c6 100644
--- a/mlir/test/Dialect/Arith/canonicalize.mlir
+++ b/mlir/test/Dialect/Arith/canonicalize.mlir
@@ -3527,3 +3527,29 @@ func.func @cmpi_dynamic_shape_no_fold(%arg0: tensor<?xi32>) -> tensor<?xi1> {
   return %0 : tensor<?xi1>
 }
 
+// -----
+
+// arith.truncf of infinity to a FiniteOnly float type (f4E2M1FN) must not fold,
+// since the type has no infinity representation. Previously this would crash
+// inside APFloat::convert with llvm_unreachable("semantics don't support inf!").
+
+// CHECK-LABEL: @truncf_inf_to_finite_only_no_fold
+//       CHECK:   arith.truncf
+func.func @truncf_inf_to_finite_only_no_fold() -> f4E2M1FN {
+  %inf = arith.constant 0x7F800000 : f32
+  %result = arith.truncf %inf : f32 to f4E2M1FN
+  return %result : f4E2M1FN
+}
+
+// -----
+
+// arith.truncf of negative infinity to a FiniteOnly float type must not fold.
+
+// CHECK-LABEL: @truncf_neg_inf_to_finite_only_no_fold
+//       CHECK:   arith.truncf
+func.func @truncf_neg_inf_to_finite_only_no_fold() -> f4E2M1FN {
+  %neg_inf = arith.constant 0xFF800000 : f32
+  %result = arith.truncf %neg_inf : f32 to f4E2M1FN
+  return %result : f4E2M1FN
+}
+



More information about the Mlir-commits mailing list