[libc-commits] [libc] [libc][math] Short-circuit certain powf range errors (PR #223719)
via libc-commits
libc-commits at lists.llvm.org
Tue Sep 15 21:59:10 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: sriramshastry
<details>
<summary>Changes</summary>
### Summary
Return overflow and underflow results directly when float bounds prove
that the exact `powf` result is outside the representable range. This
avoids the log2 and exp2 approximations for those inputs.
Rounding-mode results, `errno`, and floating-point exceptions are
preserved.
### Correctness
- Compared 16,214,688 records against main across all four rounding
modes.
- Result bits, `errno`, and floating-point exception flags matched.
- LLVM libc smoke tests passed: 20/20 across default, no-FMA, no-round,
and combined configurations.
### Performance
LLVM has no checked-in `powf_perf` target. Measurements used a minimal
driver that directly instantiates LLVM's unmodified
`BINARY_INPUT_SINGLE_OUTPUT_PERF` macro from `PerfTest.h`.
Three alternating CPU 0 comparisons produced these median savings:
- Denormal range: 3.53 ns (2.01%).
- Normal range: 53.13 ns (78.64%).
- Close-exponent range: 2.95 ns (15.89%).
CPU frequency scaling was enabled, so results are reported in ns/op and
are not converted to cycles.
---
Full diff: https://github.com/llvm/llvm-project/pull/223719.diff
1 Files Affected:
- (modified) libc/src/__support/math/powf.h (+36)
``````````diff
diff --git a/libc/src/__support/math/powf.h b/libc/src/__support/math/powf.h
index 944b477ac44612..b95d3d2bd10d7c 100644
--- a/libc/src/__support/math/powf.h
+++ b/libc/src/__support/math/powf.h
@@ -37,6 +37,7 @@
#include "src/__support/FPUtil/double_double.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/FPUtil/sqrt.h" // Speedup for powf(x, 1/2) = sqrtf(x)
#include "src/__support/FPUtil/triple_double.h"
#include "src/__support/common.h"
@@ -693,6 +694,26 @@ LIBC_INLINE float powf(float x, float y) {
return FloatBits::quiet_nan().get_val();
}
+ if (y_abs > 0x4f17'0000U && y_abs < 0x7f80'0000U && x_u != 0 &&
+ x_u < 0x7f80'0000U && x_u != 0x3f80'0000U &&
+ x_u != 0x4000'0000U && x_u != 0x4120'0000U) {
+ const bool overflow = (x_u > 0x3f80'0000U) != (y_u > 0x8000'0000U);
+ if (overflow) {
+ fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
+ static volatile float rounding_test = 0x1.0p-25f;
+ if (1.0f - rounding_test != 1.0f)
+ return FloatBits::max_normal().get_val();
+ fputil::set_errno_if_required(ERANGE);
+ return FloatBits::inf().get_val();
+ }
+
+ fputil::raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+ if (fputil::fenv_is_round_up())
+ return FloatBits::min_subnormal().get_val();
+ fputil::set_errno_if_required(ERANGE);
+ return 0.0f;
+ }
+
// Exceptional exponents.
if (y == 0.0f)
return 1.0f;
@@ -781,6 +802,21 @@ LIBC_INLINE float powf(float x, float y) {
}
}
+ if (LIBC_UNLIKELY(y_u >= 0x3f80'0000U && y_u < 0x7f80'0000U && x_u > 0 &&
+ x_u < 0x3f00'0000U)) {
+ // If x is in [2^(e - 127), 2^(e - 126)), then
+ // log2(x) < -(126 - e). Use this bound to identify results below
+ // 2^-150 without evaluating log2(x).
+ int log2_bound = 126 - static_cast<int>(x_u >> FloatBits::FRACTION_LEN);
+ if (LIBC_UNLIKELY(static_cast<double>(y) * log2_bound >= 150.0)) {
+ fputil::raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
+ if (fputil::fenv_is_round_up())
+ return FloatBits::min_subnormal().get_val();
+ fputil::set_errno_if_required(ERANGE);
+ return 0.0f;
+ }
+ }
+
int ex = -FloatBits::EXP_BIAS;
uint64_t sign = 0;
``````````
</details>
https://github.com/llvm/llvm-project/pull/223719
More information about the libc-commits
mailing list