From 23b9596764e1f49b0512b0cb626f63fd227e02e0 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Wed, 5 Jun 2024 16:46:48 +0200 Subject: [PATCH 1/2] [libc][math] Add MPFR unit tests for nearbyint{,f,l,f16} --- libc/test/src/math/CMakeLists.txt | 64 ++++++++++++ libc/test/src/math/NearbyIntTest.h | 128 +++++++++++++++++++++++ libc/test/src/math/nearbyint_test.cpp | 13 +++ libc/test/src/math/nearbyintf16_test.cpp | 13 +++ libc/test/src/math/nearbyintf_test.cpp | 13 +++ libc/test/src/math/nearbyintl_test.cpp | 13 +++ 6 files changed, 244 insertions(+) create mode 100644 libc/test/src/math/NearbyIntTest.h create mode 100644 libc/test/src/math/nearbyint_test.cpp create mode 100644 libc/test/src/math/nearbyintf16_test.cpp create mode 100644 libc/test/src/math/nearbyintf_test.cpp create mode 100644 libc/test/src/math/nearbyintl_test.cpp diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index ba588662f469e..aaf1009ba0f75 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -574,6 +574,70 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + nearbyint_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyint_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyint + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl +) + +add_fp_unittest( + nearbyintf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintf + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl +) + +add_fp_unittest( + nearbyintl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintl_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintl + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl +) + +add_fp_unittest( + nearbyintf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf16_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintf16 + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl +) + add_fp_unittest( rint_test NEED_MPFR diff --git a/libc/test/src/math/NearbyIntTest.h b/libc/test/src/math/NearbyIntTest.h new file mode 100644 index 0000000000000..fabe4bf00e150 --- /dev/null +++ b/libc/test/src/math/NearbyIntTest.h @@ -0,0 +1,128 @@ +//===-- Utility class to test different flavors of nearbyint ----*- 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_TEST_SRC_MATH_NEARBYINTTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_NEARBYINTTEST_H + +#include "src/__support/CPP/algorithm.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +#include "hdr/fenv_macros.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(T) + + static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, + FE_TOWARDZERO, FE_TONEAREST}; + + static constexpr StorageType MIN_SUBNORMAL = + FPBits::min_subnormal().uintval(); + static constexpr StorageType MAX_SUBNORMAL = + FPBits::max_subnormal().uintval(); + static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); + static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); + + static mpfr::RoundingMode to_mpfr_rounding_mode(int mode) { + switch (mode) { + case FE_UPWARD: + return mpfr::RoundingMode::Upward; + case FE_DOWNWARD: + return mpfr::RoundingMode::Downward; + case FE_TOWARDZERO: + return mpfr::RoundingMode::TowardZero; + case FE_TONEAREST: + return mpfr::RoundingMode::Nearest; + default: + __builtin_unreachable(); + } + } + +public: + using NearbyIntFunc = T (*)(T); + + void test_round_numbers(NearbyIntFunc func) { + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mpfr_mode)); + } + } + + void test_fractions(NearbyIntFunc func) { + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mpfr_mode)); + EXPECT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode)); + EXPECT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode)); + } + } + + void test_subnormal_range(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + const StorageType STEP = LIBC_NAMESPACE::cpp::max( + static_cast((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT), + StorageType(1)); + for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) { + T x = FPBits(i).get_val(); + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + } + } + } + + void test_normal_range(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + const StorageType STEP = LIBC_NAMESPACE::cpp::max( + static_cast((MAX_NORMAL - MIN_NORMAL) / COUNT), + StorageType(1)); + for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) { + FPBits xbits(i); + T x = xbits.get_val(); + // In normal range on x86 platforms, the long double implicit 1 bit can be + // zero making the numbers NaN. We will skip them. + if (xbits.is_nan()) + continue; + + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + } + } + } +}; + +#define LIST_NEARBYINT_TESTS(F, func) \ + using LlvmLibcNearbyIntTest = NearbyIntTestTemplate; \ + TEST_F(LlvmLibcNearbyIntTest, RoundNumbers) { test_round_numbers(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, Fractions) { test_fractions(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, SubnormalRange) { \ + test_subnormal_range(&func); \ + } \ + TEST_F(LlvmLibcNearbyIntTest, NormalRange) { test_normal_range(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_NEARBYINTTEST_H diff --git a/libc/test/src/math/nearbyint_test.cpp b/libc/test/src/math/nearbyint_test.cpp new file mode 100644 index 0000000000000..11a5c3372e73e --- /dev/null +++ b/libc/test/src/math/nearbyint_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyint -------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyint.h" + +LIST_NEARBYINT_TESTS(double, LIBC_NAMESPACE::nearbyint) diff --git a/libc/test/src/math/nearbyintf16_test.cpp b/libc/test/src/math/nearbyintf16_test.cpp new file mode 100644 index 0000000000000..e6ec250cec91f --- /dev/null +++ b/libc/test/src/math/nearbyintf16_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintf16 ----------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintf16.h" + +LIST_NEARBYINT_TESTS(float16, LIBC_NAMESPACE::nearbyintf16) diff --git a/libc/test/src/math/nearbyintf_test.cpp b/libc/test/src/math/nearbyintf_test.cpp new file mode 100644 index 0000000000000..fd26153cfffb9 --- /dev/null +++ b/libc/test/src/math/nearbyintf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintf ------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintf.h" + +LIST_NEARBYINT_TESTS(float, LIBC_NAMESPACE::nearbyintf) diff --git a/libc/test/src/math/nearbyintl_test.cpp b/libc/test/src/math/nearbyintl_test.cpp new file mode 100644 index 0000000000000..a6d81a1439e17 --- /dev/null +++ b/libc/test/src/math/nearbyintl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintl ------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintl.h" + +LIST_NEARBYINT_TESTS(long double, LIBC_NAMESPACE::nearbyintl) From da0abfb27c9b72428cae68b6b3cc788df5904411 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 13:57:24 +0200 Subject: [PATCH 2/2] fixup! [libc][math] Add MPFR unit tests for nearbyint{,f,l,f16} --- libc/test/src/math/CMakeLists.txt | 12 ++--- libc/test/src/math/NearbyIntTest.h | 80 +++++++++++++----------------- 2 files changed, 39 insertions(+), 53 deletions(-) diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index aaf1009ba0f75..5c6f0c31c680a 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -584,10 +584,9 @@ add_fp_unittest( HDRS NearbyIntTest.h DEPENDS - libc.hdr.fenv_macros libc.src.math.nearbyint libc.src.__support.CPP.algorithm - libc.src.__support.FPUtil.fenv_impl + libc.src.__support.CPP.array ) add_fp_unittest( @@ -600,10 +599,9 @@ add_fp_unittest( HDRS NearbyIntTest.h DEPENDS - libc.hdr.fenv_macros libc.src.math.nearbyintf libc.src.__support.CPP.algorithm - libc.src.__support.FPUtil.fenv_impl + libc.src.__support.CPP.array ) add_fp_unittest( @@ -616,10 +614,9 @@ add_fp_unittest( HDRS NearbyIntTest.h DEPENDS - libc.hdr.fenv_macros libc.src.math.nearbyintl libc.src.__support.CPP.algorithm - libc.src.__support.FPUtil.fenv_impl + libc.src.__support.CPP.array ) add_fp_unittest( @@ -632,10 +629,9 @@ add_fp_unittest( HDRS NearbyIntTest.h DEPENDS - libc.hdr.fenv_macros libc.src.math.nearbyintf16 libc.src.__support.CPP.algorithm - libc.src.__support.FPUtil.fenv_impl + libc.src.__support.CPP.array ) add_fp_unittest( diff --git a/libc/test/src/math/NearbyIntTest.h b/libc/test/src/math/NearbyIntTest.h index fabe4bf00e150..88cdf453f0556 100644 --- a/libc/test/src/math/NearbyIntTest.h +++ b/libc/test/src/math/NearbyIntTest.h @@ -10,13 +10,13 @@ #define LLVM_LIBC_TEST_SRC_MATH_NEARBYINTTEST_H #include "src/__support/CPP/algorithm.h" -#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/CPP/array.h" #include "test/UnitTest/FEnvSafeTest.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" -#include "hdr/fenv_macros.h" +using namespace LIBC_NAMESPACE::fputil::testing; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; @@ -25,8 +25,13 @@ class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { DECLARE_SPECIAL_CONSTANTS(T) - static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, - FE_TOWARDZERO, FE_TONEAREST}; + static constexpr LIBC_NAMESPACE::cpp::array ROUNDING_MODES = + { + RoundingMode::Upward, + RoundingMode::Downward, + RoundingMode::TowardZero, + RoundingMode::Nearest, + }; static constexpr StorageType MIN_SUBNORMAL = FPBits::min_subnormal().uintval(); @@ -35,47 +40,32 @@ class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); - static mpfr::RoundingMode to_mpfr_rounding_mode(int mode) { - switch (mode) { - case FE_UPWARD: - return mpfr::RoundingMode::Upward; - case FE_DOWNWARD: - return mpfr::RoundingMode::Downward; - case FE_TOWARDZERO: - return mpfr::RoundingMode::TowardZero; - case FE_TONEAREST: - return mpfr::RoundingMode::Nearest; - default: - __builtin_unreachable(); - } - } - public: using NearbyIntFunc = T (*)(T); void test_round_numbers(NearbyIntFunc func) { - for (int mode : ROUNDING_MODES) { - LIBC_NAMESPACE::fputil::set_round(mode); - mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); - EXPECT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mpfr_mode)); - EXPECT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mpfr_mode)); - EXPECT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mpfr_mode)); - EXPECT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mpfr_mode)); - EXPECT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mpfr_mode)); - EXPECT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mpfr_mode)); + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mode)); + EXPECT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mode)); + EXPECT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mode)); + EXPECT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mode)); + EXPECT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mode)); + EXPECT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mode)); + } } } void test_fractions(NearbyIntFunc func) { - for (int mode : ROUNDING_MODES) { - LIBC_NAMESPACE::fputil::set_round(mode); - mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); - EXPECT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode)); - EXPECT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mpfr_mode)); - EXPECT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mpfr_mode)); - EXPECT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode)); - EXPECT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mpfr_mode)); - EXPECT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode)); + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mode)); + EXPECT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mode)); + EXPECT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mode)); + EXPECT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mode)); + EXPECT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mode)); + EXPECT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mode)); + } } } @@ -86,10 +76,10 @@ class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { StorageType(1)); for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) { T x = FPBits(i).get_val(); - for (int mode : ROUNDING_MODES) { - LIBC_NAMESPACE::fputil::set_round(mode); - mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); - EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(x), mpfr::round(x, mode)); + } } } } @@ -107,10 +97,10 @@ class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { if (xbits.is_nan()) continue; - for (int mode : ROUNDING_MODES) { - LIBC_NAMESPACE::fputil::set_round(mode); - mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); - EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(x), mpfr::round(x, mode)); + } } } }