[flang-commits] [flang] [flang]- Fix for IEEE_IS_NAN sets IEEE_INVALID after inspecting a sNaN (PR #205276)
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 23 02:19:29 PDT 2026
https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/205276
>From 5d45dd17d83f20a8a593add5b047e79722a0f0db Mon Sep 17 00:00:00 2001
From: ejose02 <ejose at amd.com>
Date: Tue, 23 Jun 2026 12:51:54 +0530
Subject: [PATCH] [flang]- Fix for IEEE_IS_NAN sets IEEE_INVALID after
inspecting a sNaN
Fixes #203818
Root cause
IEEE_IS_NAN was lowered through genIsFPClass to llvm.intr.is.fpclass, which inspects the operand on a floating-point class path that could set IEEE_INVALID when the argument is a signaling NaN on the affected configuration.
Fix
Stop using the llvm.intr.is.fpclass intrinsic path for this predicate and instead classify NaNs from the raw IEEE layout with arith.bitcast to an integer type and bit masks, including the x87 extended-real case where infinity uses a nonzero significand pattern.
---
flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 37 ++++++++++++++++-
.../Lower/Intrinsics/ieee_class_queries.f90 | 10 ++---
flang/test/Lower/Intrinsics/isnan.f90 | 40 +++++++++++--------
3 files changed, 65 insertions(+), 22 deletions(-)
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 04f7741adf943..7474e6b3f72f7 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5333,7 +5333,42 @@ mlir::Value IntrinsicLibrary::genIeeeIsNan(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
// Check if arg X is a (signaling or quiet) NaN.
assert(args.size() == 1);
- return genIsFPClass(resultType, args, nanTest);
+ auto ft = mlir::cast<mlir::FloatType>(args[0].getType());
+ const llvm::fltSemantics &sem = ft.getFloatSemantics();
+ const unsigned w = llvm::APFloatBase::semanticsSizeInBits(sem);
+ const auto sk = llvm::APFloatBase::SemanticsToEnum(sem);
+ const unsigned t = sk == llvm::APFloatBase::S_x87DoubleExtended
+ ? 64u
+ : llvm::APFloatBase::semanticsPrecision(sem) - 1u;
+ const unsigned e = w - 1u - t;
+ mlir::Type iTy = builder.getIntegerType(w);
+ mlir::Value u = mlir::arith::BitcastOp::create(builder, loc, iTy, args[0]);
+ mlir::Value eM = mlir::arith::ConstantOp::create(
+ builder, loc, iTy,
+ builder.getIntegerAttr(iTy, llvm::APInt::getBitsSet(w, t, t + e)));
+ mlir::Value sM = mlir::arith::ConstantOp::create(
+ builder, loc, iTy,
+ builder.getIntegerAttr(iTy, llvm::APInt::getLowBitsSet(w, t)));
+ mlir::Value ex = mlir::arith::AndIOp::create(builder, loc, u, eM);
+ mlir::Value exAll1 = mlir::arith::CmpIOp::create(
+ builder, loc, mlir::arith::CmpIPredicate::eq, ex, eM);
+ mlir::Value sg = mlir::arith::AndIOp::create(builder, loc, u, sM);
+ mlir::Value isNan;
+ if (sk == llvm::APFloatBase::S_x87DoubleExtended) {
+ llvm::APInt x87InfSig(w, 0);
+ x87InfSig.setBit(63);
+ mlir::Value notInf = mlir::arith::CmpIOp::create(
+ builder, loc, mlir::arith::CmpIPredicate::ne, sg,
+ mlir::arith::ConstantOp::create(
+ builder, loc, iTy, builder.getIntegerAttr(iTy, x87InfSig)));
+ isNan = mlir::arith::AndIOp::create(builder, loc, exAll1, notInf);
+ } else {
+ mlir::Value notZero = mlir::arith::CmpIOp::create(
+ builder, loc, mlir::arith::CmpIPredicate::ne, sg,
+ builder.createIntegerConstant(loc, iTy, 0));
+ isNan = mlir::arith::AndIOp::create(builder, loc, exAll1, notZero);
+ }
+ return builder.createConvert(loc, resultType, isNan);
}
// IEEE_IS_NEGATIVE
diff --git a/flang/test/Lower/Intrinsics/ieee_class_queries.f90 b/flang/test/Lower/Intrinsics/ieee_class_queries.f90
index 8d20ff8f3178f..f42e523341184 100644
--- a/flang/test/Lower/Intrinsics/ieee_class_queries.f90
+++ b/flang/test/Lower/Intrinsics/ieee_class_queries.f90
@@ -14,35 +14,35 @@
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 504 : i32}> : (f16) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 60 : i32}> : (f16) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 360 : i32}> : (f16) -> i1
- ! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f16) -> i1
+ ! CHECK: arith.bitcast %{{.*}} : f16 to i16
print*, ieee_is_finite(x2), ieee_is_negative(x2), ieee_is_normal(x2), &
ieee_is_nan(x2)
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 504 : i32}> : (bf16) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 60 : i32}> : (bf16) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 360 : i32}> : (bf16) -> i1
- ! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (bf16) -> i1
+ ! CHECK: arith.bitcast %{{.*}} : bf16 to i16
print*, ieee_is_finite(x3), ieee_is_negative(x3), ieee_is_normal(x3), &
ieee_is_nan(x3)
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 504 : i32}> : (f32) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 60 : i32}> : (f32) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 360 : i32}> : (f32) -> i1
- ! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
+ ! CHECK: arith.bitcast %{{.*}} : f32 to i32
print*, ieee_is_finite(x4), ieee_is_negative(x4), ieee_is_normal(x4), &
ieee_is_nan(x4)
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 504 : i32}> : (f64) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 60 : i32}> : (f64) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 360 : i32}> : (f64) -> i1
- ! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
+ ! CHECK: arith.bitcast %{{.*}} : f64 to i64
print*, ieee_is_finite(x8), ieee_is_negative(x8), ieee_is_normal(x8), &
ieee_is_nan(x8)
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 504 : i32}> : (f128) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 60 : i32}> : (f128) -> i1
! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 360 : i32}> : (f128) -> i1
- ! CHECK: "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
+ ! CHECK: arith.bitcast %{{.*}} : f128 to i128
print*, ieee_is_finite(x16), ieee_is_negative(x16), ieee_is_normal(x16), &
ieee_is_nan(x16)
diff --git a/flang/test/Lower/Intrinsics/isnan.f90 b/flang/test/Lower/Intrinsics/isnan.f90
index 6535724b2ce3b..b26ff3bec58c0 100644
--- a/flang/test/Lower/Intrinsics/isnan.f90
+++ b/flang/test/Lower/Intrinsics/isnan.f90
@@ -4,8 +4,9 @@
subroutine isnan_f32(r)
real :: r
i = isnan(r)
- ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
- ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK: arith.bitcast %{{.*}} : f32 to i32
+ ! CHECK-NOT: llvm.intr.is.fpclass
+ ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine isnan_f32
! CHECK-LABEL: ieee_is_nan_f32
@@ -13,16 +14,18 @@ subroutine ieee_is_nan_f32(r)
use ieee_arithmetic
real :: r
i = ieee_is_nan(r)
- ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
- ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK: arith.bitcast %{{.*}} : f32 to i32
+ ! CHECK-NOT: llvm.intr.is.fpclass
+ ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine ieee_is_nan_f32
! CHECK-LABEL: isnan_f64
subroutine isnan_f64(r)
real(KIND=8) :: r
i = isnan(r)
- ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
- ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK: arith.bitcast %{{.*}} : f64 to i64
+ ! CHECK-NOT: llvm.intr.is.fpclass
+ ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine isnan_f64
! CHECK-LABEL: ieee_is_nan_f64
@@ -30,8 +33,9 @@ subroutine ieee_is_nan_f64(r)
use ieee_arithmetic
real(KIND=8) :: r
i = ieee_is_nan(r)
- ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
- ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK: arith.bitcast %{{.*}} : f64 to i64
+ ! CHECK-NOT: llvm.intr.is.fpclass
+ ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine ieee_is_nan_f64
! CHECK-KIND10-LABEL: isnan_f80
@@ -39,8 +43,9 @@ subroutine isnan_f80(r)
integer, parameter :: kind10 = merge(10, 4, selected_real_kind(p=18).eq.10)
real(KIND=kind10) :: r
i = isnan(r)
- ! CHECK-KIND10: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f80) -> i1
- ! CHECK-KIND10: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK-KIND10: arith.bitcast %{{.*}} : f80 to i80
+ ! CHECK-KIND10-NOT: llvm.intr.is.fpclass
+ ! CHECK-KIND10: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine isnan_f80
! CHECK-KIND10-LABEL: ieee_is_nan_f80
@@ -49,8 +54,9 @@ subroutine ieee_is_nan_f80(r)
integer, parameter :: kind10 = merge(10, 4, selected_real_kind(p=18).eq.10)
real(KIND=kind10) :: r
i = ieee_is_nan(r)
- ! CHECK-KIND10: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f80) -> i1
- ! CHECK-KIND10: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK-KIND10: arith.bitcast %{{.*}} : f80 to i80
+ ! CHECK-KIND10-NOT: llvm.intr.is.fpclass
+ ! CHECK-KIND10: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine ieee_is_nan_f80
! CHECK-KIND16-LABEL: isnan_f128
@@ -58,8 +64,9 @@ subroutine isnan_f128(r)
integer, parameter :: kind16 = merge(16, 4, selected_real_kind(p=33).eq.16)
real(KIND=kind16) :: r
i = isnan(r)
- ! CHECK-KIND16: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
- ! CHECK-KIND16: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK-KIND16: arith.bitcast %{{.*}} : f128 to i128
+ ! CHECK-KIND16-NOT: llvm.intr.is.fpclass
+ ! CHECK-KIND16: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine isnan_f128
! CHECK-KIND16-LABEL: ieee_is_nan_f128
@@ -68,6 +75,7 @@ subroutine ieee_is_nan_f128(r)
integer, parameter :: kind16 = merge(16, 4, selected_real_kind(p=33).eq.16)
real(KIND=kind16) :: r
i = ieee_is_nan(r)
- ! CHECK-KIND16: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
- ! CHECK-KIND16: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+ ! CHECK-KIND16: arith.bitcast %{{.*}} : f128 to i128
+ ! CHECK-KIND16-NOT: llvm.intr.is.fpclass
+ ! CHECK-KIND16: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
end subroutine ieee_is_nan_f128
More information about the flang-commits
mailing list