From 72ee00596424b8598e63f09c104eb19b2ad6d8a1 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 28 Nov 2023 12:41:27 -0800 Subject: [PATCH 1/2] [libc][NFC] unify nextafter and nexttoward code Previously the nextafter and nexttoward implementations were almost identical, with the exception of whether or not the second argument was a template or just long double. This patch unifies them by making the two argument templates independent. --- .../__support/FPUtil/ManipulationFunctions.h | 53 ++++--------------- libc/src/math/generic/nexttoward.cpp | 4 +- libc/src/math/generic/nexttowardf.cpp | 4 +- libc/src/math/generic/nexttowardl.cpp | 5 +- 4 files changed, 18 insertions(+), 48 deletions(-) diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h index f1768885d4ca5..6624d8c34d293 100644 --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -144,59 +144,26 @@ LIBC_INLINE T ldexp(T x, int exp) { return normal; } -template , int> = 0> -LIBC_INLINE T nextafter(T from, T to) { - FPBits from_bits(from); - if (from_bits.is_nan()) - return from; - - FPBits to_bits(to); - if (to_bits.is_nan()) - return to; - - if (from == to) - return to; - - using UIntType = typename FPBits::UIntType; - UIntType int_val = from_bits.uintval(); - UIntType sign_mask = (UIntType(1) << (sizeof(T) * 8 - 1)); - if (from != T(0.0)) { - if ((from < to) == (from > T(0.0))) { - ++int_val; - } else { - --int_val; - } - } else { - int_val = (to_bits.uintval() & sign_mask) + UIntType(1); - } - - UIntType exponent_bits = int_val & FloatProperties::EXPONENT_MASK; - if (exponent_bits == UIntType(0)) - raise_except_if_required(FE_UNDERFLOW | FE_INEXACT); - else if (exponent_bits == FloatProperties::EXPONENT_MASK) - raise_except_if_required(FE_OVERFLOW | FE_INEXACT); - - return cpp::bit_cast(int_val); -} - -template -LIBC_INLINE cpp::enable_if_t, T> -nexttoward(T from, long double to) { +template < + typename T, typename U, + cpp::enable_if_t && cpp::is_floating_point_v, + int> = 0> +LIBC_INLINE T nextafter(T from, U to) { FPBits from_bits(from); if (from_bits.is_nan()) return from; - FPBits to_bits(to); + FPBits to_bits(to); if (to_bits.is_nan()) - return to; + return static_cast(to); - if ((long double)from == to) - return to; + if (static_cast(from) == to) + return static_cast(to); using UIntType = typename FPBits::UIntType; UIntType int_val = from_bits.uintval(); if (from != T(0.0)) { - if ((from < to) == (from > T(0.0))) { + if ((static_cast(from) < to) == (from > T(0.0))) { ++int_val; } else { --int_val; diff --git a/libc/src/math/generic/nexttoward.cpp b/libc/src/math/generic/nexttoward.cpp index 38b45d6d2f65d..ce3e4e6a69ad2 100644 --- a/libc/src/math/generic/nexttoward.cpp +++ b/libc/src/math/generic/nexttoward.cpp @@ -13,7 +13,9 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(double, nexttoward, (double x, long double y)) { - return fputil::nexttoward(x, y); + // We can reuse the nextafter implementation because the internal nextafter is + // templated on the types of the arguments. + return fputil::nextafter(x, y); } } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/nexttowardf.cpp b/libc/src/math/generic/nexttowardf.cpp index 59a9f805a6946..3b0762c50160a 100644 --- a/libc/src/math/generic/nexttowardf.cpp +++ b/libc/src/math/generic/nexttowardf.cpp @@ -13,7 +13,9 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(float, nexttowardf, (float x, long double y)) { - return fputil::nexttoward(x, y); + // We can reuse the nextafter implementation because the internal nextafter is + // templated on the types of the arguments. + return fputil::nextafter(x, y); } } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/nexttowardl.cpp b/libc/src/math/generic/nexttowardl.cpp index 0c887ae0671bc..e9f7f83907603 100644 --- a/libc/src/math/generic/nexttowardl.cpp +++ b/libc/src/math/generic/nexttowardl.cpp @@ -13,9 +13,8 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(long double, nexttowardl, (long double x, long double y)) { - // We can reuse the nextafter implementation because nexttoward behaves - // exactly same as nextafter in case of long doubles. Also, we have explcitly - // handled the special 80-bit long doubles in nextafter implementation. + // We can reuse the nextafter implementation because the internal nextafter is + // templated on the types of the arguments. return fputil::nextafter(x, y); } From 7f25d411c91d74d3873f3a952b274bf28a1bc262 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 28 Nov 2023 15:11:51 -0800 Subject: [PATCH 2/2] Fix constant definitions --- libc/src/__support/FPUtil/ManipulationFunctions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h index 6624d8c34d293..9286deee2d92c 100644 --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -162,8 +162,8 @@ LIBC_INLINE T nextafter(T from, U to) { using UIntType = typename FPBits::UIntType; UIntType int_val = from_bits.uintval(); - if (from != T(0.0)) { - if ((static_cast(from) < to) == (from > T(0.0))) { + if (from != FPBits::zero()) { + if ((static_cast(from) < to) == (from > FPBits::zero())) { ++int_val; } else { --int_val;