[flang-commits] [flang] 9e8f677 - [flang] Lower exponentiation without using pgmath.

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Wed Dec 14 15:33:12 PST 2022


Author: Slava Zakharin
Date: 2022-12-14T15:32:51-08:00
New Revision: 9e8f6772990131d6aa62ba7010907d9dceb45d08

URL: https://github.com/llvm/llvm-project/commit/9e8f6772990131d6aa62ba7010907d9dceb45d08
DIFF: https://github.com/llvm/llvm-project/commit/9e8f6772990131d6aa62ba7010907d9dceb45d08.diff

LOG: [flang] Lower exponentiation without using pgmath.

Exponentiation is lowered to either math::FPowI or Fortran runtime
call (in case of --math-runtime=precise).

MathToFuncs convertor will convert math::FPowI operations with
exponent width >32 to calls of outlined implementations and otherwise
will leave the operation to MathToLLVM convertor.

Reviewed By: jeanPerier

Differential Revision: https://reviews.llvm.org/D139806

Added: 
    

Modified: 
    flang/include/flang/Runtime/numeric.h
    flang/lib/Lower/IntrinsicCall.cpp
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/runtime/numeric.cpp
    flang/test/Lower/HLFIR/binary-ops.f90
    flang/test/Lower/math-lowering.f90
    flang/test/Lower/power-operator.f90
    flang/unittests/Runtime/Numeric.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Runtime/numeric.h b/flang/include/flang/Runtime/numeric.h
index 4b656a762e31c..2710659081013 100644
--- a/flang/include/flang/Runtime/numeric.h
+++ b/flang/include/flang/Runtime/numeric.h
@@ -377,6 +377,40 @@ CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)(
     CppTypeFor<TypeCategory::Real, 16>);
 #endif
 
+CppTypeFor<TypeCategory::Real, 4> RTNAME(FPow4i)(
+    CppTypeFor<TypeCategory::Real, 4> b,
+    CppTypeFor<TypeCategory::Integer, 4> e);
+CppTypeFor<TypeCategory::Real, 8> RTNAME(FPow8i)(
+    CppTypeFor<TypeCategory::Real, 8> b,
+    CppTypeFor<TypeCategory::Integer, 4> e);
+#if LDBL_MANT_DIG == 64
+CppTypeFor<TypeCategory::Real, 10> RTNAME(FPow10i)(
+    CppTypeFor<TypeCategory::Real, 10> b,
+    CppTypeFor<TypeCategory::Integer, 4> e);
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTNAME(FPow16i)(
+    CppTypeFor<TypeCategory::Real, 16> b,
+    CppTypeFor<TypeCategory::Integer, 4> e);
+#endif
+
+CppTypeFor<TypeCategory::Real, 4> RTNAME(FPow4k)(
+    CppTypeFor<TypeCategory::Real, 4> b,
+    CppTypeFor<TypeCategory::Integer, 8> e);
+CppTypeFor<TypeCategory::Real, 8> RTNAME(FPow8k)(
+    CppTypeFor<TypeCategory::Real, 8> b,
+    CppTypeFor<TypeCategory::Integer, 8> e);
+#if LDBL_MANT_DIG == 64
+CppTypeFor<TypeCategory::Real, 10> RTNAME(FPow10k)(
+    CppTypeFor<TypeCategory::Real, 10> b,
+    CppTypeFor<TypeCategory::Integer, 8> e);
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTNAME(FPow16k)(
+    CppTypeFor<TypeCategory::Real, 16> b,
+    CppTypeFor<TypeCategory::Integer, 8> e);
+#endif
+
 } // extern "C"
 } // namespace Fortran::runtime
 #endif // FORTRAN_RUNTIME_NUMERIC_H_

diff  --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index bda58064796d4..595576cd7084d 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -1513,9 +1513,14 @@ static constexpr MathOperation mathOperations[] = {
      genComplexMathOp<mlir::complex::PowOp>},
     {"pow", "cpow", genComplexComplexComplexFuncType<8>,
      genComplexMathOp<mlir::complex::PowOp>},
-    // TODO: add PowIOp in math and complex dialects.
-    {"pow", "llvm.powi.f32.i32", genF32F32IntFuncType<32>, genLibCall},
-    {"pow", "llvm.powi.f64.i32", genF64F64IntFuncType<32>, genLibCall},
+    {"pow", RTNAME_STRING(FPow4i), genF32F32IntFuncType<32>,
+     genMathOp<mlir::math::FPowIOp>},
+    {"pow", RTNAME_STRING(FPow8i), genF64F64IntFuncType<32>,
+     genMathOp<mlir::math::FPowIOp>},
+    {"pow", RTNAME_STRING(FPow4k), genF32F32IntFuncType<64>,
+     genMathOp<mlir::math::FPowIOp>},
+    {"pow", RTNAME_STRING(FPow8k), genF64F64IntFuncType<64>,
+     genMathOp<mlir::math::FPowIOp>},
     {"pow", RTNAME_STRING(cpowi), genComplexComplexIntFuncType<4, 32>,
      genLibCall},
     {"pow", RTNAME_STRING(zpowi), genComplexComplexIntFuncType<8, 32>,

diff  --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 85f2f2173a5c3..b195ad0992ac1 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3628,7 +3628,14 @@ class FIRToLLVMLowering
     // function operations in it. We have to run such conversions
     // as passes here.
     mlir::OpPassManager mathConvertionPM("builtin.module");
-    mathConvertionPM.addPass(mlir::createConvertMathToFuncs());
+
+    // Convert math::FPowI operations to inline implementation
+    // only if the exponent's width is greater than 32, otherwise,
+    // it will be lowered to LLVM intrinsic operation by a later conversion.
+    mlir::ConvertMathToFuncsOptions mathToFuncsOptions{};
+    mathToFuncsOptions.minWidthOfFPowIExponent = 33;
+    mathConvertionPM.addPass(
+        mlir::createConvertMathToFuncs(mathToFuncsOptions));
     mathConvertionPM.addPass(mlir::createConvertComplexToStandardPass());
     if (mlir::failed(runPipeline(mathConvertionPM, mod)))
       return signalPassFailure();

diff  --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp
index 0a37fc96d313c..7afa5802db049 100644
--- a/flang/runtime/numeric.cpp
+++ b/flang/runtime/numeric.cpp
@@ -255,6 +255,38 @@ template <int PREC, typename T> inline T Nearest(T x, bool positive) {
   }
 }
 
+// Exponentiation operator for (Real ** Integer) cases (10.1.5.2.1).
+template <typename BTy, typename ETy> BTy FPowI(BTy base, ETy exp) {
+  if (exp == ETy{0})
+    return BTy{1};
+  bool isNegativePower{exp < ETy{0}};
+  bool isMinPower{exp == std::numeric_limits<ETy>::min()};
+  if (isMinPower) {
+    exp = std::numeric_limits<ETy>::max();
+  } else if (isNegativePower) {
+    exp = -exp;
+  }
+  BTy result{1};
+  BTy origBase{base};
+  while (true) {
+    if (exp & ETy{1}) {
+      result *= base;
+    }
+    exp >>= 1;
+    if (exp == ETy{0}) {
+      break;
+    }
+    base *= base;
+  }
+  if (isMinPower) {
+    result *= origBase;
+  }
+  if (isNegativePower) {
+    result = BTy{1} / result;
+  }
+  return result;
+}
+
 extern "C" {
 
 CppTypeFor<TypeCategory::Integer, 1> RTNAME(Ceiling4_1)(
@@ -871,5 +903,55 @@ CppTypeFor<TypeCategory::Real, 16> RTNAME(Spacing16)(
   return Spacing<113>(x);
 }
 #endif
+
+CppTypeFor<TypeCategory::Real, 4> RTNAME(FPow4i)(
+    CppTypeFor<TypeCategory::Real, 4> b,
+    CppTypeFor<TypeCategory::Integer, 4> e) {
+  return FPowI(b, e);
+}
+CppTypeFor<TypeCategory::Real, 8> RTNAME(FPow8i)(
+    CppTypeFor<TypeCategory::Real, 8> b,
+    CppTypeFor<TypeCategory::Integer, 4> e) {
+  return FPowI(b, e);
+}
+#if LDBL_MANT_DIG == 64
+CppTypeFor<TypeCategory::Real, 10> RTNAME(FPow10i)(
+    CppTypeFor<TypeCategory::Real, 10> b,
+    CppTypeFor<TypeCategory::Integer, 4> e) {
+  return FPowI(b, e);
+}
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTNAME(FPow16i)(
+    CppTypeFor<TypeCategory::Real, 16> b,
+    CppTypeFor<TypeCategory::Integer, 4> e) {
+  return FPowI(b, e);
+}
+#endif
+
+CppTypeFor<TypeCategory::Real, 4> RTNAME(FPow4k)(
+    CppTypeFor<TypeCategory::Real, 4> b,
+    CppTypeFor<TypeCategory::Integer, 8> e) {
+  return FPowI(b, e);
+}
+CppTypeFor<TypeCategory::Real, 8> RTNAME(FPow8k)(
+    CppTypeFor<TypeCategory::Real, 8> b,
+    CppTypeFor<TypeCategory::Integer, 8> e) {
+  return FPowI(b, e);
+}
+#if LDBL_MANT_DIG == 64
+CppTypeFor<TypeCategory::Real, 10> RTNAME(FPow10k)(
+    CppTypeFor<TypeCategory::Real, 10> b,
+    CppTypeFor<TypeCategory::Integer, 8> e) {
+  return FPowI(b, e);
+}
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+CppTypeFor<TypeCategory::Real, 16> RTNAME(FPow16k)(
+    CppTypeFor<TypeCategory::Real, 16> b,
+    CppTypeFor<TypeCategory::Integer, 8> e) {
+  return FPowI(b, e);
+}
+#endif
 } // extern "C"
 } // namespace Fortran::runtime

diff  --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90
index fb7b7648f7132..8e5dced1396d0 100644
--- a/flang/test/Lower/HLFIR/binary-ops.f90
+++ b/flang/test/Lower/HLFIR/binary-ops.f90
@@ -180,7 +180,7 @@ subroutine real_to_int_power(x, y, z)
 ! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 ! CHECK:  %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<f32>
 ! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
-! CHECK:  %[[VAL_8:.*]] = fir.call @llvm.powi.f32.i32(%[[VAL_6]], %[[VAL_7]]) fastmath<contract> : (f32, i32) -> f32
+! CHECK:  %[[VAL_8:.*]] = math.fpowi %[[VAL_6]], %[[VAL_7]] fastmath<contract> : f32, i32
 
 subroutine complex_to_int_power(x, y, z)
   complex :: x, y

diff  --git a/flang/test/Lower/math-lowering.f90 b/flang/test/Lower/math-lowering.f90
index 1bf5639f717fe..b6b720045f24b 100644
--- a/flang/test/Lower/math-lowering.f90
+++ b/flang/test/Lower/math-lowering.f90
@@ -449,35 +449,51 @@ function test_real8(x)
 ! RUN: bbc -emit-fir %t/exponentiation.f90 -o - --math-runtime=precise | FileCheck --check-prefixes=ALL,PRECISE %t/exponentiation.f90
 ! RUN: %flang_fc1 -emit-fir -mllvm -math-runtime=precise %t/exponentiation.f90 -o - | FileCheck --check-prefixes=ALL,PRECISE %t/exponentiation.f90
 
-function test_real4(x, y, s, i)
+function test_real4(x, y, s, i, k)
   real :: x, y, test_real4
   integer(2) :: s
   integer(4) :: i
-  test_real4 = x ** s + x ** y + x ** i
+  integer(8) :: k
+  test_real4 = x ** s + x ** y + x ** i + x ** k
 end function
 
 ! ALL-LABEL: @_QPtest_real4
 ! ALL: [[STOI:%[A-Za-z0-9._]+]] = fir.convert {{%[A-Za-z0-9._]+}} : (i16) -> i32
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) {{.*}}: (f32, i32) -> f32
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow4i({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f32, i32) -> f32
 ! FAST: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32
 ! RELAXED: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32
 ! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @powf({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f32, f32) -> f32
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f32.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f32, i32) -> f32
-
-function test_real8(x, y, s, i)
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow4i({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f32, i32) -> f32
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f32, i64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow4k({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f32, i64) -> f32
+
+function test_real8(x, y, s, i, k)
   real(8) :: x, y, test_real8
   integer(2) :: s
   integer(4) :: i
-  test_real8 = x ** s + x ** y + x ** i
+  integer(8) :: k
+  test_real8 = x ** s + x ** y + x ** i + x ** k
 end function
 
 ! ALL-LABEL: @_QPtest_real8
 ! ALL: [[STOI:%[A-Za-z0-9._]+]] = fir.convert {{%[A-Za-z0-9._]+}} : (i16) -> i32
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, [[STOI]]) {{.*}}: (f64, i32) -> f64
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow8i({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f64, i32) -> f64
 ! FAST: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64
 ! RELAXED: {{%[A-Za-z0-9._]+}} = math.powf {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64
 ! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @pow({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f64, f64) -> f64
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.powi.f64.i32({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f64, i32) -> f64
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i32
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i32
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow8i({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f64, i32) -> f64
+! FAST: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i64
+! RELAXED: {{%[A-Za-z0-9._]+}} = math.fpowi {{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}} {{.*}}: f64, i64
+! PRECISE: {{%[A-Za-z0-9._]+}} = fir.call @_FortranAFPow8k({{%[A-Za-z0-9._]+}}, {{%[A-Za-z0-9._]+}}) {{.*}}: (f64, i64) -> f64
 
 //--- sign.f90
 ! RUN: bbc -emit-fir %t/sign.f90 -o - --math-runtime=fast | FileCheck --check-prefixes=ALL,FAST %t/sign.f90

diff  --git a/flang/test/Lower/power-operator.f90 b/flang/test/Lower/power-operator.f90
index 867830f959aa0..67b93d33e63cc 100644
--- a/flang/test/Lower/power-operator.f90
+++ b/flang/test/Lower/power-operator.f90
@@ -1,9 +1,9 @@
-! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST"
-! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE"
-! RUN: bbc --disable-mlir-complex -emit-fir %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE"
-! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,CMPLX-FAST"
-! RUN: %flang_fc1 -emit-fir -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE"
-! RUN: %flang_fc1 -emit-fir -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="CMPLX-PRECISE"
+! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,FAST"
+! RUN: bbc --math-runtime=precise -emit-fir %s -o - | FileCheck %s --check-prefixes="PRECISE"
+! RUN: bbc --disable-mlir-complex -emit-fir %s -o - | FileCheck %s --check-prefixes="PRECISE"
+! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s --check-prefixes="CHECK,FAST"
+! RUN: %flang_fc1 -emit-fir -mllvm --math-runtime=precise %s -o - | FileCheck %s --check-prefixes="PRECISE"
+! RUN: %flang_fc1 -emit-fir -mllvm --disable-mlir-complex %s -o - | FileCheck %s --check-prefixes="PRECISE"
 
 ! Test power operation lowering
 
@@ -12,7 +12,7 @@ subroutine pow_r4_i4(x, y, z)
   real :: x, z
   integer :: y
   z = x ** y
-  ! CHECK: call @llvm.powi.f32.i32
+  ! CHECK: math.fpowi {{.*}} : f32, i32
 end subroutine
 
 ! CHECK-LABEL: pow_r4_r4
@@ -27,7 +27,7 @@ subroutine pow_r4_i8(x, y, z)
   real :: x, z
   integer(8) :: y
   z = x ** y
-  ! CHECK: call @__fs_powk_1
+  ! CHECK: math.fpowi {{.*}} : f32, i64
 end subroutine
 
 ! CHECK-LABEL: pow_r8_i4
@@ -35,7 +35,7 @@ subroutine pow_r8_i4(x, y, z)
   real(8) :: x, z
   integer :: y
   z = x ** y
-  ! CHECK: call @llvm.powi.f64.i32
+  ! CHECK: math.fpowi {{.*}} : f64, i32
 end subroutine
 
 ! CHECK-LABEL: pow_r8_i8
@@ -43,7 +43,7 @@ subroutine pow_r8_i8(x, y, z)
   real(8) :: x, z
   integer(8) :: y
   z = x ** y
-  ! CHECK: call @__fd_powk_1
+  ! CHECK: math.fpowi {{.*}} : f64, i64
 end subroutine
 
 ! CHECK-LABEL: pow_r8_r8
@@ -126,15 +126,15 @@ subroutine pow_c8_i8(x, y, z)
 subroutine pow_c4_c4(x, y, z)
   complex :: x, y, z
   z = x ** y
-  ! CMPLX-FAST: complex.pow %{{.*}}, %{{.*}} : complex<f32>
-  ! CMPLX-PRECISE: call @cpowf
+  ! FAST: complex.pow %{{.*}}, %{{.*}} : complex<f32>
+  ! PRECISE: call @cpowf
 end subroutine
 
 ! CHECK-LABEL: pow_c8_c8
 subroutine pow_c8_c8(x, y, z)
   complex(8) :: x, y, z
   z = x ** y
-  ! CMPLX-FAST: complex.pow %{{.*}}, %{{.*}} : complex<f64>
-  ! CMPLX-PRECISE: call @cpow
+  ! FAST: complex.pow %{{.*}}, %{{.*}} : complex<f64>
+  ! PRECISE: call @cpow
 end subroutine
 

diff  --git a/flang/unittests/Runtime/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp
index 04770af50ca3e..456d25fa4e1eb 100644
--- a/flang/unittests/Runtime/Numeric.cpp
+++ b/flang/unittests/Runtime/Numeric.cpp
@@ -205,3 +205,82 @@ TEST(Numeric, Spacing) {
   EXPECT_TRUE(
       std::isnan(RTNAME(Spacing8)(std::numeric_limits<Real<8>>::quiet_NaN())));
 }
+
+TEST(Numeric, FPowI) {
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{0}, Int<4>{0}), Real<4>{1});
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{0.3}, Int<4>{0}), Real<4>{1});
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{2}, Int<4>{-1}), Real<4>{0.5});
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{0.5}, Int<4>{-1}), Real<4>{2});
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{-3}, Int<4>{3}), Real<4>{-27});
+  EXPECT_EQ(RTNAME(FPow4i)(Real<4>{-2}, Int<4>{-3}), Real<4>{-0.125});
+
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{0}, Int<8>{0}), Real<4>{1});
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{0.3}, Int<8>{0}), Real<4>{1});
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{2}, Int<8>{-1}), Real<4>{0.5});
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{0.5}, Int<8>{-1}), Real<4>{2});
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{-3}, Int<8>{3}), Real<4>{-27});
+  EXPECT_EQ(RTNAME(FPow4k)(Real<4>{-2}, Int<8>{-3}), Real<4>{-0.125});
+
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{0}, Int<4>{0}), Real<8>{1});
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{0.3}, Int<4>{0}), Real<8>{1});
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{2}, Int<4>{-1}), Real<8>{0.5});
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{0.5}, Int<4>{-1}), Real<8>{2});
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{-3}, Int<4>{3}), Real<8>{-27});
+  EXPECT_EQ(RTNAME(FPow8i)(Real<8>{-2}, Int<4>{-3}), Real<8>{-0.125});
+
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{0}, Int<8>{0}), Real<8>{1});
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{0.3}, Int<8>{0}), Real<8>{1});
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{2}, Int<8>{-1}), Real<8>{0.5});
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{0.5}, Int<8>{-1}), Real<8>{2});
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{-3}, Int<8>{3}), Real<8>{-27});
+  EXPECT_EQ(RTNAME(FPow8k)(Real<8>{-2}, Int<8>{-3}), Real<8>{-0.125});
+
+#if LDBL_MANT_DIG == 64
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{0}, Int<4>{0}), Real<10>{1});
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{0.3}, Int<4>{0}), Real<10>{1});
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{2}, Int<4>{-1}), Real<10>{0.5});
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{0.5}, Int<4>{-1}), Real<10>{2});
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{-3}, Int<4>{3}), Real<10>{-27});
+  EXPECT_EQ(RTNAME(FPow10i)(Real<10>{-2}, Int<4>{-3}), Real<10>{-0.125});
+
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{0}, Int<8>{0}), Real<10>{1});
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{0.3}, Int<8>{0}), Real<10>{1});
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{2}, Int<8>{-1}), Real<10>{0.5});
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{0.5}, Int<8>{-1}), Real<10>{2});
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{-3}, Int<8>{3}), Real<10>{-27});
+  EXPECT_EQ(RTNAME(FPow10k)(Real<10>{-2}, Int<8>{-3}), Real<10>{-0.125});
+#endif
+#if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{0}, Int<4>{0}), Real<16>{1});
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{0.3}, Int<4>{0}), Real<16>{1});
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{2}, Int<4>{-1}), Real<16>{0.5});
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{0.5}, Int<4>{-1}), Real<16>{2});
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{-3}, Int<4>{3}), Real<16>{-27});
+  EXPECT_EQ(RTNAME(FPow16i)(Real<16>{-2}, Int<4>{-3}), Real<16>{-0.125});
+
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{0}, Int<8>{0}), Real<16>{1});
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{0.3}, Int<8>{0}), Real<16>{1});
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{2}, Int<8>{-1}), Real<16>{0.5});
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{0.5}, Int<8>{-1}), Real<16>{2});
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{-3}, Int<8>{3}), Real<16>{-27});
+  EXPECT_EQ(RTNAME(FPow16k)(Real<16>{-2}, Int<8>{-3}), Real<16>{-0.125});
+#endif
+
+  // Test some extreme values.
+  if (sizeof(double) == sizeof(std::uint64_t)) {
+    // (0x3FF0000000000001 ** -2147483648) ~ 0x3FEFFFFF00000401
+    double base;
+    *reinterpret_cast<std::uint64_t *>(&base) = 4607182418800017409ULL;
+    double result;
+    *reinterpret_cast<std::uint64_t *>(&result) = 4607182414505051137ULL;
+    EXPECT_TRUE(std::abs(RTNAME(FPow8i)(Real<8>{base},
+                             Int<4>{std::numeric_limits<Int<4>>::min()}) -
+                    Real<8>{result}) < 0.00000000001);
+
+    // (0x3FF0000000000001 ** 4294967296ULL) ~ 0x3FF00001000007FF
+    *reinterpret_cast<std::uint64_t *>(&base) = 4607182418800017409ULL;
+    *reinterpret_cast<std::uint64_t *>(&result) = 4607182423094986751ULL;
+    EXPECT_TRUE(std::abs(RTNAME(FPow8k)(Real<8>{base}, Int<8>{4294967296ULL}) -
+                    Real<8>{result}) < 0.00000000001);
+  }
+}


        


More information about the flang-commits mailing list