diff --git a/flang/include/flang/Runtime/numeric.h b/flang/include/flang/Runtime/numeric.h --- a/flang/include/flang/Runtime/numeric.h +++ b/flang/include/flang/Runtime/numeric.h @@ -377,6 +377,40 @@ CppTypeFor); #endif +CppTypeFor RTNAME(FPow4i)( + CppTypeFor b, + CppTypeFor e); +CppTypeFor RTNAME(FPow8i)( + CppTypeFor b, + CppTypeFor e); +#if LDBL_MANT_DIG == 64 +CppTypeFor RTNAME(FPow10i)( + CppTypeFor b, + CppTypeFor e); +#endif +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor RTNAME(FPow16i)( + CppTypeFor b, + CppTypeFor e); +#endif + +CppTypeFor RTNAME(FPow4k)( + CppTypeFor b, + CppTypeFor e); +CppTypeFor RTNAME(FPow8k)( + CppTypeFor b, + CppTypeFor e); +#if LDBL_MANT_DIG == 64 +CppTypeFor RTNAME(FPow10k)( + CppTypeFor b, + CppTypeFor e); +#endif +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor RTNAME(FPow16k)( + CppTypeFor b, + CppTypeFor 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 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -1513,9 +1513,14 @@ genComplexMathOp}, {"pow", "cpow", genComplexComplexComplexFuncType<8>, genComplexMathOp}, - // 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}, + {"pow", RTNAME_STRING(FPow8i), genF64F64IntFuncType<32>, + genMathOp}, + {"pow", RTNAME_STRING(FPow4k), genF32F32IntFuncType<64>, + genMathOp}, + {"pow", RTNAME_STRING(FPow8k), genF64F64IntFuncType<64>, + genMathOp}, {"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 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3628,7 +3628,14 @@ // 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 --- a/flang/runtime/numeric.cpp +++ b/flang/runtime/numeric.cpp @@ -255,6 +255,38 @@ } } +// Exponentiation operator for (Real ** Integer) cases (10.1.5.2.1). +template BTy FPowI(BTy base, ETy exp) { + if (exp == ETy{0}) + return BTy{1}; + bool isNegativePower{exp < ETy{0}}; + bool isMinPower{exp == std::numeric_limits::min()}; + if (isMinPower) { + exp = std::numeric_limits::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 RTNAME(Ceiling4_1)( @@ -871,5 +903,55 @@ return Spacing<113>(x); } #endif + +CppTypeFor RTNAME(FPow4i)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +CppTypeFor RTNAME(FPow8i)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +#if LDBL_MANT_DIG == 64 +CppTypeFor RTNAME(FPow10i)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +#endif +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor RTNAME(FPow16i)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +#endif + +CppTypeFor RTNAME(FPow4k)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +CppTypeFor RTNAME(FPow8k)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +#if LDBL_MANT_DIG == 64 +CppTypeFor RTNAME(FPow10k)( + CppTypeFor b, + CppTypeFor e) { + return FPowI(b, e); +} +#endif +#if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +CppTypeFor RTNAME(FPow16k)( + CppTypeFor b, + CppTypeFor 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 --- a/flang/test/Lower/HLFIR/binary-ops.f90 +++ b/flang/test/Lower/HLFIR/binary-ops.f90 @@ -180,7 +180,7 @@ ! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref -! CHECK: %[[VAL_8:.*]] = fir.call @llvm.powi.f32.i32(%[[VAL_6]], %[[VAL_7]]) fastmath : (f32, i32) -> f32 +! CHECK: %[[VAL_8:.*]] = math.fpowi %[[VAL_6]], %[[VAL_7]] fastmath : 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 --- a/flang/test/Lower/math-lowering.f90 +++ b/flang/test/Lower/math-lowering.f90 @@ -449,35 +449,51 @@ ! 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 --- 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 @@ 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 @@ 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 @@ 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 @@ 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_c4_c4(x, y, z) complex :: x, y, z z = x ** y - ! CMPLX-FAST: complex.pow %{{.*}}, %{{.*}} : complex - ! CMPLX-PRECISE: call @cpowf + ! FAST: complex.pow %{{.*}}, %{{.*}} : complex + ! 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 - ! CMPLX-PRECISE: call @cpow + ! FAST: complex.pow %{{.*}}, %{{.*}} : complex + ! PRECISE: call @cpow end subroutine diff --git a/flang/unittests/Runtime/Numeric.cpp b/flang/unittests/Runtime/Numeric.cpp --- a/flang/unittests/Runtime/Numeric.cpp +++ b/flang/unittests/Runtime/Numeric.cpp @@ -205,3 +205,82 @@ EXPECT_TRUE( std::isnan(RTNAME(Spacing8)(std::numeric_limits>::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(&base) = 4607182418800017409ULL; + double result; + *reinterpret_cast(&result) = 4607182414505051137ULL; + EXPECT_TRUE(std::abs(RTNAME(FPow8i)(Real<8>{base}, + Int<4>{std::numeric_limits>::min()}) - + Real<8>{result}) < 0.00000000001); + + // (0x3FF0000000000001 ** 4294967296ULL) ~ 0x3FF00001000007FF + *reinterpret_cast(&base) = 4607182418800017409ULL; + *reinterpret_cast(&result) = 4607182423094986751ULL; + EXPECT_TRUE(std::abs(RTNAME(FPow8k)(Real<8>{base}, Int<8>{4294967296ULL}) - + Real<8>{result}) < 0.00000000001); + } +}