[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