[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