[flang-commits] [flang] [llvm] [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 Aug 11 04:40:40 PDT 2026


https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/205276

>From f61fc3d16452a8a1e2bdadb2793fe79a82aa8850 Mon Sep 17 00:00:00 2001
From: ejose02 <ejose at amd.com>
Date: Tue, 23 Jun 2026 12:51:54 +0530
Subject: [PATCH 1/2] [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 6987092ea921d..dfad1495c335c 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5370,7 +5370,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

>From 797e2ecb00e668c17d534b05f8ed2dd318da1e57 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Tue, 11 Aug 2026 11:37:00 +0000
Subject: [PATCH 2/2] The IEEE_INVALID issue on signaling NaN is fixed in
 expandIS_FPCLASS by avoiding FP compares for fcNan. Restore genIeeeIsNan to
 lower via genIsFPClass/llvm.intr.is.fpclass and updated FileCheck tests.

---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp |  37 +---
 .../Lower/Intrinsics/ieee_class_queries.f90   |  10 +-
 flang/test/Lower/Intrinsics/isnan.f90         |  40 ++--
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |   6 -
 llvm/test/CodeGen/X86/is_fpclass.ll           | 194 +++++++++---------
 5 files changed, 122 insertions(+), 165 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index dfad1495c335c..6987092ea921d 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -5370,42 +5370,7 @@ 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);
-  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);
+  return genIsFPClass(resultType, args, nanTest);
 }
 
 // IEEE_IS_NEGATIVE
diff --git a/flang/test/Lower/Intrinsics/ieee_class_queries.f90 b/flang/test/Lower/Intrinsics/ieee_class_queries.f90
index f42e523341184..8d20ff8f3178f 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:     arith.bitcast %{{.*}} : f16 to i16
+  ! CHECK:     "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f16) -> i1
   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:     arith.bitcast %{{.*}} : bf16 to i16
+  ! CHECK:     "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (bf16) -> i1
   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:     arith.bitcast %{{.*}} : f32 to i32
+  ! CHECK:     "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
   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:     arith.bitcast %{{.*}} : f64 to i64
+  ! CHECK:     "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
   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:     arith.bitcast %{{.*}} : f128 to i128
+  ! CHECK:     "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
   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 b26ff3bec58c0..6535724b2ce3b 100644
--- a/flang/test/Lower/Intrinsics/isnan.f90
+++ b/flang/test/Lower/Intrinsics/isnan.f90
@@ -4,9 +4,8 @@
 subroutine isnan_f32(r)
   real :: r
   i = isnan(r)
-  ! CHECK: arith.bitcast %{{.*}} : f32 to i32
-  ! CHECK-NOT: llvm.intr.is.fpclass
-  ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine isnan_f32
 
 ! CHECK-LABEL: ieee_is_nan_f32
@@ -14,18 +13,16 @@ subroutine ieee_is_nan_f32(r)
   use ieee_arithmetic
   real :: r
   i = ieee_is_nan(r)
-  ! CHECK: arith.bitcast %{{.*}} : f32 to i32
-  ! CHECK-NOT: llvm.intr.is.fpclass
-  ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f32) -> i1
+  ! CHECK: fir.convert %[[l]] : (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: arith.bitcast %{{.*}} : f64 to i64
-  ! CHECK-NOT: llvm.intr.is.fpclass
-  ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine isnan_f64
 
 ! CHECK-LABEL: ieee_is_nan_f64
@@ -33,9 +30,8 @@ subroutine ieee_is_nan_f64(r)
   use ieee_arithmetic
   real(KIND=8) :: r
   i = ieee_is_nan(r)
-  ! CHECK: arith.bitcast %{{.*}} : f64 to i64
-  ! CHECK-NOT: llvm.intr.is.fpclass
-  ! CHECK: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f64) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine ieee_is_nan_f64
 
 ! CHECK-KIND10-LABEL: isnan_f80
@@ -43,9 +39,8 @@ 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: arith.bitcast %{{.*}} : f80 to i80
-  ! CHECK-KIND10-NOT: llvm.intr.is.fpclass
-  ! CHECK-KIND10: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK-KIND10: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f80) -> i1
+  ! CHECK-KIND10: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine isnan_f80
 
 ! CHECK-KIND10-LABEL: ieee_is_nan_f80
@@ -54,9 +49,8 @@ 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: arith.bitcast %{{.*}} : f80 to i80
-  ! CHECK-KIND10-NOT: llvm.intr.is.fpclass
-  ! CHECK-KIND10: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK-KIND10: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f80) -> i1
+  ! CHECK-KIND10: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine ieee_is_nan_f80
 
 ! CHECK-KIND16-LABEL: isnan_f128
@@ -64,9 +58,8 @@ 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: arith.bitcast %{{.*}} : f128 to i128
-  ! CHECK-KIND16-NOT: llvm.intr.is.fpclass
-  ! CHECK-KIND16: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK-KIND16: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
+  ! CHECK-KIND16: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine isnan_f128
 
 ! CHECK-KIND16-LABEL: ieee_is_nan_f128
@@ -75,7 +68,6 @@ 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: arith.bitcast %{{.*}} : f128 to i128
-  ! CHECK-KIND16-NOT: llvm.intr.is.fpclass
-  ! CHECK-KIND16: fir.convert %{{.*}} : (i1) -> !fir.logical<4>
+  ! CHECK-KIND16: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}) <{bit = 3 : i32}> : (f128) -> i1
+  ! CHECK-KIND16: fir.convert %[[l]] : (i1) -> !fir.logical<4>
 end subroutine ieee_is_nan_f128
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 6f47bf1b81c57..4d1ae1cd7b686 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -10447,12 +10447,6 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
                           *IsCmp0 ? OrderedCmpOpcode : UnorderedCmpOpcode);
     }
 
-    if (FPTestMask == fcNan &&
-        isCondCodeLegalOrCustom(IsInvertedFP ? ISD::SETO : ISD::SETUO,
-                                OperandVT.getScalarType().getSimpleVT()))
-      return DAG.getSetCC(DL, ResultVT, Op, Op,
-                          IsInvertedFP ? ISD::SETO : ISD::SETUO);
-
     bool IsOrderedInf = FPTestMask == fcInf;
     if ((FPTestMask == fcInf || FPTestMask == (fcInf | fcNan)) &&
         isCondCodeLegalOrCustom(IsOrderedInf ? OrderedCmpOpcode
diff --git a/llvm/test/CodeGen/X86/is_fpclass.ll b/llvm/test/CodeGen/X86/is_fpclass.ll
index 9b9732f433ace..25e0411f8f190 100644
--- a/llvm/test/CodeGen/X86/is_fpclass.ll
+++ b/llvm/test/CodeGen/X86/is_fpclass.ll
@@ -6,18 +6,18 @@
 define i1 @isnan_f(float %x) {
 ; X86-LABEL: isnan_f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %al
+; X86-NEXT:    movl $2147483647, %eax # imm = 0x7FFFFFFF
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X86-NEXT:    setge %al
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: isnan_f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    ucomiss %xmm0, %xmm0
-; X64-NEXT:    setp %al
+; X64-NEXT:    movd %xmm0, %eax
+; X64-NEXT:    andl $2147483647, %eax # imm = 0x7FFFFFFF
+; X64-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X64-NEXT:    setge %al
 ; X64-NEXT:    retq
 entry:
   %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 3)  ; "nan"
@@ -27,18 +27,18 @@ entry:
 define i1 @isnot_nan_f(float %x) {
 ; X86-LABEL: isnot_nan_f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %al
+; X86-NEXT:    movl $2147483647, %eax # imm = 0x7FFFFFFF
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X86-NEXT:    setl %al
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: isnot_nan_f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    ucomiss %xmm0, %xmm0
-; X64-NEXT:    setnp %al
+; X64-NEXT:    movd %xmm0, %eax
+; X64-NEXT:    andl $2147483647, %eax # imm = 0x7FFFFFFF
+; X64-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X64-NEXT:    setl %al
 ; X64-NEXT:    retq
 entry:
   %0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 1020)  ; 0x3fc = "zero|subnormal|normal|inf"
@@ -1095,19 +1095,34 @@ entry:
 define i1 @isnan_d(double %x) {
 ; X86-LABEL: isnan_d:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    fldl {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %al
+; X86-NEXT:    movl $2147483647, %eax # imm = 0x7FFFFFFF
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    cmpl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl $2146435072, %ecx # imm = 0x7FF00000
+; X86-NEXT:    sbbl %eax, %ecx
+; X86-NEXT:    setl %al
 ; X86-NEXT:    retl
 ;
-; X64-LABEL: isnan_d:
-; X64:       # %bb.0: # %entry
-; X64-NEXT:    ucomisd %xmm0, %xmm0
-; X64-NEXT:    setp %al
-; X64-NEXT:    retq
+; X64-GENERIC-LABEL: isnan_d:
+; X64-GENERIC:       # %bb.0: # %entry
+; X64-GENERIC-NEXT:    movq %xmm0, %rax
+; X64-GENERIC-NEXT:    movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; X64-GENERIC-NEXT:    andq %rax, %rcx
+; X64-GENERIC-NEXT:    movabsq $9218868437227405312, %rax # imm = 0x7FF0000000000000
+; X64-GENERIC-NEXT:    cmpq %rax, %rcx
+; X64-GENERIC-NEXT:    setg %al
+; X64-GENERIC-NEXT:    retq
+;
+; X64-NDD-LABEL: isnan_d:
+; X64-NDD:       # %bb.0: # %entry
+; X64-NDD-NEXT:    movq %xmm0, %rax
+; X64-NDD-NEXT:    movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF
+; X64-NDD-NEXT:    andq %rcx, %rax
+; X64-NDD-NEXT:    movabsq $9218868437227405312, %rcx # imm = 0x7FF0000000000000
+; X64-NDD-NEXT:    cmpq %rcx, %rax
+; X64-NDD-NEXT:    setg %al
+; X64-NDD-NEXT:    retq
 entry:
   %0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 3)  ; "nan"
   ret i1 %0
@@ -1411,18 +1426,18 @@ entry:
 define <1 x i1> @isnan_v1f(<1 x float> %x) {
 ; X86-LABEL: isnan_v1f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %al
+; X86-NEXT:    movl $2147483647, %eax # imm = 0x7FFFFFFF
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X86-NEXT:    setge %al
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: isnan_v1f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    ucomiss %xmm0, %xmm0
-; X64-NEXT:    setp %al
+; X64-NEXT:    movd %xmm0, %eax
+; X64-NEXT:    andl $2147483647, %eax # imm = 0x7FFFFFFF
+; X64-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X64-NEXT:    setge %al
 ; X64-NEXT:    retq
 entry:
   %0 = tail call <1 x i1> @llvm.is.fpclass.v1f32(<1 x float> %x, i32 3)  ; "nan"
@@ -1453,25 +1468,21 @@ entry:
 define <2 x i1> @isnan_v2f(<2 x float> %x) {
 ; X86-LABEL: isnan_v2f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %cl
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %dl
-; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    andl %ecx, %eax
+; X86-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X86-NEXT:    setge %al
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    cmpl $2139095041, %ecx # imm = 0x7F800001
+; X86-NEXT:    setge %dl
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: isnan_v2f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    cmpunordps %xmm0, %xmm0
 ; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[0,1,1,3]
+; X64-NEXT:    andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    pcmpgtd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
 ; X64-NEXT:    retq
 entry:
   %0 = tail call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 3)  ; "nan"
@@ -1482,25 +1493,23 @@ entry:
 define <2 x i1> @isnot_nan_v2f(<2 x float> %x) {
 ; X86-LABEL: isnot_nan_v2f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %cl
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setnp %dl
-; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    andl %ecx, %eax
+; X86-NEXT:    cmpl $2139095041, %eax # imm = 0x7F800001
+; X86-NEXT:    setl %al
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    cmpl $2139095041, %ecx # imm = 0x7F800001
+; X86-NEXT:    setl %dl
 ; X86-NEXT:    retl
 ;
 ; X64-LABEL: isnot_nan_v2f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    cmpordps %xmm0, %xmm0
 ; X64-NEXT:    shufps {{.*#+}} xmm0 = xmm0[0,1,1,3]
+; X64-NEXT:    andps {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    movdqa {{.*#+}} xmm1 = [2139095041,2139095041,2139095041,u]
+; X64-NEXT:    pcmpgtd %xmm0, %xmm1
+; X64-NEXT:    movdqa %xmm1, %xmm0
 ; X64-NEXT:    retq
 entry:
   %0 = tail call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 1020)  ; 0x3fc = "zero|subnormal|normal|inf"
@@ -1534,44 +1543,41 @@ entry:
 define <4 x i1> @isnan_v4f(<4 x float> %x) {
 ; X86-LABEL: isnan_v4f:
 ; X86:       # %bb.0: # %entry
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    flds {{[0-9]+}}(%esp)
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %dh
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    .cfi_def_cfa_offset 8
+; X86-NEXT:    .cfi_offset %esi, -8
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl $2147483647, %ecx # imm = 0x7FFFFFFF
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT:    andl %ecx, %edx
+; X86-NEXT:    cmpl $2139095041, %edx # imm = 0x7F800001
+; X86-NEXT:    setge %dh
 ; X86-NEXT:    shlb $2, %dh
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %dl
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    andl %ecx, %esi
+; X86-NEXT:    cmpl $2139095041, %esi # imm = 0x7F800001
+; X86-NEXT:    setge %dl
 ; X86-NEXT:    shlb $3, %dl
 ; X86-NEXT:    orb %dh, %dl
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %dh
-; X86-NEXT:    fucomp %st(0)
-; X86-NEXT:    fnstsw %ax
-; X86-NEXT:    # kill: def $ah killed $ah killed $ax
-; X86-NEXT:    sahf
-; X86-NEXT:    setp %al
-; X86-NEXT:    addb %al, %al
-; X86-NEXT:    orb %dh, %al
-; X86-NEXT:    orb %dl, %al
-; X86-NEXT:    movb %al, (%ecx)
-; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    andl %ecx, %esi
+; X86-NEXT:    cmpl $2139095041, %esi # imm = 0x7F800001
+; X86-NEXT:    setge %dh
+; X86-NEXT:    andl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    cmpl $2139095041, %ecx # imm = 0x7F800001
+; X86-NEXT:    setge %cl
+; X86-NEXT:    addb %cl, %cl
+; X86-NEXT:    orb %dh, %cl
+; X86-NEXT:    orb %dl, %cl
+; X86-NEXT:    movb %cl, (%eax)
+; X86-NEXT:    popl %esi
+; X86-NEXT:    .cfi_def_cfa_offset 4
 ; X86-NEXT:    retl $4
 ;
 ; X64-LABEL: isnan_v4f:
 ; X64:       # %bb.0: # %entry
-; X64-NEXT:    cmpunordps %xmm0, %xmm0
+; X64-NEXT:    pand {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
+; X64-NEXT:    pcmpgtd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0
 ; X64-NEXT:    retq
 entry:
   %0 = tail call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %x, i32 3)  ; "nan"



More information about the flang-commits mailing list