diff --git a/flang/lib/Evaluate/fold-logical.cpp b/flang/lib/Evaluate/fold-logical.cpp index 4c3476a53c1a2..43406497a9e66 100644 --- a/flang/lib/Evaluate/fold-logical.cpp +++ b/flang/lib/Evaluate/fold-logical.cpp @@ -174,10 +174,13 @@ Expr> FoldIntrinsicFunction( } else if (name == "__builtin_ieee_is_normal") { auto restorer{context.messages().DiscardMessages()}; using DefaultReal = Type; - return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFunc([](const Scalar &x) { - return Scalar{x.IsNormal()}; - })); + if (args[0] && args[0]->UnwrapExpr() && + IsActuallyConstant(*args[0]->UnwrapExpr())) { + return FoldElementalIntrinsic(context, std::move(funcRef), + ScalarFunc([](const Scalar &x) { + return Scalar{x.IsNormal()}; + })); + } } else if (name == "is_contiguous") { if (args.at(0)) { if (auto *expr{args[0]->UnwrapExpr()}) { diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index 14081b7e9a6c3..84d534febdba5 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -241,6 +241,7 @@ struct IntrinsicLibrary { fir::ExtendedValue genIchar(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genFindloc(mlir::Type, llvm::ArrayRef); mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef); + mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef); template fir::ExtendedValue genIeeeTypeCompare(mlir::Type, llvm::ArrayRef); @@ -251,6 +252,8 @@ struct IntrinsicLibrary { fir::ExtendedValue genIsContiguous(mlir::Type, llvm::ArrayRef); mlir::Value genIsNan(mlir::Type, llvm::ArrayRef); + mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef, + int fpclass); mlir::Value genIshft(mlir::Type, llvm::ArrayRef); mlir::Value genIshftc(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); @@ -623,6 +626,7 @@ static constexpr IntrinsicHandler handlers[]{ {"ieee_class_ne", &I::genIeeeTypeCompare}, {"ieee_is_finite", &I::genIeeeIsFinite}, {"ieee_is_nan", &I::genIsNan}, + {"ieee_is_normal", &I::genIeeeIsNormal}, {"ieee_round_eq", &I::genIeeeTypeCompare}, {"ieee_round_ne", &I::genIeeeTypeCompare}, {"ieor", &I::genIeor}, @@ -3603,6 +3607,13 @@ IntrinsicLibrary::genIeeeIsFinite(mlir::Type resultType, exponent, maxExponent)); } +mlir::Value +IntrinsicLibrary::genIeeeIsNormal(mlir::Type resultType, + llvm::ArrayRef args) { + // Check if is positive or negative normal + return genIsFPClass(resultType, args, 0b101101000); +} + // IEOR mlir::Value IntrinsicLibrary::genIeor(mlir::Type resultType, llvm::ArrayRef args) { @@ -3693,18 +3704,24 @@ IntrinsicLibrary::genIsContiguous(mlir::Type resultType, fir::runtime::genIsContiguous(builder, loc, fir::getBase(args[0]))); } -mlir::Value IntrinsicLibrary::genIsNan(mlir::Type resultType, - llvm::ArrayRef args) { +mlir::Value IntrinsicLibrary::genIsFPClass(mlir::Type resultType, + llvm::ArrayRef args, + int fpclass) { 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); + mlir::Value test = builder.createIntegerConstant(loc, i32ty, fpclass); + mlir::Value isfpclass = + builder.create(loc, i1ty, args[0], test); + return builder.createConvert(loc, resultType, isfpclass); +} + +mlir::Value IntrinsicLibrary::genIsNan(mlir::Type resultType, + llvm::ArrayRef args) { + // Check is signaling or quiet nan + return genIsFPClass(resultType, args, 0b11); } // ISHFT diff --git a/flang/test/Lower/Intrinsics/ieee_is_normal.f90 b/flang/test/Lower/Intrinsics/ieee_is_normal.f90 new file mode 100644 index 0000000000000..84b3d2bf0a6d3 --- /dev/null +++ b/flang/test/Lower/Intrinsics/ieee_is_normal.f90 @@ -0,0 +1,64 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s +! RUN: flang-new -fc1 -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: ieee_is_normal_f16 +subroutine ieee_is_normal_f16(r) + use ieee_arithmetic + real(KIND=2) :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f16, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_f16 + +! CHECK-LABEL: ieee_is_normal_bf16 +subroutine ieee_is_normal_bf16(r) + use ieee_arithmetic + real(KIND=3) :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (bf16, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_bf16 + + + +! CHECK-LABEL: ieee_is_normal_f32 +subroutine ieee_is_normal_f32(r) + use ieee_arithmetic + real :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f32, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_f32 + +! CHECK-LABEL: ieee_is_normal_f64 +subroutine ieee_is_normal_f64(r) + use ieee_arithmetic + real(KIND=8) :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f64, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_f64 + +! CHECK-LABEL: ieee_is_normal_f80 +subroutine ieee_is_normal_f80(r) + use ieee_arithmetic + real(KIND=10) :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f80, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_f80 + +! CHECK-LABEL: ieee_is_normal_f128 +subroutine ieee_is_normal_f128(r) + use ieee_arithmetic + real(KIND=16) :: r + i = ieee_is_normal(r) + ! CHECK: %[[test:.*]] = arith.constant 360 : i32 + ! CHECK: %[[l:.*]] = "llvm.intr.is.fpclass"(%{{.*}}, %[[test]]) : (f128, i32) -> i1 + ! CHECK: fir.convert %[[l]] : (i1) -> !fir.logical<4> +end subroutine ieee_is_normal_f128