Skip to content

Commit f5dcfb9

Browse files
authored
[libc][math][c23] Add {totalorder,totalordermag}f16 C23 math functions (#95014)
Part of #93566.
1 parent b746bab commit f5dcfb9

18 files changed

+480
-4
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ if(LIBC_TYPES_HAS_FLOAT16)
541541
libc.src.math.rintf16
542542
libc.src.math.roundf16
543543
libc.src.math.roundevenf16
544+
libc.src.math.totalorderf16
545+
libc.src.math.totalordermagf16
544546
libc.src.math.truncf16
545547
libc.src.math.ufromfpf16
546548
libc.src.math.ufromfpxf16

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,8 @@ if(LIBC_TYPES_HAS_FLOAT16)
571571
libc.src.math.rintf16
572572
libc.src.math.roundf16
573573
libc.src.math.roundevenf16
574+
libc.src.math.totalorderf16
575+
libc.src.math.totalordermagf16
574576
libc.src.math.truncf16
575577
libc.src.math.ufromfpf16
576578
libc.src.math.ufromfpxf16

libc/docs/c23.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ Additions:
4242
* rsqrt*
4343
* __STDC_IEC_60559_DFP__ functions (_Decimal32, _Decimal64, _Decimal128)
4444
* compoundn*
45-
* totalorder*
46-
* totalordermag*
45+
* totalorder* |check|
46+
* totalordermag* |check|
4747
* getpayload*
4848
* setpayload*
4949
* iscannonical

libc/docs/math/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ Basic Operations
210210
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
211211
| scalbn | |check| | |check| | |check| | | |check| | 7.12.6.19 | F.10.3.19 |
212212
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
213+
| totalorder | | | | |check| | | F.10.12.1 | N/A |
214+
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
215+
| totalordermag | | | | |check| | | F.10.12.2 | N/A |
216+
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
213217
| trunc | |check| | |check| | |check| | |check| | |check| | 7.12.9.9 | F.10.6.9 |
214218
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
215219
| ufromfp | |check| | |check| | |check| | |check| | |check| | 7.12.9.10 | F.10.6.10 |

libc/spec/stdc.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,10 @@ def StdC : StandardSpec<"stdc"> {
710710
FunctionSpec<"canonicalizel", RetValSpec<IntType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
711711
GuardedFunctionSpec<"canonicalizef16", RetValSpec<IntType>, [ArgSpec<Float16Type>, ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
712712
GuardedFunctionSpec<"canonicalizef128", RetValSpec<IntType>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
713+
714+
GuardedFunctionSpec<"totalorderf16", RetValSpec<IntType>, [ArgSpec<Float16Ptr>, ArgSpec<Float16Ptr>], "LIBC_TYPES_HAS_FLOAT16">,
715+
716+
GuardedFunctionSpec<"totalordermagf16", RetValSpec<IntType>, [ArgSpec<Float16Ptr>, ArgSpec<Float16Ptr>], "LIBC_TYPES_HAS_FLOAT16">,
713717
]
714718
>;
715719

libc/src/__support/FPUtil/BasicOperations.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,31 @@ LIBC_INLINE int canonicalize(T &cx, const T &x) {
240240
return 0;
241241
}
242242

243+
template <typename T>
244+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
245+
totalorder(T x, T y) {
246+
using FPBits = FPBits<T>;
247+
FPBits x_bits(x);
248+
FPBits y_bits(y);
249+
250+
using StorageType = typename FPBits::StorageType;
251+
StorageType x_u = x_bits.uintval();
252+
StorageType y_u = y_bits.uintval();
253+
254+
using signed_t = cpp::make_signed_t<StorageType>;
255+
signed_t x_signed = static_cast<signed_t>(x_u);
256+
signed_t y_signed = static_cast<signed_t>(y_u);
257+
258+
bool both_neg = (x_u & y_u & FPBits::SIGN_MASK) != 0;
259+
return x_signed == y_signed || ((x_signed <= y_signed) != both_neg);
260+
}
261+
262+
template <typename T>
263+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
264+
totalordermag(T x, T y) {
265+
return FPBits<T>(x).abs().uintval() <= FPBits<T>(y).abs().uintval();
266+
}
267+
243268
} // namespace fputil
244269
} // namespace LIBC_NAMESPACE
245270

libc/src/math/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ add_math_entrypoint_object(tanhf)
369369
add_math_entrypoint_object(tgamma)
370370
add_math_entrypoint_object(tgammaf)
371371

372+
add_math_entrypoint_object(totalorderf16)
373+
374+
add_math_entrypoint_object(totalordermagf16)
375+
372376
add_math_entrypoint_object(trunc)
373377
add_math_entrypoint_object(truncf)
374378
add_math_entrypoint_object(truncl)

libc/src/math/generic/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3577,3 +3577,27 @@ add_entrypoint_object(
35773577
COMPILE_OPTIONS
35783578
-O3
35793579
)
3580+
3581+
add_entrypoint_object(
3582+
totalorderf16
3583+
SRCS
3584+
totalorderf16.cpp
3585+
HDRS
3586+
../totalorderf16.h
3587+
DEPENDS
3588+
libc.src.__support.FPUtil.basic_operations
3589+
COMPILE_OPTIONS
3590+
-O3
3591+
)
3592+
3593+
add_entrypoint_object(
3594+
totalordermagf16
3595+
SRCS
3596+
totalordermagf16.cpp
3597+
HDRS
3598+
../totalordermagf16.h
3599+
DEPENDS
3600+
libc.src.__support.FPUtil.basic_operations
3601+
COMPILE_OPTIONS
3602+
-O3
3603+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of totalorderf16 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/totalorderf16.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, totalorderf16, (const float16 *x, const float16 *y)) {
16+
return static_cast<int>(fputil::totalorder(*x, *y));
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 totalordermagf16 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/totalordermagf16.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, totalordermagf16,
16+
(const float16 *x, const float16 *y)) {
17+
return static_cast<int>(fputil::totalordermag(*x, *y));
18+
}
19+
20+
} // namespace LIBC_NAMESPACE

libc/src/math/totalorderf16.h

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

libc/src/math/totalordermagf16.h

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

libc/test/UnitTest/FPMatcher.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ template <typename T> struct FPTest : public Test {
9797
LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); \
9898
const T zero = FPBits::zero(Sign::POS).get_val(); \
9999
const T neg_zero = FPBits::zero(Sign::NEG).get_val(); \
100-
const T aNaN = FPBits::quiet_nan().get_val(); \
101-
const T sNaN = FPBits::signaling_nan().get_val(); \
100+
const T aNaN = FPBits::quiet_nan(Sign::POS).get_val(); \
101+
const T neg_aNaN = FPBits::quiet_nan(Sign::NEG).get_val(); \
102+
const T sNaN = FPBits::signaling_nan(Sign::POS).get_val(); \
103+
const T neg_sNaN = FPBits::signaling_nan(Sign::NEG).get_val(); \
102104
const T inf = FPBits::inf(Sign::POS).get_val(); \
103105
const T neg_inf = FPBits::inf(Sign::NEG).get_val(); \
104106
const T min_normal = FPBits::min_normal().get_val(); \

libc/test/src/math/smoke/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,3 +3519,27 @@ add_fp_unittest(
35193519
libc.src.math.powf
35203520
libc.src.__support.FPUtil.fp_bits
35213521
)
3522+
3523+
add_fp_unittest(
3524+
totalorderf16_test
3525+
SUITE
3526+
libc-math-smoke-tests
3527+
SRCS
3528+
totalorderf16_test.cpp
3529+
HDRS
3530+
TotalOrderTest.h
3531+
DEPENDS
3532+
libc.src.math.totalorderf16
3533+
)
3534+
3535+
add_fp_unittest(
3536+
totalordermagf16_test
3537+
SUITE
3538+
libc-math-smoke-tests
3539+
SRCS
3540+
totalordermagf16_test.cpp
3541+
HDRS
3542+
TotalOrderMagTest.h
3543+
DEPENDS
3544+
libc.src.math.totalordermagf16
3545+
)
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===-- Utility class to test flavors of totalordermag ----------*- 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 LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H
10+
#define LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H
11+
12+
#include "test/UnitTest/FEnvSafeTest.h"
13+
#include "test/UnitTest/FPMatcher.h"
14+
#include "test/UnitTest/Test.h"
15+
16+
template <typename T>
17+
class TotalOrderMagTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
18+
19+
DECLARE_SPECIAL_CONSTANTS(T)
20+
21+
public:
22+
typedef int (*TotalOrderMagFunc)(const T *, const T *);
23+
24+
bool funcWrapper(TotalOrderMagFunc func, T x, T y) {
25+
return func(&x, &y) != 0;
26+
}
27+
28+
void testXLesserThanY(TotalOrderMagFunc func) {
29+
EXPECT_TRUE(funcWrapper(func, neg_inf, inf));
30+
31+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.1)));
32+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(123.38)));
33+
34+
EXPECT_FALSE(funcWrapper(func, T(-0.1), T(0.0)));
35+
EXPECT_FALSE(funcWrapper(func, T(-123.38), T(0.0)));
36+
37+
EXPECT_TRUE(funcWrapper(func, T(-0.1), T(0.1)));
38+
EXPECT_TRUE(funcWrapper(func, T(-123.38), T(123.38)));
39+
}
40+
41+
void testXGreaterThanY(TotalOrderMagFunc func) {
42+
EXPECT_TRUE(funcWrapper(func, inf, neg_inf));
43+
44+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(-0.1)));
45+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(-123.38)));
46+
47+
EXPECT_FALSE(funcWrapper(func, T(0.1), T(0.0)));
48+
EXPECT_FALSE(funcWrapper(func, T(123.38), T(0.0)));
49+
50+
EXPECT_TRUE(funcWrapper(func, T(0.1), T(-0.1)));
51+
EXPECT_TRUE(funcWrapper(func, T(123.38), T(-123.38)));
52+
}
53+
54+
void testXEqualToY(TotalOrderMagFunc func) {
55+
EXPECT_TRUE(funcWrapper(func, inf, inf));
56+
EXPECT_TRUE(funcWrapper(func, neg_inf, neg_inf));
57+
58+
EXPECT_TRUE(funcWrapper(func, T(-0.0), T(0.0)));
59+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(-0.0)));
60+
61+
EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.0)));
62+
EXPECT_TRUE(funcWrapper(func, T(-0.0), T(-0.0)));
63+
EXPECT_TRUE(funcWrapper(func, T(0.1), T(0.1)));
64+
EXPECT_TRUE(funcWrapper(func, T(-0.1), T(-0.1)));
65+
EXPECT_TRUE(funcWrapper(func, T(123.38), T(123.38)));
66+
EXPECT_TRUE(funcWrapper(func, T(-123.38), T(-123.38)));
67+
}
68+
69+
void testSingleNaN(TotalOrderMagFunc func) {
70+
EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(0.0)));
71+
EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(0.1)));
72+
EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(123.38)));
73+
74+
EXPECT_TRUE(funcWrapper(func, T(0.0), neg_aNaN));
75+
EXPECT_TRUE(funcWrapper(func, T(0.1), neg_aNaN));
76+
EXPECT_TRUE(funcWrapper(func, T(123.38), neg_aNaN));
77+
78+
EXPECT_TRUE(funcWrapper(func, T(0.0), aNaN));
79+
EXPECT_TRUE(funcWrapper(func, T(0.1), aNaN));
80+
EXPECT_TRUE(funcWrapper(func, T(123.38), aNaN));
81+
82+
EXPECT_FALSE(funcWrapper(func, aNaN, T(0.0)));
83+
EXPECT_FALSE(funcWrapper(func, aNaN, T(0.1)));
84+
EXPECT_FALSE(funcWrapper(func, aNaN, T(123.38)));
85+
}
86+
87+
void testNaNSigns(TotalOrderMagFunc func) {
88+
EXPECT_TRUE(funcWrapper(func, neg_aNaN, aNaN));
89+
EXPECT_FALSE(funcWrapper(func, neg_aNaN, sNaN));
90+
EXPECT_TRUE(funcWrapper(func, neg_sNaN, aNaN));
91+
EXPECT_TRUE(funcWrapper(func, neg_sNaN, sNaN));
92+
93+
EXPECT_TRUE(funcWrapper(func, aNaN, neg_aNaN));
94+
EXPECT_FALSE(funcWrapper(func, aNaN, neg_sNaN));
95+
EXPECT_TRUE(funcWrapper(func, sNaN, neg_aNaN));
96+
EXPECT_TRUE(funcWrapper(func, sNaN, neg_sNaN));
97+
}
98+
99+
void testQuietVsSignalingNaN(TotalOrderMagFunc func) {
100+
EXPECT_FALSE(funcWrapper(func, neg_aNaN, neg_sNaN));
101+
EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_aNaN));
102+
EXPECT_TRUE(funcWrapper(func, sNaN, aNaN));
103+
EXPECT_FALSE(funcWrapper(func, aNaN, sNaN));
104+
}
105+
106+
void testNaNPayloads(TotalOrderMagFunc func) {
107+
T qnan_123 = FPBits::quiet_nan(Sign::POS, 0x123).get_val();
108+
T neg_qnan_123 = FPBits::quiet_nan(Sign::NEG, 0x123).get_val();
109+
T snan_123 = FPBits::signaling_nan(Sign::POS, 0x123).get_val();
110+
T neg_snan_123 = FPBits::signaling_nan(Sign::NEG, 0x123).get_val();
111+
112+
EXPECT_TRUE(funcWrapper(func, aNaN, aNaN));
113+
EXPECT_TRUE(funcWrapper(func, sNaN, sNaN));
114+
EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123));
115+
EXPECT_TRUE(funcWrapper(func, sNaN, snan_123));
116+
EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN));
117+
EXPECT_FALSE(funcWrapper(func, snan_123, sNaN));
118+
119+
EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN));
120+
EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN));
121+
EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123));
122+
EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123));
123+
EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN));
124+
EXPECT_FALSE(funcWrapper(func, neg_snan_123, neg_sNaN));
125+
}
126+
};
127+
128+
#define LIST_TOTALORDERMAG_TESTS(T, func) \
129+
using LlvmLibcTotalOrderMagTest = TotalOrderMagTestTemplate<T>; \
130+
TEST_F(LlvmLibcTotalOrderMagTest, XLesserThanY) { testXLesserThanY(&func); } \
131+
TEST_F(LlvmLibcTotalOrderMagTest, XGreaterThanY) { \
132+
testXGreaterThanY(&func); \
133+
} \
134+
TEST_F(LlvmLibcTotalOrderMagTest, XEqualToY) { testXEqualToY(&func); } \
135+
TEST_F(LlvmLibcTotalOrderMagTest, SingleNaN) { testSingleNaN(&func); } \
136+
TEST_F(LlvmLibcTotalOrderMagTest, NaNSigns) { testNaNSigns(&func); } \
137+
TEST_F(LlvmLibcTotalOrderMagTest, QuietVsSignalingNaN) { \
138+
testQuietVsSignalingNaN(&func); \
139+
} \
140+
TEST_F(LlvmLibcTotalOrderMagTest, NaNPayloads) { testNaNPayloads(&func); }
141+
142+
#endif // LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H

0 commit comments

Comments
 (0)