aboutsummaryrefslogtreecommitdiff
path: root/libc/src
diff options
context:
space:
mode:
Diffstat (limited to 'libc/src')
-rw-r--r--libc/src/__support/GPU/allocator.cpp72
-rw-r--r--libc/src/__support/math/CMakeLists.txt78
-rw-r--r--libc/src/__support/math/asin_utils.h2
-rw-r--r--libc/src/__support/math/atan2.h209
-rw-r--r--libc/src/__support/math/atan2f.h351
-rw-r--r--libc/src/__support/math/atan2f128.h212
-rw-r--r--libc/src/__support/math/atan2f_float.h (renamed from libc/src/math/generic/atan2f_float.h)24
-rw-r--r--libc/src/__support/math/atanf16.h119
-rw-r--r--libc/src/__support/math/atanhf.h76
-rw-r--r--libc/src/__support/threads/CMakeLists.txt8
-rw-r--r--libc/src/__support/threads/gpu/CMakeLists.txt5
-rw-r--r--libc/src/__support/threads/gpu/mutex.h32
-rw-r--r--libc/src/__support/threads/mutex.h57
-rw-r--r--libc/src/math/generic/CMakeLists.txt49
-rw-r--r--libc/src/math/generic/atan2.cpp187
-rw-r--r--libc/src/math/generic/atan2f.cpp328
-rw-r--r--libc/src/math/generic/atan2f128.cpp190
-rw-r--r--libc/src/math/generic/atan2l.cpp4
-rw-r--r--libc/src/math/generic/atanf16.cpp95
-rw-r--r--libc/src/math/generic/atanhf.cpp56
-rw-r--r--libc/src/sched/CMakeLists.txt7
-rw-r--r--libc/src/sched/getcpu.h20
-rw-r--r--libc/src/sched/linux/CMakeLists.txt36
-rw-r--r--libc/src/sched/linux/getcpu.cpp29
-rw-r--r--libc/src/sched/linux/sched_getaffinity.cpp4
-rw-r--r--libc/src/sched/linux/sched_getcpucount.cpp3
-rw-r--r--libc/src/sched/linux/sched_getscheduler.cpp1
-rw-r--r--libc/src/sched/linux/sched_rr_get_interval.cpp2
-rw-r--r--libc/src/sched/linux/sched_setaffinity.cpp4
-rw-r--r--libc/src/sched/sched_getaffinity.h5
-rw-r--r--libc/src/sched/sched_getcpucount.h3
-rw-r--r--libc/src/sched/sched_getparam.h4
-rw-r--r--libc/src/sched/sched_getscheduler.h3
-rw-r--r--libc/src/sched/sched_rr_get_interval.h4
-rw-r--r--libc/src/sched/sched_setaffinity.h5
-rw-r--r--libc/src/sched/sched_setparam.h4
-rw-r--r--libc/src/sched/sched_setscheduler.h4
-rw-r--r--libc/src/wchar/wcstok.cpp13
38 files changed, 1301 insertions, 1004 deletions
diff --git a/libc/src/__support/GPU/allocator.cpp b/libc/src/__support/GPU/allocator.cpp
index 8fff4cc..250bebd 100644
--- a/libc/src/__support/GPU/allocator.cpp
+++ b/libc/src/__support/GPU/allocator.cpp
@@ -156,7 +156,7 @@ static inline constexpr uint32_t get_start_index(uint32_t chunk_size) {
// Returns the id of the lane below this one that acts as its leader.
static inline uint32_t get_leader_id(uint64_t ballot, uint32_t id) {
- uint64_t mask = id < BITS_IN_DWORD ? ~0ull << (id + 1) : 0;
+ uint64_t mask = id < BITS_IN_DWORD - 1 ? ~0ull << (id + 1) : 0;
return BITS_IN_DWORD - cpp::countl_zero(ballot & ~mask) - 1;
}
@@ -266,38 +266,31 @@ struct Slab {
// Randomly walks the bitfield until it finds a free bit. Allocations attempt
// to put lanes right next to each other for better caching and convergence.
- void *allocate(uint64_t lane_mask, uint64_t uniform) {
+ void *allocate(uint64_t uniform, uint32_t reserved) {
uint32_t chunk_size = get_chunk_size();
uint32_t state = impl::entropy();
- // The uniform mask represents which lanes contain a uniform target pointer.
- // We attempt to place these next to each other.
- void *result = nullptr;
- uint32_t after = ~0u;
- uint32_t old_index = 0;
- for (uint64_t mask = lane_mask; mask;
- mask = gpu::ballot(lane_mask, !result)) {
- if (result)
- continue;
-
- // We try using any known empty bits from the previous attempt first.
- uint32_t start = gpu::shuffle(
- mask, cpp::countr_zero(uniform & mask),
- ~after ? (old_index & ~(BITS_IN_WORD - 1)) + cpp::countr_zero(~after)
- : __builtin_align_down(impl::xorshift32(state), BITS_IN_WORD));
+ // Try to find the empty bit in the bitfield to finish the allocation. We
+ // start at the number of allocations as this is guaranteed to be available
+ // until the user starts freeing memory.
+ uint64_t lane_mask = gpu::get_lane_mask();
+ uint32_t start = gpu::shuffle(
+ lane_mask, cpp::countr_zero(uniform & lane_mask), reserved);
+ for (;;) {
+ uint64_t lane_mask = gpu::get_lane_mask();
// Each lane tries to claim one bit in a single contiguous mask.
- uint32_t id = impl::lane_count(uniform & mask, gpu::get_lane_id());
+ uint32_t id = impl::lane_count(uniform & lane_mask, gpu::get_lane_id());
uint32_t index = (start + id) % usable_bits(chunk_size);
uint32_t slot = index / BITS_IN_WORD;
uint32_t bit = index % BITS_IN_WORD;
// Get the mask of bits destined for the same slot and coalesce it.
uint32_t leader = impl::get_leader_id(
- uniform & gpu::ballot(mask, !id || index % BITS_IN_WORD == 0),
+ uniform & gpu::ballot(lane_mask, !id || index % BITS_IN_WORD == 0),
gpu::get_lane_id());
- uint32_t length = cpp::popcount(uniform & mask) -
- impl::lane_count(uniform & mask, leader);
+ uint32_t length = cpp::popcount(uniform & lane_mask) -
+ impl::lane_count(uniform & lane_mask, leader);
uint32_t bitmask =
static_cast<uint32_t>(
(uint64_t(1) << cpp::min(length, BITS_IN_WORD)) - 1)
@@ -307,18 +300,23 @@ struct Slab {
if (gpu::get_lane_id() == leader)
before = cpp::AtomicRef(get_bitfield()[slot])
.fetch_or(bitmask, cpp::MemoryOrder::RELAXED);
- before = gpu::shuffle(mask, leader, before);
- if (~before & (1 << bit))
- result = ptr_from_index(index, chunk_size);
- else
- sleep_briefly();
+ before = gpu::shuffle(lane_mask, leader, before);
+ if (~before & (1 << bit)) {
+ cpp::atomic_thread_fence(cpp::MemoryOrder::ACQUIRE);
+ return ptr_from_index(index, chunk_size);
+ }
- after = before | bitmask;
- old_index = index;
+ // If the previous operation found an empty bit we move there, otherwise
+ // we generate new random index to start at.
+ uint32_t after = before | bitmask;
+ start = gpu::shuffle(
+ gpu::get_lane_mask(),
+ cpp::countr_zero(uniform & gpu::get_lane_mask()),
+ ~after ? __builtin_align_down(index, BITS_IN_WORD) +
+ cpp::countr_zero(~after)
+ : __builtin_align_down(impl::xorshift32(state), BITS_IN_WORD));
+ sleep_briefly();
}
-
- cpp::atomic_thread_fence(cpp::MemoryOrder::ACQUIRE);
- return result;
}
// Deallocates memory by resetting its corresponding bit in the bitfield.
@@ -507,7 +505,8 @@ static cpp::Atomic<uint32_t> indices[] = {
#undef S
// Tries to find a slab in the table that can support the given chunk size.
-static Slab *find_slab(uint32_t chunk_size, uint64_t &uniform) {
+static Slab *find_slab(uint32_t chunk_size, uint64_t &uniform,
+ uint32_t &reserved) {
// We start at the index of the last successful allocation for this kind.
uint32_t chunk_id = impl::get_chunk_id(chunk_size);
uint32_t start = indices[chunk_id].load(cpp::MemoryOrder::RELAXED);
@@ -520,7 +519,6 @@ static Slab *find_slab(uint32_t chunk_size, uint64_t &uniform) {
if (!offset ||
slots[index].use_count() < Slab::available_chunks(chunk_size)) {
uint64_t lane_mask = gpu::get_lane_mask();
- uint32_t reserved = 0;
Slab *slab = slots[index].try_lock(lane_mask, uniform & lane_mask,
reserved, chunk_size, index);
@@ -580,12 +578,12 @@ void *allocate(uint64_t size) {
// Try to find a slab for the rounded up chunk size and allocate from it.
uint32_t chunk_size = impl::get_chunk_size(static_cast<uint32_t>(size));
uint64_t uniform = gpu::match_any(gpu::get_lane_mask(), chunk_size);
- Slab *slab = find_slab(chunk_size, uniform);
- if (!slab || impl::is_sentinel(reinterpret_cast<uintptr_t>(slab)))
+ uint32_t reserved = 0;
+ Slab *slab = find_slab(chunk_size, uniform, reserved);
+ if (!slab)
return nullptr;
- uint64_t lane_mask = gpu::get_lane_mask();
- void *ptr = slab->allocate(lane_mask, uniform);
+ void *ptr = slab->allocate(uniform, reserved);
return ptr;
}
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 95acc962..500dd9d 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -158,7 +158,7 @@ add_header_library(
asinhf16
HDRS
asinhf16.h
-DEPENDS
+ DEPENDS
.acoshf_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
@@ -176,7 +176,7 @@ add_header_library(
atan_utils
HDRS
atan_utils.h
-DEPENDS
+ DEPENDS
libc.src.__support.integer_literals
libc.src.__support.FPUtil.double_double
libc.src.__support.FPUtil.dyadic_float
@@ -189,7 +189,21 @@ add_header_library(
atan
HDRS
atan.h
-DEPENDS
+ 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(
+ atan2
+ HDRS
+ atan2.h
+ DEPENDS
.atan_utils
libc.src.__support.FPUtil.double_double
libc.src.__support.FPUtil.fenv_impl
@@ -200,6 +214,38 @@ DEPENDS
)
add_header_library(
+ atan2f
+ HDRS
+ atan2f_float.h
+ atan2f.h
+ DEPENDS
+ .inv_trigf_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.FPUtil.polyeval
+ libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+)
+
+add_header_library(
+ atan2f128
+ HDRS
+ atan2f128.h
+ DEPENDS
+ .atan_utils
+ libc.src.__support.integer_literals
+ libc.src.__support.uint128
+ libc.src.__support.FPUtil.dyadic_float
+ 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(
atanf
HDRS
atanf.h
@@ -215,6 +261,32 @@ add_header_library(
)
add_header_library(
+ atanf16
+ HDRS
+ atanf16.h
+ DEPENDS
+ libc.src.__support.FPUtil.cast
+ libc.src.__support.FPUtil.except_value_utils
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.polyeval
+ libc.src.__support.FPUtil.sqrt
+ libc.src.__support.macros.optimization
+)
+
+add_header_library(
+ atanhf
+ HDRS
+ atanhf.h
+ DEPENDS
+ .acoshf_utils
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.macros.optimization
+)
+
+add_header_library(
asinf
HDRS
asinf.h
diff --git a/libc/src/__support/math/asin_utils.h b/libc/src/__support/math/asin_utils.h
index e0c9096..efe779c 100644
--- a/libc/src/__support/math/asin_utils.h
+++ b/libc/src/__support/math/asin_utils.h
@@ -45,7 +45,7 @@ static constexpr double ASIN_COEFFS[12] = {
0x1.2b5993bda1d9bp-6, -0x1.806aff270bf25p-7, 0x1.02614e5ed3936p-5,
};
-LIBC_INLINE static constexpr double asin_eval(double u) {
+LIBC_INLINE double asin_eval(double u) {
double u2 = u * u;
double c0 = fputil::multiply_add(u, ASIN_COEFFS[1], ASIN_COEFFS[0]);
double c1 = fputil::multiply_add(u, ASIN_COEFFS[3], ASIN_COEFFS[2]);
diff --git a/libc/src/__support/math/atan2.h b/libc/src/__support/math/atan2.h
new file mode 100644
index 0000000..90ed926
--- /dev/null
+++ b/libc/src/__support/math/atan2.h
@@ -0,0 +1,209 @@
+//===-- Implementation header for atan2 -------------------------*- 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_ATAN2_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2_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 {
+
+// There are several range reduction steps we can take for atan2(y, x) as
+// follow:
+
+// * Range reduction 1: signness
+// atan2(y, x) will return a number between -PI and PI representing the angle
+// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
+// In particular, we have that:
+// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
+// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
+// Since atan function is odd, we can use the formula:
+// atan(-u) = -atan(u)
+// to adjust the above conditions a bit further:
+// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
+// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
+// Which can be simplified to:
+// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
+// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
+
+// * Range reduction 2: reciprocal
+// Now that the argument inside atan is positive, we can use the formula:
+// atan(1/x) = pi/2 - atan(x)
+// to make the argument inside atan <= 1 as follow:
+// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
+// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
+// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
+// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
+
+// * Range reduction 3: look up table.
+// After the previous two range reduction steps, we reduce the problem to
+// compute atan(u) with 0 <= u <= 1, or to be precise:
+// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
+// An accurate polynomial approximation for the whole [0, 1] input range will
+// require a very large degree. To make it more efficient, we reduce the input
+// range further by finding an integer idx such that:
+// | n/d - idx/64 | <= 1/128.
+// In particular,
+// idx := round(2^6 * n/d)
+// Then for the fast pass, we find a polynomial approximation for:
+// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64)
+// For the accurate pass, we use the addition formula:
+// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) )
+// = atan( (n - d*(idx/64))/(d + n*(idx/64)) )
+// And for the fast pass, we use degree-9 Taylor polynomial to compute the RHS:
+// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9
+// with absolute errors bounded by:
+// |atan(u) - P(u)| < |u|^11 / 11 < 2^-80
+// and relative errors bounded by:
+// |(atan(u) - P(u)) / P(u)| < u^10 / 11 < 2^-73.
+
+LIBC_INLINE static constexpr double atan2(double y, double x) {
+ using namespace atan_internal;
+ using FPBits = fputil::FPBits<double>;
+
+ constexpr double IS_NEG[2] = {1.0, -1.0};
+ constexpr DoubleDouble ZERO = {0.0, 0.0};
+ constexpr DoubleDouble MZERO = {-0.0, -0.0};
+ constexpr DoubleDouble PI = {0x1.1a62633145c07p-53, 0x1.921fb54442d18p+1};
+ constexpr DoubleDouble MPI = {-0x1.1a62633145c07p-53, -0x1.921fb54442d18p+1};
+ constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
+ 0x1.921fb54442d18p0};
+ constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
+ -0x1.921fb54442d18p0};
+ constexpr DoubleDouble PI_OVER_4 = {0x1.1a62633145c07p-55,
+ 0x1.921fb54442d18p-1};
+ constexpr DoubleDouble THREE_PI_OVER_4 = {0x1.a79394c9e8a0ap-54,
+ 0x1.2d97c7f3321d2p+1};
+ // Adjustment for constant term:
+ // CONST_ADJ[x_sign][y_sign][recip]
+ constexpr DoubleDouble CONST_ADJ[2][2][2] = {
+ {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}},
+ {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}};
+
+ FPBits x_bits(x), y_bits(y);
+ bool x_sign = x_bits.sign().is_neg();
+ bool y_sign = y_bits.sign().is_neg();
+ x_bits = x_bits.abs();
+ y_bits = y_bits.abs();
+ uint64_t x_abs = x_bits.uintval();
+ uint64_t y_abs = y_bits.uintval();
+ bool recip = x_abs < y_abs;
+ uint64_t min_abs = recip ? x_abs : y_abs;
+ uint64_t max_abs = !recip ? x_abs : y_abs;
+ unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
+ unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
+
+ double num = FPBits(min_abs).get_val();
+ double den = FPBits(max_abs).get_val();
+
+ // Check for exceptional cases, whether inputs are 0, inf, nan, or close to
+ // overflow, or close to underflow.
+ if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) {
+ if (x_bits.is_nan() || y_bits.is_nan()) {
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
+ unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
+
+ // Exceptional cases:
+ // EXCEPT[y_except][x_except][x_is_neg]
+ // with x_except & y_except:
+ // 0: zero
+ // 1: finite, non-zero
+ // 2: infinity
+ constexpr DoubleDouble EXCEPTS[3][3][2] = {
+ {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}},
+ {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}},
+ {{PI_OVER_2, PI_OVER_2},
+ {PI_OVER_2, PI_OVER_2},
+ {PI_OVER_4, THREE_PI_OVER_4}},
+ };
+
+ if ((x_except != 1) || (y_except != 1)) {
+ DoubleDouble r = EXCEPTS[y_except][x_except][x_sign];
+ return fputil::multiply_add(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo);
+ }
+ bool scale_up = min_exp < 128U;
+ bool scale_down = max_exp > 0x7ffU - 128U;
+ // At least one input is denormal, multiply both numerator and denominator
+ // by some large enough power of 2 to normalize denormal inputs.
+ if (scale_up) {
+ num *= 0x1.0p64;
+ if (!scale_down)
+ den *= 0x1.0p64;
+ } else if (scale_down) {
+ den *= 0x1.0p-64;
+ if (!scale_up)
+ num *= 0x1.0p-64;
+ }
+
+ min_abs = FPBits(num).uintval();
+ max_abs = FPBits(den).uintval();
+ min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
+ max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
+ }
+
+ double final_sign = IS_NEG[(x_sign != y_sign) != recip];
+ DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip];
+ unsigned exp_diff = max_exp - min_exp;
+ // We have the following bound for normalized n and d:
+ // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1).
+ if (LIBC_UNLIKELY(exp_diff > 54)) {
+ return fputil::multiply_add(final_sign, const_term.hi,
+ final_sign * (const_term.lo + num / den));
+ }
+
+ double k = fputil::nearest_integer(64.0 * num / den);
+ unsigned idx = static_cast<unsigned>(k);
+ // k = idx / 64
+ k *= 0x1.0p-6;
+
+ // Range reduction:
+ // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64)))
+ // = atan((n - d * k/64)) / (d + n * k/64))
+ DoubleDouble num_k = fputil::exact_mult(num, k);
+ DoubleDouble den_k = fputil::exact_mult(den, k);
+
+ // num_dd = n - d * k
+ DoubleDouble num_dd = fputil::exact_add(num - den_k.hi, -den_k.lo);
+ // den_dd = d + n * k
+ DoubleDouble den_dd = fputil::exact_add(den, num_k.hi);
+ den_dd.lo += num_k.lo;
+
+ // q = (n - d * k) / (d + n * k)
+ DoubleDouble q = fputil::div(num_dd, den_dd);
+ // p ~ atan(q)
+ DoubleDouble p = atan_eval(q);
+
+ DoubleDouble r = fputil::add(const_term, fputil::add(ATAN_I[idx], p));
+ r.hi *= final_sign;
+ r.lo *= final_sign;
+
+ return r.hi + r.lo;
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2_H
diff --git a/libc/src/__support/math/atan2f.h b/libc/src/__support/math/atan2f.h
new file mode 100644
index 0000000..e3b1932
--- /dev/null
+++ b/libc/src/__support/math/atan2f.h
@@ -0,0 +1,351 @@
+//===-- Implementation header for atan2f ------------------------*- 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_ATAN2F_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F_H
+
+#include "inv_trigf_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.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
+
+#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \
+ defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)
+
+// We use float-float implementation to reduce size.
+#include "atan2f_float.h"
+
+#else
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+namespace atan2f_internal {
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+// Look up tables for accurate pass:
+
+// atan(i/16) with i = 0..16, generated by Sollya with:
+// > for i from 0 to 16 do {
+// a = round(atan(i/16), D, RN);
+// b = round(atan(i/16) - a, D, RN);
+// print("{", b, ",", a, "},");
+// };
+static constexpr fputil::DoubleDouble ATAN_I[17] = {
+ {0.0, 0.0},
+ {-0x1.c934d86d23f1dp-60, 0x1.ff55bb72cfdeap-5},
+ {-0x1.cd37686760c17p-59, 0x1.fd5ba9aac2f6ep-4},
+ {0x1.347b0b4f881cap-58, 0x1.7b97b4bce5b02p-3},
+ {0x1.8ab6e3cf7afbdp-57, 0x1.f5b75f92c80ddp-3},
+ {-0x1.963a544b672d8p-57, 0x1.362773707ebccp-2},
+ {-0x1.c63aae6f6e918p-56, 0x1.6f61941e4def1p-2},
+ {-0x1.24dec1b50b7ffp-56, 0x1.a64eec3cc23fdp-2},
+ {0x1.a2b7f222f65e2p-56, 0x1.dac670561bb4fp-2},
+ {-0x1.d5b495f6349e6p-56, 0x1.0657e94db30dp-1},
+ {-0x1.928df287a668fp-58, 0x1.1e00babdefeb4p-1},
+ {0x1.1021137c71102p-55, 0x1.345f01cce37bbp-1},
+ {0x1.2419a87f2a458p-56, 0x1.4978fa3269ee1p-1},
+ {0x1.0028e4bc5e7cap-57, 0x1.5d58987169b18p-1},
+ {-0x1.8c34d25aadef6p-56, 0x1.700a7c5784634p-1},
+ {-0x1.bf76229d3b917p-56, 0x1.819d0b7158a4dp-1},
+ {0x1.1a62633145c07p-55, 0x1.921fb54442d18p-1},
+};
+
+// Taylor polynomial, generated by Sollya with:
+// > for i from 0 to 8 do {
+// j = (-1)^(i + 1)/(2*i + 1);
+// a = round(j, D, RN);
+// b = round(j - a, D, RN);
+// print("{", b, ",", a, "},");
+// };
+static constexpr fputil::DoubleDouble COEFFS[9] = {
+ {0.0, 1.0}, // 1
+ {-0x1.5555555555555p-56, -0x1.5555555555555p-2}, // -1/3
+ {-0x1.999999999999ap-57, 0x1.999999999999ap-3}, // 1/5
+ {-0x1.2492492492492p-57, -0x1.2492492492492p-3}, // -1/7
+ {0x1.c71c71c71c71cp-58, 0x1.c71c71c71c71cp-4}, // 1/9
+ {0x1.745d1745d1746p-59, -0x1.745d1745d1746p-4}, // -1/11
+ {-0x1.3b13b13b13b14p-58, 0x1.3b13b13b13b14p-4}, // 1/13
+ {-0x1.1111111111111p-60, -0x1.1111111111111p-4}, // -1/15
+ {0x1.e1e1e1e1e1e1ep-61, 0x1.e1e1e1e1e1e1ep-5}, // 1/17
+};
+
+// Veltkamp's splitting of a double precision into hi + lo, where the hi part is
+// slightly smaller than an even split, so that the product of
+// hi * (s1 * k + s2) is exact,
+// where:
+// s1, s2 are single precsion,
+// 1/16 <= s1/s2 <= 1
+// 1/16 <= k <= 1 is an integer.
+// So the maximal precision of (s1 * k + s2) is:
+// prec(s1 * k + s2) = 2 + log2(msb(s2)) - log2(lsb(k_d * s1))
+// = 2 + log2(msb(s1)) + 4 - log2(lsb(k_d)) - log2(lsb(s1))
+// = 2 + log2(lsb(s1)) + 23 + 4 - (-4) - log2(lsb(s1))
+// = 33.
+// Thus, the Veltkamp splitting constant is C = 2^33 + 1.
+// This is used when FMA instruction is not available.
+[[maybe_unused]] LIBC_INLINE static constexpr fputil::DoubleDouble
+split_d(double a) {
+ fputil::DoubleDouble r{0.0, 0.0};
+ constexpr double C = 0x1.0p33 + 1.0;
+ double t1 = C * a;
+ double t2 = a - t1;
+ r.hi = t1 + t2;
+ r.lo = a - r.hi;
+ return r;
+}
+
+// Compute atan( num_d / den_d ) in double-double precision.
+// num_d = min(|x|, |y|)
+// den_d = max(|x|, |y|)
+// q_d = num_d / den_d
+// idx, k_d = round( 2^4 * num_d / den_d )
+// final_sign = sign of the final result
+// const_term = the constant term in the final expression.
+LIBC_INLINE static float
+atan2f_double_double(double num_d, double den_d, double q_d, int idx,
+ double k_d, double final_sign,
+ const fputil::DoubleDouble &const_term) {
+ fputil::DoubleDouble q;
+ double num_r = 0, den_r = 0;
+
+ if (idx != 0) {
+ // The following range reduction is accurate even without fma for
+ // 1/16 <= n/d <= 1.
+ // atan(n/d) - atan(idx/16) = atan((n/d - idx/16) / (1 + (n/d) * (idx/16)))
+ // = atan((n - d*(idx/16)) / (d + n*idx/16))
+ k_d *= 0x1.0p-4;
+ num_r = fputil::multiply_add(k_d, -den_d, num_d); // Exact
+ den_r = fputil::multiply_add(k_d, num_d, den_d); // Exact
+ q.hi = num_r / den_r;
+ } else {
+ // For 0 < n/d < 1/16, we just need to calculate the lower part of their
+ // quotient.
+ q.hi = q_d;
+ num_r = num_d;
+ den_r = den_d;
+ }
+#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+ q.lo = fputil::multiply_add(q.hi, -den_r, num_r) / den_r;
+#else
+ // Compute `(num_r - q.hi * den_r) / den_r` accurately without FMA
+ // instructions.
+ fputil::DoubleDouble q_hi_dd = split_d(q.hi);
+ double t1 = fputil::multiply_add(q_hi_dd.hi, -den_r, num_r); // Exact
+ double t2 = fputil::multiply_add(q_hi_dd.lo, -den_r, t1);
+ q.lo = t2 / den_r;
+#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+
+ // Taylor polynomial, evaluating using Horner's scheme:
+ // P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9 - x^11/11 + x^13/13 - x^15/15
+ // + x^17/17
+ // = x*(1 + x^2*(-1/3 + x^2*(1/5 + x^2*(-1/7 + x^2*(1/9 + x^2*
+ // *(-1/11 + x^2*(1/13 + x^2*(-1/15 + x^2 * 1/17))))))))
+ fputil::DoubleDouble q2 = fputil::quick_mult(q, q);
+ fputil::DoubleDouble p_dd =
+ fputil::polyeval(q2, COEFFS[0], COEFFS[1], COEFFS[2], COEFFS[3],
+ COEFFS[4], COEFFS[5], COEFFS[6], COEFFS[7], COEFFS[8]);
+ fputil::DoubleDouble r_dd =
+ fputil::add(const_term, fputil::multiply_add(q, p_dd, ATAN_I[idx]));
+ r_dd.hi *= final_sign;
+ r_dd.lo *= final_sign;
+
+ // Make sure the sum is normalized:
+ fputil::DoubleDouble rr = fputil::exact_add(r_dd.hi, r_dd.lo);
+ // Round to odd.
+ uint64_t rr_bits = cpp::bit_cast<uint64_t>(rr.hi);
+ if (LIBC_UNLIKELY(((rr_bits & 0xfff'ffff) == 0) && (rr.lo != 0.0))) {
+ Sign hi_sign = fputil::FPBits<double>(rr.hi).sign();
+ Sign lo_sign = fputil::FPBits<double>(rr.lo).sign();
+ if (hi_sign == lo_sign) {
+ ++rr_bits;
+ } else if ((rr_bits & fputil::FPBits<double>::FRACTION_MASK) > 0) {
+ --rr_bits;
+ }
+ }
+
+ return static_cast<float>(cpp::bit_cast<double>(rr_bits));
+}
+
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+} // namespace atan2f_internal
+
+// There are several range reduction steps we can take for atan2(y, x) as
+// follow:
+
+// * Range reduction 1: signness
+// atan2(y, x) will return a number between -PI and PI representing the angle
+// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
+// In particular, we have that:
+// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
+// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
+// Since atan function is odd, we can use the formula:
+// atan(-u) = -atan(u)
+// to adjust the above conditions a bit further:
+// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
+// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
+// Which can be simplified to:
+// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
+// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
+
+// * Range reduction 2: reciprocal
+// Now that the argument inside atan is positive, we can use the formula:
+// atan(1/x) = pi/2 - atan(x)
+// to make the argument inside atan <= 1 as follow:
+// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
+// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
+// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
+// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
+
+// * Range reduction 3: look up table.
+// After the previous two range reduction steps, we reduce the problem to
+// compute atan(u) with 0 <= u <= 1, or to be precise:
+// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
+// An accurate polynomial approximation for the whole [0, 1] input range will
+// require a very large degree. To make it more efficient, we reduce the input
+// range further by finding an integer idx such that:
+// | n/d - idx/16 | <= 1/32.
+// In particular,
+// idx := 2^-4 * round(2^4 * n/d)
+// Then for the fast pass, we find a polynomial approximation for:
+// atan( n/d ) ~ atan( idx/16 ) + (n/d - idx/16) * Q(n/d - idx/16)
+// For the accurate pass, we use the addition formula:
+// atan( n/d ) - atan( idx/16 ) = atan( (n/d - idx/16)/(1 + (n*idx)/(16*d)) )
+// = atan( (n - d * idx/16)/(d + n * idx/16) )
+// And finally we use Taylor polynomial to compute the RHS in the accurate pass:
+// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9 - u^11/11 + u^13/13 -
+// - u^15/15 + u^17/17
+// It's error in double-double precision is estimated in Sollya to be:
+// > P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9 - x^11/11 + x^13/13 - x^15/15
+// + x^17/17;
+// > dirtyinfnorm(atan(x) - P, [-2^-5, 2^-5]);
+// 0x1.aec6f...p-100
+// which is about rounding errors of double-double (2^-104).
+
+LIBC_INLINE static constexpr float atan2f(float y, float x) {
+ using namespace atan2f_internal;
+ using namespace inv_trigf_utils_internal;
+ using FPBits = typename fputil::FPBits<float>;
+ constexpr double IS_NEG[2] = {1.0, -1.0};
+ constexpr double PI = 0x1.921fb54442d18p1;
+ constexpr double PI_LO = 0x1.1a62633145c07p-53;
+ constexpr double PI_OVER_4 = 0x1.921fb54442d18p-1;
+ constexpr double PI_OVER_2 = 0x1.921fb54442d18p0;
+ constexpr double THREE_PI_OVER_4 = 0x1.2d97c7f3321d2p+1;
+ // Adjustment for constant term:
+ // CONST_ADJ[x_sign][y_sign][recip]
+ constexpr fputil::DoubleDouble CONST_ADJ[2][2][2] = {
+ {{{0.0, 0.0}, {-PI_LO / 2, -PI_OVER_2}},
+ {{-0.0, -0.0}, {-PI_LO / 2, -PI_OVER_2}}},
+ {{{-PI_LO, -PI}, {PI_LO / 2, PI_OVER_2}},
+ {{-PI_LO, -PI}, {PI_LO / 2, PI_OVER_2}}}};
+
+ FPBits x_bits(x), y_bits(y);
+ bool x_sign = x_bits.sign().is_neg();
+ bool y_sign = y_bits.sign().is_neg();
+ x_bits.set_sign(Sign::POS);
+ y_bits.set_sign(Sign::POS);
+ uint32_t x_abs = x_bits.uintval();
+ uint32_t y_abs = y_bits.uintval();
+ uint32_t max_abs = x_abs > y_abs ? x_abs : y_abs;
+ uint32_t min_abs = x_abs <= y_abs ? x_abs : y_abs;
+ float num_f = FPBits(min_abs).get_val();
+ float den_f = FPBits(max_abs).get_val();
+ double num_d = static_cast<double>(num_f);
+ double den_d = static_cast<double>(den_f);
+
+ if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || num_d == 0.0)) {
+ if (x_bits.is_nan() || y_bits.is_nan()) {
+ if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ double x_d = static_cast<double>(x);
+ double y_d = static_cast<double>(y);
+ size_t x_except = (x_d == 0.0) ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);
+ size_t y_except = (y_d == 0.0) ? 0 : (y_abs == 0x7f80'0000 ? 2 : 1);
+
+ // Exceptional cases:
+ // EXCEPT[y_except][x_except][x_is_neg]
+ // with x_except & y_except:
+ // 0: zero
+ // 1: finite, non-zero
+ // 2: infinity
+ constexpr double EXCEPTS[3][3][2] = {
+ {{0.0, PI}, {0.0, PI}, {0.0, PI}},
+ {{PI_OVER_2, PI_OVER_2}, {0.0, 0.0}, {0.0, PI}},
+ {{PI_OVER_2, PI_OVER_2},
+ {PI_OVER_2, PI_OVER_2},
+ {PI_OVER_4, THREE_PI_OVER_4}},
+ };
+
+ double r = IS_NEG[y_sign] * EXCEPTS[y_except][x_except][x_sign];
+
+ return static_cast<float>(r);
+ }
+
+ bool recip = x_abs < y_abs;
+ double final_sign = IS_NEG[(x_sign != y_sign) != recip];
+ fputil::DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip];
+ double q_d = num_d / den_d;
+
+ double k_d = fputil::nearest_integer(q_d * 0x1.0p4);
+ int idx = static_cast<int>(k_d);
+ double r = 0.0;
+
+#ifdef LIBC_MATH_HAS_SMALL_TABLES
+ double p = atan_eval_no_table(num_d, den_d, k_d * 0x1.0p-4);
+ r = final_sign * (p + (const_term.hi + ATAN_K_OVER_16[idx]));
+#else
+ q_d = fputil::multiply_add(k_d, -0x1.0p-4, q_d);
+
+ double p = atan_eval(q_d, idx);
+ r = final_sign *
+ fputil::multiply_add(q_d, p, const_term.hi + ATAN_COEFFS[idx][0]);
+#endif // LIBC_MATH_HAS_SMALL_TABLES
+
+#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ return static_cast<float>(r);
+#else
+ constexpr uint32_t LOWER_ERR = 4;
+ // Mask sticky bits in double precision before rounding to single precision.
+ constexpr uint32_t MASK =
+ mask_trailing_ones<uint32_t, fputil::FPBits<double>::SIG_LEN -
+ FPBits::SIG_LEN - 1>();
+ constexpr uint32_t UPPER_ERR = MASK - LOWER_ERR;
+
+ uint32_t r_bits = static_cast<uint32_t>(cpp::bit_cast<uint64_t>(r)) & MASK;
+
+ // Ziv's rounding test.
+ if (LIBC_LIKELY(r_bits > LOWER_ERR && r_bits < UPPER_ERR))
+ return static_cast<float>(r);
+
+ return atan2f_double_double(num_d, den_d, q_d, idx, k_d, final_sign,
+ const_term);
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F_H
diff --git a/libc/src/__support/math/atan2f128.h b/libc/src/__support/math/atan2f128.h
new file mode 100644
index 0000000..89efaf1
--- /dev/null
+++ b/libc/src/__support/math/atan2f128.h
@@ -0,0 +1,212 @@
+//===-- Implementation header for atan2f128 ---------------------*- 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_ATAN2F128_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F128_H
+
+#include "include/llvm-libc-types/float128.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT128
+
+#include "atan_utils.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/dyadic_float.h"
+#include "src/__support/FPUtil/nearest_integer.h"
+#include "src/__support/integer_literals.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+#include "src/__support/uint128.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+// There are several range reduction steps we can take for atan2(y, x) as
+// follow:
+
+// * Range reduction 1: signness
+// atan2(y, x) will return a number between -PI and PI representing the angle
+// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
+// In particular, we have that:
+// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
+// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
+// Since atan function is odd, we can use the formula:
+// atan(-u) = -atan(u)
+// to adjust the above conditions a bit further:
+// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
+// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
+// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
+// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
+// Which can be simplified to:
+// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
+// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
+
+// * Range reduction 2: reciprocal
+// Now that the argument inside atan is positive, we can use the formula:
+// atan(1/x) = pi/2 - atan(x)
+// to make the argument inside atan <= 1 as follow:
+// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
+// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
+// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
+// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
+
+// * Range reduction 3: look up table.
+// After the previous two range reduction steps, we reduce the problem to
+// compute atan(u) with 0 <= u <= 1, or to be precise:
+// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
+// An accurate polynomial approximation for the whole [0, 1] input range will
+// require a very large degree. To make it more efficient, we reduce the input
+// range further by finding an integer idx such that:
+// | n/d - idx/64 | <= 1/128.
+// In particular,
+// idx := round(2^6 * n/d)
+// Then for the fast pass, we find a polynomial approximation for:
+// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64)
+// For the accurate pass, we use the addition formula:
+// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) )
+// = atan( (n - d*(idx/64))/(d + n*(idx/64)) )
+// And for the fast pass, we use degree-13 minimax polynomial to compute the
+// RHS:
+// atan(u) ~ P(u) = u - c_3 * u^3 + c_5 * u^5 - c_7 * u^7 + c_9 *u^9 -
+// - c_11 * u^11 + c_13 * u^13
+// with absolute errors bounded by:
+// |atan(u) - P(u)| < 2^-121
+// and relative errors bounded by:
+// |(atan(u) - P(u)) / P(u)| < 2^-114.
+
+LIBC_INLINE static constexpr float128 atan2f128(float128 y, float128 x) {
+ using Float128 = fputil::DyadicFloat<128>;
+
+ constexpr Float128 ZERO = {Sign::POS, 0, 0_u128};
+ constexpr Float128 MZERO = {Sign::NEG, 0, 0_u128};
+ constexpr Float128 PI = {Sign::POS, -126,
+ 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
+ constexpr Float128 MPI = {Sign::NEG, -126,
+ 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
+ constexpr Float128 PI_OVER_2 = {Sign::POS, -127,
+ 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
+ constexpr Float128 MPI_OVER_2 = {Sign::NEG, -127,
+ 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
+ constexpr Float128 PI_OVER_4 = {Sign::POS, -128,
+ 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
+ constexpr Float128 THREE_PI_OVER_4 = {
+ Sign::POS, -128, 0x96cbe3f9'990e91a7'9394c9e8'a0a5159d_u128};
+
+ // Adjustment for constant term:
+ // CONST_ADJ[x_sign][y_sign][recip]
+ constexpr Float128 CONST_ADJ[2][2][2] = {
+ {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}},
+ {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}};
+
+ using namespace atan_internal;
+ using FPBits = fputil::FPBits<float128>;
+ using Float128 = fputil::DyadicFloat<128>;
+
+ FPBits x_bits(x), y_bits(y);
+ bool x_sign = x_bits.sign().is_neg();
+ bool y_sign = y_bits.sign().is_neg();
+ x_bits = x_bits.abs();
+ y_bits = y_bits.abs();
+ UInt128 x_abs = x_bits.uintval();
+ UInt128 y_abs = y_bits.uintval();
+ bool recip = x_abs < y_abs;
+ UInt128 min_abs = recip ? x_abs : y_abs;
+ UInt128 max_abs = !recip ? x_abs : y_abs;
+ unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
+ unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
+
+ Float128 num(FPBits(min_abs).get_val());
+ Float128 den(FPBits(max_abs).get_val());
+
+ // Check for exceptional cases, whether inputs are 0, inf, nan, or close to
+ // overflow, or close to underflow.
+ if (LIBC_UNLIKELY(max_exp >= 0x7fffU || min_exp == 0U)) {
+ if (x_bits.is_nan() || y_bits.is_nan())
+ return FPBits::quiet_nan().get_val();
+ unsigned x_except = x == 0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
+ unsigned y_except = y == 0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
+
+ // Exceptional cases:
+ // EXCEPT[y_except][x_except][x_is_neg]
+ // with x_except & y_except:
+ // 0: zero
+ // 1: finite, non-zero
+ // 2: infinity
+ constexpr Float128 EXCEPTS[3][3][2] = {
+ {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}},
+ {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}},
+ {{PI_OVER_2, PI_OVER_2},
+ {PI_OVER_2, PI_OVER_2},
+ {PI_OVER_4, THREE_PI_OVER_4}},
+ };
+
+ if ((x_except != 1) || (y_except != 1)) {
+ Float128 r = EXCEPTS[y_except][x_except][x_sign];
+ if (y_sign)
+ r.sign = r.sign.negate();
+ return static_cast<float128>(r);
+ }
+ }
+
+ bool final_sign = ((x_sign != y_sign) != recip);
+ Float128 const_term = CONST_ADJ[x_sign][y_sign][recip];
+ int exp_diff = den.exponent - num.exponent;
+ // We have the following bound for normalized n and d:
+ // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1).
+ if (LIBC_UNLIKELY(exp_diff > FPBits::FRACTION_LEN + 2)) {
+ if (final_sign)
+ const_term.sign = const_term.sign.negate();
+ return static_cast<float128>(const_term);
+ }
+
+ // Take 24 leading bits of num and den to convert to float for fast division.
+ // We also multiply the numerator by 64 using integer addition directly to the
+ // exponent field.
+ float num_f =
+ cpp::bit_cast<float>(static_cast<uint32_t>(num.mantissa >> 104) +
+ (6U << fputil::FPBits<float>::FRACTION_LEN));
+ float den_f = cpp::bit_cast<float>(
+ static_cast<uint32_t>(den.mantissa >> 104) +
+ (static_cast<uint32_t>(exp_diff) << fputil::FPBits<float>::FRACTION_LEN));
+
+ float k = fputil::nearest_integer(num_f / den_f);
+ unsigned idx = static_cast<unsigned>(k);
+
+ // k_f128 = idx / 64
+ Float128 k_f128(Sign::POS, -6, Float128::MantissaType(idx));
+
+ // Range reduction:
+ // atan(n/d) - atan(k) = atan((n/d - k/64) / (1 + (n/d) * (k/64)))
+ // = atan((n - d * k/64)) / (d + n * k/64))
+ // num_f128 = n - d * k/64
+ Float128 num_f128 = fputil::multiply_add(den, -k_f128, num);
+ // den_f128 = d + n * k/64
+ Float128 den_f128 = fputil::multiply_add(num, k_f128, den);
+
+ // q = (n - d * k) / (d + n * k)
+ Float128 q = fputil::quick_mul(num_f128, fputil::approx_reciprocal(den_f128));
+ // p ~ atan(q)
+ Float128 p = atan_eval(q);
+
+ Float128 r =
+ fputil::quick_add(const_term, fputil::quick_add(ATAN_I_F128[idx], p));
+ if (final_sign)
+ r.sign = r.sign.negate();
+
+ return static_cast<float128>(r);
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT128
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F128_H
diff --git a/libc/src/math/generic/atan2f_float.h b/libc/src/__support/math/atan2f_float.h
index 1fd853d..8bd7095 100644
--- a/libc/src/math/generic/atan2f_float.h
+++ b/libc/src/__support/math/atan2f_float.h
@@ -1,4 +1,4 @@
-//===-- Single-precision atan2f function ----------------------------------===//
+//===-- Single-precision atan2f float function ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,18 +6,21 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H
+#define LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_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/FPUtil/rounding_mode.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/math/atan2f.h"
namespace LIBC_NAMESPACE_DECL {
-namespace {
+namespace math {
+
+namespace atan2f_internal {
using FloatFloat = fputil::FloatFloat;
@@ -27,7 +30,7 @@ using FloatFloat = fputil::FloatFloat;
// b = round(atan(i/16) - a, SG, RN);
// print("{", b, ",", a, "},");
// };
-constexpr FloatFloat ATAN_I[17] = {
+static constexpr FloatFloat ATAN_I[17] = {
{0.0f, 0.0f},
{-0x1.1a6042p-30f, 0x1.ff55bcp-5f},
{-0x1.54f424p-30f, 0x1.fd5baap-4f},
@@ -57,7 +60,7 @@ constexpr FloatFloat ATAN_I[17] = {
// For x = x_hi + x_lo, fully expand the polynomial and drop any terms less than
// ulp(x_hi^3 / 3) gives us:
// P(x) ~ x_hi - x_hi^3/3 + x_lo * (1 - x_hi^2)
-FloatFloat atan_eval(const FloatFloat &x) {
+LIBC_INLINE static constexpr FloatFloat atan_eval(const FloatFloat &x) {
FloatFloat p;
p.hi = x.hi;
float x_hi_sq = x.hi * x.hi;
@@ -70,7 +73,7 @@ FloatFloat atan_eval(const FloatFloat &x) {
return p;
}
-} // anonymous namespace
+} // namespace atan2f_internal
// There are several range reduction steps we can take for atan2(y, x) as
// follow:
@@ -121,7 +124,8 @@ FloatFloat atan_eval(const FloatFloat &x) {
// > dirtyinfnorm(atan(x) - P, [-2^-5, 2^-5]);
// 0x1.995...p-28.
-LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
+LIBC_INLINE static constexpr float atan2f(float y, float x) {
+ using namespace atan2f_internal;
using FPBits = typename fputil::FPBits<float>;
constexpr float IS_NEG[2] = {1.0f, -1.0f};
constexpr FloatFloat ZERO = {0.0f, 0.0f};
@@ -234,4 +238,8 @@ LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
return final_sign * r.hi;
}
+} // namespace math
+
} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H
diff --git a/libc/src/__support/math/atanf16.h b/libc/src/__support/math/atanf16.h
new file mode 100644
index 0000000..f75d145
--- /dev/null
+++ b/libc/src/__support/math/atanf16.h
@@ -0,0 +1,119 @@
+//===-- Implementation header for atanf16 -----------------------*- 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_ATANF16_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATANF16_H
+
+#include "include/llvm-libc-macros/float16-macros.h"
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/except_value_utils.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/sqrt.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE static constexpr float16 atanf16(float16 x) {
+ // Generated by Solly using the following command:
+ // > round(pi/2, SG, RN);
+ constexpr float PI_2 = 0x1.921fb6p0;
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ constexpr size_t N_EXCEPTS = 6;
+
+ constexpr fputil::ExceptValues<float16, N_EXCEPTS> ATANF16_EXCEPTS{{
+ // (input, RZ output, RU offset, RD offset, RN offset)
+ {0x2745, 0x2744, 1, 0, 1},
+ {0x3099, 0x3090, 1, 0, 1},
+ {0x3c6c, 0x3aae, 1, 0, 1},
+ {0x466e, 0x3daa, 1, 0, 1},
+ {0x48ae, 0x3ddb, 1, 0, 0},
+ {0x5619, 0x3e3d, 1, 0, 1},
+ }};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ using FPBits = fputil::FPBits<float16>;
+ FPBits xbits(x);
+
+ uint16_t x_u = xbits.uintval();
+ uint16_t x_abs = x_u & 0x7fff;
+ bool x_sign = x_u >> 15;
+ float sign = (x_sign ? -1.0 : 1.0);
+
+ // |x| >= +/-inf
+ if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
+ if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+
+ // atanf16(+/-inf) = +/-pi/2
+ return fputil::cast<float16>(sign * PI_2);
+ }
+
+ float xf = x;
+ float xsq = xf * xf;
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Handle exceptional values
+ if (auto r = ATANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
+ LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+#endif
+
+ // |x| <= 0x1p0, |x| <= 1
+ if (x_abs <= 0x3c00) {
+ // atanf16(+/-0) = +/-0
+ if (LIBC_UNLIKELY(x_abs == 0))
+ return x;
+
+ // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
+ // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
+ // [0, 1]);
+ float result = fputil::polyeval(
+ xsq, 0x1.fffffcp-1f, -0x1.55519ep-2f, 0x1.98f6a8p-3f, -0x1.1f0a92p-3f,
+ 0x1.95b654p-4f, -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
+ return fputil::cast<float16>(xf * result);
+ }
+
+ // If |x| > 1
+ // y = atan(x) = sign(x) * atan(|x|)
+ // atan(|x|) = pi/2 - atan(1/|x|)
+ // Recall, 1/|x| < 1
+ float x_inv_sq = 1.0f / xsq;
+ float x_inv = fputil::sqrt<float>(x_inv_sq);
+
+ // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
+ // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
+ // [0, 1]);
+ float interm =
+ fputil::polyeval(x_inv_sq, 0x1.fffffcp-1f, -0x1.55519ep-2f,
+ 0x1.98f6a8p-3f, -0x1.1f0a92p-3f, 0x1.95b654p-4f,
+ -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
+
+ return fputil::cast<float16>(sign *
+ fputil::multiply_add(x_inv, -interm, PI_2));
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATANF16_H
diff --git a/libc/src/__support/math/atanhf.h b/libc/src/__support/math/atanhf.h
new file mode 100644
index 0000000..b3ee5bb
--- /dev/null
+++ b/libc/src/__support/math/atanhf.h
@@ -0,0 +1,76 @@
+//===-- Implementation header for atanhf ------------------------*- 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_ATANHF_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_ATANHF_H
+
+#include "acoshf_utils.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE static constexpr float atanhf(float x) {
+ using namespace acoshf_internal;
+ using FPBits = typename fputil::FPBits<float>;
+
+ FPBits xbits(x);
+ Sign sign = xbits.sign();
+ uint32_t x_abs = xbits.abs().uintval();
+
+ // |x| >= 1.0
+ if (LIBC_UNLIKELY(x_abs >= 0x3F80'0000U)) {
+ 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| == 1.0
+ if (x_abs == 0x3F80'0000U) {
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_DIVBYZERO);
+ return FPBits::inf(sign).get_val();
+ } else {
+ fputil::set_errno_if_required(EDOM);
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ }
+
+ // |x| < ~0.10
+ if (LIBC_UNLIKELY(x_abs <= 0x3dcc'0000U)) {
+ // |x| <= 2^-26
+ if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
+ return static_cast<float>(LIBC_UNLIKELY(x_abs == 0)
+ ? x
+ : (x + 0x1.5555555555555p-2 * x * x * x));
+ }
+
+ double xdbl = x;
+ double x2 = xdbl * xdbl;
+ // Pure Taylor series.
+ double pe = fputil::polyeval(x2, 0.0, 0x1.5555555555555p-2,
+ 0x1.999999999999ap-3, 0x1.2492492492492p-3,
+ 0x1.c71c71c71c71cp-4, 0x1.745d1745d1746p-4);
+ return static_cast<float>(fputil::multiply_add(xdbl, pe, xdbl));
+ }
+ double xdbl = x;
+ return static_cast<float>(0.5 * log_eval((xdbl + 1.0) / (xdbl - 1.0)));
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATANHF_H
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index b084346..f8a4493 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -42,6 +42,14 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.mutex)
.mutex
libc.src.__support.CPP.mutex
)
+elseif(NOT (LIBC_CONF_THREAD_MODE STREQUAL LIBC_THREAD_MODE_PLATFORM))
+ add_header_library(
+ mutex
+ HDRS
+ mutex.h
+ DEPENDS
+ .mutex_common
+ )
endif()
add_header_library(
diff --git a/libc/src/__support/threads/gpu/CMakeLists.txt b/libc/src/__support/threads/gpu/CMakeLists.txt
deleted file mode 100644
index ea89feb..0000000
--- a/libc/src/__support/threads/gpu/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-add_header_library(
- mutex
- HDRS
- mutex.h
-)
diff --git a/libc/src/__support/threads/gpu/mutex.h b/libc/src/__support/threads/gpu/mutex.h
deleted file mode 100644
index c8c484e..0000000
--- a/libc/src/__support/threads/gpu/mutex.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===--- Implementation of a GPU mutex class --------------------*- 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_THREADS_GPU_MUTEX_H
-#define LLVM_LIBC_SRC___SUPPORT_THREADS_GPU_MUTEX_H
-
-#include "src/__support/macros/attributes.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/threads/mutex_common.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-/// Implementation of a simple passthrough mutex which guards nothing. A
-/// complete Mutex locks in general cannot be implemented on the GPU. We simply
-/// define the Mutex interface and require that only a single thread executes
-/// code requiring a mutex lock.
-struct Mutex {
- LIBC_INLINE constexpr Mutex(bool, bool, bool, bool) {}
-
- LIBC_INLINE MutexError lock() { return MutexError::NONE; }
- LIBC_INLINE MutexError unlock() { return MutexError::NONE; }
- LIBC_INLINE MutexError reset() { return MutexError::NONE; }
-};
-
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_GPU_MUTEX_H
diff --git a/libc/src/__support/threads/mutex.h b/libc/src/__support/threads/mutex.h
index 392b389..cbef0d0 100644
--- a/libc/src/__support/threads/mutex.h
+++ b/libc/src/__support/threads/mutex.h
@@ -9,10 +9,35 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_MUTEX_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_MUTEX_H
-#include "src/__support/macros/properties/architectures.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+// Uses the platform specific specialization
+#define LIBC_THREAD_MODE_PLATFORM 0
+
+// Mutex guards nothing, used in single-threaded implementations
+#define LIBC_THREAD_MODE_SINGLE 1
+
+// Vendor provides implementation
+#define LIBC_THREAD_MODE_EXTERNAL 2
+
+#if !defined(LIBC_THREAD_MODE)
+#error LIBC_THREAD_MODE is undefined
+#endif // LIBC_THREAD_MODE
+
+#if LIBC_THREAD_MODE != LIBC_THREAD_MODE_PLATFORM && \
+ LIBC_THREAD_MODE != LIBC_THREAD_MODE_SINGLE && \
+ LIBC_THREAD_MODE != LIBC_THREAD_MODE_EXTERNAL
+#error LIBC_THREAD_MODE must be one of the following values: \
+LIBC_THREAD_MODE_PLATFORM, \
+LIBC_THREAD_MODE_SINGLE, \
+LIBC_THREAD_MODE_EXTERNAL.
+#endif
+
+#if LIBC_THREAD_MODE == LIBC_THREAD_MODE_PLATFORM
// Platform independent code will include this header file which pulls
-// the platfrom specific specializations using platform macros.
+// the platform specific specializations using platform macros.
//
// The platform specific specializations should define a class by name
// Mutex with non-static methods having the following signature:
@@ -39,8 +64,32 @@
#if defined(__linux__)
#include "src/__support/threads/linux/mutex.h"
-#elif defined(LIBC_TARGET_ARCH_IS_GPU)
-#include "src/__support/threads/gpu/mutex.h"
#endif // __linux__
+#elif LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE
+
+#include "src/__support/threads/mutex_common.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+/// Implementation of a simple passthrough mutex which guards nothing. A
+/// complete Mutex locks in general cannot be implemented on the GPU, or on some
+/// baremetal platforms. We simply define the Mutex interface and require that
+/// only a single thread executes code requiring a mutex lock.
+struct Mutex {
+ LIBC_INLINE constexpr Mutex(bool, bool, bool, bool) {}
+
+ LIBC_INLINE MutexError lock() { return MutexError::NONE; }
+ LIBC_INLINE MutexError unlock() { return MutexError::NONE; }
+ LIBC_INLINE MutexError reset() { return MutexError::NONE; }
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#elif LIBC_THREAD_MODE == LIBC_THREAD_MODE_EXTERNAL
+
+// TODO: Implement the interfacing, if necessary, e.g. "extern struct Mutex;"
+
+#endif // LIBC_THREAD_MODE == LIBC_THREAD_MODE_PLATFORM
+
#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_MUTEX_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 701dc4b..bac043f 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3922,10 +3922,7 @@ add_entrypoint_object(
HDRS
../atanhf.h
DEPENDS
- .explogxf
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.macros.optimization
+ libc.src.__support.math.atanhf
)
add_entrypoint_object(
@@ -4037,17 +4034,7 @@ add_entrypoint_object(
HDRS
../atanf16.h
DEPENDS
- libc.hdr.errno_macros
- libc.hdr.fenv_macros
- libc.src.__support.FPUtil.cast
- libc.src.__support.FPUtil.except_value_utils
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.multiply_add
- libc.src.__support.FPUtil.polyeval
- libc.src.__support.FPUtil.sqrt
- libc.src.__support.macros.optimization
- libc.src.__support.macros.properties.types
+ libc.src.__support.math.atanf16
)
add_entrypoint_object(
@@ -4068,18 +4055,8 @@ add_entrypoint_object(
atan2f.cpp
HDRS
../atan2f.h
- atan2f_float.h
DEPENDS
- libc.hdr.fenv_macros
- 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.FPUtil.polyeval
- libc.src.__support.FPUtil.rounding_mode
- libc.src.__support.macros.optimization
- libc.src.__support.math.inv_trigf_utils
+ libc.src.__support.math.atan2f
)
add_entrypoint_object(
@@ -4089,13 +4066,7 @@ add_entrypoint_object(
HDRS
../atan2.h
DEPENDS
- libc.src.__support.math.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.atan2
)
add_entrypoint_object(
@@ -4105,7 +4076,7 @@ add_entrypoint_object(
HDRS
../atan2l.h
DEPENDS
- .atan2
+ libc.src.__support.math.atan2
)
add_entrypoint_object(
@@ -4115,15 +4086,7 @@ add_entrypoint_object(
HDRS
../atan2f128.h
DEPENDS
- libc.src.__support.math.atan_utils
- libc.src.__support.integer_literals
- libc.src.__support.uint128
- libc.src.__support.FPUtil.dyadic_float
- 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.macros.properties.types
+ libc.src.__support.math.atan2f128
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp
index 58042d3..4aaa63d 100644
--- a/libc/src/math/generic/atan2.cpp
+++ b/libc/src/math/generic/atan2.cpp
@@ -7,195 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2.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_utils.h"
+#include "src/__support/math/atan2.h"
namespace LIBC_NAMESPACE_DECL {
-// There are several range reduction steps we can take for atan2(y, x) as
-// follow:
-
-// * Range reduction 1: signness
-// atan2(y, x) will return a number between -PI and PI representing the angle
-// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
-// In particular, we have that:
-// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
-// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
-// Since atan function is odd, we can use the formula:
-// atan(-u) = -atan(u)
-// to adjust the above conditions a bit further:
-// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
-// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
-// Which can be simplified to:
-// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
-// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
-
-// * Range reduction 2: reciprocal
-// Now that the argument inside atan is positive, we can use the formula:
-// atan(1/x) = pi/2 - atan(x)
-// to make the argument inside atan <= 1 as follow:
-// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
-// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
-// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
-// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
-
-// * Range reduction 3: look up table.
-// After the previous two range reduction steps, we reduce the problem to
-// compute atan(u) with 0 <= u <= 1, or to be precise:
-// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
-// An accurate polynomial approximation for the whole [0, 1] input range will
-// require a very large degree. To make it more efficient, we reduce the input
-// range further by finding an integer idx such that:
-// | n/d - idx/64 | <= 1/128.
-// In particular,
-// idx := round(2^6 * n/d)
-// Then for the fast pass, we find a polynomial approximation for:
-// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64)
-// For the accurate pass, we use the addition formula:
-// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) )
-// = atan( (n - d*(idx/64))/(d + n*(idx/64)) )
-// And for the fast pass, we use degree-9 Taylor polynomial to compute the RHS:
-// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9
-// with absolute errors bounded by:
-// |atan(u) - P(u)| < |u|^11 / 11 < 2^-80
-// and relative errors bounded by:
-// |(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};
- constexpr DoubleDouble ZERO = {0.0, 0.0};
- constexpr DoubleDouble MZERO = {-0.0, -0.0};
- constexpr DoubleDouble PI = {0x1.1a62633145c07p-53, 0x1.921fb54442d18p+1};
- constexpr DoubleDouble MPI = {-0x1.1a62633145c07p-53, -0x1.921fb54442d18p+1};
- constexpr DoubleDouble PI_OVER_2 = {0x1.1a62633145c07p-54,
- 0x1.921fb54442d18p0};
- constexpr DoubleDouble MPI_OVER_2 = {-0x1.1a62633145c07p-54,
- -0x1.921fb54442d18p0};
- constexpr DoubleDouble PI_OVER_4 = {0x1.1a62633145c07p-55,
- 0x1.921fb54442d18p-1};
- constexpr DoubleDouble THREE_PI_OVER_4 = {0x1.a79394c9e8a0ap-54,
- 0x1.2d97c7f3321d2p+1};
- // Adjustment for constant term:
- // CONST_ADJ[x_sign][y_sign][recip]
- constexpr DoubleDouble CONST_ADJ[2][2][2] = {
- {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}},
- {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}};
-
- FPBits x_bits(x), y_bits(y);
- bool x_sign = x_bits.sign().is_neg();
- bool y_sign = y_bits.sign().is_neg();
- x_bits = x_bits.abs();
- y_bits = y_bits.abs();
- uint64_t x_abs = x_bits.uintval();
- uint64_t y_abs = y_bits.uintval();
- bool recip = x_abs < y_abs;
- uint64_t min_abs = recip ? x_abs : y_abs;
- uint64_t max_abs = !recip ? x_abs : y_abs;
- unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
- unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
-
- double num = FPBits(min_abs).get_val();
- double den = FPBits(max_abs).get_val();
-
- // Check for exceptional cases, whether inputs are 0, inf, nan, or close to
- // overflow, or close to underflow.
- if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) {
- if (x_bits.is_nan() || y_bits.is_nan()) {
- if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
- unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
-
- // Exceptional cases:
- // EXCEPT[y_except][x_except][x_is_neg]
- // with x_except & y_except:
- // 0: zero
- // 1: finite, non-zero
- // 2: infinity
- constexpr DoubleDouble EXCEPTS[3][3][2] = {
- {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}},
- {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}},
- {{PI_OVER_2, PI_OVER_2},
- {PI_OVER_2, PI_OVER_2},
- {PI_OVER_4, THREE_PI_OVER_4}},
- };
-
- if ((x_except != 1) || (y_except != 1)) {
- DoubleDouble r = EXCEPTS[y_except][x_except][x_sign];
- return fputil::multiply_add(IS_NEG[y_sign], r.hi, IS_NEG[y_sign] * r.lo);
- }
- bool scale_up = min_exp < 128U;
- bool scale_down = max_exp > 0x7ffU - 128U;
- // At least one input is denormal, multiply both numerator and denominator
- // by some large enough power of 2 to normalize denormal inputs.
- if (scale_up) {
- num *= 0x1.0p64;
- if (!scale_down)
- den *= 0x1.0p64;
- } else if (scale_down) {
- den *= 0x1.0p-64;
- if (!scale_up)
- num *= 0x1.0p-64;
- }
-
- min_abs = FPBits(num).uintval();
- max_abs = FPBits(den).uintval();
- min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
- max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
- }
-
- double final_sign = IS_NEG[(x_sign != y_sign) != recip];
- DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip];
- unsigned exp_diff = max_exp - min_exp;
- // We have the following bound for normalized n and d:
- // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1).
- if (LIBC_UNLIKELY(exp_diff > 54)) {
- return fputil::multiply_add(final_sign, const_term.hi,
- final_sign * (const_term.lo + num / den));
- }
-
- double k = fputil::nearest_integer(64.0 * num / den);
- unsigned idx = static_cast<unsigned>(k);
- // k = idx / 64
- k *= 0x1.0p-6;
-
- // Range reduction:
- // atan(n/d) - atan(k/64) = atan((n/d - k/64) / (1 + (n/d) * (k/64)))
- // = atan((n - d * k/64)) / (d + n * k/64))
- DoubleDouble num_k = fputil::exact_mult(num, k);
- DoubleDouble den_k = fputil::exact_mult(den, k);
-
- // num_dd = n - d * k
- DoubleDouble num_dd = fputil::exact_add(num - den_k.hi, -den_k.lo);
- // den_dd = d + n * k
- DoubleDouble den_dd = fputil::exact_add(den, num_k.hi);
- den_dd.lo += num_k.lo;
-
- // q = (n - d * k) / (d + n * k)
- DoubleDouble q = fputil::div(num_dd, den_dd);
- // p ~ atan(q)
- DoubleDouble p = atan_eval(q);
-
- DoubleDouble r = fputil::add(const_term, fputil::add(ATAN_I[idx], p));
- r.hi *= final_sign;
- r.lo *= final_sign;
-
- return r.hi + r.lo;
+ return math::atan2(y, x);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/atan2f.cpp b/libc/src/math/generic/atan2f.cpp
index 32b977f..7c56788 100644
--- a/libc/src/math/generic/atan2f.cpp
+++ b/libc/src/math/generic/atan2f.cpp
@@ -7,336 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2f.h"
-#include "hdr/fenv_macros.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.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/FPUtil/rounding_mode.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/__support/math/inv_trigf_utils.h"
-
-#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \
- defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)
-
-// We use float-float implementation to reduce size.
-#include "src/math/generic/atan2f_float.h"
-
-#else
+#include "src/__support/math/atan2f.h"
namespace LIBC_NAMESPACE_DECL {
-namespace {
-
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
-// Look up tables for accurate pass:
-
-// atan(i/16) with i = 0..16, generated by Sollya with:
-// > for i from 0 to 16 do {
-// a = round(atan(i/16), D, RN);
-// b = round(atan(i/16) - a, D, RN);
-// print("{", b, ",", a, "},");
-// };
-constexpr fputil::DoubleDouble ATAN_I[17] = {
- {0.0, 0.0},
- {-0x1.c934d86d23f1dp-60, 0x1.ff55bb72cfdeap-5},
- {-0x1.cd37686760c17p-59, 0x1.fd5ba9aac2f6ep-4},
- {0x1.347b0b4f881cap-58, 0x1.7b97b4bce5b02p-3},
- {0x1.8ab6e3cf7afbdp-57, 0x1.f5b75f92c80ddp-3},
- {-0x1.963a544b672d8p-57, 0x1.362773707ebccp-2},
- {-0x1.c63aae6f6e918p-56, 0x1.6f61941e4def1p-2},
- {-0x1.24dec1b50b7ffp-56, 0x1.a64eec3cc23fdp-2},
- {0x1.a2b7f222f65e2p-56, 0x1.dac670561bb4fp-2},
- {-0x1.d5b495f6349e6p-56, 0x1.0657e94db30dp-1},
- {-0x1.928df287a668fp-58, 0x1.1e00babdefeb4p-1},
- {0x1.1021137c71102p-55, 0x1.345f01cce37bbp-1},
- {0x1.2419a87f2a458p-56, 0x1.4978fa3269ee1p-1},
- {0x1.0028e4bc5e7cap-57, 0x1.5d58987169b18p-1},
- {-0x1.8c34d25aadef6p-56, 0x1.700a7c5784634p-1},
- {-0x1.bf76229d3b917p-56, 0x1.819d0b7158a4dp-1},
- {0x1.1a62633145c07p-55, 0x1.921fb54442d18p-1},
-};
-
-// Taylor polynomial, generated by Sollya with:
-// > for i from 0 to 8 do {
-// j = (-1)^(i + 1)/(2*i + 1);
-// a = round(j, D, RN);
-// b = round(j - a, D, RN);
-// print("{", b, ",", a, "},");
-// };
-constexpr fputil::DoubleDouble COEFFS[9] = {
- {0.0, 1.0}, // 1
- {-0x1.5555555555555p-56, -0x1.5555555555555p-2}, // -1/3
- {-0x1.999999999999ap-57, 0x1.999999999999ap-3}, // 1/5
- {-0x1.2492492492492p-57, -0x1.2492492492492p-3}, // -1/7
- {0x1.c71c71c71c71cp-58, 0x1.c71c71c71c71cp-4}, // 1/9
- {0x1.745d1745d1746p-59, -0x1.745d1745d1746p-4}, // -1/11
- {-0x1.3b13b13b13b14p-58, 0x1.3b13b13b13b14p-4}, // 1/13
- {-0x1.1111111111111p-60, -0x1.1111111111111p-4}, // -1/15
- {0x1.e1e1e1e1e1e1ep-61, 0x1.e1e1e1e1e1e1ep-5}, // 1/17
-};
-
-// Veltkamp's splitting of a double precision into hi + lo, where the hi part is
-// slightly smaller than an even split, so that the product of
-// hi * (s1 * k + s2) is exact,
-// where:
-// s1, s2 are single precsion,
-// 1/16 <= s1/s2 <= 1
-// 1/16 <= k <= 1 is an integer.
-// So the maximal precision of (s1 * k + s2) is:
-// prec(s1 * k + s2) = 2 + log2(msb(s2)) - log2(lsb(k_d * s1))
-// = 2 + log2(msb(s1)) + 4 - log2(lsb(k_d)) - log2(lsb(s1))
-// = 2 + log2(lsb(s1)) + 23 + 4 - (-4) - log2(lsb(s1))
-// = 33.
-// Thus, the Veltkamp splitting constant is C = 2^33 + 1.
-// This is used when FMA instruction is not available.
-[[maybe_unused]] constexpr fputil::DoubleDouble split_d(double a) {
- fputil::DoubleDouble r{0.0, 0.0};
- constexpr double C = 0x1.0p33 + 1.0;
- double t1 = C * a;
- double t2 = a - t1;
- r.hi = t1 + t2;
- r.lo = a - r.hi;
- return r;
-}
-
-// Compute atan( num_d / den_d ) in double-double precision.
-// num_d = min(|x|, |y|)
-// den_d = max(|x|, |y|)
-// q_d = num_d / den_d
-// idx, k_d = round( 2^4 * num_d / den_d )
-// final_sign = sign of the final result
-// const_term = the constant term in the final expression.
-float atan2f_double_double(double num_d, double den_d, double q_d, int idx,
- double k_d, double final_sign,
- const fputil::DoubleDouble &const_term) {
- fputil::DoubleDouble q;
- double num_r, den_r;
-
- if (idx != 0) {
- // The following range reduction is accurate even without fma for
- // 1/16 <= n/d <= 1.
- // atan(n/d) - atan(idx/16) = atan((n/d - idx/16) / (1 + (n/d) * (idx/16)))
- // = atan((n - d*(idx/16)) / (d + n*idx/16))
- k_d *= 0x1.0p-4;
- num_r = fputil::multiply_add(k_d, -den_d, num_d); // Exact
- den_r = fputil::multiply_add(k_d, num_d, den_d); // Exact
- q.hi = num_r / den_r;
- } else {
- // For 0 < n/d < 1/16, we just need to calculate the lower part of their
- // quotient.
- q.hi = q_d;
- num_r = num_d;
- den_r = den_d;
- }
-#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
- q.lo = fputil::multiply_add(q.hi, -den_r, num_r) / den_r;
-#else
- // Compute `(num_r - q.hi * den_r) / den_r` accurately without FMA
- // instructions.
- fputil::DoubleDouble q_hi_dd = split_d(q.hi);
- double t1 = fputil::multiply_add(q_hi_dd.hi, -den_r, num_r); // Exact
- double t2 = fputil::multiply_add(q_hi_dd.lo, -den_r, t1);
- q.lo = t2 / den_r;
-#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE
-
- // Taylor polynomial, evaluating using Horner's scheme:
- // P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9 - x^11/11 + x^13/13 - x^15/15
- // + x^17/17
- // = x*(1 + x^2*(-1/3 + x^2*(1/5 + x^2*(-1/7 + x^2*(1/9 + x^2*
- // *(-1/11 + x^2*(1/13 + x^2*(-1/15 + x^2 * 1/17))))))))
- fputil::DoubleDouble q2 = fputil::quick_mult(q, q);
- fputil::DoubleDouble p_dd =
- fputil::polyeval(q2, COEFFS[0], COEFFS[1], COEFFS[2], COEFFS[3],
- COEFFS[4], COEFFS[5], COEFFS[6], COEFFS[7], COEFFS[8]);
- fputil::DoubleDouble r_dd =
- fputil::add(const_term, fputil::multiply_add(q, p_dd, ATAN_I[idx]));
- r_dd.hi *= final_sign;
- r_dd.lo *= final_sign;
-
- // Make sure the sum is normalized:
- fputil::DoubleDouble rr = fputil::exact_add(r_dd.hi, r_dd.lo);
- // Round to odd.
- uint64_t rr_bits = cpp::bit_cast<uint64_t>(rr.hi);
- if (LIBC_UNLIKELY(((rr_bits & 0xfff'ffff) == 0) && (rr.lo != 0.0))) {
- Sign hi_sign = fputil::FPBits<double>(rr.hi).sign();
- Sign lo_sign = fputil::FPBits<double>(rr.lo).sign();
- if (hi_sign == lo_sign) {
- ++rr_bits;
- } else if ((rr_bits & fputil::FPBits<double>::FRACTION_MASK) > 0) {
- --rr_bits;
- }
- }
-
- return static_cast<float>(cpp::bit_cast<double>(rr_bits));
-}
-
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
-} // anonymous namespace
-
-// There are several range reduction steps we can take for atan2(y, x) as
-// follow:
-
-// * Range reduction 1: signness
-// atan2(y, x) will return a number between -PI and PI representing the angle
-// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
-// In particular, we have that:
-// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
-// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
-// Since atan function is odd, we can use the formula:
-// atan(-u) = -atan(u)
-// to adjust the above conditions a bit further:
-// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
-// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
-// Which can be simplified to:
-// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
-// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
-
-// * Range reduction 2: reciprocal
-// Now that the argument inside atan is positive, we can use the formula:
-// atan(1/x) = pi/2 - atan(x)
-// to make the argument inside atan <= 1 as follow:
-// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
-// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
-// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
-// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
-
-// * Range reduction 3: look up table.
-// After the previous two range reduction steps, we reduce the problem to
-// compute atan(u) with 0 <= u <= 1, or to be precise:
-// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
-// An accurate polynomial approximation for the whole [0, 1] input range will
-// require a very large degree. To make it more efficient, we reduce the input
-// range further by finding an integer idx such that:
-// | n/d - idx/16 | <= 1/32.
-// In particular,
-// idx := 2^-4 * round(2^4 * n/d)
-// Then for the fast pass, we find a polynomial approximation for:
-// atan( n/d ) ~ atan( idx/16 ) + (n/d - idx/16) * Q(n/d - idx/16)
-// For the accurate pass, we use the addition formula:
-// atan( n/d ) - atan( idx/16 ) = atan( (n/d - idx/16)/(1 + (n*idx)/(16*d)) )
-// = atan( (n - d * idx/16)/(d + n * idx/16) )
-// And finally we use Taylor polynomial to compute the RHS in the accurate pass:
-// atan(u) ~ P(u) = u - u^3/3 + u^5/5 - u^7/7 + u^9/9 - u^11/11 + u^13/13 -
-// - u^15/15 + u^17/17
-// It's error in double-double precision is estimated in Sollya to be:
-// > P = x - x^3/3 + x^5/5 -x^7/7 + x^9/9 - x^11/11 + x^13/13 - x^15/15
-// + x^17/17;
-// > dirtyinfnorm(atan(x) - P, [-2^-5, 2^-5]);
-// 0x1.aec6f...p-100
-// which is about rounding errors of double-double (2^-104).
-
LLVM_LIBC_FUNCTION(float, atan2f, (float y, float x)) {
- using namespace inv_trigf_utils_internal;
- using FPBits = typename fputil::FPBits<float>;
- constexpr double IS_NEG[2] = {1.0, -1.0};
- constexpr double PI = 0x1.921fb54442d18p1;
- constexpr double PI_LO = 0x1.1a62633145c07p-53;
- constexpr double PI_OVER_4 = 0x1.921fb54442d18p-1;
- constexpr double PI_OVER_2 = 0x1.921fb54442d18p0;
- constexpr double THREE_PI_OVER_4 = 0x1.2d97c7f3321d2p+1;
- // Adjustment for constant term:
- // CONST_ADJ[x_sign][y_sign][recip]
- constexpr fputil::DoubleDouble CONST_ADJ[2][2][2] = {
- {{{0.0, 0.0}, {-PI_LO / 2, -PI_OVER_2}},
- {{-0.0, -0.0}, {-PI_LO / 2, -PI_OVER_2}}},
- {{{-PI_LO, -PI}, {PI_LO / 2, PI_OVER_2}},
- {{-PI_LO, -PI}, {PI_LO / 2, PI_OVER_2}}}};
-
- FPBits x_bits(x), y_bits(y);
- bool x_sign = x_bits.sign().is_neg();
- bool y_sign = y_bits.sign().is_neg();
- x_bits.set_sign(Sign::POS);
- y_bits.set_sign(Sign::POS);
- uint32_t x_abs = x_bits.uintval();
- uint32_t y_abs = y_bits.uintval();
- uint32_t max_abs = x_abs > y_abs ? x_abs : y_abs;
- uint32_t min_abs = x_abs <= y_abs ? x_abs : y_abs;
- float num_f = FPBits(min_abs).get_val();
- float den_f = FPBits(max_abs).get_val();
- double num_d = static_cast<double>(num_f);
- double den_d = static_cast<double>(den_f);
-
- if (LIBC_UNLIKELY(max_abs >= 0x7f80'0000U || num_d == 0.0)) {
- if (x_bits.is_nan() || y_bits.is_nan()) {
- if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- double x_d = static_cast<double>(x);
- double y_d = static_cast<double>(y);
- size_t x_except = (x_d == 0.0) ? 0 : (x_abs == 0x7f80'0000 ? 2 : 1);
- size_t y_except = (y_d == 0.0) ? 0 : (y_abs == 0x7f80'0000 ? 2 : 1);
-
- // Exceptional cases:
- // EXCEPT[y_except][x_except][x_is_neg]
- // with x_except & y_except:
- // 0: zero
- // 1: finite, non-zero
- // 2: infinity
- constexpr double EXCEPTS[3][3][2] = {
- {{0.0, PI}, {0.0, PI}, {0.0, PI}},
- {{PI_OVER_2, PI_OVER_2}, {0.0, 0.0}, {0.0, PI}},
- {{PI_OVER_2, PI_OVER_2},
- {PI_OVER_2, PI_OVER_2},
- {PI_OVER_4, THREE_PI_OVER_4}},
- };
-
- double r = IS_NEG[y_sign] * EXCEPTS[y_except][x_except][x_sign];
-
- return static_cast<float>(r);
- }
-
- bool recip = x_abs < y_abs;
- double final_sign = IS_NEG[(x_sign != y_sign) != recip];
- fputil::DoubleDouble const_term = CONST_ADJ[x_sign][y_sign][recip];
- double q_d = num_d / den_d;
-
- double k_d = fputil::nearest_integer(q_d * 0x1.0p4);
- int idx = static_cast<int>(k_d);
- double r;
-
-#ifdef LIBC_MATH_HAS_SMALL_TABLES
- double p = atan_eval_no_table(num_d, den_d, k_d * 0x1.0p-4);
- r = final_sign * (p + (const_term.hi + ATAN_K_OVER_16[idx]));
-#else
- q_d = fputil::multiply_add(k_d, -0x1.0p-4, q_d);
-
- double p = atan_eval(q_d, idx);
- r = final_sign *
- fputil::multiply_add(q_d, p, const_term.hi + ATAN_COEFFS[idx][0]);
-#endif // LIBC_MATH_HAS_SMALL_TABLES
-
-#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- return static_cast<float>(r);
-#else
- constexpr uint32_t LOWER_ERR = 4;
- // Mask sticky bits in double precision before rounding to single precision.
- constexpr uint32_t MASK =
- mask_trailing_ones<uint32_t, fputil::FPBits<double>::SIG_LEN -
- FPBits::SIG_LEN - 1>();
- constexpr uint32_t UPPER_ERR = MASK - LOWER_ERR;
-
- uint32_t r_bits = static_cast<uint32_t>(cpp::bit_cast<uint64_t>(r)) & MASK;
-
- // Ziv's rounding test.
- if (LIBC_LIKELY(r_bits > LOWER_ERR && r_bits < UPPER_ERR))
- return static_cast<float>(r);
-
- return atan2f_double_double(num_d, den_d, q_d, idx, k_d, final_sign,
- const_term);
-#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ return math::atan2f(y, x);
}
} // namespace LIBC_NAMESPACE_DECL
-
-#endif
diff --git a/libc/src/math/generic/atan2f128.cpp b/libc/src/math/generic/atan2f128.cpp
index 8838d94..ec051dd 100644
--- a/libc/src/math/generic/atan2f128.cpp
+++ b/libc/src/math/generic/atan2f128.cpp
@@ -7,198 +7,12 @@
//===----------------------------------------------------------------------===//
#include "src/math/atan2f128.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/dyadic_float.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/nearest_integer.h"
-#include "src/__support/integer_literals.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/__support/macros/properties/types.h"
-#include "src/__support/math/atan_utils.h"
-#include "src/__support/uint128.h"
+#include "src/__support/math/atan2f128.h"
namespace LIBC_NAMESPACE_DECL {
-namespace {
-
-using Float128 = fputil::DyadicFloat<128>;
-
-static constexpr Float128 ZERO = {Sign::POS, 0, 0_u128};
-static constexpr Float128 MZERO = {Sign::NEG, 0, 0_u128};
-static constexpr Float128 PI = {Sign::POS, -126,
- 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
-static constexpr Float128 MPI = {Sign::NEG, -126,
- 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
-static constexpr Float128 PI_OVER_2 = {
- Sign::POS, -127, 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
-static constexpr Float128 MPI_OVER_2 = {
- Sign::NEG, -127, 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
-static constexpr Float128 PI_OVER_4 = {
- Sign::POS, -128, 0xc90fdaa2'2168c234'c4c6628b'80dc1cd1_u128};
-static constexpr Float128 THREE_PI_OVER_4 = {
- Sign::POS, -128, 0x96cbe3f9'990e91a7'9394c9e8'a0a5159d_u128};
-
-// Adjustment for constant term:
-// CONST_ADJ[x_sign][y_sign][recip]
-static constexpr Float128 CONST_ADJ[2][2][2] = {
- {{ZERO, MPI_OVER_2}, {MZERO, MPI_OVER_2}},
- {{MPI, PI_OVER_2}, {MPI, PI_OVER_2}}};
-
-} // anonymous namespace
-
-// There are several range reduction steps we can take for atan2(y, x) as
-// follow:
-
-// * Range reduction 1: signness
-// atan2(y, x) will return a number between -PI and PI representing the angle
-// forming by the 0x axis and the vector (x, y) on the 0xy-plane.
-// In particular, we have that:
-// atan2(y, x) = atan( y/x ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi + atan( y/x ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( y/x ) if x < 0 and y < 0 (III-quadrant)
-// = atan( y/x ) if x >= 0 and y < 0 (IV-quadrant)
-// Since atan function is odd, we can use the formula:
-// atan(-u) = -atan(u)
-// to adjust the above conditions a bit further:
-// atan2(y, x) = atan( |y|/|x| ) if x >= 0 and y >= 0 (I-quadrant)
-// = pi - atan( |y|/|x| ) if x < 0 and y >= 0 (II-quadrant)
-// = -pi + atan( |y|/|x| ) if x < 0 and y < 0 (III-quadrant)
-// = -atan( |y|/|x| ) if x >= 0 and y < 0 (IV-quadrant)
-// Which can be simplified to:
-// atan2(y, x) = sign(y) * atan( |y|/|x| ) if x >= 0
-// = sign(y) * (pi - atan( |y|/|x| )) if x < 0
-
-// * Range reduction 2: reciprocal
-// Now that the argument inside atan is positive, we can use the formula:
-// atan(1/x) = pi/2 - atan(x)
-// to make the argument inside atan <= 1 as follow:
-// atan2(y, x) = sign(y) * atan( |y|/|x|) if 0 <= |y| <= x
-// = sign(y) * (pi/2 - atan( |x|/|y| ) if 0 <= x < |y|
-// = sign(y) * (pi - atan( |y|/|x| )) if 0 <= |y| <= -x
-// = sign(y) * (pi/2 + atan( |x|/|y| )) if 0 <= -x < |y|
-
-// * Range reduction 3: look up table.
-// After the previous two range reduction steps, we reduce the problem to
-// compute atan(u) with 0 <= u <= 1, or to be precise:
-// atan( n / d ) where n = min(|x|, |y|) and d = max(|x|, |y|).
-// An accurate polynomial approximation for the whole [0, 1] input range will
-// require a very large degree. To make it more efficient, we reduce the input
-// range further by finding an integer idx such that:
-// | n/d - idx/64 | <= 1/128.
-// In particular,
-// idx := round(2^6 * n/d)
-// Then for the fast pass, we find a polynomial approximation for:
-// atan( n/d ) ~ atan( idx/64 ) + (n/d - idx/64) * Q(n/d - idx/64)
-// For the accurate pass, we use the addition formula:
-// atan( n/d ) - atan( idx/64 ) = atan( (n/d - idx/64)/(1 + (n*idx)/(64*d)) )
-// = atan( (n - d*(idx/64))/(d + n*(idx/64)) )
-// And for the fast pass, we use degree-13 minimax polynomial to compute the
-// RHS:
-// atan(u) ~ P(u) = u - c_3 * u^3 + c_5 * u^5 - c_7 * u^7 + c_9 *u^9 -
-// - c_11 * u^11 + c_13 * u^13
-// with absolute errors bounded by:
-// |atan(u) - P(u)| < 2^-121
-// and relative errors bounded by:
-// |(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>;
-
- FPBits x_bits(x), y_bits(y);
- bool x_sign = x_bits.sign().is_neg();
- bool y_sign = y_bits.sign().is_neg();
- x_bits = x_bits.abs();
- y_bits = y_bits.abs();
- UInt128 x_abs = x_bits.uintval();
- UInt128 y_abs = y_bits.uintval();
- bool recip = x_abs < y_abs;
- UInt128 min_abs = recip ? x_abs : y_abs;
- UInt128 max_abs = !recip ? x_abs : y_abs;
- unsigned min_exp = static_cast<unsigned>(min_abs >> FPBits::FRACTION_LEN);
- unsigned max_exp = static_cast<unsigned>(max_abs >> FPBits::FRACTION_LEN);
-
- Float128 num(FPBits(min_abs).get_val());
- Float128 den(FPBits(max_abs).get_val());
-
- // Check for exceptional cases, whether inputs are 0, inf, nan, or close to
- // overflow, or close to underflow.
- if (LIBC_UNLIKELY(max_exp >= 0x7fffU || min_exp == 0U)) {
- if (x_bits.is_nan() || y_bits.is_nan())
- return FPBits::quiet_nan().get_val();
- unsigned x_except = x == 0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1);
- unsigned y_except = y == 0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1);
-
- // Exceptional cases:
- // EXCEPT[y_except][x_except][x_is_neg]
- // with x_except & y_except:
- // 0: zero
- // 1: finite, non-zero
- // 2: infinity
- constexpr Float128 EXCEPTS[3][3][2] = {
- {{ZERO, PI}, {ZERO, PI}, {ZERO, PI}},
- {{PI_OVER_2, PI_OVER_2}, {ZERO, ZERO}, {ZERO, PI}},
- {{PI_OVER_2, PI_OVER_2},
- {PI_OVER_2, PI_OVER_2},
- {PI_OVER_4, THREE_PI_OVER_4}},
- };
-
- if ((x_except != 1) || (y_except != 1)) {
- Float128 r = EXCEPTS[y_except][x_except][x_sign];
- if (y_sign)
- r.sign = r.sign.negate();
- return static_cast<float128>(r);
- }
- }
-
- bool final_sign = ((x_sign != y_sign) != recip);
- Float128 const_term = CONST_ADJ[x_sign][y_sign][recip];
- int exp_diff = den.exponent - num.exponent;
- // We have the following bound for normalized n and d:
- // 2^(-exp_diff - 1) < n/d < 2^(-exp_diff + 1).
- if (LIBC_UNLIKELY(exp_diff > FPBits::FRACTION_LEN + 2)) {
- if (final_sign)
- const_term.sign = const_term.sign.negate();
- return static_cast<float128>(const_term);
- }
-
- // Take 24 leading bits of num and den to convert to float for fast division.
- // We also multiply the numerator by 64 using integer addition directly to the
- // exponent field.
- float num_f =
- cpp::bit_cast<float>(static_cast<uint32_t>(num.mantissa >> 104) +
- (6U << fputil::FPBits<float>::FRACTION_LEN));
- float den_f = cpp::bit_cast<float>(
- static_cast<uint32_t>(den.mantissa >> 104) +
- (static_cast<uint32_t>(exp_diff) << fputil::FPBits<float>::FRACTION_LEN));
-
- float k = fputil::nearest_integer(num_f / den_f);
- unsigned idx = static_cast<unsigned>(k);
-
- // k_f128 = idx / 64
- Float128 k_f128(Sign::POS, -6, Float128::MantissaType(idx));
-
- // Range reduction:
- // atan(n/d) - atan(k) = atan((n/d - k/64) / (1 + (n/d) * (k/64)))
- // = atan((n - d * k/64)) / (d + n * k/64))
- // num_f128 = n - d * k/64
- Float128 num_f128 = fputil::multiply_add(den, -k_f128, num);
- // den_f128 = d + n * k/64
- Float128 den_f128 = fputil::multiply_add(num, k_f128, den);
-
- // q = (n - d * k) / (d + n * k)
- Float128 q = fputil::quick_mul(num_f128, fputil::approx_reciprocal(den_f128));
- // p ~ atan(q)
- Float128 p = atan_eval(q);
-
- Float128 r =
- fputil::quick_add(const_term, fputil::quick_add(ATAN_I_F128[idx], p));
- if (final_sign)
- r.sign = r.sign.negate();
-
- return static_cast<float128>(r);
+ return math::atan2f128(y, x);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/atan2l.cpp b/libc/src/math/generic/atan2l.cpp
index 47a2e985..a7824c6 100644
--- a/libc/src/math/generic/atan2l.cpp
+++ b/libc/src/math/generic/atan2l.cpp
@@ -9,7 +9,7 @@
#include "src/math/atan2l.h"
#include "src/__support/common.h"
#include "src/__support/macros/properties/types.h"
-#include "src/math/atan2.h"
+#include "src/__support/math/atan2.h"
namespace LIBC_NAMESPACE_DECL {
@@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long double, atan2l, (long double y, long double x)) {
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
return static_cast<long double>(
- atan2(static_cast<double>(y), static_cast<double>(x)));
+ math::atan2(static_cast<double>(y), static_cast<double>(x)));
#else
#error "Extended precision is not yet supported"
#endif
diff --git a/libc/src/math/generic/atanf16.cpp b/libc/src/math/generic/atanf16.cpp
index 9b6ec65..7191c42 100644
--- a/libc/src/math/generic/atanf16.cpp
+++ b/libc/src/math/generic/atanf16.cpp
@@ -7,101 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/math/atanf16.h"
-#include "hdr/errno_macros.h"
-#include "hdr/fenv_macros.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/PolyEval.h"
-#include "src/__support/FPUtil/cast.h"
-#include "src/__support/FPUtil/except_value_utils.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/sqrt.h"
-#include "src/__support/macros/optimization.h"
+#include "src/__support/math/atanf16.h"
namespace LIBC_NAMESPACE_DECL {
-// Generated by Solly using the following command:
-// > round(pi/2, SG, RN);
-static constexpr float PI_2 = 0x1.921fb6p0;
-
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-static constexpr size_t N_EXCEPTS = 6;
-
-static constexpr fputil::ExceptValues<float16, N_EXCEPTS> ATANF16_EXCEPTS{{
- // (input, RZ output, RU offset, RD offset, RN offset)
- {0x2745, 0x2744, 1, 0, 1},
- {0x3099, 0x3090, 1, 0, 1},
- {0x3c6c, 0x3aae, 1, 0, 1},
- {0x466e, 0x3daa, 1, 0, 1},
- {0x48ae, 0x3ddb, 1, 0, 0},
- {0x5619, 0x3e3d, 1, 0, 1},
-}};
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-
-LLVM_LIBC_FUNCTION(float16, atanf16, (float16 x)) {
- using FPBits = fputil::FPBits<float16>;
- FPBits xbits(x);
-
- uint16_t x_u = xbits.uintval();
- uint16_t x_abs = x_u & 0x7fff;
- bool x_sign = x_u >> 15;
- float sign = (x_sign ? -1.0 : 1.0);
-
- // |x| >= +/-inf
- if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
- if (xbits.is_nan()) {
- if (xbits.is_signaling_nan()) {
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- return x;
- }
-
- // atanf16(+/-inf) = +/-pi/2
- return fputil::cast<float16>(sign * PI_2);
- }
-
- float xf = x;
- float xsq = xf * xf;
-#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- // Handle exceptional values
- if (auto r = ATANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
- LIBC_UNLIKELY(r.has_value()))
- return r.value();
-#endif
-
- // |x| <= 0x1p0, |x| <= 1
- if (x_abs <= 0x3c00) {
- // atanf16(+/-0) = +/-0
- if (LIBC_UNLIKELY(x_abs == 0))
- return x;
-
- // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
- // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
- // [0, 1]);
- float result = fputil::polyeval(
- xsq, 0x1.fffffcp-1f, -0x1.55519ep-2f, 0x1.98f6a8p-3f, -0x1.1f0a92p-3f,
- 0x1.95b654p-4f, -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
- return fputil::cast<float16>(xf * result);
- }
-
- // If |x| > 1
- // y = atan(x) = sign(x) * atan(|x|)
- // atan(|x|) = pi/2 - atan(1/|x|)
- // Recall, 1/|x| < 1
- float x_inv_sq = 1.0f / xsq;
- float x_inv = fputil::sqrt<float>(x_inv_sq);
-
- // Degree-14 minimax odd polynomial of atan(x) generated by Sollya with:
- // > P = fpminimax(atan(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], [|SG...|],
- // [0, 1]);
- float interm =
- fputil::polyeval(x_inv_sq, 0x1.fffffcp-1f, -0x1.55519ep-2f,
- 0x1.98f6a8p-3f, -0x1.1f0a92p-3f, 0x1.95b654p-4f,
- -0x1.e65492p-5f, 0x1.8c0c36p-6f, -0x1.32316ep-8f);
-
- return fputil::cast<float16>(sign *
- fputil::multiply_add(x_inv, -interm, PI_2));
-}
+LLVM_LIBC_FUNCTION(float16, atanf16, (float16 x)) { return math::atanf16(x); }
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/atanhf.cpp b/libc/src/math/generic/atanhf.cpp
index 602a8f0..81706190 100644
--- a/libc/src/math/generic/atanhf.cpp
+++ b/libc/src/math/generic/atanhf.cpp
@@ -7,62 +7,10 @@
//===----------------------------------------------------------------------===//
#include "src/math/atanhf.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
-#include "src/math/generic/explogxf.h"
+#include "src/__support/math/atanhf.h"
namespace LIBC_NAMESPACE_DECL {
-LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
- using namespace acoshf_internal;
- using FPBits = typename fputil::FPBits<float>;
-
- FPBits xbits(x);
- Sign sign = xbits.sign();
- uint32_t x_abs = xbits.abs().uintval();
-
- // |x| >= 1.0
- if (LIBC_UNLIKELY(x_abs >= 0x3F80'0000U)) {
- 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| == 1.0
- if (x_abs == 0x3F80'0000U) {
- fputil::set_errno_if_required(ERANGE);
- fputil::raise_except_if_required(FE_DIVBYZERO);
- return FPBits::inf(sign).get_val();
- } else {
- fputil::set_errno_if_required(EDOM);
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- }
-
- // |x| < ~0.10
- if (LIBC_UNLIKELY(x_abs <= 0x3dcc'0000U)) {
- // |x| <= 2^-26
- if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) {
- return static_cast<float>(LIBC_UNLIKELY(x_abs == 0)
- ? x
- : (x + 0x1.5555555555555p-2 * x * x * x));
- }
-
- double xdbl = x;
- double x2 = xdbl * xdbl;
- // Pure Taylor series.
- double pe = fputil::polyeval(x2, 0.0, 0x1.5555555555555p-2,
- 0x1.999999999999ap-3, 0x1.2492492492492p-3,
- 0x1.c71c71c71c71cp-4, 0x1.745d1745d1746p-4);
- return static_cast<float>(fputil::multiply_add(xdbl, pe, xdbl));
- }
- double xdbl = x;
- return static_cast<float>(0.5 * log_eval((xdbl + 1.0) / (xdbl - 1.0)));
-}
+LLVM_LIBC_FUNCTION(float, atanhf, (float x)) { return math::atanhf(x); }
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sched/CMakeLists.txt b/libc/src/sched/CMakeLists.txt
index e6c37d3..d1d1de0 100644
--- a/libc/src/sched/CMakeLists.txt
+++ b/libc/src/sched/CMakeLists.txt
@@ -3,6 +3,13 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
add_entrypoint_object(
+ getcpu
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.getcpu
+)
+
+add_entrypoint_object(
sched_getaffinity
ALIAS
DEPENDS
diff --git a/libc/src/sched/getcpu.h b/libc/src/sched/getcpu.h
new file mode 100644
index 0000000..4c90e64
--- /dev/null
+++ b/libc/src/sched/getcpu.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for getcpu ------------------------*- 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_SCHED_GETCPU_H
+#define LLVM_LIBC_SRC_SCHED_GETCPU_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int getcpu(unsigned int *cpu, unsigned int *node);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SCHED_GETCPU_H
diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt
index e690e76..ceb755f 100644
--- a/libc/src/sched/linux/CMakeLists.txt
+++ b/libc/src/sched/linux/CMakeLists.txt
@@ -1,4 +1,15 @@
add_entrypoint_object(
+ getcpu
+ SRCS
+ getcpu.cpp
+ HDRS
+ ../getcpu.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
sched_getaffinity
SRCS
sched_getaffinity.cpp
@@ -6,7 +17,9 @@ add_entrypoint_object(
../sched_getaffinity.h
DEPENDS
libc.hdr.stdint_proxy
- libc.include.sched
+ libc.hdr.types.cpu_set_t
+ libc.hdr.types.pid_t
+ libc.hdr.types.size_t
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
@@ -18,7 +31,9 @@ add_entrypoint_object(
HDRS
../sched_setaffinity.h
DEPENDS
- libc.include.sched
+ libc.hdr.types.cpu_set_t
+ libc.hdr.types.pid_t
+ libc.hdr.types.size_t
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
@@ -30,7 +45,8 @@ add_entrypoint_object(
HDRS
../sched_getcpucount.h
DEPENDS
- libc.include.sched
+ libc.hdr.types.cpu_set_t
+ libc.hdr.types.size_t
)
add_entrypoint_object(
@@ -52,9 +68,10 @@ add_entrypoint_object(
HDRS
../sched_setparam.h
DEPENDS
+ libc.hdr.types.pid_t
+ libc.hdr.types.struct_sched_param
libc.include.sys_syscall
libc.include.time
- libc.include.sched
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
@@ -66,9 +83,10 @@ add_entrypoint_object(
HDRS
../sched_getparam.h
DEPENDS
+ libc.hdr.types.pid_t
+ libc.hdr.types.struct_sched_param
libc.include.sys_syscall
libc.include.time
- libc.include.sched
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
@@ -80,9 +98,10 @@ add_entrypoint_object(
HDRS
../sched_setscheduler.h
DEPENDS
+ libc.hdr.types.pid_t
+ libc.hdr.types.struct_sched_param
libc.include.sys_syscall
libc.include.time
- libc.include.sched
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
@@ -94,7 +113,7 @@ add_entrypoint_object(
HDRS
../sched_getscheduler.h
DEPENDS
- libc.include.sched
+ libc.hdr.types.pid_t
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
@@ -131,8 +150,9 @@ add_entrypoint_object(
HDRS
../sched_rr_get_interval.h
DEPENDS
+ libc.hdr.types.pid_t
+ libc.hdr.types.struct_timespec
libc.include.sys_syscall
- libc.include.sched
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
diff --git a/libc/src/sched/linux/getcpu.cpp b/libc/src/sched/linux/getcpu.cpp
new file mode 100644
index 0000000..a34b693
--- /dev/null
+++ b/libc/src/sched/linux/getcpu.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of getcpu ------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sched/getcpu.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, getcpu, (unsigned int *cpu, unsigned int *node)) {
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_getcpu, cpu, node, nullptr);
+ if (ret < 0) {
+ libc_errno = -ret;
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sched/linux/sched_getaffinity.cpp b/libc/src/sched/linux/sched_getaffinity.cpp
index 4a5e91a..d652f7f7 100644
--- a/libc/src/sched/linux/sched_getaffinity.cpp
+++ b/libc/src/sched/linux/sched_getaffinity.cpp
@@ -14,7 +14,9 @@
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include <sched.h>
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/size_t.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/linux/sched_getcpucount.cpp b/libc/src/sched/linux/sched_getcpucount.cpp
index 7ae166e..dcc2338 100644
--- a/libc/src/sched/linux/sched_getcpucount.cpp
+++ b/libc/src/sched/linux/sched_getcpucount.cpp
@@ -12,7 +12,8 @@
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
-#include <sched.h>
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/size_t.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/linux/sched_getscheduler.cpp b/libc/src/sched/linux/sched_getscheduler.cpp
index d8e0296..10625f2 100644
--- a/libc/src/sched/linux/sched_getscheduler.cpp
+++ b/libc/src/sched/linux/sched_getscheduler.cpp
@@ -13,6 +13,7 @@
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "hdr/types/pid_t.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/linux/sched_rr_get_interval.cpp b/libc/src/sched/linux/sched_rr_get_interval.cpp
index 5668d596b..eecbaa4 100644
--- a/libc/src/sched/linux/sched_rr_get_interval.cpp
+++ b/libc/src/sched/linux/sched_rr_get_interval.cpp
@@ -13,6 +13,8 @@
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_timespec.h"
#include <sys/syscall.h> // For syscall numbers.
#ifdef SYS_sched_rr_get_interval_time64
diff --git a/libc/src/sched/linux/sched_setaffinity.cpp b/libc/src/sched/linux/sched_setaffinity.cpp
index 93e930d..3c7ed91 100644
--- a/libc/src/sched/linux/sched_setaffinity.cpp
+++ b/libc/src/sched/linux/sched_setaffinity.cpp
@@ -13,7 +13,9 @@
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include <sched.h>
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/size_t.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_getaffinity.h b/libc/src/sched/sched_getaffinity.h
index 52ec5bc..8623089 100644
--- a/libc/src/sched/sched_getaffinity.h
+++ b/libc/src/sched/sched_getaffinity.h
@@ -10,7 +10,10 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_GETAFFINITY_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/size_t.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_getcpucount.h b/libc/src/sched/sched_getcpucount.h
index 8f35301..0667d8c 100644
--- a/libc/src/sched/sched_getcpucount.h
+++ b/libc/src/sched/sched_getcpucount.h
@@ -10,7 +10,8 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_GETCPUCOUNT_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/cpu_set_t.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_getparam.h b/libc/src/sched/sched_getparam.h
index e1b2365..00defdf 100644
--- a/libc/src/sched/sched_getparam.h
+++ b/libc/src/sched/sched_getparam.h
@@ -10,7 +10,9 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_GETPARAM_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sched_param.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_getscheduler.h b/libc/src/sched/sched_getscheduler.h
index d29e902..6407dbf 100644
--- a/libc/src/sched/sched_getscheduler.h
+++ b/libc/src/sched/sched_getscheduler.h
@@ -10,7 +10,8 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_GETSCHEDULER_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/pid_t.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_rr_get_interval.h b/libc/src/sched/sched_rr_get_interval.h
index ff09329..4195c14 100644
--- a/libc/src/sched/sched_rr_get_interval.h
+++ b/libc/src/sched/sched_rr_get_interval.h
@@ -10,7 +10,9 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_RR_GET_INTERVAL_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_timespec.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_setaffinity.h b/libc/src/sched/sched_setaffinity.h
index cb2303d..f6739ab 100644
--- a/libc/src/sched/sched_setaffinity.h
+++ b/libc/src/sched/sched_setaffinity.h
@@ -10,7 +10,10 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_SETAFFINITY_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/pid_t.h"
+#include "hdr/types/size_t.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_setparam.h b/libc/src/sched/sched_setparam.h
index e4691a7..5a69b09 100644
--- a/libc/src/sched/sched_setparam.h
+++ b/libc/src/sched/sched_setparam.h
@@ -10,7 +10,9 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_SETPARAM_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sched_param.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/sched/sched_setscheduler.h b/libc/src/sched/sched_setscheduler.h
index e745002..c5cb148 100644
--- a/libc/src/sched/sched_setscheduler.h
+++ b/libc/src/sched/sched_setscheduler.h
@@ -10,7 +10,9 @@
#define LLVM_LIBC_SRC_SCHED_SCHED_SETSCHEDULER_H
#include "src/__support/macros/config.h"
-#include <sched.h>
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sched_param.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/wchar/wcstok.cpp b/libc/src/wchar/wcstok.cpp
index ed4f0aa..85513a6 100644
--- a/libc/src/wchar/wcstok.cpp
+++ b/libc/src/wchar/wcstok.cpp
@@ -27,17 +27,22 @@ LLVM_LIBC_FUNCTION(wchar_t *, wcstok,
wchar_t *tok_start = str;
while (*tok_start != L'\0' && internal::wcschr(delims, *tok_start))
++tok_start;
+ if (*tok_start == L'\0') {
+ *context = nullptr;
+ return nullptr;
+ }
wchar_t *tok_end = tok_start;
while (*tok_end != L'\0' && !internal::wcschr(delims, *tok_end))
++tok_end;
- if (*tok_end != L'\0') {
+ if (*tok_end == L'\0') {
+ *context = nullptr;
+ } else {
*tok_end = L'\0';
- ++tok_end;
+ *context = tok_end + 1;
}
- *context = tok_end;
- return *tok_start == L'\0' ? nullptr : tok_start;
+ return tok_start;
}
} // namespace LIBC_NAMESPACE_DECL