[libc][math] Refractor logf to Header only#176834
Merged
Merged
Conversation
Member
|
@llvm/pr-subscribers-libc Author: Anikesh Parashar (an1k3sh) ChangesResolves #175368 Full diff: https://github.com/llvm/llvm-project/pull/176834.diff 9 Files Affected:
diff --git a/libc/shared/math.h b/libc/shared/math.h
index d58238703701d..6cbacc059b6ee 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -76,6 +76,7 @@
#include "math/logbf.h"
#include "math/logbf128.h"
#include "math/logbf16.h"
+#include "math/logf.h"
#include "math/rsqrtf.h"
#include "math/rsqrtf16.h"
#include "math/sin.h"
diff --git a/libc/shared/math/logf.h b/libc/shared/math/logf.h
new file mode 100644
index 0000000000000..aa1caa4f0272a
--- /dev/null
+++ b/libc/shared/math/logf.h
@@ -0,0 +1,23 @@
+//===-- Shared logf 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_LOGF_H
+#define LLVM_LIBC_SHARED_MATH_LOGF_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/logf.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace shared {
+using math::logf;
+} // namespace shared
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_LOGF_H
\ No newline at end of file
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index bf1c4463b8066..5f234f2263532 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -1148,6 +1148,23 @@ add_header_library(
libc.src.__support.FPUtil.manipulation_functions
)
+add_header_library(
+ logf
+ HDRS
+ logf.h
+ DEPENDS
+ .common_constants
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.FPUtil.except_value_utils
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+ libc.src.__support.macros.properties.cpu_features
+)
+
add_header_library(
log_range_reduction
HDRS
diff --git a/libc/src/__support/math/logf.h b/libc/src/__support/math/logf.h
new file mode 100644
index 0000000000000..dc85483ea011c
--- /dev/null
+++ b/libc/src/__support/math/logf.h
@@ -0,0 +1,193 @@
+//===-- Single-precision log(x) function ----------------------------------===//
+//
+// 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_LOGF_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGF_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/macros/properties/cpu_features.h"
+#include "src/__support/math/common_constants.h" // Lookup table for (1/f) and log(f)
+#include "src/math/logf.h"
+
+// This is an algorithm for log(x) in single precision which is correctly
+// rounded for all rounding modes, based on the implementation of log(x) from
+// the RLIBM project at:
+// https://people.cs.rutgers.edu/~sn349/rlibm
+
+// Step 1 - Range reduction:
+// For x = 2^m * 1.mant, log(x) = m * log(2) + log(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:
+// log(1.mant) = log(f) + log(1.mant / f)
+// = log(f) + log(1 + d/f)
+// ~ log(f) + P(d/f)
+// since d/f is sufficiently small.
+// log(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
+// paper:
+// 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, January 16-22, 2022.
+// https://people.cs.rutgers.edu/~sn349/papers/rlibmall-popl-2022.pdf
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+static constexpr float logf(float x) {
+ using namespace common_constants_internal;
+ constexpr double LOG_2 = 0x1.62e42fefa39efp-1;
+ using FPBits = typename fputil::FPBits<float>;
+
+ FPBits xbits(x);
+ uint32_t x_u = xbits.uintval();
+
+ int m = -FPBits::EXP_BIAS;
+
+ using fputil::round_result_slightly_down;
+ using fputil::round_result_slightly_up;
+
+ // Small inputs
+ if (x_u < 0x4c5d65a5U) {
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Hard-to-round cases.
+ switch (x_u) {
+ case 0x3f7f4d6fU: // x = 0x1.fe9adep-1f
+ return round_result_slightly_up(-0x1.659ec8p-9f);
+ case 0x41178febU: // x = 0x1.2f1fd6p+3f
+ return round_result_slightly_up(0x1.1fcbcep+1f);
+#ifdef LIBC_TARGET_CPU_HAS_FMA
+ case 0x3f800000U: // x = 1.0f
+ return 0.0f;
+#else
+ case 0x1e88452dU: // x = 0x1.108a5ap-66f
+ return round_result_slightly_up(-0x1.6d7b18p+5f);
+#endif // LIBC_TARGET_CPU_HAS_FMA
+ }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Subnormal inputs.
+ if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) {
+ if (x == 0.0f) {
+ // Return -inf and raise FE_DIVBYZERO
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_DIVBYZERO);
+ return FPBits::inf(Sign::NEG).get_val();
+ }
+ // Normalize denormal inputs.
+ xbits = FPBits(xbits.get_val() * 0x1.0p23f);
+ m -= 23;
+ x_u = xbits.uintval();
+ }
+ } else {
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Hard-to-round cases.
+ switch (x_u) {
+ case 0x4c5d65a5U: // x = 0x1.bacb4ap+25f
+ return round_result_slightly_down(0x1.1e0696p+4f);
+ case 0x65d890d3U: // x = 0x1.b121a6p+76f
+ return round_result_slightly_down(0x1.a9a3f2p+5f);
+ case 0x6f31a8ecU: // x = 0x1.6351d8p+95f
+ return round_result_slightly_down(0x1.08b512p+6f);
+ case 0x7a17f30aU: // x = 0x1.2fe614p+117f
+ return round_result_slightly_up(0x1.451436p+6f);
+#ifndef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+ case 0x500ffb03U: // x = 0x1.1ff606p+33f
+ return round_result_slightly_up(0x1.6fdd34p+4f);
+ case 0x5cd69e88U: // x = 0x1.ad3d1p+58f
+ return round_result_slightly_up(0x1.45c146p+5f);
+ case 0x5ee8984eU: // x = 0x1.d1309cp+62f;
+ return round_result_slightly_up(0x1.5c9442p+5f);
+#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+ }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Exceptional inputs.
+ if (LIBC_UNLIKELY(x_u > FPBits::max_normal().uintval())) {
+ if (x_u == 0x8000'0000U) {
+ // Return -inf and raise FE_DIVBYZERO
+ 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()) {
+ // Return NaN and raise FE_INVALID
+ fputil::set_errno_if_required(EDOM);
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ // x is +inf or nan
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+
+ return x;
+ }
+ }
+
+#ifndef LIBC_TARGET_CPU_HAS_FMA
+ // Returning the correct +0 when x = 1.0 for non-FMA targets with FE_DOWNWARD
+ // rounding mode.
+ if (LIBC_UNLIKELY((x_u & 0x007f'ffffU) == 0))
+ return static_cast<float>(
+ static_cast<double>(m + xbits.get_biased_exponent()) * LOG_2);
+#endif // LIBC_TARGET_CPU_HAS_FMA
+
+ uint32_t mant = xbits.get_mantissa();
+ // Extract 7 leading fractional bits of the mantissa
+ int index = mant >> 16;
+ // Add unbiased exponent. Add an extra 1 if the 7 leading fractional bits are
+ // all 1's.
+ m += static_cast<int>((x_u + (1 << 16)) >> 23);
+
+ // Set bits to 1.m
+ xbits.set_biased_exponent(0x7F);
+
+ float u = xbits.get_val();
+ double v = 0.0;
+#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
+
+ // Degree-5 polynomial approximation of log generated by Sollya with:
+ // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]);
+ constexpr double COEFFS[4] = {-0x1.000000000fe63p-1, 0x1.555556e963c16p-2,
+ -0x1.000028dedf986p-2, 0x1.966681bfda7f7p-3};
+ double v2 = v * v; // Exact
+ double p2 = fputil::multiply_add(v, COEFFS[3], COEFFS[2]);
+ double p1 = fputil::multiply_add(v, COEFFS[1], COEFFS[0]);
+ double p0 = LOG_R[index] + v;
+ double r = fputil::multiply_add(static_cast<double>(m), LOG_2,
+ fputil::polyeval(v2, p0, p1, p2));
+ return static_cast<float>(r);
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGF_H
\ No newline at end of file
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index b578d1805f2a8..96d2e22f98fa3 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -2120,6 +2120,7 @@ add_entrypoint_object(
libc.src.__support.macros.optimization
libc.src.__support.macros.properties.cpu_features
libc.src.__support.math.common_constants
+ libc.src.__support.math.logf
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp
index 4d2947dc14db0..80b757ddf3658 100644
--- a/libc/src/math/generic/logf.cpp
+++ b/libc/src/math/generic/logf.cpp
@@ -7,16 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/math/logf.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/macros/properties/cpu_features.h"
-#include "src/__support/math/common_constants.h" // Lookup table for (1/f) and log(f)
+#include "src/__support/math/logf.h" // Lookup table for (1/f) and log(f)
// This is an algorithm for log(x) in single precision which is correctly
// rounded for all rounding modes, based on the implementation of log(x) from
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index cfc2eda1aaec9..bf8d8eca9abf5 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -68,6 +68,7 @@ add_fp_unittest(
libc.src.__support.math.logbf
libc.src.__support.math.logbf128
libc.src.__support.math.logbf16
+ libc.src.__support.math.logf
libc.src.__support.math.ldexpf
libc.src.__support.math.ldexpf128
libc.src.__support.math.ldexpf16
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 88e6ecc98a0a7..e1ce06831bb3b 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -73,6 +73,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::exp2f(0.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::expm1f(0.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::hypotf(0.0f, 0.0f));
+ EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::logf(1.0f));
EXPECT_FP_EQ_ALL_ROUNDING(0.75f,
LIBC_NAMESPACE::shared::frexpf(24.0f, &exponent));
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 90b1da0e3376e..74b7b4901d6da 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -2977,6 +2977,23 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_math_logf",
+ hdrs = ["src/__support/math/logf.h"],
+ deps = [
+ ":__support_common",
+ ":__support_fputil_except_value_utils",
+ ":__support_fputil_fenv_impl",
+ ":__support_fputil_fp_bits",
+ ":__support_fputil_multiply_add",
+ ":__support_fputil_polyeval",
+ ":__support_macros_config",
+ ":__support_macros_optimization",
+ ":__support_macros_properties_cpu_features",
+ ":__support_math_common_constants",
+ ],
+)
+
libc_support_library(
name = "__support_math_exp_constants",
hdrs = ["src/__support/math/exp_constants.h"],
|
🐧 Linux x64 Test Results✅ The build succeeded and no tests ran. This is expected in some build configurations. |
bassiounix
requested changes
Jan 23, 2026
bassiounix
reviewed
Jan 23, 2026
bassiounix
reviewed
Jan 23, 2026
Co-authored-by: Muhammad Bassiouni <60100307+bassiounix@users.noreply.github.com>
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
bassiounix
requested changes
Jan 26, 2026
bassiounix
approved these changes
Jan 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #175368