Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc][math] Implement nexttoward functions #72763

Merged
merged 2 commits into from Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions libc/config/darwin/arm/entrypoints.txt
Expand Up @@ -199,6 +199,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
Expand Down
3 changes: 3 additions & 0 deletions libc/config/darwin/x86_64/entrypoints.txt
Expand Up @@ -178,6 +178,9 @@ set(TARGET_LIBM_ENTRYPOINTS
#libc.src.math.nextafter
#libc.src.math.nextafterf
#libc.src.math.nextafterl
#libc.src.math.nexttoward
#libc.src.math.nexttowardf
#libc.src.math.nexttowardl
#libc.src.math.remainderf
#libc.src.math.remainder
#libc.src.math.remainderl
Expand Down
2 changes: 2 additions & 0 deletions libc/config/gpu/entrypoints.txt
Expand Up @@ -219,6 +219,8 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nearbyintf
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.pow
libc.src.math.powf
libc.src.math.remainder
Expand Down
3 changes: 3 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Expand Up @@ -316,6 +316,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
Expand Down
3 changes: 3 additions & 0 deletions libc/config/linux/riscv/entrypoints.txt
Expand Up @@ -325,6 +325,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
Expand Down
3 changes: 3 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Expand Up @@ -329,6 +329,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
Expand Down
3 changes: 3 additions & 0 deletions libc/config/windows/entrypoints.txt
Expand Up @@ -198,6 +198,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.nextafter
libc.src.math.nextafterf
libc.src.math.nextafterl
libc.src.math.nexttoward
libc.src.math.nexttowardf
libc.src.math.nexttowardl
libc.src.math.powf
libc.src.math.remainderf
libc.src.math.remainder
Expand Down
6 changes: 3 additions & 3 deletions libc/docs/math/index.rst
Expand Up @@ -230,11 +230,11 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| nextafterl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| nexttoward | | | | | | | | | | | | |
| nexttoward | |check| | |check| | | |check| | |check| | | | |check| | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| nexttowardf | | | | | | | | | | | | |
| nexttowardf | |check| | |check| | | |check| | |check| | | | |check| | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| nexttowardl | | | | | | | | | | | | |
| nexttowardl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| remainder | |check| | |check| | | |check| | |check| | | | |check| | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Expand Down
4 changes: 4 additions & 0 deletions libc/spec/stdc.td
Expand Up @@ -492,6 +492,10 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"nextafter", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
FunctionSpec<"nextafterl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,

FunctionSpec<"nexttowardf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<LongDoubleType>]>,
FunctionSpec<"nexttoward", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<LongDoubleType>]>,
FunctionSpec<"nexttowardl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,

FunctionSpec<"powf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
FunctionSpec<"pow", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,

Expand Down
1 change: 1 addition & 0 deletions libc/src/__support/FPUtil/CMakeLists.txt
Expand Up @@ -94,6 +94,7 @@ add_header_library(
HDRS
ManipulationFunctions.h
DEPENDS
.fenv_impl
.fp_bits
.nearest_integer_operations
.normal_float
Expand Down
46 changes: 45 additions & 1 deletion libc/src/__support/FPUtil/ManipulationFunctions.h
Expand Up @@ -10,12 +10,14 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H

#include "FPBits.h"
#include "FloatProperties.h"
#include "NearestIntegerOperations.h"
#include "NormalFloat.h"
#include "PlatformDefs.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY

Expand Down Expand Up @@ -169,8 +171,50 @@ LIBC_INLINE T nextafter(T from, T to) {
int_val = (to_bits.uintval() & sign_mask) + UIntType(1);
}

UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
if (exponent_bits == UIntType(0))
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
Comment on lines +174 to +178
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably test the exceptions in the tests for nextafter too. Will do that in a separate pr?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM. Thanks for fixing this TODO item.


return cpp::bit_cast<T>(int_val);
}

template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
nexttoward(T from, long double to) {
FPBits<T> from_bits(from);
if (from_bits.is_nan())
return from;

FPBits<long double> to_bits(to);
if (to_bits.is_nan())
return to;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm observing the following warnings when building ninja check-libc with clang:

[286/3491] Building CXX object projects/libc/src/math/gene...es/libc.src.math.generic.nexttowardf.dir/nexttowardf.cpp.o
In file included from /android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:10:
/android0/llvm-project/libc/src/__support/FPUtil/ManipulationFunctions.h:191:12: warning: implicit conversion loses floating-point precision: 'long double' to 'cpp::enable_if_t<cpp::is_floating_point_v<float>, float>' (aka 'float') [-Wimplicit-float-conversion]
    return to;
    ~~~~~~ ^~
/android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:16:18: note: in instantiation of function template specialization '__llvm_libc_18_0_0_git::fputil::nexttoward<float>' requested here
  return fputil::nexttoward(x, y);
                 ^
In file included from /android0/llvm-project/libc/src/math/generic/nexttowardf.cpp:10:
/android0/llvm-project/libc/src/__support/FPUtil/ManipulationFunctions.h:194:12: warning: implicit conversion loses floating-point precision: 'long double' to 'cpp::enable_if_t<cpp::is_floating_point_v<float>, float>' (aka 'float') [-Wimplicit-float-conversion]
    return to;
    ~~~~~~ ^~

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That issue should be fixed by #73698. Are you on an updated checkout?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, thanks, slightly behind!


if ((long double)from == to)
return to;

using UIntType = typename FPBits<T>::UIntType;
UIntType int_val = from_bits.uintval();
if (from != T(0.0)) {
if ((from < to) == (from > T(0.0))) {
++int_val;
} else {
--int_val;
}
} else {
int_val = FPBits<T>::MIN_SUBNORMAL;
if (to_bits.get_sign())
int_val |= FloatProperties<T>::SIGN_MASK;
}

UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
if (exponent_bits == UIntType(0))
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);

return cpp::bit_cast<T>(int_val);
// TODO: Raise floating point exceptions as required by the standard.
}

} // namespace fputil
Expand Down
11 changes: 10 additions & 1 deletion libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
Expand Up @@ -16,6 +16,7 @@
#endif

#include "src/__support/CPP/bit.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"

#include <stdint.h>
Expand Down Expand Up @@ -59,6 +60,8 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// which is what is expected. Since NaNs are handling separately,
// it will never overflow "beyond" infinity.
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
if (from_bits.is_inf())
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits;
} else {
++int_val;
Expand Down Expand Up @@ -105,15 +108,21 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// which is what is expected. Since NaNs are handling separately,
// it will never overflow "beyond" infinity.
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
if (from_bits.is_inf())
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits;
} else {
++int_val;
}
}
}

UIntType implicit_bit =
int_val & (UIntType(1) << MantissaWidth<long double>::VALUE);
if (implicit_bit == UIntType(0))
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);

return cpp::bit_cast<long double>(int_val);
// TODO: Raise floating point exceptions as required by the standard.
}

} // namespace fputil
Expand Down
4 changes: 4 additions & 0 deletions libc/src/math/CMakeLists.txt
Expand Up @@ -187,6 +187,10 @@ add_math_entrypoint_object(nextafter)
add_math_entrypoint_object(nextafterf)
add_math_entrypoint_object(nextafterl)

add_math_entrypoint_object(nexttoward)
add_math_entrypoint_object(nexttowardf)
add_math_entrypoint_object(nexttowardl)

add_math_entrypoint_object(pow)
add_math_entrypoint_object(powf)

Expand Down
36 changes: 36 additions & 0 deletions libc/src/math/generic/CMakeLists.txt
Expand Up @@ -1474,6 +1474,42 @@ add_entrypoint_object(
-O2
)

add_entrypoint_object(
nexttoward
SRCS
nexttoward.cpp
HDRS
../nexttoward.h
DEPENDS
libc.src.__support.FPUtil.manipulation_functions
COMPILE_OPTIONS
-O3
)

add_entrypoint_object(
nexttowardf
SRCS
nexttowardf.cpp
HDRS
../nexttowardf.h
DEPENDS
libc.src.__support.FPUtil.manipulation_functions
COMPILE_OPTIONS
-O3
)

add_entrypoint_object(
nexttowardl
SRCS
nexttowardl.cpp
HDRS
../nexttowardl.h
DEPENDS
libc.src.__support.FPUtil.manipulation_functions
COMPILE_OPTIONS
-O3
)

add_entrypoint_object(
fmod
SRCS
Expand Down
19 changes: 19 additions & 0 deletions libc/src/math/generic/nexttoward.cpp
@@ -0,0 +1,19 @@
//===-- Implementation of nexttoward function -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/math/nexttoward.h"
#include "src/__support/FPUtil/ManipulationFunctions.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(double, nexttoward, (double x, long double y)) {
return fputil::nexttoward(x, y);
}

} // namespace LIBC_NAMESPACE
19 changes: 19 additions & 0 deletions libc/src/math/generic/nexttowardf.cpp
@@ -0,0 +1,19 @@
//===-- Implementation of nexttowardf function ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/math/nexttowardf.h"
#include "src/__support/FPUtil/ManipulationFunctions.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(float, nexttowardf, (float x, long double y)) {
return fputil::nexttoward(x, y);
}

} // namespace LIBC_NAMESPACE
22 changes: 22 additions & 0 deletions libc/src/math/generic/nexttowardl.cpp
@@ -0,0 +1,22 @@
//===-- Implementation of nexttowardl function ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/math/nexttowardl.h"
#include "src/__support/FPUtil/ManipulationFunctions.h"
#include "src/__support/common.h"

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.
return fputil::nextafter(x, y);
nishantwrp marked this conversation as resolved.
Show resolved Hide resolved
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/math/nexttoward.h
@@ -0,0 +1,18 @@
//===-- Implementation header for nexttoward --------------------*- 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_MATH_NEXTTOWARD_H
#define LLVM_LIBC_SRC_MATH_NEXTTOWARD_H

namespace LIBC_NAMESPACE {

double nexttoward(double x, long double y);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
18 changes: 18 additions & 0 deletions libc/src/math/nexttowardf.h
@@ -0,0 +1,18 @@
//===-- Implementation header for nexttowardf -------------------*- 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_MATH_NEXTTOWARDF_H
#define LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H

namespace LIBC_NAMESPACE {

float nexttowardf(float x, long double y);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
18 changes: 18 additions & 0 deletions libc/src/math/nexttowardl.h
@@ -0,0 +1,18 @@
//===-- Implementation header for nexttowardl -------------------*- 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_MATH_NEXTTOWARDL_H
#define LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H

namespace LIBC_NAMESPACE {

long double nexttowardl(long double x, long double y);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H