Skip to content

Commit 19ca79e

Browse files
authored
[libc][math][c23] Implement canonicalize functions (#85940)
Fixes: #85286
1 parent 603db74 commit 19ca79e

22 files changed

+895
-267
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ set(TARGET_LIBM_ENTRYPOINTS
350350
libc.src.math.asinhf
351351
libc.src.math.atanf
352352
libc.src.math.atanhf
353+
libc.src.math.canonicalize
354+
libc.src.math.canonicalizef
355+
libc.src.math.canonicalizel
353356
libc.src.math.copysign
354357
libc.src.math.copysignf
355358
libc.src.math.copysignl
@@ -516,6 +519,7 @@ set(TARGET_LIBM_ENTRYPOINTS
516519
if(LIBC_TYPES_HAS_FLOAT128)
517520
list(APPEND TARGET_LIBM_ENTRYPOINTS
518521
# math.h C23 _Float128 entrypoints
522+
libc.src.math.canonicalizef128
519523
libc.src.math.ceilf128
520524
libc.src.math.copysignf128
521525
libc.src.math.fabsf128

libc/docs/math/index.rst

Lines changed: 276 additions & 267 deletions
Large diffs are not rendered by default.

libc/spec/stdc.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,11 @@ def StdC : StandardSpec<"stdc"> {
636636
FunctionSpec<"nan", RetValSpec<DoubleType>, [ArgSpec<ConstCharPtr>]>,
637637
FunctionSpec<"nanl", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharPtr>]>,
638638
GuardedFunctionSpec<"nanf128", RetValSpec<Float128Type>, [ArgSpec<ConstCharPtr>], "LIBC_TYPES_HAS_FLOAT128">,
639+
640+
FunctionSpec<"canonicalize", RetValSpec<IntType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
641+
FunctionSpec<"canonicalizef", RetValSpec<IntType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
642+
FunctionSpec<"canonicalizel", RetValSpec<IntType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
643+
GuardedFunctionSpec<"canonicalizef128", RetValSpec<IntType>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
639644
]
640645
>;
641646

libc/src/__support/FPUtil/BasicOperations.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
1010
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
1111

12+
#include "FEnvImpl.h"
1213
#include "FPBits.h"
1314

1415
#include "FEnvImpl.h"
1516
#include "src/__support/CPP/type_traits.h"
17+
#include "src/__support/UInt128.h"
1618
#include "src/__support/common.h"
19+
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
1720

1821
namespace LIBC_NAMESPACE {
1922
namespace fputil {
@@ -178,6 +181,66 @@ LIBC_INLINE T fdim(T x, T y) {
178181
return (x > y ? x - y : 0);
179182
}
180183

184+
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
185+
LIBC_INLINE int canonicalize(T &cx, const T &x) {
186+
FPBits<T> sx(x);
187+
if constexpr (get_fp_type<T>() == FPType::X86_Binary80) {
188+
// All the pseudo and unnormal numbers are not canonical.
189+
// More precisely :
190+
// Exponent | Significand | Meaning
191+
// | Bits 63-62 | Bits 61-0 |
192+
// All Ones | 00 | Zero | Pseudo Infinity, Value = Infinty
193+
// All Ones | 00 | Non-Zero | Pseudo NaN, Value = SNaN
194+
// All Ones | 01 | Anything | Pseudo NaN, Value = SNaN
195+
// | Bit 63 | Bits 62-0 |
196+
// All zeroes | One | Anything | Pseudo Denormal, Value =
197+
// | | | (−1)**s × m × 2**−16382
198+
// All Other | Zero | Anything | Unnormal, Value =
199+
// Values | | | (−1)**s × m × 2**−16382
200+
bool bit63 = sx.get_implicit_bit();
201+
UInt128 mantissa = sx.get_explicit_mantissa();
202+
bool bit62 = ((mantissa & (1ULL << 62)) >> 62);
203+
int exponent = sx.get_biased_exponent();
204+
if (exponent == 0x7FFF) {
205+
if (!bit63 && !bit62) {
206+
if (mantissa == 0)
207+
cx = FPBits<T>::inf(sx.sign()).get_val();
208+
else {
209+
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
210+
raise_except_if_required(FE_INVALID);
211+
return 1;
212+
}
213+
} else if (!bit63 && bit62) {
214+
cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
215+
raise_except_if_required(FE_INVALID);
216+
return 1;
217+
} else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
218+
cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa())
219+
.get_val();
220+
raise_except_if_required(FE_INVALID);
221+
return 1;
222+
} else
223+
cx = x;
224+
} else if (exponent == 0 && bit63)
225+
cx = FPBits<T>::make_value(mantissa, 0).get_val();
226+
else if (exponent != 0 && !bit63)
227+
cx = FPBits<T>::make_value(mantissa, 0).get_val();
228+
else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
229+
cx =
230+
FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
231+
raise_except_if_required(FE_INVALID);
232+
return 1;
233+
} else
234+
cx = x;
235+
} else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
236+
cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
237+
raise_except_if_required(FE_INVALID);
238+
return 1;
239+
} else
240+
cx = x;
241+
return 0;
242+
}
243+
181244
} // namespace fputil
182245
} // namespace LIBC_NAMESPACE
183246

libc/src/__support/FPUtil/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ add_header_library(
8282
BasicOperations.h
8383
DEPENDS
8484
.fp_bits
85+
.fenv_impl
8586
libc.src.__support.CPP.type_traits
87+
libc.src.__support.uint128
8688
libc.src.__support.common
89+
libc.src.__support.macros.optimization
8790
)
8891

8992
add_header_library(

libc/src/math/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ add_math_entrypoint_object(atan2f)
5959
add_math_entrypoint_object(atanh)
6060
add_math_entrypoint_object(atanhf)
6161

62+
add_math_entrypoint_object(canonicalize)
63+
add_math_entrypoint_object(canonicalizef)
64+
add_math_entrypoint_object(canonicalizef128)
65+
add_math_entrypoint_object(canonicalizel)
66+
6267
add_math_entrypoint_object(ceil)
6368
add_math_entrypoint_object(ceilf)
6469
add_math_entrypoint_object(ceill)

libc/src/math/canonicalize.h

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

libc/src/math/canonicalizef.h

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

libc/src/math/canonicalizef128.h

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

libc/src/math/canonicalizel.h

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

libc/src/math/generic/CMakeLists.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,51 @@
1+
add_entrypoint_object(
2+
canonicalize
3+
SRCS
4+
canonicalize.cpp
5+
HDRS
6+
../canonicalize.h
7+
COMPILE_OPTIONS
8+
-O3
9+
DEPENDS
10+
libc.src.__support.FPUtil.basic_operations
11+
)
12+
13+
add_entrypoint_object(
14+
canonicalizef
15+
SRCS
16+
canonicalizef.cpp
17+
HDRS
18+
../canonicalizef.h
19+
COMPILE_OPTIONS
20+
-O3
21+
DEPENDS
22+
libc.src.__support.FPUtil.basic_operations
23+
)
24+
25+
add_entrypoint_object(
26+
canonicalizef128
27+
SRCS
28+
canonicalizef128.cpp
29+
HDRS
30+
../canonicalizef128.h
31+
COMPILE_OPTIONS
32+
-O3
33+
DEPENDS
34+
libc.src.__support.FPUtil.basic_operations
35+
)
36+
37+
add_entrypoint_object(
38+
canonicalizel
39+
SRCS
40+
canonicalizel.cpp
41+
HDRS
42+
../canonicalizel.h
43+
COMPILE_OPTIONS
44+
-O3
45+
DEPENDS
46+
libc.src.__support.FPUtil.basic_operations
47+
)
48+
149
add_entrypoint_object(
250
ceil
351
SRCS
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of canonicalize 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/canonicalize.h"
10+
#include "src/__support/FPUtil/BasicOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(int, canonicalize, (double *cx, const double *x)) {
16+
return fputil::canonicalize(*cx, *x);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of canonicalizef 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/canonicalizef.h"
10+
#include "src/__support/FPUtil/BasicOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(int, canonicalizef, (float *cx, const float *x)) {
16+
return fputil::canonicalize(*cx, *x);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of canonicalizef128 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/canonicalizef128.h"
10+
#include "src/__support/FPUtil/BasicOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(int, canonicalizef128, (float128 * cx, const float128 *x)) {
16+
return fputil::canonicalize(*cx, *x);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation of canonicalizel 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/canonicalizel.h"
10+
#include "src/__support/FPUtil/BasicOperations.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(int, canonicalizel,
16+
(long double *cx, const long double *x)) {
17+
return fputil::canonicalize(*cx, *x);
18+
}
19+
20+
} // namespace LIBC_NAMESPACE

0 commit comments

Comments
 (0)