[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