[flang-commits] [flang] 43c071f - [flang] Lower power operations
Valentin Clement via flang-commits
flang-commits at lists.llvm.org
Mon Feb 28 05:49:23 PST 2022
Author: Valentin Clement
Date: 2022-02-28T14:49:14+01:00
New Revision: 43c071fa4cb7df8d9f843fec246be653b7ad8e0a
URL: https://github.com/llvm/llvm-project/commit/43c071fa4cb7df8d9f843fec246be653b7ad8e0a
DIFF: https://github.com/llvm/llvm-project/commit/43c071fa4cb7df8d9f843fec246be653b7ad8e0a.diff
LOG: [flang] Lower power operations
Lower the power operation for real, integer
and complex.
The power operation is lowered to library calls.
This patch is part of the upstreaming effort from fir-dev branch.
Depends on D120403
Reviewed By: schweitz
Differential Revision: https://reviews.llvm.org/D120556
Added:
flang/test/Lower/llvm-math.f90
flang/test/Lower/power-operator.f90
Modified:
flang/include/flang/Lower/IntrinsicCall.h
flang/lib/Lower/ConvertExpr.cpp
flang/lib/Lower/IntrinsicCall.cpp
Removed:
################################################################################
diff --git a/flang/include/flang/Lower/IntrinsicCall.h b/flang/include/flang/Lower/IntrinsicCall.h
index 6b5b460786bd3..a85bd419a14e5 100644
--- a/flang/include/flang/Lower/IntrinsicCall.h
+++ b/flang/include/flang/Lower/IntrinsicCall.h
@@ -78,6 +78,17 @@ ArgLoweringRule lowerIntrinsicArgumentAs(mlir::Location,
/// 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 the given 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
index 12e292815b13f..60745b83cc11f 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -532,14 +532,20 @@ class ScalarExprLowering {
template <Fortran::common::TypeCategory TC, int KIND>
ExtValue genval(
const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &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 <Fortran::common::TypeCategory TC, int KIND>
ExtValue genval(
const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
&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 <int KIND>
diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index 2cb2aa0ba81c5..b1e8b39923146 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -148,6 +148,17 @@ static const IntrinsicHandler *findIntrinsicHandler(llvm::StringRef name) {
// Math runtime description and matching utility
//===----------------------------------------------------------------------===//
+/// Command line option to modify math runtime version used to implement
+/// intrinsics.
+enum MathRuntimeVersion { fastVersion, llvmOnly };
+llvm::cl::opt<MathRuntimeVersion> mathRuntimeVersion(
+ "math-runtime", llvm::cl::desc("Select math runtime version:"),
+ llvm::cl::values(
+ clEnumValN(fastVersion, "fast", "use pgmath fast runtime"),
+ clEnumValN(llvmOnly, "llvm",
+ "only use LLVM intrinsics (may be incomplete)")),
+ llvm::cl::init(fastVersion));
+
struct RuntimeFunction {
// llvm::StringRef comparison operator are not constexpr, so use string_view.
using Key = std::string_view;
@@ -176,12 +187,24 @@ static mlir::FunctionType genF64F64FuncType(mlir::MLIRContext *context) {
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.
@@ -373,8 +396,12 @@ static mlir::FuncOp getRuntimeFunction(mlir::Location loc,
using RtMap = Fortran::common::StaticMultimapView<RuntimeFunction>;
static constexpr RtMap pgmathF(pgmathFast);
static_assert(pgmathF.Verify() && "map must be sorted");
- match = searchFunctionInLibrary(loc, builder, pgmathF, name, funcType,
- &bestNearMatch, bestMatchDistance);
+ if (mathRuntimeVersion == fastVersion) {
+ match = searchFunctionInLibrary(loc, builder, pgmathF, name, funcType,
+ &bestNearMatch, bestMatchDistance);
+ } else {
+ assert(mathRuntimeVersion == llvmOnly && "unknown math runtime");
+ }
if (match)
return match;
@@ -602,3 +629,9 @@ Fortran::lower::genIntrinsicCall(fir::FirOpBuilder &builder, mlir::Location loc,
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/llvm-math.f90 b/flang/test/Lower/llvm-math.f90
new file mode 100644
index 0000000000000..661c9b19a845b
--- /dev/null
+++ b/flang/test/Lower/llvm-math.f90
@@ -0,0 +1,25 @@
+! RUN: bbc -emit-fir %s -o - --math-runtime=llvm | FileCheck %s
+
+ SUBROUTINE POW_WRAPPER(IN, IN2, OUT)
+ DOUBLE PRECISION IN, IN2
+ OUT = IN ** IN2
+ RETURN
+ END
+
+! CHECK-LABEL: func @_QPpow_wrapper(
+! CHECK-SAME: %{{.*}}: !fir.ref<f64>{{.*}}, %{{.*}}: !fir.ref<f64>{{.*}}, %{{.*}}: !fir.ref<f32>{{.*}}) {
+! CHECK-NEXT: %0 = fir.load %arg0 : !fir.ref<f64>
+! CHECK-NEXT: %1 = fir.load %arg1 : !fir.ref<f64>
+! CHECK-NEXT: %2 = fir.call @llvm.pow.f64(%0, %1) : (f64, f64) -> f64
+
+ SUBROUTINE POWF_WRAPPER(IN, IN2, OUT)
+ REAL IN, IN2
+ OUT = IN ** IN2
+ RETURN
+ END
+
+! CHECK-LABEL: func @_QPpowf_wrapper(
+! CHECK-SAME: %{{.*}}: !fir.ref<f32>{{.*}}, %{{.*}}: !fir.ref<f32>{{.*}}, %{{.*}}: !fir.ref<f32>{{.*}}) {
+! CHECK-NEXT: %0 = fir.load %arg0 : !fir.ref<f32>
+! CHECK-NEXT: %1 = fir.load %arg1 : !fir.ref<f32>
+! CHECK-NEXT: %2 = fir.call @llvm.pow.f32(%0, %1) : (f32, f32) -> f32
diff --git a/flang/test/Lower/power-operator.f90 b/flang/test/Lower/power-operator.f90
new file mode 100644
index 0000000000000..afde20e73e097
--- /dev/null
+++ b/flang/test/Lower/power-operator.f90
@@ -0,0 +1,104 @@
+! 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_r4
+subroutine pow_r4_r4(x, y, z)
+ real :: x, z, y
+ z = x ** y
+ ! CHECK: call @__fs_pow_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_r8_r8
+subroutine pow_r8_r8(x, y, z)
+ real(8) :: x, z, y
+ z = x ** y
+ ! CHECK: call @__fd_pow_1
+end subroutine
+
+! CHECK-LABEL: pow_r4_r8
+subroutine pow_r4_r8(x, y, z)
+ real(4) :: x
+ real(8) :: z, y
+ z = x ** y
+ ! CHECK: %{{.*}} = fir.convert %{{.*}} : (f32) -> f64
+ ! CHECK: call @__fd_pow_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
More information about the flang-commits
mailing list