[libc-commits] [libc] [libc] Add MPFR testing infra for float128. (PR #119499)

via libc-commits libc-commits at lists.llvm.org
Tue Dec 10 20:50:40 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: None (lntue)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/119499.diff


6 Files Affected:

- (modified) libc/src/__support/complex_type.h (+3-5) 
- (modified) libc/src/__support/macros/properties/complex_types.h (+5) 
- (modified) libc/src/__support/macros/properties/types.h (+5) 
- (modified) libc/test/src/math/CMakeLists.txt (+13) 
- (added) libc/test/src/math/sqrtf128_test.cpp (+43) 
- (modified) libc/utils/MPFRWrapper/MPFRUtils.cpp (+96-6) 


``````````diff
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

``````````

</details>


https://github.com/llvm/llvm-project/pull/119499


More information about the libc-commits mailing list