diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp --- a/flang/lib/Evaluate/fold-logical.cpp +++ b/flang/lib/Evaluate/fold-logical.cpp @@ -155,14 +155,15 @@ } } } 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; - return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFunc([](const Scalar &x) { - return Scalar{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(context, std::move(funcRef), + ScalarFunc([](const Scalar &x) { + return Scalar{x.IsNotANumber()}; + })); + } } else if (name == "__builtin_ieee_is_negative") { auto restorer{context.messages().DiscardMessages()}; using DefaultReal = Type; diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -250,6 +250,7 @@ fir::ExtendedValue genIparity(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genIsContiguous(mlir::Type, llvm::ArrayRef); + mlir::Value genIsNan(mlir::Type, llvm::ArrayRef); mlir::Value genIshft(mlir::Type, llvm::ArrayRef); mlir::Value genIshftc(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); @@ -621,6 +622,7 @@ {"ieee_class_eq", &I::genIeeeTypeCompare}, {"ieee_class_ne", &I::genIeeeTypeCompare}, {"ieee_is_finite", &I::genIeeeIsFinite}, + {"ieee_is_nan", &I::genIsNan}, {"ieee_round_eq", &I::genIeeeTypeCompare}, {"ieee_round_ne", &I::genIeeeTypeCompare}, {"ieor", &I::genIeor}, @@ -643,6 +645,7 @@ /*isElemental=*/false}, {"ishft", &I::genIshft}, {"ishftc", &I::genIshftc}, + {"isnan", &I::genIsNan}, {"lbound", &I::genLbound, {{{"array", asInquired}, {"dim", asValue}, {"kind", asValue}}}, @@ -3690,6 +3693,20 @@ fir::runtime::genIsContiguous(builder, loc, fir::getBase(args[0]))); } +mlir::Value IntrinsicLibrary::genIsNan(mlir::Type resultType, + llvm::ArrayRef 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(loc, i1ty, args[0], nan); + return builder.createConvert(loc, resultType, isnan); +} + // ISHFT mlir::Value IntrinsicLibrary::genIshft(mlir::Type resultType, llvm::ArrayRef args) { diff --git a/flang/test/Lower/Intrinsics/isnan.f90 b/flang/test/Lower/Intrinsics/isnan.f90 new file mode 100644 --- /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