-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc] Add MPFR testing infra for float128. #119499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libc Author: None (lntue) ChangesFull diff: https://github.com/llvm/llvm-project/pull/119499.diff 6 Files Affected:
diff --git a/libc/src/__support/complex_type.h b/libc/src/__support/complex_type.h
index a6207d38d0eb57..d505d46d1a73f1 100644
--- a/libc/src/__support/complex_type.h
+++ b/libc/src/__support/complex_type.h
@@ -36,8 +36,7 @@ template <> struct make_complex<float16> {
using type = cfloat16;
};
#endif
-#if defined(LIBC_TYPES_HAS_CFLOAT128) && \
- !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
+#ifdef LIBC_TYPES_CFLOAT128_IS_NOT_COMPLEX_LONG_DOUBLE
template <> struct make_complex<float128> {
using type = cfloat128;
};
@@ -62,8 +61,7 @@ template <> struct make_real<cfloat16> {
using type = float16;
};
#endif
-#if defined(LIBC_TYPES_HAS_CFLOAT128) && \
- !defined(LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE)
+#ifdef LIBC_TYPES_CFLOAT128_IS_NOT_COMPLEX_LONG_DOUBLE
template <> struct make_real<cfloat128> {
using type = float128;
};
@@ -71,7 +69,7 @@ template <> struct make_real<cfloat128> {
template <typename T> using make_real_t = typename make_real<T>::type;
-template <typename T> LIBC_INLINE constexpr T conjugate(T c) {
+template <typename T> LIBC_INLINE static constexpr T conjugate(T c) {
Complex<make_real_t<T>> c_c = cpp::bit_cast<Complex<make_real_t<T>>>(c);
c_c.imag = -c_c.imag;
return cpp::bit_cast<T>(c_c);
diff --git a/libc/src/__support/macros/properties/complex_types.h b/libc/src/__support/macros/properties/complex_types.h
index 3f4a7646649c64..ede4d6b7c7d9de 100644
--- a/libc/src/__support/macros/properties/complex_types.h
+++ b/libc/src/__support/macros/properties/complex_types.h
@@ -22,4 +22,9 @@
// LIBC_TYPES_HAS_CFLOAT128 and 'cfloat128' type are provided by
// "include/llvm-libc-types/cfloat128.h"
+#if defined(LIBC_TYPES_HAS_CFLOAT128) && \
+ !defined(LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE)
+#define LIBC_TYPES_CFLOAT128_IS_NOT_COMPLEX_LONG_DOUBLE
+#endif
+
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CTYPES_H
diff --git a/libc/src/__support/macros/properties/types.h b/libc/src/__support/macros/properties/types.h
index 30c742c007ca19..6293b9d4d292ae 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -31,6 +31,11 @@
#define LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE
#endif
+#if defined(LIBC_TYPES_HAS_FLOAT128) && \
+ !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
+#define LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+#endif
+
// int64 / uint64 support
#if defined(UINT64_MAX)
#define LIBC_TYPES_HAS_INT64
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index ea75720df4f430..02e974f34abf88 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -1549,6 +1549,19 @@ add_fp_unittest(
libc.src.math.sqrtf16
)
+add_fp_unittest(
+ sqrtf128_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ sqrtf128_test.cpp
+ HDRS
+ SqrtTest.h
+ DEPENDS
+ libc.src.math.sqrtf128
+)
+
add_fp_unittest(
generic_sqrtf_test
NEED_MPFR
diff --git a/libc/test/src/math/sqrtf128_test.cpp b/libc/test/src/math/sqrtf128_test.cpp
new file mode 100644
index 00000000000000..25229f834d33c7
--- /dev/null
+++ b/libc/test/src/math/sqrtf128_test.cpp
@@ -0,0 +1,43 @@
+//===-- Unittests for sqrtf128 --------------------------------------------===//
+//
+// 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 "SqrtTest.h"
+
+#include "src/math/sqrtf128.h"
+
+#include "src/__support/integer_literals.h"
+
+LIST_SQRT_TESTS(float128, LIBC_NAMESPACE::sqrtf128)
+
+TEST_F(LlvmLibcSqrtTest, SpecialInputs) {
+ constexpr float128 INPUTS[] = {
+ 0x0.000000dee2f5b6a26c8f07f05442p-16382q,
+ 0x0.000000c86d174c5ad8ae54a548e7p-16382q,
+ 0x0.000020ab15cfe0b8e488e128f535p-16382q,
+ 0x0.0000219e97732a9970f2511989bap-16382q,
+ 0x0.000026e477546ae99ef57066f9fdp-16382q,
+ 0x0.00002d0f88d27a496b3e533f5067p-16382q,
+ 0x1.0000000000000000000000000001p+0q,
+ 0x1.0000000000000000000000000003p+0q,
+ 0x1.0000000000000000000000000005p+0q,
+ 0x1.2af17a4ae6f93d11310c49c11b59p+0q,
+ 0x1.c4f5074269525063a26051a0ad27p+0q,
+ 0x1.035cb5f298a801dc4be9b1f8cd97p+1q,
+ 0x1.274be02380427e709beab4dedeb4p+1q,
+ 0x1.64e797cfdbaa3f7e2f33279dbc6p+1q,
+ 0x1.d78d8352b48608b510bfd5c75315p+1q,
+ 0x1.fffffffffffffffffffffffffffbp+1q,
+ 0x1.fffffffffffffffffffffffffffdp+1q,
+ 0x1.ffffffffffffffffffffffffffffp+1q,
+ };
+
+ for (auto input : INPUTS) {
+ ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sqrt, input,
+ LIBC_NAMESPACE::sqrtf128(input), 0.5);
+ }
+}
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 00592c5cb15f38..0dac497bb779af 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -22,6 +22,13 @@
#include "mpfr_inc.h"
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+extern "C" {
+int mpfr_set_float128(mpfr_ptr, float128, mpfr_rnd_t);
+float128 mpfr_get_float128(mpfr_srcptr, mpfr_rnd_t);
+}
+#endif
+
template <typename T> using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
namespace LIBC_NAMESPACE_DECL {
@@ -47,8 +54,18 @@ template <> struct ExtraPrecision<double> {
};
template <> struct ExtraPrecision<long double> {
+#ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128
+ static constexpr unsigned int VALUE = 512;
+#else
static constexpr unsigned int VALUE = 256;
+#endif
+};
+
+#if defined(LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE)
+template <> struct ExtraPrecision<float128> {
+ static constexpr unsigned int VALUE = 512;
};
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
// If the ulp tolerance is less than or equal to 0.5, we would check that the
// result is rounded correctly with respect to the rounding mode by using the
@@ -134,6 +151,19 @@ class MPFRNumber {
mpfr_set_ld(value, x, mpfr_rounding);
}
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+ template <typename XType,
+ cpp::enable_if_t<cpp::is_same_v<float128, XType>, int> = 0>
+ explicit MPFRNumber(XType x,
+ unsigned int precision = ExtraPrecision<XType>::VALUE,
+ RoundingMode rounding = RoundingMode::Nearest)
+ : mpfr_precision(precision),
+ mpfr_rounding(get_mpfr_rounding_mode(rounding)) {
+ mpfr_init2(value, mpfr_precision);
+ mpfr_set_float128(value, x, mpfr_rounding);
+ }
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+
template <typename XType,
cpp::enable_if_t<cpp::is_integral_v<XType>, int> = 0>
explicit MPFRNumber(XType x,
@@ -647,7 +677,7 @@ class MPFRNumber {
// These functions are useful for debugging.
template <typename T> T as() const;
- void dump(const char *msg) const { mpfr_printf("%s%.128Rf\n", msg, value); }
+ void dump(const char *msg) const { mpfr_printf("%s%.128g\n", msg, value); }
// Return the ULP (units-in-the-last-place) difference between the
// stored MPFR and a floating point number.
@@ -770,6 +800,13 @@ template <> float16 MPFRNumber::as<float16>() const {
}
#endif
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template <> float128 MPFRNumber::as<float128>() const {
+ return mpfr_get_float128(value, mpfr_rounding);
+}
+
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+
namespace internal {
template <typename InputType>
@@ -997,7 +1034,27 @@ template void explain_unary_operation_single_output_error(Operation op, double,
template void explain_unary_operation_single_output_error(Operation op,
long double, float16,
double, RoundingMode);
-#endif
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template void explain_unary_operation_single_output_error(Operation op,
+ float128, float16,
+ double, RoundingMode);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template void explain_unary_operation_single_output_error(Operation op,
+ float128, float128,
+ double, RoundingMode);
+template void explain_unary_operation_single_output_error(Operation op,
+ float128, float,
+ double, RoundingMode);
+template void explain_unary_operation_single_output_error(Operation op,
+ float128, double,
+ double, RoundingMode);
+template void explain_unary_operation_single_output_error(Operation op,
+ float128, long double,
+ double, RoundingMode);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
template <typename T>
void explain_unary_operation_two_outputs_error(
@@ -1228,7 +1285,25 @@ template bool compare_unary_operation_single_output(Operation, double, float16,
template bool compare_unary_operation_single_output(Operation, long double,
float16, double,
RoundingMode);
-#endif
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template bool compare_unary_operation_single_output(Operation, float128,
+ float16, double,
+ RoundingMode);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template bool compare_unary_operation_single_output(Operation, float128,
+ float128, double,
+ RoundingMode);
+template bool compare_unary_operation_single_output(Operation, float128, float,
+ double, RoundingMode);
+template bool compare_unary_operation_single_output(Operation, float128, double,
+ double, RoundingMode);
+template bool compare_unary_operation_single_output(Operation, float128,
+ long double, double,
+ RoundingMode);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
template <typename T>
bool compare_unary_operation_two_outputs(Operation op, T input,
@@ -1398,9 +1473,14 @@ template <typename T> bool round_to_long(T x, long &result) {
template bool round_to_long<float>(float, long &);
template bool round_to_long<double>(double, long &);
template bool round_to_long<long double>(long double, long &);
+
#ifdef LIBC_TYPES_HAS_FLOAT16
template bool round_to_long<float16>(float16, long &);
-#endif
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template bool round_to_long<float128>(float128, long &);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
MPFRNumber mpfr(x);
@@ -1410,9 +1490,14 @@ template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
template bool round_to_long<float>(float, RoundingMode, long &);
template bool round_to_long<double>(double, RoundingMode, long &);
template bool round_to_long<long double>(long double, RoundingMode, long &);
+
#ifdef LIBC_TYPES_HAS_FLOAT16
template bool round_to_long<float16>(float16, RoundingMode, long &);
-#endif
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template bool round_to_long<float128>(float128, RoundingMode, long &);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
template <typename T> T round(T x, RoundingMode mode) {
MPFRNumber mpfr(x);
@@ -1423,9 +1508,14 @@ template <typename T> T round(T x, RoundingMode mode) {
template float round<float>(float, RoundingMode);
template double round<double>(double, RoundingMode);
template long double round<long double>(long double, RoundingMode);
+
#ifdef LIBC_TYPES_HAS_FLOAT16
template float16 round<float16>(float16, RoundingMode);
-#endif
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+template float128 round<float128>(float128, RoundingMode);
+#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
} // namespace mpfr
} // namespace testing
|
libc/src/__support/complex_type.h
Outdated
template <> struct make_real<cfloat128> { | ||
using type = float128; | ||
}; | ||
#endif | ||
|
||
template <typename T> using make_real_t = typename make_real<T>::type; | ||
|
||
template <typename T> LIBC_INLINE constexpr T conjugate(T c) { | ||
template <typename T> LIBC_INLINE static constexpr T conjugate(T c) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If conjugate
is already in a namespace, does it still need static
linkage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to make conj to be local to the TU?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just playing around to see if this symbol is exposed in the static archives and object files or not. Reverted it back to before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think more generally, we can probably remove this pattern throughout the codebase; I've been noticing that we're not super consistent.
No description provided.