[flang-commits] [flang] [llvm] [flang] Fix wrong result for exponentiation when denormal is expected (PR #205262)
via flang-commits
flang-commits at lists.llvm.org
Thu Oct 22 00:00:54 PDT 2026
https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/205262
>From c61d029ab811633ebca8e5d2c049a5f0f2ca3f6f Mon Sep 17 00:00:00 2001
From: ejose02 <ejose at amd.com>
Date: Tue, 23 Jun 2026 11:13:36 +0530
Subject: [PATCH 1/5] [flang] Fix wrong result for exponentiation when denormal
is expected
Fixes #192639
Root cause:
Negative integer exponents used exponentiation-by-squaring that divides by successively squared bases; for |base| > 1 intermediates overflow before the final divide.
Fix:
For real types with negative exponent and |base| > 1, evaluate (1/base)^|exp| instead. Apply the same rule in compile-time IntPower and runtime FPowI.
---
flang-rt/lib/runtime/numeric.cpp | 4 ++++
flang-rt/unittests/Runtime/Numeric.cpp | 1 +
flang/lib/Evaluate/int-power.h | 18 ++++++++++++++++++
flang/test/Evaluate/folding07.f90 | 1 +
4 files changed, 24 insertions(+)
diff --git a/flang-rt/lib/runtime/numeric.cpp b/flang-rt/lib/runtime/numeric.cpp
index a5191fbbe1f9fb..bdcca4dda49a93 100644
--- a/flang-rt/lib/runtime/numeric.cpp
+++ b/flang-rt/lib/runtime/numeric.cpp
@@ -208,6 +208,10 @@ RT_API_ATTRS BTy FPowI(BTy base, ETy exp) {
} else if (isNegativePower) {
exp = -exp;
}
+ if (isNegativePower && base != BTy{0} && std::abs(base) > BTy{1}) {
+ base = BTy{1} / base;
+ isNegativePower = false;
+ }
BTy result{1};
BTy origBase{base};
while (true) {
diff --git a/flang-rt/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/Runtime/Numeric.cpp
index 1c8ccc42626680..60a03c232b8a0c 100644
--- a/flang-rt/unittests/Runtime/Numeric.cpp
+++ b/flang-rt/unittests/Runtime/Numeric.cpp
@@ -271,6 +271,7 @@ TEST(Numeric, FPowI) {
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_NE(RTNAME(FPow4i)(Real<4>{2}, Int<4>{-133}), Real<4>{0});
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});
diff --git a/flang/lib/Evaluate/int-power.h b/flang/lib/Evaluate/int-power.h
index 2ee012ceb77a38..f9c0f3e9b657e4 100644
--- a/flang/lib/Evaluate/int-power.h
+++ b/flang/lib/Evaluate/int-power.h
@@ -15,6 +15,10 @@
namespace Fortran::evaluate {
+namespace value {
+template <typename W, int P> class Real;
+}
+
template <typename REAL, typename INT>
ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
const INT &power,
@@ -51,6 +55,20 @@ ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
return result;
}
+template <typename W, int P, typename INT>
+ValueWithRealFlags<value::Real<W, P>> IntPower(const value::Real<W, P> &base,
+ const INT &power,
+ Rounding rounding = TargetCharacteristics::defaultRounding) {
+ using REAL = value::Real<W, P>;
+ REAL one{REAL::FromInteger(INT{1}).value};
+ if (power.IsNegative() && !base.IsZero() &&
+ base.ABS().Compare(one) == Relation::Greater) {
+ REAL recip{one.Divide(base, rounding).value};
+ return TimesIntPowerOf(one, recip, power.ABS().value, rounding);
+ }
+ return TimesIntPowerOf(one, base, power, rounding);
+}
+
template <typename REAL, typename INT>
ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
Rounding rounding = TargetCharacteristics::defaultRounding) {
diff --git a/flang/test/Evaluate/folding07.f90 b/flang/test/Evaluate/folding07.f90
index d51df7acf7b8a6..0952ae7b348479 100644
--- a/flang/test/Evaluate/folding07.f90
+++ b/flang/test/Evaluate/folding07.f90
@@ -307,5 +307,6 @@ module m
logical, parameter :: test_set_exponent_1 = set_exponent(1., 1) == 1.
logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
+ logical, parameter :: test_pow_denorm_neg = 2.0**(-133) /= 0.0
end module
>From 8dff4e46899c323e98ebc80290912ca4070fca7e Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Thu, 8 Oct 2026 11:18:30 +0000
Subject: [PATCH 2/5] Use ABSTy in FPowI and propagate IntPower divide flags
---
flang-rt/lib/runtime/numeric.cpp | 2 +-
flang/lib/Evaluate/int-power.h | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/flang-rt/lib/runtime/numeric.cpp b/flang-rt/lib/runtime/numeric.cpp
index bdcca4dda49a93..ed827ca00e1c16 100644
--- a/flang-rt/lib/runtime/numeric.cpp
+++ b/flang-rt/lib/runtime/numeric.cpp
@@ -208,7 +208,7 @@ RT_API_ATTRS BTy FPowI(BTy base, ETy exp) {
} else if (isNegativePower) {
exp = -exp;
}
- if (isNegativePower && base != BTy{0} && std::abs(base) > BTy{1}) {
+ if (isNegativePower && base != BTy{0} && ABSTy<BTy>::compute(base) > BTy{1}) {
base = BTy{1} / base;
isNegativePower = false;
}
diff --git a/flang/lib/Evaluate/int-power.h b/flang/lib/Evaluate/int-power.h
index f9c0f3e9b657e4..c3d8e5ae1aa31c 100644
--- a/flang/lib/Evaluate/int-power.h
+++ b/flang/lib/Evaluate/int-power.h
@@ -63,8 +63,11 @@ ValueWithRealFlags<value::Real<W, P>> IntPower(const value::Real<W, P> &base,
REAL one{REAL::FromInteger(INT{1}).value};
if (power.IsNegative() && !base.IsZero() &&
base.ABS().Compare(one) == Relation::Greater) {
- REAL recip{one.Divide(base, rounding).value};
- return TimesIntPowerOf(one, recip, power.ABS().value, rounding);
+ ValueWithRealFlags<REAL> result;
+ REAL recip{one.Divide(base, rounding).AccumulateFlags(result.flags)};
+ result.value = TimesIntPowerOf(one, recip, power.ABS().value, rounding)
+ .AccumulateFlags(result.flags);
+ return result;
}
return TimesIntPowerOf(one, base, power, rounding);
}
>From 3789c9bbdc7f2379d762317b1e43ebae804891db Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Fri, 9 Oct 2026 11:32:58 +0000
Subject: [PATCH 3/5] [flang] Overflow-gated IntPower retry and stronger pow
tests
---
flang-rt/unittests/Runtime/Numeric.cpp | 9 +++++++-
flang/lib/Evaluate/int-power.h | 30 +++++++++++++-------------
flang/test/Evaluate/folding07.f90 | 5 ++++-
3 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/flang-rt/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/Runtime/Numeric.cpp
index 60a03c232b8a0c..fa11d24db9ce5a 100644
--- a/flang-rt/unittests/Runtime/Numeric.cpp
+++ b/flang-rt/unittests/Runtime/Numeric.cpp
@@ -271,7 +271,10 @@ TEST(Numeric, FPowI) {
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_NE(RTNAME(FPow4i)(Real<4>{2}, Int<4>{-133}), Real<4>{0});
+ EXPECT_EQ(
+ RTNAME(FPow4i)(Real<4>{2}, Int<4>{-133}), std::ldexp(Real<4>{1}, -133));
+ EXPECT_EQ(RTNAME(FPow4i)(Real<4>{2}, std::numeric_limits<Int<4>>::min()),
+ Real<4>{0});
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});
@@ -279,6 +282,8 @@ TEST(Numeric, FPowI) {
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(FPow4k)(Real<4>{2}, Int<8>{-133}), std::ldexp(Real<4>{1}, -133));
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});
@@ -286,6 +291,8 @@ TEST(Numeric, FPowI) {
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(FPow8i)(Real<8>{2}, Int<4>{-1070}), std::ldexp(Real<8>{1}, -1070));
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});
diff --git a/flang/lib/Evaluate/int-power.h b/flang/lib/Evaluate/int-power.h
index c3d8e5ae1aa31c..3f9aa1b1612a1f 100644
--- a/flang/lib/Evaluate/int-power.h
+++ b/flang/lib/Evaluate/int-power.h
@@ -11,17 +11,14 @@
// Computes an integer power of a real or complex value.
+#include "flang/Evaluate/real.h"
#include "flang/Evaluate/target.h"
namespace Fortran::evaluate {
-namespace value {
-template <typename W, int P> class Real;
-}
-
template <typename REAL, typename INT>
ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
- const INT &power,
+ const INT &power, bool forceMultiply = false,
Rounding rounding = TargetCharacteristics::defaultRounding) {
ValueWithRealFlags<REAL> result{factor};
if (base.IsNotANumber()) {
@@ -32,7 +29,7 @@ ValueWithRealFlags<REAL> TimesIntPowerOf(const REAL &factor, const REAL &base,
result.flags.set(RealFlag::InvalidArgument);
}
} else {
- bool negativePower{power.IsNegative()};
+ bool negativePower{!forceMultiply && power.IsNegative()};
INT absPower{power.ABS().value};
REAL squares{base};
int nbits{INT::bits - absPower.LEADZ()};
@@ -61,22 +58,25 @@ ValueWithRealFlags<value::Real<W, P>> IntPower(const value::Real<W, P> &base,
Rounding rounding = TargetCharacteristics::defaultRounding) {
using REAL = value::Real<W, P>;
REAL one{REAL::FromInteger(INT{1}).value};
- if (power.IsNegative() && !base.IsZero() &&
- base.ABS().Compare(one) == Relation::Greater) {
- ValueWithRealFlags<REAL> result;
- REAL recip{one.Divide(base, rounding).AccumulateFlags(result.flags)};
- result.value = TimesIntPowerOf(one, recip, power.ABS().value, rounding)
- .AccumulateFlags(result.flags);
- return result;
+ ValueWithRealFlags<REAL> result{
+ TimesIntPowerOf(one, base, power, /*forceMultiply=*/false, rounding)};
+ if (result.flags.test(RealFlag::Overflow) && power.IsNegative() &&
+ !base.IsZero() && base.ABS().Compare(one) == Relation::Greater) {
+ ValueWithRealFlags<REAL> retry;
+ REAL recip{one.Divide(base, rounding).AccumulateFlags(retry.flags)};
+ retry.value =
+ TimesIntPowerOf(one, recip, power, /*forceMultiply=*/true, rounding)
+ .AccumulateFlags(retry.flags);
+ return retry;
}
- return TimesIntPowerOf(one, base, power, rounding);
+ return result;
}
template <typename REAL, typename INT>
ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
Rounding rounding = TargetCharacteristics::defaultRounding) {
REAL one{REAL::FromInteger(INT{1}).value};
- return TimesIntPowerOf(one, base, power, rounding);
+ return TimesIntPowerOf(one, base, power, /*forceMultiply=*/false, rounding);
}
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_INT_POWER_H_
diff --git a/flang/test/Evaluate/folding07.f90 b/flang/test/Evaluate/folding07.f90
index 0952ae7b348479..8fc0a20f246eb7 100644
--- a/flang/test/Evaluate/folding07.f90
+++ b/flang/test/Evaluate/folding07.f90
@@ -307,6 +307,9 @@ module m
logical, parameter :: test_set_exponent_1 = set_exponent(1., 1) == 1.
logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
- logical, parameter :: test_pow_denorm_neg = 2.0**(-133) /= 0.0
+ logical, parameter :: test_pow_subnormal_4 = 2.0_4**(-133) == scale(1.0_4, -133)
+ logical, parameter :: test_pow_neg_3 = 3.0**(-2) == 1.0/3.0**2
+ logical, parameter :: test_pow_neg_7 = 7.0**(-5) == 1.0/7.0**5
+ logical, parameter :: test_pow_min_int1 = 1.5_8**(-128_1) < 1.0_8
end module
>From a20e465dd957f02257f88d1e6e8f32918e257eb0 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Mon, 12 Oct 2026 07:19:51 +0000
Subject: [PATCH 4/5] [flang][flang-rt] Gate FPowI retry on zero quotient;
extend pow fold tests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Retry from 1/base only when a negative power divides to zero, so
subnormal results are preserved without the 1–3 ULP loss from always
reciprocating |base|>1. Drop ABSTy from FPowI. Add folding and unit
tests from review, including the IntPower retry case.
---
flang-rt/lib/runtime/numeric.cpp | 35 +++++++++++++++-----------
flang-rt/unittests/Runtime/Numeric.cpp | 3 +++
flang/test/Evaluate/folding07.f90 | 7 ++++++
3 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/flang-rt/lib/runtime/numeric.cpp b/flang-rt/lib/runtime/numeric.cpp
index ed827ca00e1c16..fd4256db8648b3 100644
--- a/flang-rt/lib/runtime/numeric.cpp
+++ b/flang-rt/lib/runtime/numeric.cpp
@@ -196,22 +196,8 @@ inline RT_API_ATTRS T Nearest(T x, bool positive) {
}
}
-// Exponentiation operator for (Real ** Integer) cases (10.1.5.2.1).
template <typename BTy, typename ETy>
-RT_API_ATTRS BTy FPowI(BTy base, ETy exp) {
- if (exp == ETy{0})
- return BTy{1};
- bool isNegativePower{exp < ETy{0}};
- bool isMinPower{exp == common::numeric_limits<ETy>::min()};
- if (isMinPower) {
- exp = common::numeric_limits<ETy>::max();
- } else if (isNegativePower) {
- exp = -exp;
- }
- if (isNegativePower && base != BTy{0} && ABSTy<BTy>::compute(base) > BTy{1}) {
- base = BTy{1} / base;
- isNegativePower = false;
- }
+RT_API_ATTRS BTy FPowIPositive(BTy base, ETy exp, bool isMinPower) {
BTy result{1};
BTy origBase{base};
while (true) {
@@ -227,8 +213,27 @@ RT_API_ATTRS BTy FPowI(BTy base, ETy exp) {
if (isMinPower) {
result *= origBase;
}
+ return result;
+}
+
+// Exponentiation operator for (Real ** Integer) cases (10.1.5.2.1).
+template <typename BTy, typename ETy>
+RT_API_ATTRS BTy FPowI(BTy base, ETy exp) {
+ if (exp == ETy{0})
+ return BTy{1};
+ bool isNegativePower{exp < ETy{0}};
+ bool isMinPower{exp == common::numeric_limits<ETy>::min()};
+ if (isMinPower) {
+ exp = common::numeric_limits<ETy>::max();
+ } else if (isNegativePower) {
+ exp = -exp;
+ }
+ BTy result{FPowIPositive(base, exp, isMinPower)};
if (isNegativePower) {
result = BTy{1} / result;
+ if (result == BTy{0} && base != BTy{0}) {
+ result = FPowIPositive(BTy{1} / base, exp, isMinPower);
+ }
}
return result;
}
diff --git a/flang-rt/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/Runtime/Numeric.cpp
index fa11d24db9ce5a..ae2e25d8b24e0d 100644
--- a/flang-rt/unittests/Runtime/Numeric.cpp
+++ b/flang-rt/unittests/Runtime/Numeric.cpp
@@ -271,6 +271,9 @@ TEST(Numeric, FPowI) {
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(FPow4i)(Real<4>{3}, Int<4>{-2}), Real<4>{1} / Real<4>{9});
+ EXPECT_EQ(
+ RTNAME(FPow4i)(Real<4>{7}, Int<4>{-5}), Real<4>{1} / Real<4>{16807});
EXPECT_EQ(
RTNAME(FPow4i)(Real<4>{2}, Int<4>{-133}), std::ldexp(Real<4>{1}, -133));
EXPECT_EQ(RTNAME(FPow4i)(Real<4>{2}, std::numeric_limits<Int<4>>::min()),
diff --git a/flang/test/Evaluate/folding07.f90 b/flang/test/Evaluate/folding07.f90
index 8fc0a20f246eb7..d9e4a2c31cc81d 100644
--- a/flang/test/Evaluate/folding07.f90
+++ b/flang/test/Evaluate/folding07.f90
@@ -308,8 +308,15 @@ module m
logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
logical, parameter :: test_pow_subnormal_4 = 2.0_4**(-133) == scale(1.0_4, -133)
+ logical, parameter :: test_pow_subnormal_8 = 2.0_8**(-1070) == scale(1.0_8, -1070)
+ logical, parameter :: test_pow_subnormal_16 = 2.0_16**(-16400) == scale(1.0_16, -16400)
logical, parameter :: test_pow_neg_3 = 3.0**(-2) == 1.0/3.0**2
logical, parameter :: test_pow_neg_7 = 7.0**(-5) == 1.0/7.0**5
+ logical, parameter :: test_pow_neg_10 = 10.0**(-2) == 1.0/10.0**2
+ logical, parameter :: test_pow_neg_2_5 = 2.5**(-9) == 1.0/2.5**9
logical, parameter :: test_pow_min_int1 = 1.5_8**(-128_1) < 1.0_8
+ logical, parameter :: test_pow_min_int1_retry = 2.0_4**(-128_1) == scale(1.0_4, -128)
+ logical, parameter :: test_pow_min_int2 = 1.0001_8**(-32768_2) < 1.0_8
+ logical, parameter :: test_pow_min_int4 = 1.0000001_8**(-huge(1)-1) < 1.0_8
end module
>From 5333dd9c893374fb6fa72a6175913966e6ab1de5 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Thu, 22 Oct 2026 06:36:14 +0000
Subject: [PATCH 5/5] Updated the test cases as per review requests
---
flang-rt/unittests/Runtime/Numeric.cpp | 6 ++++++
flang/test/Evaluate/folding07.f90 | 7 +++++++
2 files changed, 13 insertions(+)
diff --git a/flang-rt/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/Runtime/Numeric.cpp
index ae2e25d8b24e0d..8b67e04b2bff4d 100644
--- a/flang-rt/unittests/Runtime/Numeric.cpp
+++ b/flang-rt/unittests/Runtime/Numeric.cpp
@@ -276,6 +276,8 @@ TEST(Numeric, FPowI) {
RTNAME(FPow4i)(Real<4>{7}, Int<4>{-5}), Real<4>{1} / Real<4>{16807});
EXPECT_EQ(
RTNAME(FPow4i)(Real<4>{2}, Int<4>{-133}), std::ldexp(Real<4>{1}, -133));
+ EXPECT_EQ(RTNAME(FPow4i)(Real<4>{3}, Int<4>{-88}),
+ static_cast<Real<4>>(std::pow(3.0f, -88.0f)));
EXPECT_EQ(RTNAME(FPow4i)(Real<4>{2}, std::numeric_limits<Int<4>>::min()),
Real<4>{0});
@@ -296,6 +298,8 @@ TEST(Numeric, FPowI) {
EXPECT_EQ(RTNAME(FPow8i)(Real<8>{-2}, Int<4>{-3}), Real<8>{-0.125});
EXPECT_EQ(
RTNAME(FPow8i)(Real<8>{2}, Int<4>{-1070}), std::ldexp(Real<8>{1}, -1070));
+ EXPECT_EQ(RTNAME(FPow8i)(Real<8>{2}, std::numeric_limits<Int<4>>::min()),
+ Real<8>{0});
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});
@@ -303,6 +307,8 @@ TEST(Numeric, FPowI) {
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});
+ EXPECT_EQ(RTNAME(FPow8k)(Real<8>{2}, std::numeric_limits<Int<8>>::min()),
+ Real<8>{0});
#if HAS_FLOAT80
EXPECT_EQ(RTNAME(FPow10i)(Real<10>{0}, Int<4>{0}), Real<10>{1});
diff --git a/flang/test/Evaluate/folding07.f90 b/flang/test/Evaluate/folding07.f90
index d9e4a2c31cc81d..af13dc3e641b9b 100644
--- a/flang/test/Evaluate/folding07.f90
+++ b/flang/test/Evaluate/folding07.f90
@@ -308,6 +308,13 @@ module m
logical, parameter :: test_set_exponent_2 = set_exponent(1., 2) == 2.
logical, parameter :: test_set_exponent_min = set_exponent(1., -149) == 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45_4
logical, parameter :: test_pow_subnormal_4 = 2.0_4**(-133) == scale(1.0_4, -133)
+ logical, parameter :: test_pow_subnormal_minpos_4 = 2.0_4**(-149) == scale(1.0_4, -149)
+ !WARN: warning: underflow on power with INTEGER exponent [-Wfolding-exception]
+ logical, parameter :: test_pow_subnormal_belowmin_4 = 2.0_4**(-150) == 0.0_4
+ logical, parameter :: test_pow_neg_base_odd_4 = (-2.0_4)**(-133) == -scale(1.0_4, -133)
+ !WARN: warning: underflow on power with INTEGER exponent [-Wfolding-exception]
+ !WARN: warning: underflow on power with INTEGER exponent [-Wfolding-exception]
+ logical, parameter :: test_pow_neg_npot_4 = 5.0_4**(-64) == (1.0_4/5.0_4)**64
logical, parameter :: test_pow_subnormal_8 = 2.0_8**(-1070) == scale(1.0_8, -1070)
logical, parameter :: test_pow_subnormal_16 = 2.0_16**(-16400) == scale(1.0_16, -16400)
logical, parameter :: test_pow_neg_3 = 3.0**(-2) == 1.0/3.0**2
More information about the flang-commits
mailing list