From 6b214b532824f6819cc50bbb9ebdf2de5e06cefb Mon Sep 17 00:00:00 2001 From: OverMighty Date: Mon, 10 Jun 2024 18:38:16 +0200 Subject: [PATCH 1/4] [libc][math][c23] Add totalorderf16 C23 math function --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/docs/c23.rst | 2 +- libc/docs/math/index.rst | 2 + libc/spec/stdc.td | 2 + libc/src/__support/FPUtil/BasicOperations.h | 43 ++++++ libc/src/__support/FPUtil/FPBits.h | 4 + libc/src/math/CMakeLists.txt | 2 + libc/src/math/generic/CMakeLists.txt | 12 ++ libc/src/math/generic/totalorderf16.cpp | 19 +++ libc/src/math/totalorderf16.h | 20 +++ libc/test/src/math/smoke/CMakeLists.txt | 12 ++ libc/test/src/math/smoke/TotalOrderTest.h | 137 ++++++++++++++++++ .../src/math/smoke/totalorderf16_test.cpp | 13 ++ 14 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 libc/src/math/generic/totalorderf16.cpp create mode 100644 libc/src/math/totalorderf16.h create mode 100644 libc/test/src/math/smoke/TotalOrderTest.h create mode 100644 libc/test/src/math/smoke/totalorderf16_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 8863749e12c6d..8206cc18284c0 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -539,6 +539,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.rintf16 libc.src.math.roundf16 libc.src.math.roundevenf16 + libc.src.math.totalorderf16 libc.src.math.truncf16 libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 31ad0bc412836..84751c7779cb9 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -569,6 +569,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.rintf16 libc.src.math.roundf16 libc.src.math.roundevenf16 + libc.src.math.totalorderf16 libc.src.math.truncf16 libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 diff --git a/libc/docs/c23.rst b/libc/docs/c23.rst index fec9b24bbd581..a771f4feab3c2 100644 --- a/libc/docs/c23.rst +++ b/libc/docs/c23.rst @@ -42,7 +42,7 @@ Additions: * rsqrt* * __STDC_IEC_60559_DFP__ functions (_Decimal32, _Decimal64, _Decimal128) * compoundn* - * totalorder* + * totalorder* |check| * totalordermag* * getpayload* * setpayload* diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 3e122fb8bc26e..727919d9e4a9e 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -210,6 +210,8 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | scalbn | |check| | |check| | |check| | | |check| | 7.12.6.19 | F.10.3.19 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| totalorder | | | | |check| | | F.10.12.1 | N/A | ++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | trunc | |check| | |check| | |check| | |check| | |check| | 7.12.9.9 | F.10.6.9 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | ufromfp | |check| | |check| | |check| | |check| | |check| | 7.12.9.10 | F.10.6.10 | diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index b5b6dbc481bd7..be97a0a0c9343 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -708,6 +708,8 @@ def StdC : StandardSpec<"stdc"> { FunctionSpec<"canonicalizel", RetValSpec, [ArgSpec, ArgSpec]>, GuardedFunctionSpec<"canonicalizef16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"canonicalizef128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT128">, + + GuardedFunctionSpec<"totalorderf16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, ] >; diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h index e5ac101fedc0e..cb669b0009265 100644 --- a/libc/src/__support/FPUtil/BasicOperations.h +++ b/libc/src/__support/FPUtil/BasicOperations.h @@ -240,6 +240,49 @@ LIBC_INLINE int canonicalize(T &cx, const T &x) { return 0; } +template +LIBC_INLINE cpp::enable_if_t, bool> +totalorder(const T *x, const T *y) { + using FPBits = FPBits; + FPBits xbits(*x); + FPBits ybits(*y); + + if (LIBC_UNLIKELY(xbits.is_zero() && ybits.is_zero() || xbits.is_nan() || + ybits.is_nan())) { + // totalOrder(−0, +0) is true. totalOrder(+0, -0) is false. + if (xbits.is_zero() && ybits.is_zero()) { + Sign xsign = xbits.sign(); + Sign ysign = ybits.sign(); + return (xsign == Sign::NEG && ysign == Sign::POS) || xsign == ysign; + } + + // totalOrder(−NaN, y) is true. totalOrder(+NaN, y) is false. + if (!ybits.is_nan()) + return xbits.is_neg(); + // totalOrder(x, +NaN) is true. totalOrder(x, -NaN) is false. + if (!xbits.is_nan()) + return ybits.is_pos(); + + // Negative sign orders below positive sign. + if (xbits.is_neg() && ybits.is_pos()) + return true; + if (xbits.is_pos() && ybits.is_neg()) + return false; + + // Signaling orders below quiet for +NaN, reverse for −NaN. + if (xbits.is_quiet_nan() && ybits.is_signaling_nan()) + return xbits.is_neg(); + if (xbits.is_signaling_nan() && ybits.is_quiet_nan()) + return ybits.is_pos(); + + // Otherwise, the order of NaNs is implementation-defined (IEEE 754-2019). + // We order by payload. + return xbits.get_nan_payload() <= ybits.get_nan_payload(); + } + + return xbits.get_val() <= ybits.get_val(); +} + } // namespace fputil } // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h index 559ecde767c30..f424e11ec9fd1 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -708,6 +708,10 @@ struct FPRepImpl : public FPRepSem { LIBC_INLINE constexpr void set_significand(StorageType sigVal) { bits = UP::merge(bits, sigVal, SIG_MASK); } + + LIBC_INLINE constexpr StorageType get_nan_payload() const { + return bits & (FRACTION_MASK >> 1); + } // Unsafe function to create a floating point representation. // It simply packs the sign, biased exponent and mantissa values without // checking bound nor normalization. diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index f8582d8d42683..5d605fe8bbcb7 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -367,6 +367,8 @@ add_math_entrypoint_object(tanhf) add_math_entrypoint_object(tgamma) add_math_entrypoint_object(tgammaf) +add_math_entrypoint_object(totalorderf16) + add_math_entrypoint_object(trunc) add_math_entrypoint_object(truncf) add_math_entrypoint_object(truncl) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index caaa0ac23dc7a..4787ecfdf8565 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3551,3 +3551,15 @@ add_entrypoint_object( COMPILE_OPTIONS -O3 ) + +add_entrypoint_object( + totalorderf16 + SRCS + totalorderf16.cpp + HDRS + ../totalorderf16.h + DEPENDS + libc.src.__support.FPUtil.basic_operations + COMPILE_OPTIONS + -O3 +) diff --git a/libc/src/math/generic/totalorderf16.cpp b/libc/src/math/generic/totalorderf16.cpp new file mode 100644 index 0000000000000..b64f1eeaf3ddf --- /dev/null +++ b/libc/src/math/generic/totalorderf16.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of totalorderf16 function --------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/totalorderf16.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(int, totalorderf16, (const float16 *x, const float16 *y)) { + return static_cast(fputil::totalorder(x, y)); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/totalorderf16.h b/libc/src/math/totalorderf16.h new file mode 100644 index 0000000000000..f5390140c4dc2 --- /dev/null +++ b/libc/src/math/totalorderf16.h @@ -0,0 +1,20 @@ +//===-- Implementation header for totalorderf16 -----------------*- 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_TOTALORDERF16_H +#define LLVM_LIBC_SRC_MATH_TOTALORDERF16_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +int totalorderf16(const float16 *x, const float16 *y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_TOTALORDERF16_H diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 84aa76c0a0881..d24e4076c0bed 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3509,3 +3509,15 @@ add_fp_unittest( libc.src.math.powf libc.src.__support.FPUtil.fp_bits ) + +add_fp_unittest( + totalorderf16_test + SUITE + libc-math-smoke-tests + SRCS + totalorderf16_test.cpp + HDRS + TotalOrderTest.h + DEPENDS + libc.src.math.totalorderf16 +) diff --git a/libc/test/src/math/smoke/TotalOrderTest.h b/libc/test/src/math/smoke/TotalOrderTest.h new file mode 100644 index 0000000000000..9ed44b1b798d1 --- /dev/null +++ b/libc/test/src/math/smoke/TotalOrderTest.h @@ -0,0 +1,137 @@ +//===-- Utility class to test different flavors of totalorder ---*- 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 LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERTEST_H +#define LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERTEST_H + +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +template +class TotalOrderTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(T) + +public: + typedef int (*TotalOrderFunc)(const T *, const T *); + + bool funcWrapper(TotalOrderFunc func, T x, T y) { return func(&x, &y) != 0; } + + void testXLesserThanY(TotalOrderFunc func) { + EXPECT_TRUE(funcWrapper(func, neg_inf, inf)); + + EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(0.0), T(123.38))); + + EXPECT_TRUE(funcWrapper(func, T(-0.1), T(0.0))); + EXPECT_TRUE(funcWrapper(func, T(-123.38), T(0.0))); + + EXPECT_TRUE(funcWrapper(func, T(-0.1), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(-123.38), T(123.38))); + } + + void testXGreaterThanY(TotalOrderFunc func) { + EXPECT_FALSE(funcWrapper(func, inf, neg_inf)); + + EXPECT_FALSE(funcWrapper(func, T(0.0), T(-0.1))); + EXPECT_FALSE(funcWrapper(func, T(0.0), T(-123.38))); + + EXPECT_FALSE(funcWrapper(func, T(0.1), T(0.0))); + EXPECT_FALSE(funcWrapper(func, T(123.38), T(0.0))); + + EXPECT_FALSE(funcWrapper(func, T(0.1), T(-0.1))); + EXPECT_FALSE(funcWrapper(func, T(123.38), T(-123.38))); + } + + void testXEqualToY(TotalOrderFunc func) { + EXPECT_TRUE(funcWrapper(func, inf, inf)); + EXPECT_TRUE(funcWrapper(func, neg_inf, neg_inf)); + + EXPECT_TRUE(funcWrapper(func, T(-0.0), T(0.0))); + EXPECT_FALSE(funcWrapper(func, T(0.0), T(-0.0))); + + EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.0))); + EXPECT_TRUE(funcWrapper(func, T(-0.0), T(-0.0))); + EXPECT_TRUE(funcWrapper(func, T(0.1), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(-0.1), T(-0.1))); + EXPECT_TRUE(funcWrapper(func, T(123.38), T(123.38))); + EXPECT_TRUE(funcWrapper(func, T(-123.38), T(-123.38))); + } + + void testSingleNaN(TotalOrderFunc func) { + EXPECT_TRUE(funcWrapper(func, -aNaN, T(0.0))); + EXPECT_TRUE(funcWrapper(func, -aNaN, T(0.1))); + EXPECT_TRUE(funcWrapper(func, -aNaN, T(123.38))); + + EXPECT_FALSE(funcWrapper(func, T(0.0), -aNaN)); + EXPECT_FALSE(funcWrapper(func, T(0.1), -aNaN)); + EXPECT_FALSE(funcWrapper(func, T(123.38), -aNaN)); + + EXPECT_TRUE(funcWrapper(func, T(0.0), aNaN)); + EXPECT_TRUE(funcWrapper(func, T(0.1), aNaN)); + EXPECT_TRUE(funcWrapper(func, T(123.38), aNaN)); + + EXPECT_FALSE(funcWrapper(func, aNaN, T(0.0))); + EXPECT_FALSE(funcWrapper(func, aNaN, T(0.1))); + EXPECT_FALSE(funcWrapper(func, aNaN, T(123.38))); + } + + void testNaNSigns(TotalOrderFunc func) { + EXPECT_TRUE(funcWrapper(func, -aNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, -aNaN, sNaN)); + EXPECT_TRUE(funcWrapper(func, -sNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, -sNaN, sNaN)); + + EXPECT_FALSE(funcWrapper(func, aNaN, -aNaN)); + EXPECT_FALSE(funcWrapper(func, aNaN, -sNaN)); + EXPECT_FALSE(funcWrapper(func, sNaN, -aNaN)); + EXPECT_FALSE(funcWrapper(func, sNaN, -sNaN)); + } + + void testQuietVsSignalingNaN(TotalOrderFunc func) { + EXPECT_TRUE(funcWrapper(func, -aNaN, -sNaN)); + EXPECT_FALSE(funcWrapper(func, -sNaN, -aNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, aNaN)); + EXPECT_FALSE(funcWrapper(func, aNaN, sNaN)); + } + + void testNaNPayloads(TotalOrderFunc func) { + T qnan_123 = FPBits::quiet_nan(Sign::POS, 0x123).get_val(); + T snan_123 = FPBits::signaling_nan(Sign::POS, 0x123).get_val(); + + EXPECT_TRUE(funcWrapper(func, aNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, -aNaN, -aNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, sNaN)); + EXPECT_TRUE(funcWrapper(func, -sNaN, -sNaN)); + + EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123)); + EXPECT_TRUE(funcWrapper(func, -aNaN, -qnan_123)); + EXPECT_TRUE(funcWrapper(func, sNaN, snan_123)); + EXPECT_TRUE(funcWrapper(func, -sNaN, -snan_123)); + + EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN)); + EXPECT_FALSE(funcWrapper(func, -qnan_123, -aNaN)); + EXPECT_FALSE(funcWrapper(func, snan_123, sNaN)); + EXPECT_FALSE(funcWrapper(func, -snan_123, -sNaN)); + } +}; + +#define LIST_TOTALORDER_TESTS(T, func) \ + using LlvmLibcTotalOrderTest = TotalOrderTestTemplate; \ + TEST_F(LlvmLibcTotalOrderTest, XLesserThanY) { testXLesserThanY(&func); } \ + TEST_F(LlvmLibcTotalOrderTest, XGreaterThanY) { testXGreaterThanY(&func); } \ + TEST_F(LlvmLibcTotalOrderTest, XEqualToY) { testXEqualToY(&func); } \ + TEST_F(LlvmLibcTotalOrderTest, SingleNaN) { testSingleNaN(&func); } \ + TEST_F(LlvmLibcTotalOrderTest, NaNSigns) { testNaNSigns(&func); } \ + TEST_F(LlvmLibcTotalOrderTest, QuietVsSignalingNaN) { \ + testQuietVsSignalingNaN(&func); \ + } \ + TEST_F(LlvmLibcTotalOrderTest, NaNPayloads) { testNaNPayloads(&func); } + +#endif // LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERTEST_H diff --git a/libc/test/src/math/smoke/totalorderf16_test.cpp b/libc/test/src/math/smoke/totalorderf16_test.cpp new file mode 100644 index 0000000000000..410c70c47c51d --- /dev/null +++ b/libc/test/src/math/smoke/totalorderf16_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for totalorderf16 ---------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "TotalOrderTest.h" + +#include "src/math/totalorderf16.h" + +LIST_TOTALORDER_TESTS(float16, LIBC_NAMESPACE::totalorderf16) From 5c725f51fe9123bf686e79368384cfc1e687394e Mon Sep 17 00:00:00 2001 From: OverMighty Date: Mon, 10 Jun 2024 19:21:48 +0200 Subject: [PATCH 2/4] [libc][math][c23] Add totalordermagf16 C23 math function --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/docs/c23.rst | 2 +- libc/docs/math/index.rst | 2 + libc/spec/stdc.td | 2 + libc/src/__support/FPUtil/BasicOperations.h | 8 + libc/src/math/CMakeLists.txt | 2 + libc/src/math/generic/CMakeLists.txt | 12 ++ libc/src/math/generic/totalordermagf16.cpp | 20 +++ libc/src/math/totalordermagf16.h | 20 +++ libc/test/UnitTest/FPMatcher.h | 6 +- libc/test/src/math/smoke/CMakeLists.txt | 12 ++ libc/test/src/math/smoke/TotalOrderMagTest.h | 143 ++++++++++++++++++ .../src/math/smoke/totalordermagf16_test.cpp | 13 ++ 14 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 libc/src/math/generic/totalordermagf16.cpp create mode 100644 libc/src/math/totalordermagf16.h create mode 100644 libc/test/src/math/smoke/TotalOrderMagTest.h create mode 100644 libc/test/src/math/smoke/totalordermagf16_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 8206cc18284c0..dba4835afb745 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -540,6 +540,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.roundf16 libc.src.math.roundevenf16 libc.src.math.totalorderf16 + libc.src.math.totalordermagf16 libc.src.math.truncf16 libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 84751c7779cb9..90505738d624d 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -570,6 +570,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.roundf16 libc.src.math.roundevenf16 libc.src.math.totalorderf16 + libc.src.math.totalordermagf16 libc.src.math.truncf16 libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 diff --git a/libc/docs/c23.rst b/libc/docs/c23.rst index a771f4feab3c2..4134befd1ed35 100644 --- a/libc/docs/c23.rst +++ b/libc/docs/c23.rst @@ -43,7 +43,7 @@ Additions: * __STDC_IEC_60559_DFP__ functions (_Decimal32, _Decimal64, _Decimal128) * compoundn* * totalorder* |check| - * totalordermag* + * totalordermag* |check| * getpayload* * setpayload* * iscannonical diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 727919d9e4a9e..953bdd8b642ad 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -212,6 +212,8 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | totalorder | | | | |check| | | F.10.12.1 | N/A | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| totalordermag | | | | |check| | | F.10.12.2 | N/A | ++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | trunc | |check| | |check| | |check| | |check| | |check| | 7.12.9.9 | F.10.6.9 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | ufromfp | |check| | |check| | |check| | |check| | |check| | 7.12.9.10 | F.10.6.10 | diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index be97a0a0c9343..b1b02a8e1ed31 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -710,6 +710,8 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"canonicalizef128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT128">, GuardedFunctionSpec<"totalorderf16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + + GuardedFunctionSpec<"totalordermagf16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, ] >; diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h index cb669b0009265..168b3d308f0ee 100644 --- a/libc/src/__support/FPUtil/BasicOperations.h +++ b/libc/src/__support/FPUtil/BasicOperations.h @@ -283,6 +283,14 @@ totalorder(const T *x, const T *y) { return xbits.get_val() <= ybits.get_val(); } +template +LIBC_INLINE cpp::enable_if_t, bool> +totalordermag(const T *x, const T *y) { + T abs_x = abs(*x); + T abs_y = abs(*y); + return totalorder(&abs_x, &abs_y); +} + } // namespace fputil } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 5d605fe8bbcb7..3c1a5c86f6b48 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -369,6 +369,8 @@ add_math_entrypoint_object(tgammaf) add_math_entrypoint_object(totalorderf16) +add_math_entrypoint_object(totalordermagf16) + add_math_entrypoint_object(trunc) add_math_entrypoint_object(truncf) add_math_entrypoint_object(truncl) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 4787ecfdf8565..a13cadc8acd0c 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3563,3 +3563,15 @@ add_entrypoint_object( COMPILE_OPTIONS -O3 ) + +add_entrypoint_object( + totalordermagf16 + SRCS + totalordermagf16.cpp + HDRS + ../totalordermagf16.h + DEPENDS + libc.src.__support.FPUtil.basic_operations + COMPILE_OPTIONS + -O3 +) diff --git a/libc/src/math/generic/totalordermagf16.cpp b/libc/src/math/generic/totalordermagf16.cpp new file mode 100644 index 0000000000000..868e155bac32b --- /dev/null +++ b/libc/src/math/generic/totalordermagf16.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of totalordermagf16 function -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/totalordermagf16.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(int, totalordermagf16, + (const float16 *x, const float16 *y)) { + return static_cast(fputil::totalordermag(x, y)); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/totalordermagf16.h b/libc/src/math/totalordermagf16.h new file mode 100644 index 0000000000000..8c6621b9783df --- /dev/null +++ b/libc/src/math/totalordermagf16.h @@ -0,0 +1,20 @@ +//===-- Implementation header for totalordermagf16 --------------*- 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_TOTALORDERMAGF16_H +#define LLVM_LIBC_SRC_MATH_TOTALORDERMAGF16_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +int totalordermagf16(const float16 *x, const float16 *y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_TOTALORDERMAGF16_H diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h index 26af5cec02b58..86b823260e197 100644 --- a/libc/test/UnitTest/FPMatcher.h +++ b/libc/test/UnitTest/FPMatcher.h @@ -97,8 +97,10 @@ template struct FPTest : public Test { LIBC_NAMESPACE::cpp::numeric_limits::max(); \ const T zero = FPBits::zero(Sign::POS).get_val(); \ const T neg_zero = FPBits::zero(Sign::NEG).get_val(); \ - const T aNaN = FPBits::quiet_nan().get_val(); \ - const T sNaN = FPBits::signaling_nan().get_val(); \ + const T aNaN = FPBits::quiet_nan(Sign::POS).get_val(); \ + const T neg_aNaN = FPBits::quiet_nan(Sign::NEG).get_val(); \ + const T sNaN = FPBits::signaling_nan(Sign::POS).get_val(); \ + const T neg_sNaN = FPBits::signaling_nan(Sign::NEG).get_val(); \ const T inf = FPBits::inf(Sign::POS).get_val(); \ const T neg_inf = FPBits::inf(Sign::NEG).get_val(); \ const T min_normal = FPBits::min_normal().get_val(); \ diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index d24e4076c0bed..706e23518ed58 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3521,3 +3521,15 @@ add_fp_unittest( DEPENDS libc.src.math.totalorderf16 ) + +add_fp_unittest( + totalordermagf16_test + SUITE + libc-math-smoke-tests + SRCS + totalordermagf16_test.cpp + HDRS + TotalOrderMagTest.h + DEPENDS + libc.src.math.totalordermagf16 +) diff --git a/libc/test/src/math/smoke/TotalOrderMagTest.h b/libc/test/src/math/smoke/TotalOrderMagTest.h new file mode 100644 index 0000000000000..013a7fc92f9b1 --- /dev/null +++ b/libc/test/src/math/smoke/TotalOrderMagTest.h @@ -0,0 +1,143 @@ +//===-- Utility class to test flavors of totalordermag ----------*- 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 LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H +#define LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H + +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +template +class TotalOrderMagTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(T) + +public: + typedef int (*TotalOrderMagFunc)(const T *, const T *); + + bool funcWrapper(TotalOrderMagFunc func, T x, T y) { + return func(&x, &y) != 0; + } + + void testXLesserThanY(TotalOrderMagFunc func) { + EXPECT_TRUE(funcWrapper(func, neg_inf, inf)); + + EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(0.0), T(123.38))); + + EXPECT_FALSE(funcWrapper(func, T(-0.1), T(0.0))); + EXPECT_FALSE(funcWrapper(func, T(-123.38), T(0.0))); + + EXPECT_TRUE(funcWrapper(func, T(-0.1), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(-123.38), T(123.38))); + } + + void testXGreaterThanY(TotalOrderMagFunc func) { + EXPECT_TRUE(funcWrapper(func, inf, neg_inf)); + + EXPECT_TRUE(funcWrapper(func, T(0.0), T(-0.1))); + EXPECT_TRUE(funcWrapper(func, T(0.0), T(-123.38))); + + EXPECT_FALSE(funcWrapper(func, T(0.1), T(0.0))); + EXPECT_FALSE(funcWrapper(func, T(123.38), T(0.0))); + + EXPECT_TRUE(funcWrapper(func, T(0.1), T(-0.1))); + EXPECT_TRUE(funcWrapper(func, T(123.38), T(-123.38))); + } + + void testXEqualToY(TotalOrderMagFunc func) { + EXPECT_TRUE(funcWrapper(func, inf, inf)); + EXPECT_TRUE(funcWrapper(func, neg_inf, neg_inf)); + + EXPECT_TRUE(funcWrapper(func, T(-0.0), T(0.0))); + EXPECT_TRUE(funcWrapper(func, T(0.0), T(-0.0))); + + EXPECT_TRUE(funcWrapper(func, T(0.0), T(0.0))); + EXPECT_TRUE(funcWrapper(func, T(-0.0), T(-0.0))); + EXPECT_TRUE(funcWrapper(func, T(0.1), T(0.1))); + EXPECT_TRUE(funcWrapper(func, T(-0.1), T(-0.1))); + EXPECT_TRUE(funcWrapper(func, T(123.38), T(123.38))); + EXPECT_TRUE(funcWrapper(func, T(-123.38), T(-123.38))); + } + + void testSingleNaN(TotalOrderMagFunc func) { + EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(0.0))); + EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(0.1))); + EXPECT_FALSE(funcWrapper(func, neg_aNaN, T(123.38))); + + EXPECT_TRUE(funcWrapper(func, T(0.0), neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, T(0.1), neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, T(123.38), neg_aNaN)); + + EXPECT_TRUE(funcWrapper(func, T(0.0), aNaN)); + EXPECT_TRUE(funcWrapper(func, T(0.1), aNaN)); + EXPECT_TRUE(funcWrapper(func, T(123.38), aNaN)); + + EXPECT_FALSE(funcWrapper(func, aNaN, T(0.0))); + EXPECT_FALSE(funcWrapper(func, aNaN, T(0.1))); + EXPECT_FALSE(funcWrapper(func, aNaN, T(123.38))); + } + + void testNaNSigns(TotalOrderMagFunc func) { + EXPECT_TRUE(funcWrapper(func, neg_aNaN, aNaN)); + EXPECT_FALSE(funcWrapper(func, neg_aNaN, sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, sNaN)); + + EXPECT_TRUE(funcWrapper(func, aNaN, neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, aNaN, neg_sNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, neg_sNaN)); + } + + void testQuietVsSignalingNaN(TotalOrderMagFunc func) { + EXPECT_FALSE(funcWrapper(func, neg_aNaN, neg_sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, aNaN)); + EXPECT_FALSE(funcWrapper(func, aNaN, sNaN)); + } + + void testNaNPayloads(TotalOrderMagFunc func) { + T qnan_123 = FPBits::quiet_nan(Sign::POS, 0x123).get_val(); + T neg_qnan_123 = FPBits::quiet_nan(Sign::NEG, 0x123).get_val(); + T snan_123 = FPBits::signaling_nan(Sign::POS, 0x123).get_val(); + T neg_snan_123 = FPBits::signaling_nan(Sign::NEG, 0x123).get_val(); + + EXPECT_TRUE(funcWrapper(func, aNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, sNaN, sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); + + EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123)); + EXPECT_TRUE(funcWrapper(func, sNaN, snan_123)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123)); + + EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN)); + EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, snan_123, sNaN)); + EXPECT_FALSE(funcWrapper(func, neg_snan_123, neg_sNaN)); + } +}; + +#define LIST_TOTALORDERMAG_TESTS(T, func) \ + using LlvmLibcTotalOrderMagTest = TotalOrderMagTestTemplate; \ + TEST_F(LlvmLibcTotalOrderMagTest, XLesserThanY) { testXLesserThanY(&func); } \ + TEST_F(LlvmLibcTotalOrderMagTest, XGreaterThanY) { \ + testXGreaterThanY(&func); \ + } \ + TEST_F(LlvmLibcTotalOrderMagTest, XEqualToY) { testXEqualToY(&func); } \ + TEST_F(LlvmLibcTotalOrderMagTest, SingleNaN) { testSingleNaN(&func); } \ + TEST_F(LlvmLibcTotalOrderMagTest, NaNSigns) { testNaNSigns(&func); } \ + TEST_F(LlvmLibcTotalOrderMagTest, QuietVsSignalingNaN) { \ + testQuietVsSignalingNaN(&func); \ + } \ + TEST_F(LlvmLibcTotalOrderMagTest, NaNPayloads) { testNaNPayloads(&func); } + +#endif // LIBC_TEST_SRC_MATH_SMOKE_TOTALORDERMAGTEST_H diff --git a/libc/test/src/math/smoke/totalordermagf16_test.cpp b/libc/test/src/math/smoke/totalordermagf16_test.cpp new file mode 100644 index 0000000000000..b09eb11cd9c3b --- /dev/null +++ b/libc/test/src/math/smoke/totalordermagf16_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for totalordermagf16 ------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "TotalOrderMagTest.h" + +#include "src/math/totalordermagf16.h" + +LIST_TOTALORDERMAG_TESTS(float16, LIBC_NAMESPACE::totalordermagf16) From e295094e321675303a231b818fac67e4b6617455 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Mon, 10 Jun 2024 19:26:02 +0200 Subject: [PATCH 3/4] [libc][math][c23] Fix NaN negation in TotalOrderTest.h --- libc/test/src/math/smoke/TotalOrderTest.h | 48 ++++++++++++----------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/libc/test/src/math/smoke/TotalOrderTest.h b/libc/test/src/math/smoke/TotalOrderTest.h index 9ed44b1b798d1..c6939e6a3eaac 100644 --- a/libc/test/src/math/smoke/TotalOrderTest.h +++ b/libc/test/src/math/smoke/TotalOrderTest.h @@ -65,13 +65,13 @@ class TotalOrderTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { } void testSingleNaN(TotalOrderFunc func) { - EXPECT_TRUE(funcWrapper(func, -aNaN, T(0.0))); - EXPECT_TRUE(funcWrapper(func, -aNaN, T(0.1))); - EXPECT_TRUE(funcWrapper(func, -aNaN, T(123.38))); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, T(0.0))); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, T(0.1))); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, T(123.38))); - EXPECT_FALSE(funcWrapper(func, T(0.0), -aNaN)); - EXPECT_FALSE(funcWrapper(func, T(0.1), -aNaN)); - EXPECT_FALSE(funcWrapper(func, T(123.38), -aNaN)); + EXPECT_FALSE(funcWrapper(func, T(0.0), neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, T(0.1), neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, T(123.38), neg_aNaN)); EXPECT_TRUE(funcWrapper(func, T(0.0), aNaN)); EXPECT_TRUE(funcWrapper(func, T(0.1), aNaN)); @@ -83,42 +83,44 @@ class TotalOrderTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { } void testNaNSigns(TotalOrderFunc func) { - EXPECT_TRUE(funcWrapper(func, -aNaN, aNaN)); - EXPECT_TRUE(funcWrapper(func, -aNaN, sNaN)); - EXPECT_TRUE(funcWrapper(func, -sNaN, aNaN)); - EXPECT_TRUE(funcWrapper(func, -sNaN, sNaN)); - - EXPECT_FALSE(funcWrapper(func, aNaN, -aNaN)); - EXPECT_FALSE(funcWrapper(func, aNaN, -sNaN)); - EXPECT_FALSE(funcWrapper(func, sNaN, -aNaN)); - EXPECT_FALSE(funcWrapper(func, sNaN, -sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, sNaN)); + + EXPECT_FALSE(funcWrapper(func, aNaN, neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, aNaN, neg_sNaN)); + EXPECT_FALSE(funcWrapper(func, sNaN, neg_aNaN)); + EXPECT_FALSE(funcWrapper(func, sNaN, neg_sNaN)); } void testQuietVsSignalingNaN(TotalOrderFunc func) { - EXPECT_TRUE(funcWrapper(func, -aNaN, -sNaN)); - EXPECT_FALSE(funcWrapper(func, -sNaN, -aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_sNaN)); + EXPECT_FALSE(funcWrapper(func, neg_sNaN, neg_aNaN)); EXPECT_TRUE(funcWrapper(func, sNaN, aNaN)); EXPECT_FALSE(funcWrapper(func, aNaN, sNaN)); } void testNaNPayloads(TotalOrderFunc func) { T qnan_123 = FPBits::quiet_nan(Sign::POS, 0x123).get_val(); + T neg_qnan_123 = FPBits::quiet_nan(Sign::NEG, 0x123).get_val(); T snan_123 = FPBits::signaling_nan(Sign::POS, 0x123).get_val(); + T neg_snan_123 = FPBits::signaling_nan(Sign::NEG, 0x123).get_val(); EXPECT_TRUE(funcWrapper(func, aNaN, aNaN)); - EXPECT_TRUE(funcWrapper(func, -aNaN, -aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); EXPECT_TRUE(funcWrapper(func, sNaN, sNaN)); - EXPECT_TRUE(funcWrapper(func, -sNaN, -sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123)); - EXPECT_TRUE(funcWrapper(func, -aNaN, -qnan_123)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123)); EXPECT_TRUE(funcWrapper(func, sNaN, snan_123)); - EXPECT_TRUE(funcWrapper(func, -sNaN, -snan_123)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123)); EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN)); - EXPECT_FALSE(funcWrapper(func, -qnan_123, -aNaN)); + EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN)); EXPECT_FALSE(funcWrapper(func, snan_123, sNaN)); - EXPECT_FALSE(funcWrapper(func, -snan_123, -sNaN)); + EXPECT_FALSE(funcWrapper(func, neg_snan_123, neg_sNaN)); } }; From 1ac6c819c48e3c5032c153f929d7025d99e65ebf Mon Sep 17 00:00:00 2001 From: OverMighty Date: Tue, 11 Jun 2024 15:55:35 +0200 Subject: [PATCH 4/4] [libc][math][c23] Refactor fputil::{totalorder,totalordermag} --- libc/src/__support/FPUtil/BasicOperations.h | 56 ++++++-------------- libc/src/__support/FPUtil/FPBits.h | 4 -- libc/src/math/generic/totalorderf16.cpp | 2 +- libc/src/math/generic/totalordermagf16.cpp | 2 +- libc/test/src/math/smoke/TotalOrderMagTest.h | 13 +++-- libc/test/src/math/smoke/TotalOrderTest.h | 15 +++--- 6 files changed, 30 insertions(+), 62 deletions(-) diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h index 168b3d308f0ee..beb8e48db8f51 100644 --- a/libc/src/__support/FPUtil/BasicOperations.h +++ b/libc/src/__support/FPUtil/BasicOperations.h @@ -242,53 +242,27 @@ LIBC_INLINE int canonicalize(T &cx, const T &x) { template LIBC_INLINE cpp::enable_if_t, bool> -totalorder(const T *x, const T *y) { +totalorder(T x, T y) { using FPBits = FPBits; - FPBits xbits(*x); - FPBits ybits(*y); - - if (LIBC_UNLIKELY(xbits.is_zero() && ybits.is_zero() || xbits.is_nan() || - ybits.is_nan())) { - // totalOrder(−0, +0) is true. totalOrder(+0, -0) is false. - if (xbits.is_zero() && ybits.is_zero()) { - Sign xsign = xbits.sign(); - Sign ysign = ybits.sign(); - return (xsign == Sign::NEG && ysign == Sign::POS) || xsign == ysign; - } - - // totalOrder(−NaN, y) is true. totalOrder(+NaN, y) is false. - if (!ybits.is_nan()) - return xbits.is_neg(); - // totalOrder(x, +NaN) is true. totalOrder(x, -NaN) is false. - if (!xbits.is_nan()) - return ybits.is_pos(); - - // Negative sign orders below positive sign. - if (xbits.is_neg() && ybits.is_pos()) - return true; - if (xbits.is_pos() && ybits.is_neg()) - return false; - - // Signaling orders below quiet for +NaN, reverse for −NaN. - if (xbits.is_quiet_nan() && ybits.is_signaling_nan()) - return xbits.is_neg(); - if (xbits.is_signaling_nan() && ybits.is_quiet_nan()) - return ybits.is_pos(); - - // Otherwise, the order of NaNs is implementation-defined (IEEE 754-2019). - // We order by payload. - return xbits.get_nan_payload() <= ybits.get_nan_payload(); - } + FPBits x_bits(x); + FPBits y_bits(y); + + using StorageType = typename FPBits::StorageType; + StorageType x_u = x_bits.uintval(); + StorageType y_u = y_bits.uintval(); + + using signed_t = cpp::make_signed_t; + signed_t x_signed = static_cast(x_u); + signed_t y_signed = static_cast(y_u); - return xbits.get_val() <= ybits.get_val(); + bool both_neg = (x_u & y_u & FPBits::SIGN_MASK) != 0; + return x_signed == y_signed || ((x_signed <= y_signed) != both_neg); } template LIBC_INLINE cpp::enable_if_t, bool> -totalordermag(const T *x, const T *y) { - T abs_x = abs(*x); - T abs_y = abs(*y); - return totalorder(&abs_x, &abs_y); +totalordermag(T x, T y) { + return FPBits(x).abs().uintval() <= FPBits(y).abs().uintval(); } } // namespace fputil diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h index f424e11ec9fd1..559ecde767c30 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -708,10 +708,6 @@ struct FPRepImpl : public FPRepSem { LIBC_INLINE constexpr void set_significand(StorageType sigVal) { bits = UP::merge(bits, sigVal, SIG_MASK); } - - LIBC_INLINE constexpr StorageType get_nan_payload() const { - return bits & (FRACTION_MASK >> 1); - } // Unsafe function to create a floating point representation. // It simply packs the sign, biased exponent and mantissa values without // checking bound nor normalization. diff --git a/libc/src/math/generic/totalorderf16.cpp b/libc/src/math/generic/totalorderf16.cpp index b64f1eeaf3ddf..e43beb33d2fd3 100644 --- a/libc/src/math/generic/totalorderf16.cpp +++ b/libc/src/math/generic/totalorderf16.cpp @@ -13,7 +13,7 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(int, totalorderf16, (const float16 *x, const float16 *y)) { - return static_cast(fputil::totalorder(x, y)); + return static_cast(fputil::totalorder(*x, *y)); } } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/totalordermagf16.cpp b/libc/src/math/generic/totalordermagf16.cpp index 868e155bac32b..09d04fbeb2d2c 100644 --- a/libc/src/math/generic/totalordermagf16.cpp +++ b/libc/src/math/generic/totalordermagf16.cpp @@ -14,7 +14,7 @@ namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(int, totalordermagf16, (const float16 *x, const float16 *y)) { - return static_cast(fputil::totalordermag(x, y)); + return static_cast(fputil::totalordermag(*x, *y)); } } // namespace LIBC_NAMESPACE diff --git a/libc/test/src/math/smoke/TotalOrderMagTest.h b/libc/test/src/math/smoke/TotalOrderMagTest.h index 013a7fc92f9b1..5fe2983a0e678 100644 --- a/libc/test/src/math/smoke/TotalOrderMagTest.h +++ b/libc/test/src/math/smoke/TotalOrderMagTest.h @@ -110,18 +110,17 @@ class TotalOrderMagTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { T neg_snan_123 = FPBits::signaling_nan(Sign::NEG, 0x123).get_val(); EXPECT_TRUE(funcWrapper(func, aNaN, aNaN)); - EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); EXPECT_TRUE(funcWrapper(func, sNaN, sNaN)); - EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); - EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123)); - EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123)); EXPECT_TRUE(funcWrapper(func, sNaN, snan_123)); - EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123)); - EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN)); - EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN)); EXPECT_FALSE(funcWrapper(func, snan_123, sNaN)); + + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123)); + EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN)); EXPECT_FALSE(funcWrapper(func, neg_snan_123, neg_sNaN)); } }; diff --git a/libc/test/src/math/smoke/TotalOrderTest.h b/libc/test/src/math/smoke/TotalOrderTest.h index c6939e6a3eaac..281b2a59f930d 100644 --- a/libc/test/src/math/smoke/TotalOrderTest.h +++ b/libc/test/src/math/smoke/TotalOrderTest.h @@ -108,19 +108,18 @@ class TotalOrderTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { T neg_snan_123 = FPBits::signaling_nan(Sign::NEG, 0x123).get_val(); EXPECT_TRUE(funcWrapper(func, aNaN, aNaN)); - EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); EXPECT_TRUE(funcWrapper(func, sNaN, sNaN)); - EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); - EXPECT_TRUE(funcWrapper(func, aNaN, qnan_123)); - EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_qnan_123)); EXPECT_TRUE(funcWrapper(func, sNaN, snan_123)); - EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_snan_123)); - EXPECT_FALSE(funcWrapper(func, qnan_123, aNaN)); - EXPECT_FALSE(funcWrapper(func, neg_qnan_123, neg_aNaN)); EXPECT_FALSE(funcWrapper(func, snan_123, sNaN)); - EXPECT_FALSE(funcWrapper(func, neg_snan_123, neg_sNaN)); + + EXPECT_TRUE(funcWrapper(func, neg_aNaN, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_sNaN, neg_sNaN)); + EXPECT_FALSE(funcWrapper(func, neg_aNaN, neg_qnan_123)); + EXPECT_FALSE(funcWrapper(func, neg_sNaN, neg_snan_123)); + EXPECT_TRUE(funcWrapper(func, neg_qnan_123, neg_aNaN)); + EXPECT_TRUE(funcWrapper(func, neg_snan_123, neg_sNaN)); } };