[llvm-branch-commits] [libc] [llvm] [libc][math] Refactor atan implementation to header-only in src/__support/math folder. (PR #150852)
Muhammad Bassiouni via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jul 27 13:46:51 PDT 2025
https://github.com/bassiounix created https://github.com/llvm/llvm-project/pull/150852
None
>From 8f3f2866eb6656784827084b7e1e1922ee0c8a56 Mon Sep 17 00:00:00 2001
From: bassiounix <muhammad.m.bassiouni at gmail.com>
Date: Sun, 27 Jul 2025 23:44:37 +0300
Subject: [PATCH] [libc][math] Refactor atan implementation to header-only in
src/__support/math folder.
---
libc/shared/math.h | 1 +
libc/shared/math/atan.h | 23 +++
libc/src/__support/math/CMakeLists.txt | 27 +++
libc/src/__support/math/atan.h | 190 ++++++++++++++++++
.../generic => __support/math}/atan_utils.h | 14 +-
libc/src/math/generic/CMakeLists.txt | 25 +--
libc/src/math/generic/atan.cpp | 167 +--------------
libc/src/math/generic/atan2.cpp | 3 +-
libc/src/math/generic/atan2f128.cpp | 3 +-
libc/test/shared/CMakeLists.txt | 1 +
libc/test/shared/shared_math_test.cpp | 1 +
.../llvm-project-overlay/libc/BUILD.bazel | 44 ++--
12 files changed, 285 insertions(+), 214 deletions(-)
create mode 100644 libc/shared/math/atan.h
create mode 100644 libc/src/__support/math/atan.h
rename libc/src/{math/generic => __support/math}/atan_utils.h (96%)
diff --git a/libc/shared/math.h b/libc/shared/math.h
index 26e33ecd45d73..70b1b7b0bef09 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -22,6 +22,7 @@
#include "math/asinf16.h"
#include "math/asinhf.h"
#include "math/asinhf16.h"
+#include "math/atan.h"
#include "math/erff.h"
#include "math/exp.h"
#include "math/exp10.h"
diff --git a/libc/shared/math/atan.h b/libc/shared/math/atan.h
new file mode 100644
index 0000000000000..b9ba89b7e6225
--- /dev/null
+++ b/libc/shared/math/atan.h
@@ -0,0 +1,23 @@
+//===-- Shared atan 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_ATAN_H
+#define LLVM_LIBC_SHARED_MATH_ATAN_H
+
+#include "shared/libc_common.h"
+#include "src/__support/math/atan.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::atan;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_ATAN_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index be208f946024a..cc02920c2a1ef 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -172,6 +172,33 @@ DEPENDS
libc.src.__support.macros.optimization
)
+add_header_library(
+ atan_utils
+ HDRS
+ atan_utils.h
+DEPENDS
+ libc.src.__support.integer_literals
+ libc.src.__support.FPUtil.double_double
+ libc.src.__support.FPUtil.dyadic_float
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.macros.optimization
+)
+
+add_header_library(
+ atan
+ HDRS
+ atan.h
+DEPENDS
+ .atan_utils
+ libc.src.__support.FPUtil.double_double
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.nearest_integer
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
asinf
HDRS
diff --git a/libc/src/__support/math/atan.h b/libc/src/__support/math/atan.h
new file mode 100644
index 0000000000000..4f42b2948aea8
--- /dev/null
+++ b/libc/src/__support/math/atan.h
@@ -0,0 +1,190 @@
+//===-- Implementation header for atan --------------------------*- 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_ATAN_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN_H
+
+#include "atan_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+// To compute atan(x), we divided it into the following cases:
+// * |x| < 2^-26:
+// Since |x| > atan(|x|) > |x| - |x|^3/3, and |x|^3/3 < ulp(x)/2, we simply
+// return atan(x) = x - sign(x) * epsilon.
+// * 2^-26 <= |x| < 1:
+// We perform range reduction mod 2^-6 = 1/64 as follow:
+// Let k = 2^(-6) * round(|x| * 2^6), then
+// atan(x) = sign(x) * atan(|x|)
+// = sign(x) * (atan(k) + atan((|x| - k) / (1 + |x|*k)).
+// We store atan(k) in a look up table, and perform intermediate steps in
+// double-double.
+// * 1 < |x| < 2^53:
+// First we perform the transformation y = 1/|x|:
+// atan(x) = sign(x) * (pi/2 - atan(1/|x|))
+// = sign(x) * (pi/2 - atan(y)).
+// Then we compute atan(y) using range reduction mod 2^-6 = 1/64 as the
+// previous case:
+// Let k = 2^(-6) * round(y * 2^6), then
+// atan(y) = atan(k) + atan((y - k) / (1 + y*k))
+// = atan(k) + atan((1/|x| - k) / (1 + k/|x|)
+// = atan(k) + atan((1 - k*|x|) / (|x| + k)).
+// * |x| >= 2^53:
+// Using the reciprocal transformation:
+// atan(x) = sign(x) * (pi/2 - atan(1/|x|)).
+// We have that:
+// atan(1/|x|) <= 1/|x| <= 2^-53,
+// which is smaller than ulp(pi/2) / 2.
+// So we can return:
+// atan(x) = sign(x) * (pi/2 - epsilon)
+
+LIBC_INLINE static constexpr double atan(double x) {
+
+ using namespace atan_internal;
+ using FPBits = fputil::FPBits<double>;
+
+ constexpr double IS_NEG[2] = {1.0, -1.0};
+ constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
+ 0x1.921fb54442d18p0};
+ constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
+ -0x1.921fb54442d18p0};
+
+ FPBits xbits(x);
+ bool x_sign = xbits.is_neg();
+ xbits = xbits.abs();
+ uint64_t x_abs = xbits.uintval();
+ int x_exp =
+ static_cast<int>(x_abs >> FPBits::FRACTION_LEN) - FPBits::EXP_BIAS;
+
+ // |x| < 1.
+ if (x_exp < 0) {
+ if (LIBC_UNLIKELY(x_exp < -26)) {
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ return x;
+#else
+ if (x == 0.0)
+ return x;
+ // |x| < 2^-26
+ return fputil::multiply_add(-0x1.0p-54, x, x);
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ }
+
+ double x_d = xbits.get_val();
+ // k = 2^-6 * round(2^6 * |x|)
+ double k = fputil::nearest_integer(0x1.0p6 * x_d);
+ unsigned idx = static_cast<unsigned>(k);
+ k *= 0x1.0p-6;
+
+ // numerator = |x| - k
+ DoubleDouble num, den;
+ num.lo = 0.0;
+ num.hi = x_d - k;
+
+ // denominator = 1 - k * |x|
+ den.hi = fputil::multiply_add(x_d, k, 1.0);
+ DoubleDouble prod = fputil::exact_mult(x_d, k);
+ // Using Dekker's 2SUM algorithm to compute the lower part.
+ den.lo = ((1.0 - den.hi) + prod.hi) + prod.lo;
+
+ // x_r = (|x| - k) / (1 + k * |x|)
+ DoubleDouble x_r = fputil::div(num, den);
+
+ // Approximating atan(x_r) using Taylor polynomial.
+ DoubleDouble p = atan_eval(x_r);
+
+ // atan(x) = sign(x) * (atan(k) + atan(x_r))
+ // = sign(x) * (atan(k) + atan( (|x| - k) / (1 + k * |x|) ))
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ return IS_NEG[x_sign] * (ATAN_I[idx].hi + (p.hi + (p.lo + ATAN_I[idx].lo)));
+#else
+
+ DoubleDouble c0 = fputil::exact_add(ATAN_I[idx].hi, p.hi);
+ double c1 = c0.lo + (ATAN_I[idx].lo + p.lo);
+ double r = IS_NEG[x_sign] * (c0.hi + c1);
+
+ return r;
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ }
+
+ // |x| >= 2^53 or x is NaN.
+ if (LIBC_UNLIKELY(x_exp >= 53)) {
+ // x is nan
+ if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+ // |x| >= 2^53
+ // atan(x) ~ sign(x) * pi/2.
+ if (x_exp >= 53)
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ return IS_NEG[x_sign] * PI_OVER_2.hi;
+#else
+ return fputil::multiply_add(IS_NEG[x_sign], PI_OVER_2.hi,
+ IS_NEG[x_sign] * PI_OVER_2.lo);
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ }
+
+ double x_d = xbits.get_val();
+ double y = 1.0 / x_d;
+
+ // k = 2^-6 * round(2^6 / |x|)
+ double k = fputil::nearest_integer(0x1.0p6 * y);
+ unsigned idx = static_cast<unsigned>(k);
+ k *= 0x1.0p-6;
+
+ // denominator = |x| + k
+ DoubleDouble den = fputil::exact_add(x_d, k);
+ // numerator = 1 - k * |x|
+ DoubleDouble num;
+ num.hi = fputil::multiply_add(-x_d, k, 1.0);
+ DoubleDouble prod = fputil::exact_mult(x_d, k);
+ // Using Dekker's 2SUM algorithm to compute the lower part.
+ num.lo = ((1.0 - num.hi) - prod.hi) - prod.lo;
+
+ // x_r = (1/|x| - k) / (1 - k/|x|)
+ // = (1 - k * |x|) / (|x| - k)
+ DoubleDouble x_r = fputil::div(num, den);
+
+ // Approximating atan(x_r) using Taylor polynomial.
+ DoubleDouble p = atan_eval(x_r);
+
+ // atan(x) = sign(x) * (pi/2 - atan(1/|x|))
+ // = sign(x) * (pi/2 - atan(k) - atan(x_r))
+ // = (-sign(x)) * (-pi/2 + atan(k) + atan((1 - k*|x|)/(|x| - k)))
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ double lo_part = p.lo + ATAN_I[idx].lo + MPI_OVER_2.lo;
+ return IS_NEG[!x_sign] * (MPI_OVER_2.hi + ATAN_I[idx].hi + (p.hi + lo_part));
+#else
+ DoubleDouble c0 = fputil::exact_add(MPI_OVER_2.hi, ATAN_I[idx].hi);
+ DoubleDouble c1 = fputil::exact_add(c0.hi, p.hi);
+ double c2 = c1.lo + (c0.lo + p.lo) + (ATAN_I[idx].lo + MPI_OVER_2.lo);
+
+ double r = IS_NEG[!x_sign] * (c1.hi + c2);
+
+ return r;
+#endif
+
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN_H
diff --git a/libc/src/math/generic/atan_utils.h b/libc/src/__support/math/atan_utils.h
similarity index 96%
rename from libc/src/math/generic/atan_utils.h
rename to libc/src/__support/math/atan_utils.h
index 24c7271b7e4ec..95613d38c413e 100644
--- a/libc/src/math/generic/atan_utils.h
+++ b/libc/src/__support/math/atan_utils.h
@@ -18,7 +18,7 @@
namespace LIBC_NAMESPACE_DECL {
-namespace {
+namespace atan_internal {
using DoubleDouble = fputil::DoubleDouble;
using Float128 = fputil::DyadicFloat<128>;
@@ -29,7 +29,7 @@ using Float128 = fputil::DyadicFloat<128>;
// b = round(atan(i/64) - a, D, RN);
// print("{", b, ",", a, "},");
// };
-constexpr DoubleDouble ATAN_I[65] = {
+static constexpr DoubleDouble ATAN_I[65] = {
{0.0, 0.0},
{-0x1.220c39d4dff5p-61, 0x1.fff555bbb729bp-7},
{-0x1.5ec431444912cp-60, 0x1.ffd55bba97625p-6},
@@ -110,7 +110,7 @@ constexpr DoubleDouble ATAN_I[65] = {
// + x_lo * (1 - x_hi^2 + x_hi^4)
// Since p.lo is ~ x^3/3, the relative error from rounding is bounded by:
// |(atan(x) - P(x))/atan(x)| < ulp(x^2) <= 2^(-14-52) = 2^-66.
-[[maybe_unused]] DoubleDouble atan_eval(const DoubleDouble &x) {
+[[maybe_unused]] LIBC_INLINE static DoubleDouble atan_eval(const DoubleDouble &x) {
DoubleDouble p;
p.hi = x.hi;
double x_hi_sq = x.hi * x.hi;
@@ -142,7 +142,7 @@ constexpr DoubleDouble ATAN_I[65] = {
// b = 2^ll + a;
// print("{Sign::POS, ", 2^(ll - 128), ",", b, "},");
// };
-constexpr Float128 ATAN_I_F128[65] = {
+static constexpr Float128 ATAN_I_F128[65] = {
{Sign::POS, 0, 0_u128},
{Sign::POS, -134, 0xfffaaadd'db94d5bb'e78c5640'15f76048_u128},
{Sign::POS, -133, 0xffeaaddd'4bb12542'779d776d'da8c6214_u128},
@@ -215,7 +215,7 @@ constexpr Float128 ATAN_I_F128[65] = {
// [0, 2^-7]);
// > dirtyinfnorm(atan(x) - P, [0, 2^-7]);
// 0x1.26016ad97f323875760f869684c0898d7b7bb8bep-122
-constexpr Float128 ATAN_POLY_F128[] = {
+static constexpr Float128 ATAN_POLY_F128[] = {
{Sign::NEG, -129, 0xaaaaaaaa'aaaaaaaa'aaaaaaa6'003c5d1d_u128},
{Sign::POS, -130, 0xcccccccc'cccccccc'cca00232'8776b063_u128},
{Sign::NEG, -130, 0x92492492'49249201'27f5268a'cb24aec0_u128},
@@ -225,7 +225,7 @@ constexpr Float128 ATAN_POLY_F128[] = {
};
// Approximate atan for |x| <= 2^-7.
-[[maybe_unused]] Float128 atan_eval(const Float128 &x) {
+[[maybe_unused]] LIBC_INLINE static constexpr Float128 atan_eval(const Float128 &x) {
Float128 x_sq = fputil::quick_mul(x, x);
Float128 x3 = fputil::quick_mul(x, x_sq);
Float128 p = fputil::polyeval(x_sq, ATAN_POLY_F128[0], ATAN_POLY_F128[1],
@@ -234,7 +234,7 @@ constexpr Float128 ATAN_POLY_F128[] = {
return fputil::multiply_add(x3, p, x);
}
-} // anonymous namespace
+} // namespace atan_internal
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 025b0290bfe70..ffb0d06c434fc 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4007,19 +4007,6 @@ add_entrypoint_object(
libc.src.errno.errno
)
-add_header_library(
- atan_utils
- HDRS
- atan_utils.h
- DEPENDS
- libc.src.__support.integer_literals
- libc.src.__support.FPUtil.double_double
- libc.src.__support.FPUtil.dyadic_float
- libc.src.__support.FPUtil.multiply_add
- libc.src.__support.FPUtil.polyeval
- libc.src.__support.macros.optimization
-)
-
add_entrypoint_object(
atanf
SRCS
@@ -4066,13 +4053,7 @@ add_entrypoint_object(
COMPILE_OPTIONS
-O3
DEPENDS
- .atan_utils
- libc.src.__support.FPUtil.double_double
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.multiply_add
- libc.src.__support.FPUtil.nearest_integer
- libc.src.__support.macros.optimization
+ libc.src.__support.math.atan
)
add_entrypoint_object(
@@ -4102,7 +4083,7 @@ add_entrypoint_object(
HDRS
../atan2.h
DEPENDS
- .atan_utils
+ libc.src.__support.math.atan_utils
libc.src.__support.FPUtil.double_double
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
@@ -4128,7 +4109,7 @@ add_entrypoint_object(
HDRS
../atan2f128.h
DEPENDS
- .atan_utils
+ libc.src.__support.math.atan_utils
libc.src.__support.integer_literals
libc.src.__support.uint128
libc.src.__support.FPUtil.dyadic_float
diff --git a/libc/src/math/generic/atan.cpp b/libc/src/math/generic/atan.cpp
index cbca60536a3fd..93bf2e108e361 100644
--- a/libc/src/math/generic/atan.cpp
+++ b/libc/src/math/generic/atan.cpp
@@ -7,173 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan.h"
-#include "atan_utils.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/double_double.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/math/atan.h"
namespace LIBC_NAMESPACE_DECL {
-// To compute atan(x), we divided it into the following cases:
-// * |x| < 2^-26:
-// Since |x| > atan(|x|) > |x| - |x|^3/3, and |x|^3/3 < ulp(x)/2, we simply
-// return atan(x) = x - sign(x) * epsilon.
-// * 2^-26 <= |x| < 1:
-// We perform range reduction mod 2^-6 = 1/64 as follow:
-// Let k = 2^(-6) * round(|x| * 2^6), then
-// atan(x) = sign(x) * atan(|x|)
-// = sign(x) * (atan(k) + atan((|x| - k) / (1 + |x|*k)).
-// We store atan(k) in a look up table, and perform intermediate steps in
-// double-double.
-// * 1 < |x| < 2^53:
-// First we perform the transformation y = 1/|x|:
-// atan(x) = sign(x) * (pi/2 - atan(1/|x|))
-// = sign(x) * (pi/2 - atan(y)).
-// Then we compute atan(y) using range reduction mod 2^-6 = 1/64 as the
-// previous case:
-// Let k = 2^(-6) * round(y * 2^6), then
-// atan(y) = atan(k) + atan((y - k) / (1 + y*k))
-// = atan(k) + atan((1/|x| - k) / (1 + k/|x|)
-// = atan(k) + atan((1 - k*|x|) / (|x| + k)).
-// * |x| >= 2^53:
-// Using the reciprocal transformation:
-// atan(x) = sign(x) * (pi/2 - atan(1/|x|)).
-// We have that:
-// atan(1/|x|) <= 1/|x| <= 2^-53,
-// which is smaller than ulp(pi/2) / 2.
-// So we can return:
-// atan(x) = sign(x) * (pi/2 - epsilon)
-
-LLVM_LIBC_FUNCTION(double, atan, (double x)) {
- using FPBits = fputil::FPBits<double>;
-
- constexpr double IS_NEG[2] = {1.0, -1.0};
- constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
- 0x1.921fb54442d18p0};
- constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
- -0x1.921fb54442d18p0};
-
- FPBits xbits(x);
- bool x_sign = xbits.is_neg();
- xbits = xbits.abs();
- uint64_t x_abs = xbits.uintval();
- int x_exp =
- static_cast<int>(x_abs >> FPBits::FRACTION_LEN) - FPBits::EXP_BIAS;
-
- // |x| < 1.
- if (x_exp < 0) {
- if (LIBC_UNLIKELY(x_exp < -26)) {
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- return x;
-#else
- if (x == 0.0)
- return x;
- // |x| < 2^-26
- return fputil::multiply_add(-0x1.0p-54, x, x);
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- }
-
- double x_d = xbits.get_val();
- // k = 2^-6 * round(2^6 * |x|)
- double k = fputil::nearest_integer(0x1.0p6 * x_d);
- unsigned idx = static_cast<unsigned>(k);
- k *= 0x1.0p-6;
-
- // numerator = |x| - k
- DoubleDouble num, den;
- num.lo = 0.0;
- num.hi = x_d - k;
-
- // denominator = 1 - k * |x|
- den.hi = fputil::multiply_add(x_d, k, 1.0);
- DoubleDouble prod = fputil::exact_mult(x_d, k);
- // Using Dekker's 2SUM algorithm to compute the lower part.
- den.lo = ((1.0 - den.hi) + prod.hi) + prod.lo;
-
- // x_r = (|x| - k) / (1 + k * |x|)
- DoubleDouble x_r = fputil::div(num, den);
-
- // Approximating atan(x_r) using Taylor polynomial.
- DoubleDouble p = atan_eval(x_r);
-
- // atan(x) = sign(x) * (atan(k) + atan(x_r))
- // = sign(x) * (atan(k) + atan( (|x| - k) / (1 + k * |x|) ))
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- return IS_NEG[x_sign] * (ATAN_I[idx].hi + (p.hi + (p.lo + ATAN_I[idx].lo)));
-#else
-
- DoubleDouble c0 = fputil::exact_add(ATAN_I[idx].hi, p.hi);
- double c1 = c0.lo + (ATAN_I[idx].lo + p.lo);
- double r = IS_NEG[x_sign] * (c0.hi + c1);
-
- return r;
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- }
-
- // |x| >= 2^53 or x is NaN.
- if (LIBC_UNLIKELY(x_exp >= 53)) {
- // x is nan
- if (xbits.is_nan()) {
- if (xbits.is_signaling_nan()) {
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- return x;
- }
- // |x| >= 2^53
- // atan(x) ~ sign(x) * pi/2.
- if (x_exp >= 53)
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- return IS_NEG[x_sign] * PI_OVER_2.hi;
-#else
- return fputil::multiply_add(IS_NEG[x_sign], PI_OVER_2.hi,
- IS_NEG[x_sign] * PI_OVER_2.lo);
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- }
-
- double x_d = xbits.get_val();
- double y = 1.0 / x_d;
-
- // k = 2^-6 * round(2^6 / |x|)
- double k = fputil::nearest_integer(0x1.0p6 * y);
- unsigned idx = static_cast<unsigned>(k);
- k *= 0x1.0p-6;
-
- // denominator = |x| + k
- DoubleDouble den = fputil::exact_add(x_d, k);
- // numerator = 1 - k * |x|
- DoubleDouble num;
- num.hi = fputil::multiply_add(-x_d, k, 1.0);
- DoubleDouble prod = fputil::exact_mult(x_d, k);
- // Using Dekker's 2SUM algorithm to compute the lower part.
- num.lo = ((1.0 - num.hi) - prod.hi) - prod.lo;
-
- // x_r = (1/|x| - k) / (1 - k/|x|)
- // = (1 - k * |x|) / (|x| - k)
- DoubleDouble x_r = fputil::div(num, den);
-
- // Approximating atan(x_r) using Taylor polynomial.
- DoubleDouble p = atan_eval(x_r);
-
- // atan(x) = sign(x) * (pi/2 - atan(1/|x|))
- // = sign(x) * (pi/2 - atan(k) - atan(x_r))
- // = (-sign(x)) * (-pi/2 + atan(k) + atan((1 - k*|x|)/(|x| - k)))
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- double lo_part = p.lo + ATAN_I[idx].lo + MPI_OVER_2.lo;
- return IS_NEG[!x_sign] * (MPI_OVER_2.hi + ATAN_I[idx].hi + (p.hi + lo_part));
-#else
- DoubleDouble c0 = fputil::exact_add(MPI_OVER_2.hi, ATAN_I[idx].hi);
- DoubleDouble c1 = fputil::exact_add(c0.hi, p.hi);
- double c2 = c1.lo + (c0.lo + p.lo) + (ATAN_I[idx].lo + MPI_OVER_2.lo);
-
- double r = IS_NEG[!x_sign] * (c1.hi + c2);
-
- return r;
-#endif
-}
+LLVM_LIBC_FUNCTION(double, atan, (double x)) { return math::atan(x); }
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp
index aa770de33fb1f..f60c30fc288aa 100644
--- a/libc/src/math/generic/atan2.cpp
+++ b/libc/src/math/generic/atan2.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2.h"
-#include "atan_utils.h"
+#include "src/__support/math/atan_utils.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/double_double.h"
@@ -72,6 +72,7 @@ namespace LIBC_NAMESPACE_DECL {
// |(atan(u) - P(u)) / P(u)| < u^10 / 11 < 2^-73.
LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) {
+ using namespace atan_internal;
using FPBits = fputil::FPBits<double>;
constexpr double IS_NEG[2] = {1.0, -1.0};
diff --git a/libc/src/math/generic/atan2f128.cpp b/libc/src/math/generic/atan2f128.cpp
index a3aba0bc7fa2a..a3e0dbf21f946 100644
--- a/libc/src/math/generic/atan2f128.cpp
+++ b/libc/src/math/generic/atan2f128.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2f128.h"
-#include "atan_utils.h"
+#include "src/__support/math/atan_utils.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/multiply_add.h"
@@ -103,6 +103,7 @@ static constexpr Float128 CONST_ADJ[2][2][2] = {
// |(atan(u) - P(u)) / P(u)| < 2^-114.
LLVM_LIBC_FUNCTION(float128, atan2f128, (float128 y, float128 x)) {
+ using namespace atan_internal;
using FPBits = fputil::FPBits<float128>;
using Float128 = fputil::DyadicFloat<128>;
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 7ddf26c1d091c..3227a78f01c8d 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -18,6 +18,7 @@ add_fp_unittest(
libc.src.__support.math.asinf16
libc.src.__support.math.asinhf
libc.src.__support.math.asinhf16
+ libc.src.__support.math.atan
libc.src.__support.math.erff
libc.src.__support.math.exp
libc.src.__support.math.exp10
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 3ddea7a6a4aa5..07eaeda130363 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -59,6 +59,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
TEST(LlvmLibcSharedMathTest, AllDouble) {
EXPECT_FP_EQ(0x1.921fb54442d18p+0, LIBC_NAMESPACE::shared::acos(0.0));
EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::asin(0.0));
+ EXPECT_FP_EQ(0x0p+0, LIBC_NAMESPACE::shared::atan(0.0));
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp(0.0));
EXPECT_FP_EQ(0x1p+0, LIBC_NAMESPACE::shared::exp10(0.0));
}
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 31334e324e705..86975cc8da954 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -2038,19 +2038,6 @@ libc_support_library(
],
)
-libc_support_library(
- name = "atan_utils",
- hdrs = ["src/math/generic/atan_utils.h"],
- deps = [
- ":__support_fputil_double_double",
- ":__support_fputil_dyadic_float",
- ":__support_fputil_multiply_add",
- ":__support_fputil_polyeval",
- ":__support_integer_literals",
- ":__support_macros_optimization",
- ],
-)
-
libc_support_library(
name = "log_range_reduction",
hdrs = ["src/math/generic/log_range_reduction.h"],
@@ -2263,6 +2250,30 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_math_atan_utils",
+ hdrs = ["src/__support/math/atan_utils.h"],
+ deps = [
+ ":__support_fputil_double_double",
+ ":__support_fputil_dyadic_float",
+ ":__support_fputil_multiply_add",
+ ":__support_fputil_polyeval",
+ ":__support_integer_literals",
+ ":__support_macros_optimization",
+ ],
+)
+
+libc_support_library(
+ name = "__support_math_atan",
+ hdrs = ["src/__support/math/atan.h"],
+ deps = [
+ ":__support_fputil_double_double",
+ ":__support_fputil_nearest_integer",
+ ":__support_macros_optimization",
+ ":__support_math_atan_utils",
+ ],
+)
+
libc_support_library(
name = "__support_math_asinf",
hdrs = ["src/__support/math/asinf.h"],
@@ -2888,10 +2899,7 @@ libc_math_function(
libc_math_function(
name = "atan",
additional_deps = [
- ":__support_fputil_double_double",
- ":__support_fputil_nearest_integer",
- ":__support_macros_optimization",
- ":atan_utils",
+ ":__support_math_atan"
],
)
@@ -2909,7 +2917,7 @@ libc_math_function(
additional_deps = [
":__support_fputil_double_double",
":__support_fputil_nearest_integer",
- ":atan_utils",
+ ":__support_math_atan_utils",
],
)
More information about the llvm-branch-commits
mailing list