[libc-commits] [libc] [libc][math] Remove unneccessary checks and speedup for pow_fast under LIBC_MATH_HAS_SMALL_TABLES. (PR #232623)

via libc-commits libc-commits at lists.llvm.org
Thu Oct 15 23:56:44 PDT 2026


https://github.com/lntue created https://github.com/llvm/llvm-project/pull/232623

This reduces code size by about 2.5 KB.

>From 9694dc3c188fa91d73201bc63934270237112cab Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 16 Oct 2026 06:49:54 +0000
Subject: [PATCH] [libc][math] Remove unneccessary checks and speedup for
 pow_fast under LIBC_MATH_HAS_SMALL_TABLES.

---
 libc/src/__support/math/pow_fast.h    |   8 +-
 libc/src/__support/math/pow_utils.h   | 172 ++++++++++++++------------
 libc/test/src/math/smoke/pow_test.cpp |  26 ++--
 3 files changed, 116 insertions(+), 90 deletions(-)

diff --git a/libc/src/__support/math/pow_fast.h b/libc/src/__support/math/pow_fast.h
index 5960bea60642b0..fb8d14bea8dfe8 100644
--- a/libc/src/__support/math/pow_fast.h
+++ b/libc/src/__support/math/pow_fast.h
@@ -36,14 +36,17 @@ LIBC_INLINE double pow(double x, double y) {
 
   FPBits xbits(x), ybits(y);
   uint64_t x_u = xbits.uintval();
-  uint64_t y_u = ybits.uintval();
   uint64_t y_a = ybits.abs().uintval();
 
+#ifndef LIBC_MATH_HAS_SMALL_TABLES
+  uint64_t y_u = ybits.uintval();
+
   if (LIBC_UNLIKELY((x_u & 0x0003'FFFF'FFFF'FFFF) == 0 ||
                     (y_u & 0x000F'FFFF'FFFF'FFFF) == 0)) {
     if (auto r = check_special_inputs(x, y); LIBC_UNLIKELY(r.has_value()))
       return r.value();
   }
+#endif // !LIBC_MATH_HAS_SMALL_TABLES
 
   double e_x = static_cast<double>(xbits.get_exponent());
   uint64_t x_mant = xbits.get_mantissa();
@@ -51,6 +54,9 @@ LIBC_INLINE double pow(double x, double y) {
   double sign_d = 1.0;
 
   if (LIBC_UNLIKELY(y_a <= Y_LOWER_BOUND || y_a >= Y_UPPER_BOUND ||
+#ifdef LIBC_MATH_HAS_SMALL_TABLES
+                    x_u == FPBits::one().uintval() ||
+#endif // LIBC_MATH_HAS_SMALL_TABLES
                     x_u >= FPBits::inf().uintval() ||
                     x_u < FPBits::min_normal().uintval())) {
     if (auto r = check_exceptional_cases(x, y, e_x, x_mant, is_neg, sign_d);
diff --git a/libc/src/__support/math/pow_utils.h b/libc/src/__support/math/pow_utils.h
index 83eba6007e20f3..305dbc67590be8 100644
--- a/libc/src/__support/math/pow_utils.h
+++ b/libc/src/__support/math/pow_utils.h
@@ -434,101 +434,115 @@ check_exceptional_cases(double &x, double &y, double &e_x, uint64_t &x_mant,
   FPBits x_abs = xbits.abs();
   FPBits y_abs = ybits.abs();
 
-  uint64_t x_u = xbits.uintval();
   uint64_t y_mant = ybits.get_mantissa();
   uint64_t x_a = x_abs.uintval();
   uint64_t y_a = y_abs.uintval();
 
-  if (LIBC_UNLIKELY(y_a <= Y_LOWER_BOUND || y_a >= Y_UPPER_BOUND ||
-                    x_u >= FPBits::inf().uintval() ||
-                    x_u < FPBits::min_normal().uintval())) {
-    // If x or y is signaling NaN
-    if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) {
-      fputil::raise_except_if_required(FE_INVALID);
-      return FPBits::quiet_nan().get_val();
-    }
+  // If x or y is signaling NaN
+  if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) {
+    fputil::raise_except_if_required(FE_INVALID);
+    return FPBits::quiet_nan().get_val();
+  }
 
-    // |y| > |1075 / log2(1 - 2^-53)|.
-    if (y_a > 0x43d7'4910'd52d'3052) {
-      if (y_a >= 0x7ff0'0000'0000'0000) {
-        // y is inf or nan
-        if (y_mant != 0) {
-          // y is NaN
-          // pow(1, NaN) = 1 is already dealt with.
-          // pow(x, NaN) = NaN
-          return y;
-        }
-
-        // Now y is +-Inf
-        if (x_abs.is_nan()) {
-          // pow(NaN, +-Inf) = NaN
-          return x;
-        }
-
-        if (x_a == 0x3ff0'0000'0000'0000) {
-          // pow(+-1, +-Inf) = 1.0
-          return 1.0;
-        }
-
-        // pow (|x| < 1, -inf) = +inf
-        // pow (|x| < 1, +inf) = 0.0
-        // pow (|x| > 1, -inf) = 0.0
-        // pow (|x| > 1, +inf) = +inf
-        return ((x_a < FPBits::one().uintval()) == y_sign)
-                   ? FPBits::inf().get_val()
-                   : 0.0;
+#ifdef LIBC_MATH_HAS_SMALL_TABLES
+  if (x == 1.0 || y == 0.0)
+    return 1.0;
+#endif // LIBC_MATH_HAS_SMALL_TABLES
+
+  // |y| > |1075 / log2(1 - 2^-53)|.
+  if (y_a > Y_UPPER_BOUND) {
+    if (y_a >= FPBits::inf().uintval()) {
+      // y is inf or nan
+      if (y_mant != 0) {
+        // y is NaN
+        // pow(1, NaN) = 1 is already dealt with.
+        // pow(x, NaN) = NaN
+        return y;
       }
-      // x^y will overflow / underflow in double precision.  Set y to a
-      // large enough exponent but not too large, so that the computations
-      // won't overflow in double precision.
-      y = y_sign ? -0x1.0p100 : 0x1.0p100;
-    }
 
-    // y is finite and non-zero.
+      // Now y is +-Inf
+      if (x_abs.is_nan()) {
+        // pow(NaN, +-Inf) = NaN
+        return x;
+      }
 
-    if (x_a == FPBits::inf().uintval()) {
-      bool out_is_neg = x_sign && is_odd_integer(y);
-      Sign out_sign = out_is_neg ? Sign::NEG : Sign::POS;
-      return y_sign ? FPBits::zero(out_sign).get_val()
-                    : FPBits::inf(out_sign).get_val();
-    }
+      if (x_a == FPBits::one().uintval()) {
+        // pow(+-1, +-Inf) = 1.0
+        return 1.0;
+      }
 
-    if (x_a > FPBits::inf().uintval()) {
-      // x is NaN.
-      // pow (aNaN, 0) is already taken care above.
-      return x;
+      // pow (|x| < 1, -inf) = +inf
+      // pow (|x| < 1, +inf) = 0.0
+      // pow (|x| > 1, -inf) = 0.0
+      // pow (|x| > 1, +inf) = +inf
+      return ((x_a < FPBits::one().uintval()) == y_sign)
+                 ? FPBits::inf().get_val()
+                 : 0.0;
     }
+    // x^y will overflow / underflow in double precision.  Set y to a
+    // large enough exponent but not too large, so that the computations
+    // won't overflow in double precision.
+    y = y_sign ? -0x1.0p100 : 0x1.0p100;
+  }
 
-    // Normalize denormal inputs.
-    if (x_a < FPBits::min_normal().uintval()) {
-      FPBits x_norm(x * 0x1.0p64);
-      e_x = static_cast<double>(x_norm.get_exponent()) - 64.0;
-      x_mant = x_norm.get_mantissa();
-    }
+  // y is finite and non-zero.
+  if (x_a > FPBits::inf().uintval()) {
+    // x is NaN.
+    // pow (aNaN, 0) is already taken care above.
+    return x;
+  }
 
-    // x is finite and negative, and y is a finite integer.
-    if (x_sign) {
-      if (is_integer(y)) {
-        x = -x;
-        if (is_odd_integer(y)) {
-          is_neg = true;
-          sign_d = -1.0;
-        }
-      } else {
-        // pow( negative, non-integer ) = NaN
-        fputil::set_errno_if_required(EDOM);
-        fputil::raise_except_if_required(FE_INVALID);
-        return FPBits::quiet_nan().get_val();
+  if (x_sign) {
+    if (is_integer(y)) {
+      x = -x;
+      if (is_odd_integer(y)) {
+        is_neg = true;
+        sign_d = -1.0;
       }
+    } else if (x != 0.0 && x_a < FPBits::inf().uintval()) {
+      // pow( negative, non-integer ) = NaN
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
+      return FPBits::quiet_nan().get_val();
     }
+  }
 
-    if (y_a <= Y_LOWER_BOUND) {
-      volatile double one = 1.0;
-      volatile double eps = ((x_a < FPBits::one().uintval()) == !y_sign)
-                                ? -0x1.0p-100
-                                : 0x1.0p-100;
-      return one + eps;
+#ifdef LIBC_MATH_HAS_SMALL_TABLES
+  if (x == 0.0) {
+    if (y_sign) {
+      // pow(0, negative number) = inf
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_DIVBYZERO);
+      return is_neg ? -FPBits::inf().get_val() : FPBits::inf().get_val();
     }
+    // pow(0, positive number) = 0
+    return is_neg ? -0.0 : 0.0;
+  }
+#endif // LIBC_MATH_HAS_SMALL_TABLES
+
+  if (x_a == FPBits::inf().uintval()) {
+    if (y_sign)
+      return is_neg ? -0.0 : 0.0;
+    return is_neg ? -FPBits::inf().get_val() : FPBits::inf().get_val();
+  }
+
+  if (y_a <= Y_LOWER_BOUND) {
+#if defined(LIBC_MATH_HAS_NO_EXCEPT) &&                                        \
+    defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY)
+    return 1.0;
+#else
+    volatile double one = 1.0;
+    volatile double eps =
+        ((x_a < FPBits::one().uintval()) == !y_sign) ? -0x1.0p-100 : 0x1.0p-100;
+    return one + eps;
+#endif // LIBC_MATH_HAS_NO_EXCEPT && LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
+  }
+
+  // Normalize denormal inputs.
+  if (x_a < FPBits::min_normal().uintval()) {
+    FPBits x_norm(x * 0x1.0p64);
+    e_x = static_cast<double>(x_norm.get_exponent()) - 64.0;
+    x_mant = x_norm.get_mantissa();
   }
 
   return cpp::nullopt;
diff --git a/libc/test/src/math/smoke/pow_test.cpp b/libc/test/src/math/smoke/pow_test.cpp
index 9e7599d9546d9d..61b3f6d0179193 100644
--- a/libc/test/src/math/smoke/pow_test.cpp
+++ b/libc/test/src/math/smoke/pow_test.cpp
@@ -206,16 +206,22 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) {
 
     // Exact powers of 10:
     EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(10.0, 0.0));
-    EXPECT_FP_EQ(10.0, LIBC_NAMESPACE::pow(10.0, 1.0));
-    EXPECT_FP_EQ(100.0, LIBC_NAMESPACE::pow(10.0, 2.0));
-    EXPECT_FP_EQ(1000.0, LIBC_NAMESPACE::pow(10.0, 3.0));
-    EXPECT_FP_EQ(10000.0, LIBC_NAMESPACE::pow(10.0, 4.0));
-    EXPECT_FP_EQ(100000.0, LIBC_NAMESPACE::pow(10.0, 5.0));
-    EXPECT_FP_EQ(1000000.0, LIBC_NAMESPACE::pow(10.0, 6.0));
-    EXPECT_FP_EQ(10000000.0, LIBC_NAMESPACE::pow(10.0, 7.0));
-    EXPECT_FP_EQ(100000000.0, LIBC_NAMESPACE::pow(10.0, 8.0));
-    EXPECT_FP_EQ(1000000000.0, LIBC_NAMESPACE::pow(10.0, 9.0));
-    EXPECT_FP_EQ(10000000000.0, LIBC_NAMESPACE::pow(10.0, 10.0));
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+    if (ROUNDING_MODES[i] == RoundingMode::Nearest) {
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+      EXPECT_FP_EQ(10.0, LIBC_NAMESPACE::pow(10.0, 1.0));
+      EXPECT_FP_EQ(100.0, LIBC_NAMESPACE::pow(10.0, 2.0));
+      EXPECT_FP_EQ(1000.0, LIBC_NAMESPACE::pow(10.0, 3.0));
+      EXPECT_FP_EQ(10000.0, LIBC_NAMESPACE::pow(10.0, 4.0));
+      EXPECT_FP_EQ(100000.0, LIBC_NAMESPACE::pow(10.0, 5.0));
+      EXPECT_FP_EQ(1000000.0, LIBC_NAMESPACE::pow(10.0, 6.0));
+      EXPECT_FP_EQ(10000000.0, LIBC_NAMESPACE::pow(10.0, 7.0));
+      EXPECT_FP_EQ(100000000.0, LIBC_NAMESPACE::pow(10.0, 8.0));
+      EXPECT_FP_EQ(1000000000.0, LIBC_NAMESPACE::pow(10.0, 9.0));
+      EXPECT_FP_EQ(10000000000.0, LIBC_NAMESPACE::pow(10.0, 10.0));
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+    }
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 
     // Overflow / Underflow:
     if (ROUNDING_MODES[i] != RoundingMode::Downward &&



More information about the libc-commits mailing list