Skip to content

Commit 0c49fc4

Browse files
authored
[libc][math] Implement nexttoward functions (#72763)
Implements the `nexttoward`, `nexttowardf` and `nexttowardl` functions. Also, raise excepts required by the standard in `nextafter` functions. cc: @lntue
1 parent f79676a commit 0c49fc4

26 files changed

+553
-5
lines changed

libc/config/darwin/arm/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ set(TARGET_LIBM_ENTRYPOINTS
199199
libc.src.math.nextafter
200200
libc.src.math.nextafterf
201201
libc.src.math.nextafterl
202+
libc.src.math.nexttoward
203+
libc.src.math.nexttowardf
204+
libc.src.math.nexttowardl
202205
libc.src.math.powf
203206
libc.src.math.remainderf
204207
libc.src.math.remainder

libc/config/darwin/x86_64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ set(TARGET_LIBM_ENTRYPOINTS
178178
#libc.src.math.nextafter
179179
#libc.src.math.nextafterf
180180
#libc.src.math.nextafterl
181+
#libc.src.math.nexttoward
182+
#libc.src.math.nexttowardf
183+
#libc.src.math.nexttowardl
181184
#libc.src.math.remainderf
182185
#libc.src.math.remainder
183186
#libc.src.math.remainderl

libc/config/gpu/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ set(TARGET_LIBM_ENTRYPOINTS
219219
libc.src.math.nearbyintf
220220
libc.src.math.nextafter
221221
libc.src.math.nextafterf
222+
libc.src.math.nexttoward
223+
libc.src.math.nexttowardf
222224
libc.src.math.pow
223225
libc.src.math.powf
224226
libc.src.math.remainder

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ set(TARGET_LIBM_ENTRYPOINTS
316316
libc.src.math.nextafter
317317
libc.src.math.nextafterf
318318
libc.src.math.nextafterl
319+
libc.src.math.nexttoward
320+
libc.src.math.nexttowardf
321+
libc.src.math.nexttowardl
319322
libc.src.math.powf
320323
libc.src.math.remainderf
321324
libc.src.math.remainder

libc/config/linux/riscv/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ set(TARGET_LIBM_ENTRYPOINTS
325325
libc.src.math.nextafter
326326
libc.src.math.nextafterf
327327
libc.src.math.nextafterl
328+
libc.src.math.nexttoward
329+
libc.src.math.nexttowardf
330+
libc.src.math.nexttowardl
328331
libc.src.math.powf
329332
libc.src.math.remainderf
330333
libc.src.math.remainder

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,9 @@ set(TARGET_LIBM_ENTRYPOINTS
329329
libc.src.math.nextafter
330330
libc.src.math.nextafterf
331331
libc.src.math.nextafterl
332+
libc.src.math.nexttoward
333+
libc.src.math.nexttowardf
334+
libc.src.math.nexttowardl
332335
libc.src.math.powf
333336
libc.src.math.remainderf
334337
libc.src.math.remainder

libc/config/windows/entrypoints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ set(TARGET_LIBM_ENTRYPOINTS
198198
libc.src.math.nextafter
199199
libc.src.math.nextafterf
200200
libc.src.math.nextafterl
201+
libc.src.math.nexttoward
202+
libc.src.math.nexttowardf
203+
libc.src.math.nexttowardl
201204
libc.src.math.powf
202205
libc.src.math.remainderf
203206
libc.src.math.remainder

libc/docs/math/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,11 +230,11 @@ Basic Operations
230230
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
231231
| nextafterl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
232232
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
233-
| nexttoward | | | | | | | | | | | | |
233+
| nexttoward | |check| | |check| | | |check| | |check| | | | |check| | | | | |
234234
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
235-
| nexttowardf | | | | | | | | | | | | |
235+
| nexttowardf | |check| | |check| | | |check| | |check| | | | |check| | | | | |
236236
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
237-
| nexttowardl | | | | | | | | | | | | |
237+
| nexttowardl | |check| | |check| | | |check| | |check| | | | |check| | | | | |
238238
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
239239
| remainder | |check| | |check| | | |check| | |check| | | | |check| | | | | |
240240
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+

libc/spec/stdc.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ def StdC : StandardSpec<"stdc"> {
492492
FunctionSpec<"nextafter", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
493493
FunctionSpec<"nextafterl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
494494

495+
FunctionSpec<"nexttowardf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<LongDoubleType>]>,
496+
FunctionSpec<"nexttoward", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<LongDoubleType>]>,
497+
FunctionSpec<"nexttowardl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
498+
495499
FunctionSpec<"powf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
496500
FunctionSpec<"pow", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
497501

libc/src/__support/FPUtil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ add_header_library(
9696
HDRS
9797
ManipulationFunctions.h
9898
DEPENDS
99+
.fenv_impl
99100
.fp_bits
100101
.nearest_integer_operations
101102
.normal_float

libc/src/__support/FPUtil/ManipulationFunctions.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_MANIPULATIONFUNCTIONS_H
1111

1212
#include "FPBits.h"
13+
#include "FloatProperties.h"
1314
#include "NearestIntegerOperations.h"
1415
#include "NormalFloat.h"
1516
#include "PlatformDefs.h"
1617

1718
#include "src/__support/CPP/bit.h"
1819
#include "src/__support/CPP/type_traits.h"
20+
#include "src/__support/FPUtil/FEnvImpl.h"
1921
#include "src/__support/macros/attributes.h"
2022
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
2123

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

174+
UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
175+
if (exponent_bits == UIntType(0))
176+
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
177+
else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
178+
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
179+
180+
return cpp::bit_cast<T>(int_val);
181+
}
182+
183+
template <typename T>
184+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
185+
nexttoward(T from, long double to) {
186+
FPBits<T> from_bits(from);
187+
if (from_bits.is_nan())
188+
return from;
189+
190+
FPBits<long double> to_bits(to);
191+
if (to_bits.is_nan())
192+
return to;
193+
194+
if ((long double)from == to)
195+
return to;
196+
197+
using UIntType = typename FPBits<T>::UIntType;
198+
UIntType int_val = from_bits.uintval();
199+
if (from != T(0.0)) {
200+
if ((from < to) == (from > T(0.0))) {
201+
++int_val;
202+
} else {
203+
--int_val;
204+
}
205+
} else {
206+
int_val = FPBits<T>::MIN_SUBNORMAL;
207+
if (to_bits.get_sign())
208+
int_val |= FloatProperties<T>::SIGN_MASK;
209+
}
210+
211+
UIntType exponent_bits = int_val & FloatProperties<T>::EXPONENT_MASK;
212+
if (exponent_bits == UIntType(0))
213+
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
214+
else if (exponent_bits == FloatProperties<T>::EXPONENT_MASK)
215+
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
216+
172217
return cpp::bit_cast<T>(int_val);
173-
// TODO: Raise floating point exceptions as required by the standard.
174218
}
175219

176220
} // namespace fputil

libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#endif
1717

1818
#include "src/__support/CPP/bit.h"
19+
#include "src/__support/FPUtil/FEnvImpl.h"
1920
#include "src/__support/FPUtil/FPBits.h"
2021

2122
#include <stdint.h>
@@ -59,6 +60,8 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
5960
// which is what is expected. Since NaNs are handling separately,
6061
// it will never overflow "beyond" infinity.
6162
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
63+
if (from_bits.is_inf())
64+
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
6265
return from_bits;
6366
} else {
6467
++int_val;
@@ -105,15 +108,21 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
105108
// which is what is expected. Since NaNs are handling separately,
106109
// it will never overflow "beyond" infinity.
107110
from_bits.set_unbiased_exponent(from_bits.get_unbiased_exponent() + 1);
111+
if (from_bits.is_inf())
112+
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
108113
return from_bits;
109114
} else {
110115
++int_val;
111116
}
112117
}
113118
}
114119

120+
UIntType implicit_bit =
121+
int_val & (UIntType(1) << MantissaWidth<long double>::VALUE);
122+
if (implicit_bit == UIntType(0))
123+
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
124+
115125
return cpp::bit_cast<long double>(int_val);
116-
// TODO: Raise floating point exceptions as required by the standard.
117126
}
118127

119128
} // namespace fputil

libc/src/math/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ add_math_entrypoint_object(nextafter)
187187
add_math_entrypoint_object(nextafterf)
188188
add_math_entrypoint_object(nextafterl)
189189

190+
add_math_entrypoint_object(nexttoward)
191+
add_math_entrypoint_object(nexttowardf)
192+
add_math_entrypoint_object(nexttowardl)
193+
190194
add_math_entrypoint_object(pow)
191195
add_math_entrypoint_object(powf)
192196

libc/src/math/generic/CMakeLists.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,42 @@ add_entrypoint_object(
14741474
-O2
14751475
)
14761476

1477+
add_entrypoint_object(
1478+
nexttoward
1479+
SRCS
1480+
nexttoward.cpp
1481+
HDRS
1482+
../nexttoward.h
1483+
DEPENDS
1484+
libc.src.__support.FPUtil.manipulation_functions
1485+
COMPILE_OPTIONS
1486+
-O3
1487+
)
1488+
1489+
add_entrypoint_object(
1490+
nexttowardf
1491+
SRCS
1492+
nexttowardf.cpp
1493+
HDRS
1494+
../nexttowardf.h
1495+
DEPENDS
1496+
libc.src.__support.FPUtil.manipulation_functions
1497+
COMPILE_OPTIONS
1498+
-O3
1499+
)
1500+
1501+
add_entrypoint_object(
1502+
nexttowardl
1503+
SRCS
1504+
nexttowardl.cpp
1505+
HDRS
1506+
../nexttowardl.h
1507+
DEPENDS
1508+
libc.src.__support.FPUtil.manipulation_functions
1509+
COMPILE_OPTIONS
1510+
-O3
1511+
)
1512+
14771513
add_entrypoint_object(
14781514
fmod
14791515
SRCS

libc/src/math/generic/nexttoward.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of nexttoward function -----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/math/nexttoward.h"
10+
#include "src/__support/FPUtil/ManipulationFunctions.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(double, nexttoward, (double x, long double y)) {
16+
return fputil::nexttoward(x, y);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/nexttowardf.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of nexttowardf function ----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/math/nexttowardf.h"
10+
#include "src/__support/FPUtil/ManipulationFunctions.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(float, nexttowardf, (float x, long double y)) {
16+
return fputil::nexttoward(x, y);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/src/math/generic/nexttowardl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- Implementation of nexttowardl function ----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/math/nexttowardl.h"
10+
#include "src/__support/FPUtil/ManipulationFunctions.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(long double, nexttowardl, (long double x, long double y)) {
16+
// We can reuse the nextafter implementation because nexttoward behaves
17+
// exactly same as nextafter in case of long doubles. Also, we have explcitly
18+
// handled the special 80-bit long doubles in nextafter implementation.
19+
return fputil::nextafter(x, y);
20+
}
21+
22+
} // namespace LIBC_NAMESPACE

libc/src/math/nexttoward.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nexttoward --------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
10+
#define LLVM_LIBC_SRC_MATH_NEXTTOWARD_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
double nexttoward(double x, long double y);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARD_H

libc/src/math/nexttowardf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nexttowardf -------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
10+
#define LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
float nexttowardf(float x, long double y);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDF_H

libc/src/math/nexttowardl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for nexttowardl -------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H
10+
#define LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
long double nexttowardl(long double x, long double y);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_NEXTTOWARDL_H

0 commit comments

Comments
 (0)