[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