[flang-commits] [flang] 4ee8aef - [flang] Implement isnan and ieee_is_nan intrinsics

David Truby via flang-commits flang-commits at lists.llvm.org
Wed Mar 1 05:28:36 PST 2023


Author: David Truby
Date: 2023-03-01T13:28:28Z
New Revision: 4ee8aef4de45a87d2bbc86bfdd052b51599c54c9

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

LOG: [flang] Implement isnan and ieee_is_nan intrinsics

To implement these we call the LLVM intrinsic is.fpclass indicating that
we are checking for either a quiet or signalling NaN.

Differential Revision: https://reviews.llvm.org/D144649

Added: 
    flang/test/Lower/Intrinsics/isnan.f90

Modified: 
    flang/lib/Evaluate/fold-logical.cpp
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp
index b2762cd4ff9e6..4c3476a53c1a2 100644
--- a/flang/lib/Evaluate/fold-logical.cpp
+++ b/flang/lib/Evaluate/fold-logical.cpp
@@ -155,14 +155,15 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
       }
     }
   } else if (name == "isnan" || name == "__builtin_ieee_is_nan") {
-    // A warning about an invalid argument is discarded from converting
-    // the argument of isnan() / IEEE_IS_NAN().
-    auto restorer{context.messages().DiscardMessages()};
     using DefaultReal = Type<TypeCategory::Real, 4>;
-    return FoldElementalIntrinsic<T, DefaultReal>(context, std::move(funcRef),
-        ScalarFunc<T, DefaultReal>([](const Scalar<DefaultReal> &x) {
-          return Scalar<T>{x.IsNotANumber()};
-        }));
+    // Only replace the type of the function if we can do the fold
+    if (args[0] && args[0]->UnwrapExpr() &&
+        IsActuallyConstant(*args[0]->UnwrapExpr())) {
+      return FoldElementalIntrinsic<T, DefaultReal>(context, std::move(funcRef),
+          ScalarFunc<T, DefaultReal>([](const Scalar<DefaultReal> &x) {
+            return Scalar<T>{x.IsNotANumber()};
+          }));
+    }
   } else if (name == "__builtin_ieee_is_negative") {
     auto restorer{context.messages().DiscardMessages()};
     using DefaultReal = Type<TypeCategory::Real, 4>;

diff  --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 5148938eca79d..0da45e87436b7 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -250,6 +250,7 @@ struct IntrinsicLibrary {
   fir::ExtendedValue genIparity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   fir::ExtendedValue genIsContiguous(mlir::Type,
                                      llvm::ArrayRef<fir::ExtendedValue>);
+  mlir::Value genIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@@ -621,6 +622,7 @@ static constexpr IntrinsicHandler handlers[]{
     {"ieee_class_eq", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
     {"ieee_class_ne", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
     {"ieee_is_finite", &I::genIeeeIsFinite},
+    {"ieee_is_nan", &I::genIsNan},
     {"ieee_round_eq", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::eq>},
     {"ieee_round_ne", &I::genIeeeTypeCompare<mlir::arith::CmpIPredicate::ne>},
     {"ieor", &I::genIeor},
@@ -643,6 +645,7 @@ static constexpr IntrinsicHandler handlers[]{
      /*isElemental=*/false},
     {"ishft", &I::genIshft},
     {"ishftc", &I::genIshftc},
+    {"isnan", &I::genIsNan},
     {"lbound",
      &I::genLbound,
      {{{"array", asInquired}, {"dim", asValue}, {"kind", asValue}}},
@@ -3690,6 +3693,20 @@ IntrinsicLibrary::genIsContiguous(mlir::Type resultType,
       fir::runtime::genIsContiguous(builder, loc, fir::getBase(args[0])));
 }
 
+mlir::Value IntrinsicLibrary::genIsNan(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 1);
+  mlir::MLIRContext *context = builder.getContext();
+  mlir::IntegerType i1ty = mlir::IntegerType::get(context, 1);
+  mlir::IntegerType i32ty = mlir::IntegerType::get(context, 32);
+  // The last two bits indicate we are checking for signalling or quiet nan.
+  mlir::Value nan = builder.createIntegerConstant(loc, i32ty, 0b11);
+
+  mlir::Value isnan =
+      builder.create<mlir::LLVM::IsFPClass>(loc, i1ty, args[0], nan);
+  return builder.createConvert(loc, resultType, isnan);
+}
+
 // ISHFT
 mlir::Value IntrinsicLibrary::genIshft(mlir::Type resultType,
                                        llvm::ArrayRef<mlir::Value> args) {

diff  --git a/flang/test/Lower/Intrinsics/isnan.f90 b/flang/test/Lower/Intrinsics/isnan.f90
new file mode 100644
index 0000000000000..7f076e9eee7e9
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/isnan.f90
@@ -0,0 +1,78 @@
+! RUN: bbc -emit-fir %s -o - | FileCheck %s
+! RUN: flang-new -fc1 -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: isnan_f32
+subroutine isnan_f32(r)
+  real :: r
+  i = isnan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f32, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine isnan_f32
+
+! CHECK-LABEL: ieee_is_nan_f32
+subroutine ieee_is_nan_f32(r)
+  use ieee_arithmetic
+  real :: r
+  i = ieee_is_nan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f32, i32) -> 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: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f64, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine isnan_f64
+
+! CHECK-LABEL: ieee_is_nan_f64
+subroutine ieee_is_nan_f64(r)
+  use ieee_arithmetic
+  real(KIND=8) :: r
+  i = ieee_is_nan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f64, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine ieee_is_nan_f64
+
+! CHECK-LABEL: isnan_f80
+subroutine isnan_f80(r)
+  real(KIND=10) :: r
+  i = isnan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f80, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine isnan_f80
+
+! CHECK-LABEL: ieee_is_nan_f80
+subroutine ieee_is_nan_f80(r)
+  use ieee_arithmetic
+  real(KIND=10) :: r
+  i = ieee_is_nan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f80, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine ieee_is_nan_f80
+
+! CHECK-LABEL: isnan_f128
+subroutine isnan_f128(r)
+  real(KIND=16) :: r
+  i = isnan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f128, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine isnan_f128
+
+! CHECK-LABEL: ieee_is_nan_f128
+subroutine ieee_is_nan_f128(r)
+  use ieee_arithmetic
+  real(KIND=16) :: r
+  i = ieee_is_nan(r)
+  ! CHECK: %[[test:.*]] = arith.constant 3 : i32
+  ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f128, i32) -> i1
+  ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4>
+end subroutine ieee_is_nan_f128


        


More information about the flang-commits mailing list