diff --git a/libc/src/__support/complex_type.h b/libc/src/__support/complex_type.h index a6207d38d0eb5..5dadfd20a0051 100644 --- a/libc/src/__support/complex_type.h +++ b/libc/src/__support/complex_type.h @@ -36,8 +36,7 @@ template <> struct make_complex { 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 { using type = cfloat128; }; @@ -62,8 +61,7 @@ template <> struct make_real { 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 { using type = float128; }; diff --git a/libc/src/__support/macros/properties/complex_types.h b/libc/src/__support/macros/properties/complex_types.h index 3f4a7646649c6..ede4d6b7c7d9d 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 30c742c007ca1..6293b9d4d292a 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 ea75720df4f43..02e974f34abf8 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 0000000000000..25229f834d33c --- /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 00592c5cb15f3..0dac497bb779a 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 using FPBits = LIBC_NAMESPACE::fputil::FPBits; namespace LIBC_NAMESPACE_DECL { @@ -47,8 +54,18 @@ template <> struct ExtraPrecision { }; template <> struct ExtraPrecision { +#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 { + 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 , int> = 0> + explicit MPFRNumber(XType x, + unsigned int precision = ExtraPrecision::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 , int> = 0> explicit MPFRNumber(XType x, @@ -647,7 +677,7 @@ class MPFRNumber { // These functions are useful for debugging. template 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() const { } #endif +#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE +template <> float128 MPFRNumber::as() const { + return mpfr_get_float128(value, mpfr_rounding); +} + +#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE + namespace internal { template @@ -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 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 bool compare_unary_operation_two_outputs(Operation op, T input, @@ -1398,9 +1473,14 @@ template bool round_to_long(T x, long &result) { template bool round_to_long(float, long &); template bool round_to_long(double, long &); template bool round_to_long(long double, long &); + #ifdef LIBC_TYPES_HAS_FLOAT16 template bool round_to_long(float16, long &); -#endif +#endif // LIBC_TYPES_HAS_FLOAT16 + +#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE +template bool round_to_long(float128, long &); +#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE template bool round_to_long(T x, RoundingMode mode, long &result) { MPFRNumber mpfr(x); @@ -1410,9 +1490,14 @@ template bool round_to_long(T x, RoundingMode mode, long &result) { template bool round_to_long(float, RoundingMode, long &); template bool round_to_long(double, RoundingMode, long &); template bool round_to_long(long double, RoundingMode, long &); + #ifdef LIBC_TYPES_HAS_FLOAT16 template bool round_to_long(float16, RoundingMode, long &); -#endif +#endif // LIBC_TYPES_HAS_FLOAT16 + +#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE +template bool round_to_long(float128, RoundingMode, long &); +#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE template T round(T x, RoundingMode mode) { MPFRNumber mpfr(x); @@ -1423,9 +1508,14 @@ template T round(T x, RoundingMode mode) { template float round(float, RoundingMode); template double round(double, RoundingMode); template long double round(long double, RoundingMode); + #ifdef LIBC_TYPES_HAS_FLOAT16 template float16 round(float16, RoundingMode); -#endif +#endif // LIBC_TYPES_HAS_FLOAT16 + +#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE +template float128 round(float128, RoundingMode); +#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE } // namespace mpfr } // namespace testing