[libc-commits] [libc] [llvm] [libc][math] Refactor log2f to Header Only. (PR #176527)

via libc-commits libc-commits at lists.llvm.org
Tue Jan 27 01:20:20 PST 2026


https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/176527

>From 47d863ae546ecf6cc8791085d3562355e348e196 Mon Sep 17 00:00:00 2001
From: anonmiraj <nabilmalek48 at gmail.com>
Date: Sat, 17 Jan 2026 03:30:44 +0200
Subject: [PATCH 1/2] [libc][math] Refactor log2f to Header Only.

---
 libc/shared/math.h                            |   1 +
 libc/shared/math/log2f.h                      |  23 +++
 libc/src/__support/math/CMakeLists.txt        |  14 ++
 libc/src/__support/math/log2f.h               | 133 ++++++++++++++++++
 libc/src/math/generic/CMakeLists.txt          |   9 +-
 libc/src/math/generic/log2f.cpp               | 113 +--------------
 libc/test/shared/CMakeLists.txt               |   1 +
 libc/test/shared/shared_math_test.cpp         |   1 +
 .../llvm-project-overlay/libc/BUILD.bazel     |  21 ++-
 9 files changed, 193 insertions(+), 123 deletions(-)
 create mode 100644 libc/shared/math/log2f.h
 create mode 100644 libc/src/__support/math/log2f.h

diff --git a/libc/shared/math.h b/libc/shared/math.h
index 7b2a12ac2bfaa..ad8183e7ac357 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -81,6 +81,7 @@
 #include "math/log10.h"
 #include "math/log1p.h"
 #include "math/log2.h"
+#include "math/log2f.h"
 #include "math/logbf.h"
 #include "math/logbf128.h"
 #include "math/logbf16.h"
diff --git a/libc/shared/math/log2f.h b/libc/shared/math/log2f.h
new file mode 100644
index 0000000000000..db0467623d01c
--- /dev/null
+++ b/libc/shared/math/log2f.h
@@ -0,0 +1,23 @@
+//===-- Shared log2f function -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SHARED_MATH_LOG2F_H
+#define LLVM_LIBC_SHARED_MATH_LOG2F_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/log2f.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::log2f;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_LOG2F_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index c0efa3dfc9c25..89094e76c56c9 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -1211,6 +1211,20 @@ add_header_library(
     libc.src.__support.macros.optimization
 )
 
+add_header_library(
+  log2f
+  HDRS
+    log2f.h
+  DEPENDS
+    .common_constants
+    libc.src.__support.FPUtil.except_value_utils
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fma
+    libc.src.__support.FPUtil.fp_bits
+    libc.src.__support.FPUtil.polyeval
+    libc.src.__support.macros.optimization
+)
+
 add_header_library(
   logbf128
   HDRS
diff --git a/libc/src/__support/math/log2f.h b/libc/src/__support/math/log2f.h
new file mode 100644
index 0000000000000..7909440c2450e
--- /dev/null
+++ b/libc/src/__support/math/log2f.h
@@ -0,0 +1,133 @@
+//===-- Implementation header for log2f ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOG2F_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_LOG2F_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"   // LIBC_UNLIKELY
+#include "common_constants.h" // Lookup table for (1/f)
+
+// This is a correctly-rounded algorithm for log2(x) in single precision with
+// round-to-nearest, tie-to-even mode from the RLIBM project at:
+// https://people.cs.rutgers.edu/~sn349/rlibm
+
+// Step 1 - Range reduction:
+//   For x = 2^m * 1.mant, log2(x) = m + log2(1.m)
+//   If x is denormal, we normalize it by multiplying x by 2^23 and subtracting
+//   m by 23.
+
+// Step 2 - Another range reduction:
+//   To compute log(1.mant), let f be the highest 8 bits including the hidden
+// bit, and d be the difference (1.mant - f), i.e. the remaining 16 bits of the
+// mantissa. Then we have the following approximation formula:
+//   log2(1.mant) = log2(f) + log2(1.mant / f)
+//                = log2(f) + log2(1 + d/f)
+//                ~ log2(f) + P(d/f)
+// since d/f is sufficiently small.
+//   log2(f) and 1/f are then stored in two 2^7 = 128 entries look-up tables.
+
+// Step 3 - Polynomial approximation:
+//   To compute P(d/f), we use a single degree-5 polynomial in double precision
+// which provides correct rounding for all but few exception values.
+//   For more detail about how this polynomial is obtained, please refer to the
+// papers:
+//   Lim, J. and Nagarakatte, S., "One Polynomial Approximation to Produce
+// Correctly Rounded Results of an Elementary Function for Multiple
+// Representations and Rounding Modes", Proceedings of the 49th ACM SIGPLAN
+// Symposium on Principles of Programming Languages (POPL-2022), Philadelphia,
+// USA, Jan. 16-22, 2022.
+// https://people.cs.rutgers.edu/~sn349/papers/rlibmall-popl-2022.pdf
+//   Aanjaneya, M., Lim, J., and Nagarakatte, S., "RLibm-Prog: Progressive
+// Polynomial Approximations for Fast Correctly Rounded Math Libraries",
+// Dept. of Comp. Sci., Rutgets U., Technical Report DCS-TR-758, Nov. 2021.
+// https://arxiv.org/pdf/2111.12852.pdf.
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE static constexpr float log2f(float x) {
+  using namespace common_constants_internal;
+  using FPBits = typename fputil::FPBits<float>;
+
+  FPBits xbits(x);
+  uint32_t x_u = xbits.uintval();
+
+  // Hard to round value(s).
+  using fputil::round_result_slightly_up;
+
+  int m = -FPBits::EXP_BIAS;
+
+  // log2(1.0f) = 0.0f.
+  if (LIBC_UNLIKELY(x_u == 0x3f80'0000U))
+    return 0.0f;
+
+  // Exceptional inputs.
+  if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
+                    x_u > FPBits::max_normal().uintval())) {
+    if (x == 0.0f) {
+      fputil::set_errno_if_required(ERANGE);
+      fputil::raise_except_if_required(FE_DIVBYZERO);
+      return FPBits::inf(Sign::NEG).get_val();
+    }
+    if (xbits.is_neg() && !xbits.is_nan()) {
+      fputil::set_errno_if_required(EDOM);
+      fputil::raise_except_if_required(FE_INVALID);
+      return FPBits::quiet_nan().get_val();
+    }
+    if (xbits.is_inf_or_nan()) {
+      return x;
+    }
+    // Normalize denormal inputs.
+    xbits = FPBits(xbits.get_val() * 0x1.0p23f);
+    m -= 23;
+  }
+
+  m += xbits.get_biased_exponent();
+  int index = xbits.get_mantissa() >> 16;
+  // Set bits to 1.m
+  xbits.set_biased_exponent(0x7F);
+
+  float u = xbits.get_val();
+#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
+  double v =
+      static_cast<double>(fputil::multiply_add(u, R[index], -1.0f)); // Exact.
+#else
+  double v =
+      fputil::multiply_add(static_cast<double>(u), RD[index], -1.0); // Exact
+#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT
+
+  double extra_factor = static_cast<double>(m) + LOG2_R[index];
+
+  // Degree-5 polynomial approximation of log2 generated by Sollya with:
+  // > P = fpminimax(log2(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]);
+  constexpr double COEFFS[5] = {0x1.71547652b8133p0, -0x1.71547652d1e33p-1,
+                                0x1.ec70a098473dep-2, -0x1.7154c5ccdf121p-2,
+                                0x1.2514fd90a130ap-2};
+
+  double vsq = v * v; // Exact
+  double c0 = fputil::multiply_add(v, COEFFS[0], extra_factor);
+  double c1 = fputil::multiply_add(v, COEFFS[2], COEFFS[1]);
+  double c2 = fputil::multiply_add(v, COEFFS[4], COEFFS[3]);
+
+  double r = fputil::polyeval(vsq, c0, c1, c2);
+
+  return static_cast<float>(r);
+}
+
+} // namespace math
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOG2F_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index f369206c39a16..c91f0fe74ffce 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -2013,13 +2013,8 @@ add_entrypoint_object(
   HDRS
     ../log2f.h
   DEPENDS
-    libc.src.__support.FPUtil.except_value_utils
-    libc.src.__support.FPUtil.fenv_impl
-    libc.src.__support.FPUtil.fp_bits
-    libc.src.__support.FPUtil.fma
-    libc.src.__support.FPUtil.polyeval
-    libc.src.__support.macros.optimization
-    libc.src.__support.math.common_constants
+    libc.src.__support.math.log2f
+    libc.src.errno.errno
 )
 
 add_entrypoint_object(
diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp
index 7353f0302ab3e..9c9d34ca3ddd3 100644
--- a/libc/src/math/generic/log2f.cpp
+++ b/libc/src/math/generic/log2f.cpp
@@ -7,119 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/math/log2f.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.h"
-#include "src/__support/FPUtil/except_value_utils.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h"   // LIBC_UNLIKELY
-#include "src/__support/math/common_constants.h" // Lookup table for (1/f)
-
-// This is a correctly-rounded algorithm for log2(x) in single precision with
-// round-to-nearest, tie-to-even mode from the RLIBM project at:
-// https://people.cs.rutgers.edu/~sn349/rlibm
-
-// Step 1 - Range reduction:
-//   For x = 2^m * 1.mant, log2(x) = m + log2(1.m)
-//   If x is denormal, we normalize it by multiplying x by 2^23 and subtracting
-//   m by 23.
-
-// Step 2 - Another range reduction:
-//   To compute log(1.mant), let f be the highest 8 bits including the hidden
-// bit, and d be the difference (1.mant - f), i.e. the remaining 16 bits of the
-// mantissa. Then we have the following approximation formula:
-//   log2(1.mant) = log2(f) + log2(1.mant / f)
-//                = log2(f) + log2(1 + d/f)
-//                ~ log2(f) + P(d/f)
-// since d/f is sufficiently small.
-//   log2(f) and 1/f are then stored in two 2^7 = 128 entries look-up tables.
-
-// Step 3 - Polynomial approximation:
-//   To compute P(d/f), we use a single degree-5 polynomial in double precision
-// which provides correct rounding for all but few exception values.
-//   For more detail about how this polynomial is obtained, please refer to the
-// papers:
-//   Lim, J. and Nagarakatte, S., "One Polynomial Approximation to Produce
-// Correctly Rounded Results of an Elementary Function for Multiple
-// Representations and Rounding Modes", Proceedings of the 49th ACM SIGPLAN
-// Symposium on Principles of Programming Languages (POPL-2022), Philadelphia,
-// USA, Jan. 16-22, 2022.
-// https://people.cs.rutgers.edu/~sn349/papers/rlibmall-popl-2022.pdf
-//   Aanjaneya, M., Lim, J., and Nagarakatte, S., "RLibm-Prog: Progressive
-// Polynomial Approximations for Fast Correctly Rounded Math Libraries",
-// Dept. of Comp. Sci., Rutgets U., Technical Report DCS-TR-758, Nov. 2021.
-// https://arxiv.org/pdf/2111.12852.pdf.
+#include "src/__support/math/log2f.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
-  using namespace common_constants_internal;
-  using FPBits = typename fputil::FPBits<float>;
-
-  FPBits xbits(x);
-  uint32_t x_u = xbits.uintval();
-
-  // Hard to round value(s).
-  using fputil::round_result_slightly_up;
-
-  int m = -FPBits::EXP_BIAS;
-
-  // log2(1.0f) = 0.0f.
-  if (LIBC_UNLIKELY(x_u == 0x3f80'0000U))
-    return 0.0f;
-
-  // Exceptional inputs.
-  if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() ||
-                    x_u > FPBits::max_normal().uintval())) {
-    if (x == 0.0f) {
-      fputil::set_errno_if_required(ERANGE);
-      fputil::raise_except_if_required(FE_DIVBYZERO);
-      return FPBits::inf(Sign::NEG).get_val();
-    }
-    if (xbits.is_neg() && !xbits.is_nan()) {
-      fputil::set_errno_if_required(EDOM);
-      fputil::raise_except_if_required(FE_INVALID);
-      return FPBits::quiet_nan().get_val();
-    }
-    if (xbits.is_inf_or_nan()) {
-      return x;
-    }
-    // Normalize denormal inputs.
-    xbits = FPBits(xbits.get_val() * 0x1.0p23f);
-    m -= 23;
-  }
-
-  m += xbits.get_biased_exponent();
-  int index = xbits.get_mantissa() >> 16;
-  // Set bits to 1.m
-  xbits.set_biased_exponent(0x7F);
-
-  float u = xbits.get_val();
-  double v;
-#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT
-  v = static_cast<double>(fputil::multiply_add(u, R[index], -1.0f)); // Exact.
-#else
-  v = fputil::multiply_add(static_cast<double>(u), RD[index], -1.0); // Exact
-#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT
-
-  double extra_factor = static_cast<double>(m) + LOG2_R[index];
-
-  // Degree-5 polynomial approximation of log2 generated by Sollya with:
-  // > P = fpminimax(log2(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]);
-  constexpr double COEFFS[5] = {0x1.71547652b8133p0, -0x1.71547652d1e33p-1,
-                                0x1.ec70a098473dep-2, -0x1.7154c5ccdf121p-2,
-                                0x1.2514fd90a130ap-2};
-
-  double vsq = v * v; // Exact
-  double c0 = fputil::multiply_add(v, COEFFS[0], extra_factor);
-  double c1 = fputil::multiply_add(v, COEFFS[2], COEFFS[1]);
-  double c2 = fputil::multiply_add(v, COEFFS[4], COEFFS[3]);
-
-  double r = fputil::polyeval(vsq, c0, c1, c2);
-
-  return static_cast<float>(r);
-}
+LLVM_LIBC_FUNCTION(float, log2f, (float x)) { return math::log2f(x); }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 0a19dfd9dbba9..17d94790d98b8 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -74,6 +74,7 @@ add_fp_unittest(
     libc.src.__support.math.log10
     libc.src.__support.math.log1p
     libc.src.__support.math.log2
+    libc.src.__support.math.log2f
     libc.src.__support.math.logbf
     libc.src.__support.math.logbf128
     libc.src.__support.math.logbf16
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index da1c62520042d..0fc5a8e483cda 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -91,6 +91,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
   ASSERT_FP_EQ(float(-1 * (8 << 5)), LIBC_NAMESPACE::shared::ldexpf(-8.0f, 5));
 
   EXPECT_EQ(long(0), LIBC_NAMESPACE::shared::llogbf(1.0f));
+  EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::log2f(2.0f));
   EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::logbf(1.0f));
   EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::rsqrtf(1.0f));
   EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::shared::sinf(0.0f));
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 9d6641a5847f1..f19e70d05def2 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3107,6 +3107,20 @@ libc_support_library(
     ],
 )
 
+libc_support_library(
+    name = "__support_math_log2f",
+    hdrs = ["src/__support/math/log2f.h"],
+    deps = [
+        ":__support_fputil_except_value_utils",
+        ":__support_fputil_fenv_impl",
+        ":__support_fputil_fma",
+        ":__support_fputil_fp_bits",
+        ":__support_fputil_polyeval",
+        ":__support_macros_optimization",
+        ":__support_math_common_constants",
+    ],
+)
+
 libc_support_library(
     name = "__support_math_logbf",
     hdrs = ["src/__support/math/logbf.h"],
@@ -4859,11 +4873,8 @@ libc_math_function(
 libc_math_function(
     name = "log2f",
     additional_deps = [
-        ":__support_fputil_fma",
-        ":__support_fputil_multiply_add",
-        ":__support_fputil_polyeval",
-        ":__support_macros_optimization",
-        ":__support_math_common_constants",
+        ":__support_math_log2f",
+        ":errno",
     ],
 )
 

>From 354240f395ca6c03684a70dbb5567f8c894a5d0d Mon Sep 17 00:00:00 2001
From: anonmiraj <ezzibrahimx at gmail.com>
Date: Sun, 25 Jan 2026 15:18:13 +0200
Subject: [PATCH 2/2] fix formatting

---
 libc/src/__support/math/log2f.h                   | 6 +++---
 libc/src/math/generic/CMakeLists.txt              | 1 -
 utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 1 -
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/libc/src/__support/math/log2f.h b/libc/src/__support/math/log2f.h
index 7909440c2450e..f3d4a5ad6a86e 100644
--- a/libc/src/__support/math/log2f.h
+++ b/libc/src/__support/math/log2f.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOG2F_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_LOG2F_H
 
+#include "common_constants.h" // Lookup table for (1/f)
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/PolyEval.h"
@@ -16,8 +17,7 @@
 #include "src/__support/FPUtil/multiply_add.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h"   // LIBC_UNLIKELY
-#include "common_constants.h" // Lookup table for (1/f)
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
 
 // This is a correctly-rounded algorithm for log2(x) in single precision with
 // round-to-nearest, tie-to-even mode from the RLIBM project at:
@@ -58,7 +58,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace math {
 
-LIBC_INLINE static constexpr float log2f(float x) {
+LIBC_INLINE static float log2f(float x) {
   using namespace common_constants_internal;
   using FPBits = typename fputil::FPBits<float>;
 
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index c91f0fe74ffce..f61eb2db89c24 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -2014,7 +2014,6 @@ add_entrypoint_object(
     ../log2f.h
   DEPENDS
     libc.src.__support.math.log2f
-    libc.src.errno.errno
 )
 
 add_entrypoint_object(
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index f19e70d05def2..5fd11825c636e 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -4874,7 +4874,6 @@ libc_math_function(
     name = "log2f",
     additional_deps = [
         ":__support_math_log2f",
-        ":errno",
     ],
 )
 



More information about the libc-commits mailing list