Skip to content

Commit b282259

Browse files
authored
[libc][math][c23] Add {,u}fromfp{,x}{,f,l,f128} functions (#86003)
Fixes #85279. cc @lntue
1 parent 32b8283 commit b282259

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+3181
-16
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,12 @@ set(TARGET_LIBM_ENTRYPOINTS
387387
libc.src.math.frexp
388388
libc.src.math.frexpf
389389
libc.src.math.frexpl
390+
libc.src.math.fromfp
391+
libc.src.math.fromfpf
392+
libc.src.math.fromfpl
393+
libc.src.math.fromfpx
394+
libc.src.math.fromfpxf
395+
libc.src.math.fromfpxl
390396
libc.src.math.hypot
391397
libc.src.math.hypotf
392398
libc.src.math.ilogb
@@ -471,6 +477,12 @@ set(TARGET_LIBM_ENTRYPOINTS
471477
libc.src.math.trunc
472478
libc.src.math.truncf
473479
libc.src.math.truncl
480+
libc.src.math.ufromfp
481+
libc.src.math.ufromfpf
482+
libc.src.math.ufromfpl
483+
libc.src.math.ufromfpx
484+
libc.src.math.ufromfpxf
485+
libc.src.math.ufromfpxl
474486
)
475487

476488
if(LIBC_TYPES_HAS_FLOAT128)
@@ -485,6 +497,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
485497
libc.src.math.fminf128
486498
libc.src.math.fmodf128
487499
libc.src.math.frexpf128
500+
libc.src.math.fromfpf128
501+
libc.src.math.fromfpxf128
488502
libc.src.math.ilogbf128
489503
libc.src.math.ldexpf128
490504
libc.src.math.llogbf128
@@ -502,6 +516,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
502516
libc.src.math.roundf128
503517
libc.src.math.sqrtf128
504518
libc.src.math.truncf128
519+
libc.src.math.ufromfpf128
520+
libc.src.math.ufromfpxf128
505521
)
506522
endif()
507523

libc/docs/dev/undefined_behavior.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,11 @@ The C standard does not specify behavior for ``printf("%s", NULL)``. We will
8181
print the string literal ``(null)`` unless using the
8282
``LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS`` option described in :ref:`printf
8383
behavior<printf_behavior>`.
84+
85+
Unknown Math Rounding Direction
86+
-------------------------------
87+
The C23 standard states that if the value of the ``rnd`` argument of the
88+
``fromfp``, ``ufromfp``, ``fromfpx`` and ``ufromfpx`` functions is not equal to
89+
the value of a math rounding direction macro, the direction of rounding is
90+
unspecified. LLVM's libc chooses to use the ``FP_INT_TONEAREST`` rounding
91+
direction in this case.

libc/docs/math/index.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,22 @@ Basic Operations
181181
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
182182
| frexpf128 | |check| | |check| | | |check| | | | | | | | | |
183183
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
184+
| fromfp | |check| | | | | | | | | | | | |
185+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
186+
| fromfpf | |check| | | | | | | | | | | | |
187+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
188+
| fromfpl | |check| | | | | | | | | | | | |
189+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
190+
| fromfpf128 | |check| | | | | | | | | | | | |
191+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
192+
| fromfpx | |check| | | | | | | | | | | | |
193+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
194+
| fromfpxf | |check| | | | | | | | | | | | |
195+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
196+
| fromfpxl | |check| | | | | | | | | | | | |
197+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
198+
| fromfpxf128 | |check| | | | | | | | | | | | |
199+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
184200
| ilogb | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
185201
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
186202
| ilogbf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
@@ -339,6 +355,22 @@ Basic Operations
339355
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
340356
| truncf128 | |check| | |check| | | |check| | | | | | | | | |
341357
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
358+
| ufromfp | |check| | | | | | | | | | | | |
359+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
360+
| ufromfpf | |check| | | | | | | | | | | | |
361+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
362+
| ufromfpl | |check| | | | | | | | | | | | |
363+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
364+
| ufromfpf128 | |check| | | | | | | | | | | | |
365+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
366+
| ufromfpx | |check| | | | | | | | | | | | |
367+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
368+
| ufromfpxf | |check| | | | | | | | | | | | |
369+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
370+
| ufromfpxl | |check| | | | | | | | | | | | |
371+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
372+
| ufromfpxf128 | |check| | | | | | | | | | | | |
373+
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
342374

343375

344376
Higher Math Functions

libc/include/llvm-libc-macros/math-macros.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
#define FP_SUBNORMAL 3
1818
#define FP_NORMAL 4
1919

20+
#define FP_INT_UPWARD 0
21+
#define FP_INT_DOWNWARD 1
22+
#define FP_INT_TOWARDZERO 2
23+
#define FP_INT_TONEARESTFROMZERO 3
24+
#define FP_INT_TONEAREST 4
25+
2026
#define MATH_ERRNO 1
2127
#define MATH_ERREXCEPT 2
2228

libc/spec/stdc.td

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ def StdC : StandardSpec<"stdc"> {
352352
Macro<"INFINITY">,
353353
Macro<"NAN">,
354354

355+
Macro<"FP_INT_UPWARD">,
356+
Macro<"FP_INT_DOWNWARD">,
357+
Macro<"FP_INT_TOWARDZERO">,
358+
Macro<"FP_INT_TONEARESTFROMZERO">,
359+
Macro<"FP_INT_TONEAREST">,
360+
355361
Macro<"FP_ILOGB0">,
356362
Macro<"FP_ILOGBNAN">,
357363

@@ -414,6 +420,26 @@ def StdC : StandardSpec<"stdc"> {
414420
FunctionSpec<"frexpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntPtr>]>,
415421
GuardedFunctionSpec<"frexpf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<IntPtr>], "LIBC_TYPES_HAS_FLOAT128">,
416422

423+
FunctionSpec<"fromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
424+
FunctionSpec<"fromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
425+
FunctionSpec<"fromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
426+
GuardedFunctionSpec<"fromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,
427+
428+
FunctionSpec<"fromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
429+
FunctionSpec<"fromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
430+
FunctionSpec<"fromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
431+
GuardedFunctionSpec<"fromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,
432+
433+
FunctionSpec<"ufromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
434+
FunctionSpec<"ufromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
435+
FunctionSpec<"ufromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
436+
GuardedFunctionSpec<"ufromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,
437+
438+
FunctionSpec<"ufromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
439+
FunctionSpec<"ufromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
440+
FunctionSpec<"ufromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
441+
GuardedFunctionSpec<"ufromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,
442+
417443
FunctionSpec<"hypot", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
418444
FunctionSpec<"hypotf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
419445

libc/src/__support/FPUtil/NearestIntegerOperations.h

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,9 @@ LIBC_INLINE T round(T x) {
140140
}
141141
}
142142

143-
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
144-
LIBC_INLINE T round_using_current_rounding_mode(T x) {
143+
template <typename T>
144+
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
145+
round_using_specific_rounding_mode(T x, int rnd) {
145146
using StorageType = typename FPBits<T>::StorageType;
146147
FPBits<T> bits(x);
147148

@@ -151,28 +152,30 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
151152

152153
bool is_neg = bits.is_neg();
153154
int exponent = bits.get_exponent();
154-
int rounding_mode = quick_get_round();
155155

156156
// If the exponent is greater than the most negative mantissa
157157
// exponent, then x is already an integer.
158158
if (exponent >= static_cast<int>(FPBits<T>::FRACTION_LEN))
159159
return x;
160160

161161
if (exponent <= -1) {
162-
switch (rounding_mode) {
163-
case FE_DOWNWARD:
162+
switch (rnd) {
163+
case FP_INT_DOWNWARD:
164164
return is_neg ? T(-1.0) : T(0.0);
165-
case FE_UPWARD:
165+
case FP_INT_UPWARD:
166166
return is_neg ? T(-0.0) : T(1.0);
167-
case FE_TOWARDZERO:
167+
case FP_INT_TOWARDZERO:
168168
return is_neg ? T(-0.0) : T(0.0);
169-
case FE_TONEAREST:
169+
case FP_INT_TONEARESTFROMZERO:
170+
if (exponent < -1)
171+
return is_neg ? T(-0.0) : T(0.0); // abs(x) < 0.5
172+
return is_neg ? T(-1.0) : T(1.0); // abs(x) >= 0.5
173+
case FP_INT_TONEAREST:
174+
default:
170175
if (exponent <= -2 || bits.get_mantissa() == 0)
171176
return is_neg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
172177
else
173178
return is_neg ? T(-1.0) : T(1.0); // abs(x) > 0.5
174-
default:
175-
__builtin_unreachable();
176179
}
177180
}
178181

@@ -194,14 +197,19 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
194197
StorageType trunc_is_odd =
195198
new_bits.get_mantissa() & (StorageType(1) << trim_size);
196199

197-
switch (rounding_mode) {
198-
case FE_DOWNWARD:
200+
switch (rnd) {
201+
case FP_INT_DOWNWARD:
199202
return is_neg ? trunc_value - T(1.0) : trunc_value;
200-
case FE_UPWARD:
203+
case FP_INT_UPWARD:
201204
return is_neg ? trunc_value : trunc_value + T(1.0);
202-
case FE_TOWARDZERO:
205+
case FP_INT_TOWARDZERO:
203206
return trunc_value;
204-
case FE_TONEAREST:
207+
case FP_INT_TONEARESTFROMZERO:
208+
if (trim_value >= half_value)
209+
return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
210+
return trunc_value;
211+
case FP_INT_TONEAREST:
212+
default:
205213
if (trim_value > half_value) {
206214
return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
207215
} else if (trim_value == half_value) {
@@ -214,11 +222,67 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
214222
} else {
215223
return trunc_value;
216224
}
225+
}
226+
}
227+
228+
template <typename T>
229+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
230+
round_using_current_rounding_mode(T x) {
231+
int rounding_mode = quick_get_round();
232+
233+
switch (rounding_mode) {
234+
case FE_DOWNWARD:
235+
return round_using_specific_rounding_mode(x, FP_INT_DOWNWARD);
236+
case FE_UPWARD:
237+
return round_using_specific_rounding_mode(x, FP_INT_UPWARD);
238+
case FE_TOWARDZERO:
239+
return round_using_specific_rounding_mode(x, FP_INT_TOWARDZERO);
240+
case FE_TONEAREST:
241+
return round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
217242
default:
218243
__builtin_unreachable();
219244
}
220245
}
221246

247+
template <bool IsSigned, typename T>
248+
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
249+
fromfp(T x, int rnd, unsigned int width) {
250+
if (width == 0U)
251+
return FPBits<T>::quiet_nan().get_val();
252+
253+
T rounded_value = round_using_specific_rounding_mode(x, rnd);
254+
255+
if constexpr (IsSigned) {
256+
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
257+
if (width - 1 > FPBits<T>::EXP_BIAS)
258+
return rounded_value;
259+
if (rounded_value < -T(1U << (width - 1U)))
260+
return FPBits<T>::quiet_nan().get_val();
261+
if (rounded_value > T((1U << (width - 1U)) - 1U))
262+
return FPBits<T>::quiet_nan().get_val();
263+
return rounded_value;
264+
}
265+
266+
if (rounded_value < T(0.0))
267+
return FPBits<T>::quiet_nan().get_val();
268+
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
269+
if (width <= FPBits<T>::EXP_BIAS && rounded_value > T(1U << width) - 1U)
270+
return FPBits<T>::quiet_nan().get_val();
271+
return rounded_value;
272+
}
273+
274+
template <bool IsSigned, typename T>
275+
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
276+
fromfpx(T x, int rnd, unsigned int width) {
277+
T rounded_value = fromfp<IsSigned>(x, rnd, width);
278+
FPBits<T> bits(rounded_value);
279+
280+
if (!bits.is_nan() && rounded_value != x)
281+
raise_except_if_required(FE_INEXACT);
282+
283+
return rounded_value;
284+
}
285+
222286
namespace internal {
223287

224288
template <typename F, typename I,

libc/src/math/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ add_math_entrypoint_object(frexpf)
127127
add_math_entrypoint_object(frexpl)
128128
add_math_entrypoint_object(frexpf128)
129129

130+
add_math_entrypoint_object(fromfp)
131+
add_math_entrypoint_object(fromfpf)
132+
add_math_entrypoint_object(fromfpl)
133+
add_math_entrypoint_object(fromfpf128)
134+
135+
add_math_entrypoint_object(fromfpx)
136+
add_math_entrypoint_object(fromfpxf)
137+
add_math_entrypoint_object(fromfpxl)
138+
add_math_entrypoint_object(fromfpxf128)
139+
130140
add_math_entrypoint_object(hypot)
131141
add_math_entrypoint_object(hypotf)
132142

@@ -267,3 +277,13 @@ add_math_entrypoint_object(trunc)
267277
add_math_entrypoint_object(truncf)
268278
add_math_entrypoint_object(truncl)
269279
add_math_entrypoint_object(truncf128)
280+
281+
add_math_entrypoint_object(ufromfp)
282+
add_math_entrypoint_object(ufromfpf)
283+
add_math_entrypoint_object(ufromfpl)
284+
add_math_entrypoint_object(ufromfpf128)
285+
286+
add_math_entrypoint_object(ufromfpx)
287+
add_math_entrypoint_object(ufromfpxf)
288+
add_math_entrypoint_object(ufromfpxl)
289+
add_math_entrypoint_object(ufromfpxf128)

libc/src/math/fromfp.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for fromfp ------------------------*- 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_FROMFP_H
10+
#define LLVM_LIBC_SRC_MATH_FROMFP_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
double fromfp(double x, int rnd, unsigned int width);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_FROMFP_H

libc/src/math/fromfpf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//===-- Implementation header for fromfpf -----------------------*- 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_FROMFPF_H
10+
#define LLVM_LIBC_SRC_MATH_FROMFPF_H
11+
12+
namespace LIBC_NAMESPACE {
13+
14+
float fromfpf(float x, int rnd, unsigned int width);
15+
16+
} // namespace LIBC_NAMESPACE
17+
18+
#endif // LLVM_LIBC_SRC_MATH_FROMFPF_H

libc/src/math/fromfpf128.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for fromfpf128 --------------------*- 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_FROMFPF128_H
10+
#define LLVM_LIBC_SRC_MATH_FROMFPF128_H
11+
12+
#include "src/__support/macros/properties/types.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
float128 fromfpf128(float128 x, int rnd, unsigned int width);
17+
18+
} // namespace LIBC_NAMESPACE
19+
20+
#endif // LLVM_LIBC_SRC_MATH_FROMFPF128_H

0 commit comments

Comments
 (0)