diff --git a/flang/include/flang/Lower/IntrinsicCall.h b/flang/include/flang/Lower/IntrinsicCall.h --- a/flang/include/flang/Lower/IntrinsicCall.h +++ b/flang/include/flang/Lower/IntrinsicCall.h @@ -78,6 +78,17 @@ /// Return place-holder for absent intrinsic arguments. fir::ExtendedValue getAbsentIntrinsicArgument(); + +//===----------------------------------------------------------------------===// +// Direct access to intrinsics that may be used by lowering outside +// of intrinsic call lowering. +//===----------------------------------------------------------------------===// + +/// Generate power function x**y with given the expected +/// result type. +mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, + mlir::Value x, mlir::Value y); + } // namespace Fortran::lower #endif // FORTRAN_LOWER_INTRINSICCALL_H diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -265,14 +265,20 @@ template ExtValue genval( const Fortran::evaluate::Power> &op) { - TODO(getLoc(), "genval Power"); + mlir::Type ty = converter.genType(TC, KIND); + mlir::Value lhs = genunbox(op.left()); + mlir::Value rhs = genunbox(op.right()); + return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs); } template ExtValue genval( const Fortran::evaluate::RealToIntPower> &op) { - TODO(getLoc(), "genval RealToInt"); + mlir::Type ty = converter.genType(TC, KIND); + mlir::Value lhs = genunbox(op.left()); + mlir::Value rhs = genunbox(op.right()); + return Fortran::lower::genPow(builder, getLoc(), ty, lhs, rhs); } template diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -204,12 +204,24 @@ return mlir::FunctionType::get(context, {t}, {t}); } +static mlir::FunctionType genF32F32F32FuncType(mlir::MLIRContext *context) { + auto t = mlir::FloatType::getF32(context); + return mlir::FunctionType::get(context, {t, t}, {t}); +} + +static mlir::FunctionType genF64F64F64FuncType(mlir::MLIRContext *context) { + auto t = mlir::FloatType::getF64(context); + return mlir::FunctionType::get(context, {t, t}, {t}); +} + // TODO : Fill-up this table with more intrinsic. // Note: These are also defined as operations in LLVM dialect. See if this // can be use and has advantages. static constexpr RuntimeFunction llvmIntrinsics[] = { {"abs", "llvm.fabs.f32", genF32F32FuncType}, {"abs", "llvm.fabs.f64", genF64F64FuncType}, + {"pow", "llvm.pow.f32", genF32F32F32FuncType}, + {"pow", "llvm.pow.f64", genF64F64F64FuncType}, }; // This helper class computes a "distance" between two function types. @@ -644,3 +656,9 @@ return IntrinsicLibrary{builder, loc}.genIntrinsicCall(name, resultType, args); } + +mlir::Value Fortran::lower::genPow(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Type type, + mlir::Value x, mlir::Value y) { + return IntrinsicLibrary{builder, loc}.genRuntimeCall("pow", type, {x, y}); +} diff --git a/flang/test/Lower/power-operator.f90 b/flang/test/Lower/power-operator.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/power-operator.f90 @@ -0,0 +1,81 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! Test power operation lowering + +! CHECK-LABEL: pow_r4_i4 +subroutine pow_r4_i4(x, y, z) + real :: x, z + integer :: y + z = x ** y + ! CHECK: call @__fs_powi_1 +end subroutine + +! CHECK-LABEL: pow_r4_i8 +subroutine pow_r4_i8(x, y, z) + real :: x, z + integer(8) :: y + z = x ** y + ! CHECK: call @__fs_powk_1 +end subroutine + +! CHECK-LABEL: pow_r8_i4 +subroutine pow_r8_i4(x, y, z) + real(8) :: x, z + integer :: y + z = x ** y + ! CHECK: call @__fd_powi_1 +end subroutine + +! CHECK-LABEL: pow_r8_i8 +subroutine pow_r8_i8(x, y, z) + real(8) :: x, z + integer(8) :: y + z = x ** y + ! CHECK: call @__fd_powk_1 +end subroutine + +! CHECK-LABEL: pow_i4_i4 +subroutine pow_i4_i4(x, y, z) + integer(4) :: x, y, z + z = x ** y + ! CHECK: call @__mth_i_ipowi +end subroutine + +! CHECK-LABEL: pow_i8_i8 +subroutine pow_i8_i8(x, y, z) + integer(8) :: x, y, z + z = x ** y + ! CHECK: call @__mth_i_kpowk +end subroutine + +! CHECK-LABEL: pow_c4_i4 +subroutine pow_c4_i4(x, y, z) + complex :: x, z + integer :: y + z = x ** y + ! CHECK: call @__fc_powi_1 +end subroutine + +! CHECK-LABEL: pow_c4_i8 +subroutine pow_c4_i8(x, y, z) + complex :: x, z + integer(8) :: y + z = x ** y + ! CHECK: call @__fc_powk_1 +end subroutine + +! CHECK-LABEL: pow_c8_i4 +subroutine pow_c8_i4(x, y, z) + complex(8) :: x, z + integer :: y + z = x ** y + ! CHECK: call @__fz_powi_1 +end subroutine + +! CHECK-LABEL: pow_c8_i8 +subroutine pow_c8_i8(x, y, z) + complex(8) :: x, z + integer(8) :: y + z = x ** y + ! CHECK: call @__fz_powk_1 +end subroutine