[libc-commits] [libc] [libc][math][c23] Add MPFR exhaustive test for fmodf16 (PR #94656)
via libc-commits
libc-commits at lists.llvm.org
Thu Jun 6 11:31:01 PDT 2024
https://github.com/overmighty created https://github.com/llvm/llvm-project/pull/94656
None
>From e880ee2eb2fc483085180c9a879518ff1ed52327 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 6 Jun 2024 17:07:37 +0200
Subject: [PATCH 1/4] [libc][math][c23] Add fmodf16 C23 math function
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/docs/math/index.rst | 2 +-
libc/spec/stdc.td | 1 +
libc/src/__support/FPUtil/FPBits.h | 2 +-
libc/src/__support/FPUtil/generic/FMod.h | 4 ++-
libc/src/math/CMakeLists.txt | 1 +
libc/src/math/fmodf16.h | 20 ++++++++++++
libc/src/math/generic/CMakeLists.txt | 13 ++++++++
libc/src/math/generic/fmodf16.cpp | 19 ++++++++++++
libc/test/src/math/smoke/CMakeLists.txt | 33 +++++++++++++++-----
libc/test/src/math/smoke/FModTest.h | 37 ++++++++++++-----------
libc/test/src/math/smoke/fmodf16_test.cpp | 13 ++++++++
13 files changed, 118 insertions(+), 29 deletions(-)
create mode 100644 libc/src/math/fmodf16.h
create mode 100644 libc/src/math/generic/fmodf16.cpp
create mode 100644 libc/test/src/math/smoke/fmodf16_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 33ecff813a1fb..193183ddeb78a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -515,6 +515,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.fminimum_magf16
libc.src.math.fminimum_mag_numf16
libc.src.math.fminimum_numf16
+ libc.src.math.fmodf16
libc.src.math.fromfpf16
libc.src.math.fromfpxf16
libc.src.math.llrintf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ebacb1c59ceec..ee748b5cd8e1a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -548,6 +548,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.fminimum_magf16
libc.src.math.fminimum_mag_numf16
libc.src.math.fminimum_numf16
+ libc.src.math.fmodf16
libc.src.math.fromfpf16
libc.src.math.fromfpxf16
libc.src.math.llrintf16
diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst
index b9507f0887cd7..24b88a52f049d 100644
--- a/libc/docs/math/index.rst
+++ b/libc/docs/math/index.rst
@@ -156,7 +156,7 @@ Basic Operations
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| fminimum_num | |check| | |check| | |check| | |check| | |check| | 7.12.12.9 | F.10.9.5 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| fmod | |check| | |check| | |check| | | |check| | 7.12.10.1 | F.10.7.1 |
+| fmod | |check| | |check| | |check| | |check| | |check| | 7.12.10.1 | F.10.7.1 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| fmul | N/A | | | N/A | | 7.12.14.3 | F.10.11 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 210f2a1325169..90e5246a63505 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -478,6 +478,7 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"fmod", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
FunctionSpec<"fmodf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
FunctionSpec<"fmodl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
+ GuardedFunctionSpec<"fmodf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>, ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
GuardedFunctionSpec<"fmodf128", RetValSpec<Float128Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT128">,
FunctionSpec<"frexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntPtr>]>,
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index d3c96d2d613d6..559ecde767c30 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -744,7 +744,7 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
if (LIBC_LIKELY(ep >= 0)) {
// Implicit number bit will be removed by mask
result.set_significand(number);
- result.set_biased_exponent(ep + 1);
+ result.set_biased_exponent(static_cast<StorageType>(ep + 1));
} else {
result.set_significand(number >> -ep);
}
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index 211ab926d28b0..f840a92b1a5a2 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -210,7 +210,9 @@ class FMod {
e_x - e_y <= int(FPB::EXP_LEN))) {
StorageType m_x = sx.get_explicit_mantissa();
StorageType m_y = sy.get_explicit_mantissa();
- StorageType d = (e_x == e_y) ? (m_x - m_y) : (m_x << (e_x - e_y)) % m_y;
+ StorageType d = (e_x == e_y)
+ ? (m_x - m_y)
+ : static_cast<StorageType>(m_x << (e_x - e_y)) % m_y;
if (d == 0)
return FPB::zero();
// iy - 1 because of "zero power" for number with power 1
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 7a349ddc53724..141f66817e53e 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -183,6 +183,7 @@ add_math_entrypoint_object(fminimum_mag_numf128)
add_math_entrypoint_object(fmod)
add_math_entrypoint_object(fmodf)
add_math_entrypoint_object(fmodl)
+add_math_entrypoint_object(fmodf16)
add_math_entrypoint_object(fmodf128)
add_math_entrypoint_object(frexp)
diff --git a/libc/src/math/fmodf16.h b/libc/src/math/fmodf16.h
new file mode 100644
index 0000000000000..ab658430275d8
--- /dev/null
+++ b/libc/src/math/fmodf16.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for fmodf16 -----------------------*- 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_FMODF16_H
+#define LLVM_LIBC_SRC_MATH_FMODF16_H
+
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE {
+
+float16 fmodf16(float16 x, float16 y);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_MATH_FMODF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index b1d786fc6b29f..9c9073c0ea7bf 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -2887,6 +2887,19 @@ add_entrypoint_object(
-O3
)
+add_entrypoint_object(
+ fmodf16
+ SRCS
+ fmodf16.cpp
+ HDRS
+ ../fmodf16.h
+ DEPENDS
+ libc.src.__support.macros.properties.types
+ libc.src.__support.FPUtil.generic.fmod
+ COMPILE_OPTIONS
+ -O3
+)
+
add_entrypoint_object(
fmodf128
SRCS
diff --git a/libc/src/math/generic/fmodf16.cpp b/libc/src/math/generic/fmodf16.cpp
new file mode 100644
index 0000000000000..0a54a65806de9
--- /dev/null
+++ b/libc/src/math/generic/fmodf16.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of fmodf16 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/fmodf16.h"
+#include "src/__support/FPUtil/generic/FMod.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float16, fmodf16, (float16 x, float16 y)) {
+ return fputil::generic::FMod<float16>::eval(x, y);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 110fa1de97d6d..07e8b5dddfa6c 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3111,10 +3111,10 @@ add_fp_unittest(
HDRS
FModTest.h
DEPENDS
+ libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.fmodf
- libc.src.__support.FPUtil.basic_operations
- libc.src.__support.FPUtil.nearest_integer_operations
+ libc.src.__support.FPUtil.fenv_impl
# FIXME: Currently fails on the GPU build.
UNIT_TEST_ONLY
)
@@ -3128,10 +3128,10 @@ add_fp_unittest(
HDRS
FModTest.h
DEPENDS
+ libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.fmod
- libc.src.__support.FPUtil.basic_operations
- libc.src.__support.FPUtil.nearest_integer_operations
+ libc.src.__support.FPUtil.fenv_impl
# FIXME: Currently fails on the GPU build.
UNIT_TEST_ONLY
)
@@ -3145,10 +3145,27 @@ add_fp_unittest(
HDRS
FModTest.h
DEPENDS
+ libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.fmodl
- libc.src.__support.FPUtil.basic_operations
- libc.src.__support.FPUtil.nearest_integer_operations
+ libc.src.__support.FPUtil.fenv_impl
+ # FIXME: Currently fails on the GPU build.
+ UNIT_TEST_ONLY
+)
+
+add_fp_unittest(
+ fmodf16_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ fmodf16_test.cpp
+ HDRS
+ FModTest.h
+ DEPENDS
+ libc.hdr.fenv_macros
+ libc.src.errno.errno
+ libc.src.math.fmodf16
+ libc.src.__support.FPUtil.fenv_impl
# FIXME: Currently fails on the GPU build.
UNIT_TEST_ONLY
)
@@ -3162,10 +3179,10 @@ add_fp_unittest(
HDRS
FModTest.h
DEPENDS
+ libc.hdr.fenv_macros
libc.src.errno.errno
libc.src.math.fmodf128
- libc.src.__support.FPUtil.basic_operations
- libc.src.__support.FPUtil.nearest_integer_operations
+ libc.src.__support.FPUtil.fenv_impl
# FIXME: Currently fails on the GPU build.
UNIT_TEST_ONLY
)
diff --git a/libc/test/src/math/smoke/FModTest.h b/libc/test/src/math/smoke/FModTest.h
index f1015d6497fcd..405e3107438d4 100644
--- a/libc/test/src/math/smoke/FModTest.h
+++ b/libc/test/src/math/smoke/FModTest.h
@@ -9,13 +9,13 @@
#ifndef LLVM_LIBC_TEST_SRC_MATH_FMODTEST_H
#define LLVM_LIBC_TEST_SRC_MATH_FMODTEST_H
-#include "src/__support/FPUtil/BasicOperations.h"
-#include "src/__support/FPUtil/NearestIntegerOperations.h"
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/errno/libc_errno.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
-#include "hdr/math_macros.h"
+#include "hdr/fenv_macros.h"
#define TEST_SPECIAL(x, y, expected, dom_err, expected_exception) \
EXPECT_FP_EQ(expected, f(x, y)); \
@@ -210,7 +210,8 @@ class FmodTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
}
void testRegularExtreme(FModFunc f) {
-
+ if constexpr (sizeof(T) < sizeof(float))
+ return;
TEST_REGULAR(0x1p127L, 0x3p-149L, 0x1p-149L);
TEST_REGULAR(0x1p127L, -0x3p-149L, 0x1p-149L);
TEST_REGULAR(0x1p127L, 0x3p-148L, 0x1p-147L);
@@ -224,20 +225,20 @@ class FmodTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
TEST_REGULAR(-0x1p127L, 0x3p-126L, -0x1p-125L);
TEST_REGULAR(-0x1p127L, -0x3p-126L, -0x1p-125L);
- if constexpr (sizeof(T) >= sizeof(double)) {
- TEST_REGULAR(0x1p1023L, 0x3p-1074L, 0x1p-1073L);
- TEST_REGULAR(0x1p1023L, -0x3p-1074L, 0x1p-1073L);
- TEST_REGULAR(0x1p1023L, 0x3p-1073L, 0x1p-1073L);
- TEST_REGULAR(0x1p1023L, -0x3p-1073L, 0x1p-1073L);
- TEST_REGULAR(0x1p1023L, 0x3p-1022L, 0x1p-1021L);
- TEST_REGULAR(0x1p1023L, -0x3p-1022L, 0x1p-1021L);
- TEST_REGULAR(-0x1p1023L, 0x3p-1074L, -0x1p-1073L);
- TEST_REGULAR(-0x1p1023L, -0x3p-1074L, -0x1p-1073L);
- TEST_REGULAR(-0x1p1023L, 0x3p-1073L, -0x1p-1073L);
- TEST_REGULAR(-0x1p1023L, -0x3p-1073L, -0x1p-1073L);
- TEST_REGULAR(-0x1p1023L, 0x3p-1022L, -0x1p-1021L);
- TEST_REGULAR(-0x1p1023L, -0x3p-1022L, -0x1p-1021L);
- }
+ if constexpr (sizeof(T) < sizeof(double))
+ return;
+ TEST_REGULAR(0x1p1023L, 0x3p-1074L, 0x1p-1073L);
+ TEST_REGULAR(0x1p1023L, -0x3p-1074L, 0x1p-1073L);
+ TEST_REGULAR(0x1p1023L, 0x3p-1073L, 0x1p-1073L);
+ TEST_REGULAR(0x1p1023L, -0x3p-1073L, 0x1p-1073L);
+ TEST_REGULAR(0x1p1023L, 0x3p-1022L, 0x1p-1021L);
+ TEST_REGULAR(0x1p1023L, -0x3p-1022L, 0x1p-1021L);
+ TEST_REGULAR(-0x1p1023L, 0x3p-1074L, -0x1p-1073L);
+ TEST_REGULAR(-0x1p1023L, -0x3p-1074L, -0x1p-1073L);
+ TEST_REGULAR(-0x1p1023L, 0x3p-1073L, -0x1p-1073L);
+ TEST_REGULAR(-0x1p1023L, -0x3p-1073L, -0x1p-1073L);
+ TEST_REGULAR(-0x1p1023L, 0x3p-1022L, -0x1p-1021L);
+ TEST_REGULAR(-0x1p1023L, -0x3p-1022L, -0x1p-1021L);
}
};
diff --git a/libc/test/src/math/smoke/fmodf16_test.cpp b/libc/test/src/math/smoke/fmodf16_test.cpp
new file mode 100644
index 0000000000000..9a48c5aa0d609
--- /dev/null
+++ b/libc/test/src/math/smoke/fmodf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for fmodf16 ---------------------------------------------===//
+//
+// 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 "FModTest.h"
+
+#include "src/math/fmodf16.h"
+
+LIST_FMOD_TESTS(float16, LIBC_NAMESPACE::fmodf16)
>From f6621ffd0a175965caa7764103796d83fab3fff2 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 6 Jun 2024 19:58:53 +0200
Subject: [PATCH 2/4] [libc][math][c23] Change fmodf16 to use generic FMod with
uint32_t
---
libc/src/math/generic/fmodf16.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/math/generic/fmodf16.cpp b/libc/src/math/generic/fmodf16.cpp
index 0a54a65806de9..a5bfd78113f63 100644
--- a/libc/src/math/generic/fmodf16.cpp
+++ b/libc/src/math/generic/fmodf16.cpp
@@ -13,7 +13,7 @@
namespace LIBC_NAMESPACE {
LLVM_LIBC_FUNCTION(float16, fmodf16, (float16 x, float16 y)) {
- return fputil::generic::FMod<float16>::eval(x, y);
+ return fputil::generic::FMod<float16, uint32_t>::eval(x, y);
}
} // namespace LIBC_NAMESPACE
>From dd51e8bf5794dbe8c5bfbb4cde55204d12199b36 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 6 Jun 2024 20:25:50 +0200
Subject: [PATCH 3/4] [libc][math][c23] Checkout MPFRUtils.cpp from branch
libc-math-ceilf16-mpfr-tests
---
libc/utils/MPFRWrapper/MPFRUtils.cpp | 39 +++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 18a8ac044a9bb..a9177fa050f86 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -12,6 +12,7 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/fpbits_str.h"
+#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FPMatcher.h"
#include "hdr/math_macros.h"
@@ -30,6 +31,12 @@ namespace mpfr {
// precision compared to the floating point precision.
template <typename T> struct ExtraPrecision;
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template <> struct ExtraPrecision<float16> {
+ static constexpr unsigned int VALUE = 128;
+};
+#endif
+
template <> struct ExtraPrecision<float> {
static constexpr unsigned int VALUE = 128;
};
@@ -85,9 +92,16 @@ class MPFRNumber {
// We use explicit EnableIf specializations to disallow implicit
// conversions. Implicit conversions can potentially lead to loss of
- // precision.
+ // precision. We exceptionally allow implicit conversions from float16
+ // to float, as the MPFR API does not support float16, thus requiring
+ // conversion to a higher-precision format.
template <typename XType,
- cpp::enable_if_t<cpp::is_same_v<float, XType>, int> = 0>
+ cpp::enable_if_t<cpp::is_same_v<float, XType>
+#ifdef LIBC_TYPES_HAS_FLOAT16
+ || cpp::is_same_v<float16, XType>
+#endif
+ ,
+ int> = 0>
explicit MPFRNumber(XType x,
unsigned int precision = ExtraPrecision<XType>::VALUE,
RoundingMode rounding = RoundingMode::Nearest)
@@ -529,8 +543,8 @@ class MPFRNumber {
// If the control reaches here, it means that this number and input are
// of the same sign but different exponent. In such a case, ULP error is
// calculated as sum of two parts.
- thisAsT = std::abs(thisAsT);
- input = std::abs(input);
+ thisAsT = FPBits<T>(thisAsT).abs().get_val();
+ input = FPBits<T>(input).abs().get_val();
T min = thisAsT > input ? input : thisAsT;
T max = thisAsT > input ? thisAsT : input;
int minExponent = FPBits<T>(min).get_exponent();
@@ -585,6 +599,14 @@ template <> long double MPFRNumber::as<long double>() const {
return mpfr_get_ld(value, mpfr_rounding);
}
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template <> float16 MPFRNumber::as<float16>() const {
+ // TODO: Either prove that this cast won't cause double-rounding errors, or
+ // find a better way to get a float16.
+ return static_cast<float16>(mpfr_get_d(value, mpfr_rounding));
+}
+#endif
+
namespace internal {
template <typename InputType>
@@ -763,6 +785,10 @@ template void explain_unary_operation_single_output_error<double>(
Operation op, double, double, double, RoundingMode);
template void explain_unary_operation_single_output_error<long double>(
Operation op, long double, long double, double, RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template void explain_unary_operation_single_output_error<float16>(
+ Operation op, float16, float16, double, RoundingMode);
+#endif
template <typename T>
void explain_unary_operation_two_outputs_error(
@@ -942,6 +968,11 @@ template bool compare_unary_operation_single_output<double>(Operation, double,
RoundingMode);
template bool compare_unary_operation_single_output<long double>(
Operation, long double, long double, double, RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template bool compare_unary_operation_single_output<float16>(Operation, float16,
+ float16, double,
+ RoundingMode);
+#endif
template <typename T>
bool compare_unary_operation_two_outputs(Operation op, T input,
>From 7e0de473b36729b6d2655b7bcca79b00a9d9bdb2 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 6 Jun 2024 20:29:46 +0200
Subject: [PATCH 4/4] [libc][math][c23] Add MPFR exhaustive test for fmodf16
---
libc/test/src/math/exhaustive/CMakeLists.txt | 15 ++
.../src/math/exhaustive/exhaustive_test.h | 150 ++++++++++++++++++
.../test/src/math/exhaustive/fmodf16_test.cpp | 41 +++++
libc/utils/MPFRWrapper/MPFRUtils.cpp | 8 +
4 files changed, 214 insertions(+)
create mode 100644 libc/test/src/math/exhaustive/fmodf16_test.cpp
diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 938e519aff084..d45528ce26da7 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -277,6 +277,21 @@ add_fp_unittest(
libc.src.__support.FPUtil.generic.fmod
)
+add_fp_unittest(
+ fmodf16_test
+ NO_RUN_POSTBUILD
+ NEED_MPFR
+ SUITE
+ libc_math_exhaustive_tests
+ SRCS
+ fmodf16_test.cpp
+ DEPENDS
+ .exhaustive_test
+ libc.src.math.fmodf16
+ LINK_LIBRARIES
+ -lpthread
+)
+
add_fp_unittest(
coshf_test
NO_RUN_POSTBUILD
diff --git a/libc/test/src/math/exhaustive/exhaustive_test.h b/libc/test/src/math/exhaustive/exhaustive_test.h
index c4ae382688a03..2c318d71ab66e 100644
--- a/libc/test/src/math/exhaustive/exhaustive_test.h
+++ b/libc/test/src/math/exhaustive/exhaustive_test.h
@@ -8,6 +8,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
@@ -68,6 +69,43 @@ struct UnaryOpChecker : public virtual LIBC_NAMESPACE::testing::Test {
}
};
+template <typename T> using BinaryOp = T(T, T);
+
+template <typename T, mpfr::Operation Op, BinaryOp<T> Func>
+struct BinaryOpChecker : public virtual LIBC_NAMESPACE::testing::Test {
+ using FloatType = T;
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<FloatType>;
+ using StorageType = typename FPBits::StorageType;
+
+ static constexpr BinaryOp<FloatType> *FUNC = Func;
+
+ // Check in a range, return the number of failures.
+ uint64_t check(StorageType x_start, StorageType x_stop, StorageType y_start,
+ StorageType y_stop, mpfr::RoundingMode rounding) {
+ mpfr::ForceRoundingMode r(rounding);
+ if (!r.success)
+ return (x_stop > x_start || y_stop > y_start);
+ StorageType xbits = x_start;
+ uint64_t failed = 0;
+ do {
+ FloatType x = FPBits(xbits).get_val();
+ StorageType ybits = y_start;
+ do {
+ FloatType y = FPBits(ybits).get_val();
+ mpfr::BinaryInput<FloatType> input{x, y};
+ bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(Op, input, FUNC(x, y),
+ 0.5, rounding);
+ failed += (!correct);
+ // Uncomment to print out failed values.
+ // if (!correct) {
+ // TEST_MPFR_MATCH(Op::Operation, x, Op::func(x, y), 0.5, rounding);
+ // }
+ } while (ybits++ < y_stop);
+ } while (xbits++ < x_stop);
+ return failed;
+ }
+};
+
// Checker class needs inherit from LIBC_NAMESPACE::testing::Test and provide
// StorageType and check method.
template <typename Checker>
@@ -167,6 +205,118 @@ struct LlvmLibcExhaustiveMathTest
};
};
+template <typename Checker>
+struct LlvmLibcBinaryInputExhaustiveMathTest
+ : public virtual LIBC_NAMESPACE::testing::Test,
+ public Checker {
+ using FloatType = typename Checker::FloatType;
+ using FPBits = typename Checker::FPBits;
+ using StorageType = typename Checker::StorageType;
+
+ static constexpr StorageType Increment = (1 << 2);
+
+ // Break [start, stop) into `nthreads` subintervals and apply *check to each
+ // subinterval in parallel.
+ void test_full_range(StorageType x_start, StorageType x_stop,
+ StorageType y_start, StorageType y_stop,
+ mpfr::RoundingMode rounding) {
+ int n_threads = std::thread::hardware_concurrency();
+ std::vector<std::thread> thread_list;
+ std::mutex mx_cur_val;
+ int current_percent = -1;
+ StorageType current_value = x_start;
+ std::atomic<uint64_t> failed(0);
+
+ for (int i = 0; i < n_threads; ++i) {
+ thread_list.emplace_back([&, this]() {
+ while (true) {
+ StorageType range_begin, range_end;
+ int new_percent = -1;
+ {
+ std::lock_guard<std::mutex> lock(mx_cur_val);
+ if (current_value == x_stop)
+ return;
+
+ range_begin = current_value;
+ if (x_stop >= Increment && x_stop - Increment >= current_value) {
+ range_end = current_value + Increment;
+ } else {
+ range_end = x_stop;
+ }
+ current_value = range_end;
+ int pc = 100.0 * (range_end - x_start) / (x_stop - x_start);
+ if (current_percent != pc) {
+ new_percent = pc;
+ current_percent = pc;
+ }
+ }
+ if (new_percent >= 0) {
+ std::stringstream msg;
+ msg << new_percent << "% is in process \r";
+ std::cout << msg.str() << std::flush;
+ }
+
+ uint64_t failed_in_range =
+ Checker::check(range_begin, range_end, y_start, y_stop, rounding);
+ if (failed_in_range > 0) {
+ using T = LIBC_NAMESPACE::cpp::conditional_t<
+ LIBC_NAMESPACE::cpp::is_same_v<FloatType, float16>, float,
+ FloatType>;
+ std::stringstream msg;
+ msg << "Test failed for " << std::dec << failed_in_range
+ << " inputs in range: " << range_begin << " to " << range_end
+ << " [0x" << std::hex << range_begin << ", 0x" << range_end
+ << "), [" << std::hexfloat
+ << static_cast<T>(FPBits(range_begin).get_val()) << ", "
+ << static_cast<T>(FPBits(range_end).get_val()) << ")\n";
+ std::cerr << msg.str() << std::flush;
+
+ failed.fetch_add(failed_in_range);
+ }
+ }
+ });
+ }
+
+ for (auto &thread : thread_list) {
+ if (thread.joinable()) {
+ thread.join();
+ }
+ }
+
+ std::cout << std::endl;
+ std::cout << "Test " << ((failed > 0) ? "FAILED" : "PASSED") << std::endl;
+ ASSERT_EQ(failed.load(), uint64_t(0));
+ }
+
+ void test_full_range_all_roundings(StorageType x_start, StorageType x_stop,
+ StorageType y_start, StorageType y_stop) {
+ test_full_range(x_start, x_stop, y_start, y_stop,
+ mpfr::RoundingMode::Nearest);
+
+ std::cout << "-- Testing for FE_UPWARD in x range [0x" << std::hex
+ << x_start << ", 0x" << x_stop << ") y range [0x" << std::hex
+ << y_start << ", 0x" << y_stop << ") --" << std::dec << std::endl;
+ test_full_range(x_start, x_stop, y_start, y_stop,
+ mpfr::RoundingMode::Upward);
+
+ std::cout << "-- Testing for FE_DOWNWARD in x range [0x" << std::hex
+ << x_start << ", 0x" << x_stop << ") y range [0x" << std::hex
+ << y_start << ", 0x" << y_stop << ") --" << std::dec << std::endl;
+ test_full_range(x_start, x_stop, y_start, y_stop,
+ mpfr::RoundingMode::Downward);
+
+ std::cout << "-- Testing for FE_TOWARDZERO in x range [0x" << std::hex
+ << x_start << ", 0x" << x_stop << ") y range [0x" << std::hex
+ << y_start << ", 0x" << y_stop << ") --" << std::dec << std::endl;
+ test_full_range(x_start, x_stop, y_start, y_stop,
+ mpfr::RoundingMode::TowardZero);
+ };
+};
+
template <typename FloatType, mpfr::Operation Op, UnaryOp<FloatType> Func>
using LlvmLibcUnaryOpExhaustiveMathTest =
LlvmLibcExhaustiveMathTest<UnaryOpChecker<FloatType, Op, Func>>;
+
+template <typename FloatType, mpfr::Operation Op, BinaryOp<FloatType> Func>
+using LlvmLibcBinaryOpExhaustiveMathTest =
+ LlvmLibcBinaryInputExhaustiveMathTest<BinaryOpChecker<FloatType, Op, Func>>;
diff --git a/libc/test/src/math/exhaustive/fmodf16_test.cpp b/libc/test/src/math/exhaustive/fmodf16_test.cpp
new file mode 100644
index 0000000000000..067cec969a4f7
--- /dev/null
+++ b/libc/test/src/math/exhaustive/fmodf16_test.cpp
@@ -0,0 +1,41 @@
+//===-- Exhaustive test for fmodf16 ---------------------------------------===//
+//
+// 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 "exhaustive_test.h"
+#include "src/math/fmodf16.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+using LlvmLibcFmodf16ExhaustiveTest =
+ LlvmLibcBinaryOpExhaustiveMathTest<float16, mpfr::Operation::Fmod,
+ LIBC_NAMESPACE::fmodf16>;
+
+// Range: [0, Inf];
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7c00U;
+
+// Range: [-Inf, 0];
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xfc00U;
+
+TEST_F(LlvmLibcFmodf16ExhaustiveTest, PostivePositiveRange) {
+ test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcFmodf16ExhaustiveTest, PostiveNegativeRange) {
+ test_full_range_all_roundings(POS_START, POS_STOP, NEG_START, NEG_STOP);
+}
+
+TEST_F(LlvmLibcFmodf16ExhaustiveTest, NegativePositiveRange) {
+ test_full_range_all_roundings(NEG_START, NEG_STOP, POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcFmodf16ExhaustiveTest, NegativeNegativeRange) {
+ test_full_range_all_roundings(NEG_START, NEG_STOP, POS_START, POS_STOP);
+}
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index a9177fa050f86..2ac6874a65464 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -907,6 +907,10 @@ template void explain_binary_operation_one_output_error<double>(
template void explain_binary_operation_one_output_error<long double>(
Operation, const BinaryInput<long double> &, long double, double,
RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template void explain_binary_operation_one_output_error<float16>(
+ Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
+#endif
template <typename T>
void explain_ternary_operation_one_output_error(Operation op,
@@ -1053,6 +1057,10 @@ template bool compare_binary_operation_one_output<double>(
template bool compare_binary_operation_one_output<long double>(
Operation, const BinaryInput<long double> &, long double, double,
RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template bool compare_binary_operation_one_output<float16>(
+ Operation, const BinaryInput<float16> &, float16, double, RoundingMode);
+#endif
template <typename T>
bool compare_ternary_operation_one_output(Operation op,
More information about the libc-commits
mailing list