From 3d9485173556c4e52426bc18239c2fb423d43ac3 Mon Sep 17 00:00:00 2001 From: Kiran Chandramohan Date: Wed, 23 Mar 2022 14:39:11 +0000 Subject: [PATCH] [Flang] Lower atan, sinh, cosh intrinsics The intrinsic computes the tan and hyperbolic sin, cosine values. By default they are lowered to runtime calls to the math library. Not all types are supported currently. The generic and llvm lowering does not lower floating point types with kind greater than 8, the llvm lowering does not support the complex types. Note: tanh is not present in fir-dev hence ignoring for now. We can add support after upstreaming is complete. sin and cos will come in separate patches since they have llvm intrinsic lowering. This is part of the upstreaming effort from the fir-dev branch in [1]. [1] https://github.com/flang-compiler/f18-llvm-project Reviewed By: PeteSteinfeld Differential Revision: https://reviews.llvm.org/D122264 Co-authored-by: Eric Schweitz Co-authored-by: William Moses --- flang/lib/Lower/IntrinsicCall.cpp | 6 + flang/test/Lower/llvm-math.f90 | 89 +++++++++++-- flang/test/Lower/trigonometric-intrinsics.f90 | 122 ++++++++++++++++++ 3 files changed, 206 insertions(+), 11 deletions(-) create mode 100644 flang/test/Lower/trigonometric-intrinsics.f90 diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index d364453387f1..0afbb7b1c6fa 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -1014,9 +1014,13 @@ static constexpr RuntimeFunction llvmIntrinsics[] = { {"aint", "llvm.trunc.f64", genF64F64FuncType}, {"anint", "llvm.round.f32", genF32F32FuncType}, {"anint", "llvm.round.f64", genF64F64FuncType}, + {"atan", "atanf", genF32F32FuncType}, + {"atan", "atan", genF64F64FuncType}, // ceil is used for CEILING but is different, it returns a real. {"ceil", "llvm.ceil.f32", genF32F32FuncType}, {"ceil", "llvm.ceil.f64", genF64F64FuncType}, + {"cosh", "coshf", genF32F32FuncType}, + {"cosh", "cosh", genF64F64FuncType}, {"exp", "llvm.exp.f32", genF32F32FuncType}, {"exp", "llvm.exp.f64", genF64F64FuncType}, // llvm.floor is used for FLOOR, but returns real. @@ -1036,6 +1040,8 @@ static constexpr RuntimeFunction llvmIntrinsics[] = { {"sign", "llvm.copysign.f64", genF64F64F64FuncType}, {"sign", "llvm.copysign.f80", genF80F80F80FuncType}, {"sign", "llvm.copysign.f128", genF128F128F128FuncType}, + {"sinh", "sinhf", genF32F32FuncType}, + {"sinh", "sinh", genF64F64FuncType}, {"sqrt", "llvm.sqrt.f32", genF32F32FuncType}, {"sqrt", "llvm.sqrt.f64", genF64F64FuncType}, }; diff --git a/flang/test/Lower/llvm-math.f90 b/flang/test/Lower/llvm-math.f90 index efe4394804c0..aab0b2b1f079 100644 --- a/flang/test/Lower/llvm-math.f90 +++ b/flang/test/Lower/llvm-math.f90 @@ -24,6 +24,17 @@ ! CHECK-NEXT: %1 = fir.load %arg1 : !fir.ref ! CHECK-NEXT: %2 = fir.call @llvm.pow.f32(%0, %1) : (f32, f32) -> f32 + SUBROUTINE ATAN_WRAPPER(IN, OUT) + DOUBLE PRECISION IN + OUT = DATAN(IN) + RETURN + END + +! CHECK: func private @fir.atan.f64.f64(%arg0: f64) +! CHECK-NEXT: %0 = fir.call @atan(%arg0) : (f64) -> f64 +! CHECK-NEXT: return %0 : f64 +! CHECK-NEXT: } + SUBROUTINE EXP_WRAPPER(IN, OUT) DOUBLE PRECISION IN OUT = DEXP(IN) @@ -33,6 +44,73 @@ ! CHECK: func private @fir.exp.f64.f64(%arg0: f64) ! CHECK-NEXT: %0 = fir.call @llvm.exp.f64(%arg0) : (f64) -> f64 ! CHECK-NEXT: return %0 : f64 +! CHECK-NEXT: } + + SUBROUTINE SINH_WRAPPER(IN, OUT) + DOUBLE PRECISION IN + OUT = DSINH(IN) + RETURN + END + +! CHECK: func private @fir.sinh.f64.f64(%arg0: f64) +! CHECK-NEXT: %0 = fir.call @sinh(%arg0) : (f64) -> f64 +! CHECK-NEXT: return %0 : f64 +! CHECK-NEXT: } + + SUBROUTINE COSH_WRAPPER(IN, OUT) + DOUBLE PRECISION IN + OUT = DCOSH(IN) + RETURN + END + +! CHECK: func private @fir.cosh.f64.f64(%arg0: f64) +! CHECK-NEXT: %0 = fir.call @cosh(%arg0) : (f64) -> f64 +! CHECK-NEXT: return %0 : f64 +! CHECK-NEXT: } + + + SUBROUTINE ATANF_WRAPPER(IN, OUT) + REAL IN + OUT = ATAN(IN) + RETURN + END + +! CHECK: func private @fir.atan.f32.f32(%arg0: f32) +! CHECK-NEXT: %0 = fir.call @atanf(%arg0) : (f32) -> f32 +! CHECK-NEXT: return %0 : f32 +! CHECK-NEXT: } + + SUBROUTINE EXPF_WRAPPER(IN, OUT) + REAL IN + OUT = EXP(IN) + RETURN + END + +! CHECK: func private @fir.exp.f32.f32(%arg0: f32) +! CHECK-NEXT: %0 = fir.call @llvm.exp.f32(%arg0) : (f32) -> f32 +! CHECK-NEXT: return %0 : f32 +! CHECK-NEXT: } + + SUBROUTINE SINHF_WRAPPER(IN, OUT) + REAL IN + OUT = SINH(IN) + RETURN + END + +! CHECK: func private @fir.sinh.f32.f32(%arg0: f32) +! CHECK-NEXT: %0 = fir.call @sinhf(%arg0) : (f32) -> f32 +! CHECK-NEXT: return %0 : f32 +! CHECK-NEXT: } + + SUBROUTINE COSHF_WRAPPER(IN, OUT) + REAL IN + OUT = COSH(IN) + RETURN + END + +! CHECK: func private @fir.cosh.f32.f32(%arg0: f32) +! CHECK-NEXT: %0 = fir.call @coshf(%arg0) : (f32) -> f32 +! CHECK-NEXT: return %0 : f32 ! CHECK-NEXT: } SUBROUTINE LOG_WRAPPER(IN, OUT) @@ -55,17 +133,6 @@ ! CHECK: func private @fir.log10.f64.f64(%arg0: f64) ! CHECK-NEXT: %0 = fir.call @llvm.log10.f64(%arg0) : (f64) -> f64 ! CHECK-NEXT: return %0 : f64 -! CHECK-NEXT: } - - SUBROUTINE EXPF_WRAPPER(IN, OUT) - REAL IN - OUT = EXP(IN) - RETURN - END - -! CHECK: func private @fir.exp.f32.f32(%arg0: f32) -! CHECK-NEXT: %0 = fir.call @llvm.exp.f32(%arg0) : (f32) -> f32 -! CHECK-NEXT: return %0 : f32 ! CHECK-NEXT: } SUBROUTINE LOGF_WRAPPER(IN, OUT) diff --git a/flang/test/Lower/trigonometric-intrinsics.f90 b/flang/test/Lower/trigonometric-intrinsics.f90 new file mode 100644 index 000000000000..8ec8f135cb7d --- /dev/null +++ b/flang/test/Lower/trigonometric-intrinsics.f90 @@ -0,0 +1,122 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s +! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: atan_testr +subroutine atan_testr(a, b) + real :: a, b +! CHECK: fir.call @fir.atan.f32.f32 + b = atan(a) +end subroutine + +! CHECK-LABEL: atan_testd +subroutine atan_testd(a, b) + real(kind=8) :: a, b +! CHECK: fir.call @fir.atan.f64.f64 + b = atan(a) +end subroutine + +! CHECK-LABEL: atan_testc +subroutine atan_testc(z) + complex :: z +! CHECK: fir.call @fir.atan.z4.z4 + z = atan(z) +end subroutine + +! CHECK-LABEL: atan_testcd +subroutine atan_testcd(z) + complex(kind=8) :: z +! CHECK: fir.call @fir.atan.z8.z8 + z = atan(z) +end subroutine + +! CHECK-LABEL: cosh_testr +subroutine cosh_testr(a, b) + real :: a, b +! CHECK: fir.call @fir.cosh.f32.f32 + b = cosh(a) +end subroutine + +! CHECK-LABEL: cosh_testd +subroutine cosh_testd(a, b) + real(kind=8) :: a, b +! CHECK: fir.call @fir.cosh.f64.f64 + b = cosh(a) +end subroutine + +! CHECK-LABEL: cosh_testc +subroutine cosh_testc(z) + complex :: z +! CHECK: fir.call @fir.cosh.z4.z4 + z = cosh(z) +end subroutine + +! CHECK-LABEL: cosh_testcd +subroutine cosh_testcd(z) + complex(kind=8) :: z +! CHECK: fir.call @fir.cosh.z8.z8 + z = cosh(z) +end subroutine + +! CHECK-LABEL: sinh_testr +subroutine sinh_testr(a, b) + real :: a, b +! CHECK: fir.call @fir.sinh.f32.f32 + b = sinh(a) +end subroutine + +! CHECK-LABEL: sinh_testd +subroutine sinh_testd(a, b) + real(kind=8) :: a, b +! CHECK: fir.call @fir.sinh.f64.f64 + b = sinh(a) +end subroutine + +! CHECK-LABEL: sinh_testc +subroutine sinh_testc(z) + complex :: z +! CHECK: fir.call @fir.sinh.z4.z4 + z = sinh(z) +end subroutine + +! CHECK-LABEL: sinh_testcd +subroutine sinh_testcd(z) + complex(kind=8) :: z +! CHECK: fir.call @fir.sinh.z8.z8 + z = sinh(z) +end subroutine + +! CHECK-LABEL: @fir.atan.f32.f32 +! CHECK: fir.call {{.*}}atan + +! CHECK-LABEL: @fir.atan.f64.f64 +! CHECK: fir.call {{.*}}atan + +! CHECK-LABEL: @fir.atan.z4.z4 +! CHECK: fir.call {{.*}}atan + +! CHECK-LABEL: @fir.atan.z8.z8 +! CHECK: fir.call {{.*}}atan + +! CHECK-LABEL: @fir.cosh.f32.f32 +! CHECK: fir.call {{.*}}cosh + +! CHECK-LABEL: @fir.cosh.f64.f64 +! CHECK: fir.call {{.*}}cosh + +! CHECK-LABEL: @fir.cosh.z4.z4 +! CHECK: fir.call {{.*}}cosh + +! CHECK-LABEL: @fir.cosh.z8.z8 +! CHECK: fir.call {{.*}}cosh + +! CHECK-LABEL: @fir.sinh.f32.f32 +! CHECK: fir.call {{.*}}sinh + +! CHECK-LABEL: @fir.sinh.f64.f64 +! CHECK: fir.call {{.*}}sinh + +! CHECK-LABEL: @fir.sinh.z4.z4 +! CHECK: fir.call {{.*}}sinh + +! CHECK-LABEL: @fir.sinh.z8.z8 +! CHECK: fir.call {{.*}}sinh