Skip to content

Commit

Permalink
[libc][math][c23] Add {,u}fromfp{,x}{,f,l,f128} functions (llvm#86003)
Browse files Browse the repository at this point in the history
Fixes llvm#85279.

cc @lntue
  • Loading branch information
overmighty authored Mar 25, 2024
1 parent 32b8283 commit b282259
Show file tree
Hide file tree
Showing 64 changed files with 3,181 additions and 16 deletions.
16 changes: 16 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.frexp
libc.src.math.frexpf
libc.src.math.frexpl
libc.src.math.fromfp
libc.src.math.fromfpf
libc.src.math.fromfpl
libc.src.math.fromfpx
libc.src.math.fromfpxf
libc.src.math.fromfpxl
libc.src.math.hypot
libc.src.math.hypotf
libc.src.math.ilogb
Expand Down Expand Up @@ -471,6 +477,12 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.trunc
libc.src.math.truncf
libc.src.math.truncl
libc.src.math.ufromfp
libc.src.math.ufromfpf
libc.src.math.ufromfpl
libc.src.math.ufromfpx
libc.src.math.ufromfpxf
libc.src.math.ufromfpxl
)

if(LIBC_TYPES_HAS_FLOAT128)
Expand All @@ -485,6 +497,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.fminf128
libc.src.math.fmodf128
libc.src.math.frexpf128
libc.src.math.fromfpf128
libc.src.math.fromfpxf128
libc.src.math.ilogbf128
libc.src.math.ldexpf128
libc.src.math.llogbf128
Expand All @@ -502,6 +516,8 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.roundf128
libc.src.math.sqrtf128
libc.src.math.truncf128
libc.src.math.ufromfpf128
libc.src.math.ufromfpxf128
)
endif()

Expand Down
8 changes: 8 additions & 0 deletions libc/docs/dev/undefined_behavior.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,11 @@ The C standard does not specify behavior for ``printf("%s", NULL)``. We will
print the string literal ``(null)`` unless using the
``LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS`` option described in :ref:`printf
behavior<printf_behavior>`.

Unknown Math Rounding Direction
-------------------------------
The C23 standard states that if the value of the ``rnd`` argument of the
``fromfp``, ``ufromfp``, ``fromfpx`` and ``ufromfpx`` functions is not equal to
the value of a math rounding direction macro, the direction of rounding is
unspecified. LLVM's libc chooses to use the ``FP_INT_TONEAREST`` rounding
direction in this case.
32 changes: 32 additions & 0 deletions libc/docs/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,22 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| frexpf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfp | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpf | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpl | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpf128 | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpx | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpxf | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpxl | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fromfpxf128 | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ilogb | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ilogbf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
Expand Down Expand Up @@ -339,6 +355,22 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| truncf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfp | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpf | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpl | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpf128 | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpx | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpxf | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpxl | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ufromfpxf128 | |check| | | | | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+


Higher Math Functions
Expand Down
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-macros/math-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
#define FP_SUBNORMAL 3
#define FP_NORMAL 4

#define FP_INT_UPWARD 0
#define FP_INT_DOWNWARD 1
#define FP_INT_TOWARDZERO 2
#define FP_INT_TONEARESTFROMZERO 3
#define FP_INT_TONEAREST 4

#define MATH_ERRNO 1
#define MATH_ERREXCEPT 2

Expand Down
26 changes: 26 additions & 0 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ def StdC : StandardSpec<"stdc"> {
Macro<"INFINITY">,
Macro<"NAN">,

Macro<"FP_INT_UPWARD">,
Macro<"FP_INT_DOWNWARD">,
Macro<"FP_INT_TOWARDZERO">,
Macro<"FP_INT_TONEARESTFROMZERO">,
Macro<"FP_INT_TONEAREST">,

Macro<"FP_ILOGB0">,
Macro<"FP_ILOGBNAN">,

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

FunctionSpec<"fromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"fromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"fromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
GuardedFunctionSpec<"fromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,

FunctionSpec<"fromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"fromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"fromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
GuardedFunctionSpec<"fromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,

FunctionSpec<"ufromfp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"ufromfpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"ufromfpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
GuardedFunctionSpec<"ufromfpf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,

FunctionSpec<"ufromfpx", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"ufromfpxf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
FunctionSpec<"ufromfpxl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>]>,
GuardedFunctionSpec<"ufromfpxf128", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntType>, ArgSpec<UnsignedIntType>], "LIBC_TYPES_HAS_FLOAT128">,

FunctionSpec<"hypot", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
FunctionSpec<"hypotf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,

Expand Down
94 changes: 79 additions & 15 deletions libc/src/__support/FPUtil/NearestIntegerOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ LIBC_INLINE T round(T x) {
}
}

template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T round_using_current_rounding_mode(T x) {
template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
round_using_specific_rounding_mode(T x, int rnd) {
using StorageType = typename FPBits<T>::StorageType;
FPBits<T> bits(x);

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

bool is_neg = bits.is_neg();
int exponent = bits.get_exponent();
int rounding_mode = quick_get_round();

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

if (exponent <= -1) {
switch (rounding_mode) {
case FE_DOWNWARD:
switch (rnd) {
case FP_INT_DOWNWARD:
return is_neg ? T(-1.0) : T(0.0);
case FE_UPWARD:
case FP_INT_UPWARD:
return is_neg ? T(-0.0) : T(1.0);
case FE_TOWARDZERO:
case FP_INT_TOWARDZERO:
return is_neg ? T(-0.0) : T(0.0);
case FE_TONEAREST:
case FP_INT_TONEARESTFROMZERO:
if (exponent < -1)
return is_neg ? T(-0.0) : T(0.0); // abs(x) < 0.5
return is_neg ? T(-1.0) : T(1.0); // abs(x) >= 0.5
case FP_INT_TONEAREST:
default:
if (exponent <= -2 || bits.get_mantissa() == 0)
return is_neg ? T(-0.0) : T(0.0); // abs(x) <= 0.5
else
return is_neg ? T(-1.0) : T(1.0); // abs(x) > 0.5
default:
__builtin_unreachable();
}
}

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

switch (rounding_mode) {
case FE_DOWNWARD:
switch (rnd) {
case FP_INT_DOWNWARD:
return is_neg ? trunc_value - T(1.0) : trunc_value;
case FE_UPWARD:
case FP_INT_UPWARD:
return is_neg ? trunc_value : trunc_value + T(1.0);
case FE_TOWARDZERO:
case FP_INT_TOWARDZERO:
return trunc_value;
case FE_TONEAREST:
case FP_INT_TONEARESTFROMZERO:
if (trim_value >= half_value)
return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
return trunc_value;
case FP_INT_TONEAREST:
default:
if (trim_value > half_value) {
return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
} else if (trim_value == half_value) {
Expand All @@ -214,11 +222,67 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
} else {
return trunc_value;
}
}
}

template <typename T>
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
round_using_current_rounding_mode(T x) {
int rounding_mode = quick_get_round();

switch (rounding_mode) {
case FE_DOWNWARD:
return round_using_specific_rounding_mode(x, FP_INT_DOWNWARD);
case FE_UPWARD:
return round_using_specific_rounding_mode(x, FP_INT_UPWARD);
case FE_TOWARDZERO:
return round_using_specific_rounding_mode(x, FP_INT_TOWARDZERO);
case FE_TONEAREST:
return round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
default:
__builtin_unreachable();
}
}

template <bool IsSigned, typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
fromfp(T x, int rnd, unsigned int width) {
if (width == 0U)
return FPBits<T>::quiet_nan().get_val();

T rounded_value = round_using_specific_rounding_mode(x, rnd);

if constexpr (IsSigned) {
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
if (width - 1 > FPBits<T>::EXP_BIAS)
return rounded_value;
if (rounded_value < -T(1U << (width - 1U)))
return FPBits<T>::quiet_nan().get_val();
if (rounded_value > T((1U << (width - 1U)) - 1U))
return FPBits<T>::quiet_nan().get_val();
return rounded_value;
}

if (rounded_value < T(0.0))
return FPBits<T>::quiet_nan().get_val();
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
if (width <= FPBits<T>::EXP_BIAS && rounded_value > T(1U << width) - 1U)
return FPBits<T>::quiet_nan().get_val();
return rounded_value;
}

template <bool IsSigned, typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
fromfpx(T x, int rnd, unsigned int width) {
T rounded_value = fromfp<IsSigned>(x, rnd, width);
FPBits<T> bits(rounded_value);

if (!bits.is_nan() && rounded_value != x)
raise_except_if_required(FE_INEXACT);

return rounded_value;
}

namespace internal {

template <typename F, typename I,
Expand Down
20 changes: 20 additions & 0 deletions libc/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ add_math_entrypoint_object(frexpf)
add_math_entrypoint_object(frexpl)
add_math_entrypoint_object(frexpf128)

add_math_entrypoint_object(fromfp)
add_math_entrypoint_object(fromfpf)
add_math_entrypoint_object(fromfpl)
add_math_entrypoint_object(fromfpf128)

add_math_entrypoint_object(fromfpx)
add_math_entrypoint_object(fromfpxf)
add_math_entrypoint_object(fromfpxl)
add_math_entrypoint_object(fromfpxf128)

add_math_entrypoint_object(hypot)
add_math_entrypoint_object(hypotf)

Expand Down Expand Up @@ -267,3 +277,13 @@ add_math_entrypoint_object(trunc)
add_math_entrypoint_object(truncf)
add_math_entrypoint_object(truncl)
add_math_entrypoint_object(truncf128)

add_math_entrypoint_object(ufromfp)
add_math_entrypoint_object(ufromfpf)
add_math_entrypoint_object(ufromfpl)
add_math_entrypoint_object(ufromfpf128)

add_math_entrypoint_object(ufromfpx)
add_math_entrypoint_object(ufromfpxf)
add_math_entrypoint_object(ufromfpxl)
add_math_entrypoint_object(ufromfpxf128)
18 changes: 18 additions & 0 deletions libc/src/math/fromfp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for fromfp ------------------------*- 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_FROMFP_H
#define LLVM_LIBC_SRC_MATH_FROMFP_H

namespace LIBC_NAMESPACE {

double fromfp(double x, int rnd, unsigned int width);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_FROMFP_H
18 changes: 18 additions & 0 deletions libc/src/math/fromfpf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for fromfpf -----------------------*- 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_FROMFPF_H
#define LLVM_LIBC_SRC_MATH_FROMFPF_H

namespace LIBC_NAMESPACE {

float fromfpf(float x, int rnd, unsigned int width);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_FROMFPF_H
20 changes: 20 additions & 0 deletions libc/src/math/fromfpf128.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for fromfpf128 --------------------*- 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_FROMFPF128_H
#define LLVM_LIBC_SRC_MATH_FROMFPF128_H

#include "src/__support/macros/properties/types.h"

namespace LIBC_NAMESPACE {

float128 fromfpf128(float128 x, int rnd, unsigned int width);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_FROMFPF128_H
Loading

0 comments on commit b282259

Please sign in to comment.