From 93dc2d321ac8328625dc2eba4f13054e0dc79002 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Wed, 26 Jun 2024 01:12:15 +0200 Subject: [PATCH 1/8] [libc][math][c23] Add f16fma 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/CMakeLists.txt | 1 + .../__support/FPUtil/generic/CMakeLists.txt | 1 + libc/src/__support/FPUtil/generic/FMA.h | 87 ++----------------- .../FPUtil/generic_hardware/CMakeLists.txt | 10 +++ .../__support/FPUtil/generic_hardware/fma.h | 29 +++++++ libc/src/__support/FPUtil/multiply_add.h | 6 +- libc/src/math/CMakeLists.txt | 1 + libc/src/math/f16fma.h | 20 +++++ libc/src/math/generic/CMakeLists.txt | 13 +++ libc/src/math/generic/f16fma.cpp | 19 ++++ libc/test/src/math/CMakeLists.txt | 15 ++++ libc/test/src/math/f16fma_test.cpp | 21 +++++ libc/test/src/math/smoke/CMakeLists.txt | 12 +++ libc/test/src/math/smoke/f16fma_test.cpp | 13 +++ libc/utils/MPFRWrapper/MPFRUtils.cpp | 6 ++ 19 files changed, 175 insertions(+), 84 deletions(-) create mode 100644 libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt create mode 100644 libc/src/__support/FPUtil/generic_hardware/fma.h create mode 100644 libc/src/math/f16fma.h create mode 100644 libc/src/math/generic/f16fma.cpp create mode 100644 libc/test/src/math/f16fma_test.cpp create mode 100644 libc/test/src/math/smoke/f16fma_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index a875a17f06b3e..f798bf282bf5d 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -506,6 +506,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ceilf16 libc.src.math.copysignf16 libc.src.math.f16divf + libc.src.math.f16fma libc.src.math.f16fmaf libc.src.math.f16sqrtf libc.src.math.fabsf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 34748ff5950ad..9d88cf2b60222 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -537,6 +537,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ceilf16 libc.src.math.copysignf16 libc.src.math.f16divf + libc.src.math.f16fma libc.src.math.f16fmaf libc.src.math.f16sqrtf libc.src.math.fabsf16 diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 95f450ab75960..30079e8410f19 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -126,7 +126,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | f16div | |check| | | | N/A | | 7.12.14.4 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| f16fma | |check| | | | N/A | | 7.12.14.5 | F.10.11 | +| f16fma | |check| | |check| | | N/A | | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 651f49deef4c1..367e6b2887dbe 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -477,6 +477,7 @@ def StdC : StandardSpec<"stdc"> { FunctionSpec<"fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, + GuardedFunctionSpec<"f16fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, FunctionSpec<"fmod", RetValSpec, [ArgSpec, ArgSpec]>, diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 900a7022c3868..0f27b79b059a3 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -227,3 +227,4 @@ add_header_library( ) add_subdirectory(generic) +add_subdirectory(generic_hardware) diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt index 33b2564bfa087..80af697903286 100644 --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -24,6 +24,7 @@ add_header_library( libc.src.__support.CPP.bit libc.src.__support.CPP.limits libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.dyadic_float libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.rounding_mode diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h index 71b150758d419..40a99fc6ca62e 100644 --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -13,6 +13,7 @@ #include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/big_int.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE @@ -106,8 +107,6 @@ LIBC_INLINE cpp::enable_if_t && sizeof(OutType) <= sizeof(InType), OutType> fma(InType x, InType y, InType z) { - using OutFPBits = fputil::FPBits; - using OutStorageType = typename OutFPBits::StorageType; using InFPBits = fputil::FPBits; using InStorageType = typename InFPBits::StorageType; @@ -115,11 +114,7 @@ fma(InType x, InType y, InType z) { constexpr size_t PROD_LEN = 2 * IN_EXPLICIT_MANT_LEN; constexpr size_t TMP_RESULT_LEN = cpp::bit_ceil(PROD_LEN + 1); using TmpResultType = UInt; - - constexpr size_t EXTRA_FRACTION_LEN = - TMP_RESULT_LEN - 1 - OutFPBits::FRACTION_LEN; - constexpr TmpResultType EXTRA_FRACTION_STICKY_MASK = - (TmpResultType(1) << (EXTRA_FRACTION_LEN - 1)) - 1; + using DyadicFloat = DyadicFloat; if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0)) return static_cast(x * y + z); @@ -182,7 +177,6 @@ fma(InType x, InType y, InType z) { constexpr int RESULT_MIN_LEN = PROD_LEN - InFPBits::FRACTION_LEN; z_mant <<= RESULT_MIN_LEN; int z_lsb_exp = z_exp - (InFPBits::FRACTION_LEN + RESULT_MIN_LEN); - bool round_bit = false; bool sticky_bits = false; bool z_shifted = false; @@ -221,85 +215,18 @@ fma(InType x, InType y, InType z) { } } - OutStorageType result = 0; - int r_exp = 0; // Unbiased exponent of the result - - int round_mode = fputil::quick_get_round(); - - // Normalize the result. - if (prod_mant != 0) { - int lead_zeros = cpp::countl_zero(prod_mant); - // Move the leading 1 to the most significant bit. - prod_mant <<= lead_zeros; - prod_lsb_exp -= lead_zeros; - r_exp = prod_lsb_exp + (cpp::numeric_limits::digits - 1) - - InFPBits::EXP_BIAS + OutFPBits::EXP_BIAS; - - if (r_exp > 0) { - // The result is normal. We will shift the mantissa to the right by the - // amount of extra bits compared to the length of the explicit mantissa in - // the output type. The rounding bit then becomes the highest bit that is - // shifted out, and the following lower bits are merged into sticky bits. - round_bit = - (prod_mant & (TmpResultType(1) << (EXTRA_FRACTION_LEN - 1))) != 0; - sticky_bits |= (prod_mant & EXTRA_FRACTION_STICKY_MASK) != 0; - result = static_cast(prod_mant >> EXTRA_FRACTION_LEN); - } else { - if (r_exp < -OutFPBits::FRACTION_LEN) { - // The result is smaller than 1/2 of the smallest denormal number. - sticky_bits = true; // since the result is non-zero. - result = 0; - } else { - // The result is denormal. - TmpResultType mask = TmpResultType(1) << (EXTRA_FRACTION_LEN - r_exp); - round_bit = (prod_mant & mask) != 0; - sticky_bits |= (prod_mant & (mask - 1)) != 0; - if (r_exp > -OutFPBits::FRACTION_LEN) - result = static_cast( - prod_mant >> (EXTRA_FRACTION_LEN + 1 - r_exp)); - else - result = 0; - } - - r_exp = 0; - } - } else { + if (prod_mant == 0) { // When there is exact cancellation, i.e., x*y == -z exactly, return -0.0 if // rounding downward and +0.0 for other rounding modes. - if (round_mode == FE_DOWNWARD) + if (quick_get_round() == FE_DOWNWARD) prod_sign = Sign::NEG; else prod_sign = Sign::POS; } - // Finalize the result. - if (LIBC_UNLIKELY(r_exp >= OutFPBits::MAX_BIASED_EXPONENT)) { - if ((round_mode == FE_TOWARDZERO) || - (round_mode == FE_UPWARD && prod_sign.is_neg()) || - (round_mode == FE_DOWNWARD && prod_sign.is_pos())) { - return OutFPBits::max_normal(prod_sign).get_val(); - } - return OutFPBits::inf(prod_sign).get_val(); - } - - // Remove hidden bit and append the exponent field and sign bit. - result = static_cast( - (result & OutFPBits::FRACTION_MASK) | - (static_cast(r_exp) << OutFPBits::FRACTION_LEN)); - if (prod_sign.is_neg()) - result |= OutFPBits::SIGN_MASK; - - // Rounding. - if (round_mode == FE_TONEAREST) { - if (round_bit && (sticky_bits || ((result & 1) != 0))) - ++result; - } else if ((round_mode == FE_UPWARD && prod_sign.is_pos()) || - (round_mode == FE_DOWNWARD && prod_sign.is_neg())) { - if (round_bit || sticky_bits) - ++result; - } - - return cpp::bit_cast(result); + DyadicFloat result(prod_sign, prod_lsb_exp - InFPBits::EXP_BIAS, prod_mant); + result.mantissa |= sticky_bits; + return result.template as(); } } // namespace generic diff --git a/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt b/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt new file mode 100644 index 0000000000000..a094d7f8a6f00 --- /dev/null +++ b/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt @@ -0,0 +1,10 @@ +add_header_library( + fma + HDRS + fma.h + DEPENDS + libc.src.__support.common + libc.src.__support.macros.properties.cpu_features + FLAGS + FMA_OPT +) diff --git a/libc/src/__support/FPUtil/generic_hardware/fma.h b/libc/src/__support/FPUtil/generic_hardware/fma.h new file mode 100644 index 0000000000000..f878728cd2de5 --- /dev/null +++ b/libc/src/__support/FPUtil/generic_hardware/fma.h @@ -0,0 +1,29 @@ +//===-- Generic hardware implementation of fused multiply-add ---*- 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 LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H +#define LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H + +#include "src/__support/common.h" +#include "src/__support/macros/properties/cpu_features.h" + +namespace LIBC_NAMESPACE::fputil::generic_hardware { + +#ifdef LIBC_TARGET_CPU_HAS_FMA +LIBC_INLINE float fma(float x, float y, float z) { + return __builtin_fmaf(x, y, z); +} + +LIBC_INLINE double fma(double x, double y, double z) { + return __builtin_fma(x, y, z); +} +#endif // LIBC_TARGET_CPU_HAS_FMA + +} // namespace LIBC_NAMESPACE::fputil::generic_hardware + +#endif // LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H diff --git a/libc/src/__support/FPUtil/multiply_add.h b/libc/src/__support/FPUtil/multiply_add.h index 622914e4265c9..9683c526aee72 100644 --- a/libc/src/__support/FPUtil/multiply_add.h +++ b/libc/src/__support/FPUtil/multiply_add.h @@ -39,17 +39,17 @@ multiply_add(T x, T y, T z) { #if defined(LIBC_TARGET_CPU_HAS_FMA) // FMA instructions are available. -#include "FMA.h" +#include "src/__support/FPUtil/generic_hardware/fma.h" namespace LIBC_NAMESPACE { namespace fputil { LIBC_INLINE float multiply_add(float x, float y, float z) { - return fma(x, y, z); + return generic_hardware::fma(x, y, z); } LIBC_INLINE double multiply_add(double x, double y, double z) { - return fma(x, y, z); + return generic_hardware::fma(x, y, z); } } // namespace fputil diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 711cbf8bbfdca..e0a59b33b8fc7 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -101,6 +101,7 @@ add_math_entrypoint_object(expm1f) add_math_entrypoint_object(f16divf) +add_math_entrypoint_object(f16fma) add_math_entrypoint_object(f16fmaf) add_math_entrypoint_object(f16sqrtf) diff --git a/libc/src/math/f16fma.h b/libc/src/math/f16fma.h new file mode 100644 index 0000000000000..d9505f88f37af --- /dev/null +++ b/libc/src/math/f16fma.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fma ------------------------*- 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_F16FMA_H +#define LLVM_LIBC_SRC_MATH_F16FMA_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fma(double x, double y, double z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMA_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index fc2024c89b5df..29a3cc79dd239 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3744,6 +3744,19 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + f16fma + SRCS + f16fma.cpp + HDRS + ../f16fma.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O0 -ggdb3 +) + add_entrypoint_object( f16fmaf SRCS diff --git a/libc/src/math/generic/f16fma.cpp b/libc/src/math/generic/f16fma.cpp new file mode 100644 index 0000000000000..10ee028c06930 --- /dev/null +++ b/libc/src/math/generic/f16fma.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16fma 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/f16fma.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fma, (double x, double y, double z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index ba588662f469e..ab3b155f0f92b 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1903,6 +1903,21 @@ add_fp_unittest( libc.src.math.f16divf ) +add_fp_unittest( + f16fma_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16fma_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fma + libc.src.stdlib.rand + libc.src.stdlib.srand +) + add_fp_unittest( f16fmaf_test NEED_MPFR diff --git a/libc/test/src/math/f16fma_test.cpp b/libc/test/src/math/f16fma_test.cpp new file mode 100644 index 0000000000000..d684c4f304fbc --- /dev/null +++ b/libc/test/src/math/f16fma_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for f16fma ----------------------------------------------===// +// +// 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 "FmaTest.h" + +#include "src/math/f16fma.h" + +using LlvmLibcF16fmaTest = FmaTestTemplate; + +TEST_F(LlvmLibcF16fmaTest, SubnormalRange) { + test_subnormal_range(&LIBC_NAMESPACE::f16fma); +} + +TEST_F(LlvmLibcF16fmaTest, NormalRange) { + test_normal_range(&LIBC_NAMESPACE::f16fma); +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index ee99fb96a52ce..21e52a917349c 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3644,6 +3644,18 @@ add_fp_unittest( libc.src.math.f16divf ) +add_fp_unittest( + f16fma_test + SUITE + libc-math-smoke-tests + SRCS + f16fma_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fma +) + add_fp_unittest( f16fmaf_test SUITE diff --git a/libc/test/src/math/smoke/f16fma_test.cpp b/libc/test/src/math/smoke/f16fma_test.cpp new file mode 100644 index 0000000000000..2e46b5bdd4682 --- /dev/null +++ b/libc/test/src/math/smoke/f16fma_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fma ----------------------------------------------===// +// +// 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 "FmaTest.h" + +#include "src/math/f16fma.h" + +LIST_NARROWING_FMA_TESTS(float16, double, LIBC_NAMESPACE::f16fma) diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index 521c2658b327a..d1c814b6bf18f 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -977,6 +977,8 @@ explain_ternary_operation_one_output_error(Operation, #ifdef LIBC_TYPES_HAS_FLOAT16 template void explain_ternary_operation_one_output_error( Operation, const TernaryInput &, float16, double, RoundingMode); +template void explain_ternary_operation_one_output_error( + Operation, const TernaryInput &, float16, double, RoundingMode); #endif template @@ -1124,6 +1126,10 @@ template bool compare_ternary_operation_one_output(Operation, const TernaryInput &, float16, double, RoundingMode); +template bool compare_ternary_operation_one_output(Operation, + const TernaryInput &, + float16, double, + RoundingMode); #endif } // namespace internal From 83bb31e2fd1adf763a5af2c9c814a5145577a16f Mon Sep 17 00:00:00 2001 From: OverMighty Date: Wed, 26 Jun 2024 14:25:47 +0200 Subject: [PATCH 2/8] fixup! [libc][math][c23] Add f16fma C23 math function Update FPUtil/CMakeLists.txt to fix circular dependency. --- libc/src/__support/FPUtil/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 0f27b79b059a3..7b52872f5f5c3 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -154,7 +154,7 @@ add_header_library( HDRS multiply_add.h DEPENDS - .fma + libc.src.__support.FPUtil.generic_hardware.fma libc.src.__support.common ) From b394739aa2b0b781350cad98120fccac9f554f4f Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 14:29:40 +0200 Subject: [PATCH 3/8] fixup! fixup! [libc][math][c23] Add f16fma C23 math function Fix conversion to output type. --- libc/src/__support/FPUtil/dyadic_float.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h index 1e1bec676d444..fb1b22467f940 100644 --- a/libc/src/__support/FPUtil/dyadic_float.h +++ b/libc/src/__support/FPUtil/dyadic_float.h @@ -156,13 +156,13 @@ template struct DyadicFloat { // d_lo is denormal, but the output is normal. int scale_up_exponent = 1 - exp_lo; T scale_up_factor = - FPBits::create_value(sign, + FPBits::create_value(Sign::POS, static_cast( FPBits::EXP_BIAS + scale_up_exponent), IMPLICIT_MASK) .get_val(); T scale_down_factor = - FPBits::create_value(sign, + FPBits::create_value(Sign::POS, static_cast( FPBits::EXP_BIAS - scale_up_exponent), IMPLICIT_MASK) From 32cd1b07e9a1aed010639e4874a41daa77d65214 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 14:49:54 +0200 Subject: [PATCH 4/8] [libc][math][c23] Add f16fmaf128 C23 math function --- libc/config/linux/aarch64/entrypoints.txt | 7 +++++++ libc/config/linux/x86_64/entrypoints.txt | 7 +++++++ libc/docs/math/index.rst | 2 +- .../include/llvm-libc-macros/float16-macros.h | 8 ++++++++ libc/spec/stdc.td | 1 + libc/src/math/CMakeLists.txt | 1 + libc/src/math/f16fmaf128.h | 20 +++++++++++++++++++ libc/src/math/generic/CMakeLists.txt | 13 ++++++++++++ libc/src/math/generic/f16fmaf128.cpp | 19 ++++++++++++++++++ libc/test/src/math/smoke/CMakeLists.txt | 12 +++++++++++ libc/test/src/math/smoke/f16fmaf128_test.cpp | 13 ++++++++++++ 11 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 libc/src/math/f16fmaf128.h create mode 100644 libc/src/math/generic/f16fmaf128.cpp create mode 100644 libc/test/src/math/smoke/f16fmaf128_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index f798bf282bf5d..587869580f39e 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -559,6 +559,13 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 ) + + if(LIBC_TYPES_HAS_FLOAT128) + list(APPEND TARGET_LIBM_ENTRYPOINTS + # math.h C23 mixed _Float16 and _Float128 entrypoints + libc.src.math.f16fma128 + ) + endif() endif() if(LIBC_TYPES_HAS_FLOAT128) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 9d88cf2b60222..9c602b2a3704a 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -588,6 +588,13 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 ) + + if(LIBC_TYPES_HAS_FLOAT128) + list(APPEND TARGET_LIBM_ENTRYPOINTS + # math.h C23 mixed _Float16 and _Float128 entrypoints + libc.src.math.f16fma128 + ) + endif() endif() if(LIBC_TYPES_HAS_FLOAT128) diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 30079e8410f19..fdcbf33d7df56 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -126,7 +126,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | f16div | |check| | | | N/A | | 7.12.14.4 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| f16fma | |check| | |check| | | N/A | | 7.12.14.5 | F.10.11 | +| f16fma | |check| | |check| | | N/A | |check| | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h index e7d8d93bca1b6..d84619d5cc5c2 100644 --- a/libc/include/llvm-libc-macros/float16-macros.h +++ b/libc/include/llvm-libc-macros/float16-macros.h @@ -9,10 +9,18 @@ #ifndef LLVM_LIBC_MACROS_FLOAT16_MACROS_H #define LLVM_LIBC_MACROS_FLOAT16_MACROS_H +#include "llvm-libc-types/float128.h" + #if defined(__FLT16_MANT_DIG__) && \ (!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \ !defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) #define LIBC_TYPES_HAS_FLOAT16 + +// TODO: This would no longer be required if HdrGen let us guard function +// declarations with multiple macros. +#ifdef LIBC_TYPES_HAS_FLOAT128 +#define LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128 +#endif // LIBC_TYPES_HAS_FLOAT128 #endif #endif // LLVM_LIBC_MACROS_FLOAT16_MACROS_H diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 367e6b2887dbe..0e347a91057d8 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -479,6 +479,7 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"f16fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16fmaf128", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, FunctionSpec<"fmod", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"fmodf", RetValSpec, [ArgSpec, ArgSpec]>, diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index e0a59b33b8fc7..9ed843aaa5d93 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -103,6 +103,7 @@ add_math_entrypoint_object(f16divf) add_math_entrypoint_object(f16fma) add_math_entrypoint_object(f16fmaf) +add_math_entrypoint_object(f16fmaf128) add_math_entrypoint_object(f16sqrtf) diff --git a/libc/src/math/f16fmaf128.h b/libc/src/math/f16fmaf128.h new file mode 100644 index 0000000000000..9203b4d30d212 --- /dev/null +++ b/libc/src/math/f16fmaf128.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fmaf128 --------------------*- 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_F16FMAF128_H +#define LLVM_LIBC_SRC_MATH_F16FMAF128_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fmaf128(float128 x, float128 y, float128 z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMAF128_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 29a3cc79dd239..9dfee2d0f90a9 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3770,6 +3770,19 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + f16fmaf128 + SRCS + f16fmaf128.cpp + HDRS + ../f16fmaf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( f16sqrtf SRCS diff --git a/libc/src/math/generic/f16fmaf128.cpp b/libc/src/math/generic/f16fmaf128.cpp new file mode 100644 index 0000000000000..5b2f801cf21fa --- /dev/null +++ b/libc/src/math/generic/f16fmaf128.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16fmaf128 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/f16fmaf128.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fmaf128, (float128 x, float128 y, float128 z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 21e52a917349c..7ccff3467ead2 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3668,6 +3668,18 @@ add_fp_unittest( libc.src.math.f16fmaf ) +add_fp_unittest( + f16fmaf128_test + SUITE + libc-math-smoke-tests + SRCS + f16fmaf128_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmaf128 +) + add_fp_unittest( f16sqrtf_test SUITE diff --git a/libc/test/src/math/smoke/f16fmaf128_test.cpp b/libc/test/src/math/smoke/f16fmaf128_test.cpp new file mode 100644 index 0000000000000..ea4003bc5f77e --- /dev/null +++ b/libc/test/src/math/smoke/f16fmaf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmaf128 ------------------------------------------===// +// +// 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 "FmaTest.h" + +#include "src/math/f16fmaf128.h" + +LIST_NARROWING_FMA_TESTS(float16, float128, LIBC_NAMESPACE::f16fmaf128) From c85a97394524e9df19512f817d0c528296cba340 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 14:59:02 +0200 Subject: [PATCH 5/8] [libc][math][c23] Add f16fmal C23 math function --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/docs/math/index.rst | 2 +- .../include/llvm-libc-macros/float16-macros.h | 2 +- libc/spec/stdc.td | 1 + libc/src/math/CMakeLists.txt | 1 + libc/src/math/f16fmal.h | 20 +++++++++++++++++++ libc/src/math/generic/CMakeLists.txt | 13 ++++++++++++ libc/src/math/generic/f16fmal.cpp | 20 +++++++++++++++++++ libc/test/src/math/CMakeLists.txt | 15 ++++++++++++++ libc/test/src/math/FmaTest.h | 13 +++++++++--- libc/test/src/math/f16fma_test.cpp | 10 +--------- libc/test/src/math/f16fmaf_test.cpp | 10 +--------- libc/test/src/math/f16fmal_test.cpp | 13 ++++++++++++ libc/test/src/math/fmaf_test.cpp | 10 +--------- libc/test/src/math/smoke/CMakeLists.txt | 12 +++++++++++ libc/test/src/math/smoke/f16fmal_test.cpp | 13 ++++++++++++ 17 files changed, 125 insertions(+), 32 deletions(-) create mode 100644 libc/src/math/f16fmal.h create mode 100644 libc/src/math/generic/f16fmal.cpp create mode 100644 libc/test/src/math/f16fmal_test.cpp create mode 100644 libc/test/src/math/smoke/f16fmal_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 587869580f39e..3a53b8ad45ae1 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -508,6 +508,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.f16divf libc.src.math.f16fma libc.src.math.f16fmaf + libc.src.math.f16fmal libc.src.math.f16sqrtf libc.src.math.fabsf16 libc.src.math.fdimf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 9c602b2a3704a..defda2dd15a31 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -539,6 +539,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.f16divf libc.src.math.f16fma libc.src.math.f16fmaf + libc.src.math.f16fmal libc.src.math.f16sqrtf libc.src.math.fabsf16 libc.src.math.fdimf16 diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index fdcbf33d7df56..b19ec3b8d9085 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -126,7 +126,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | f16div | |check| | | | N/A | | 7.12.14.4 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| f16fma | |check| | |check| | | N/A | |check| | 7.12.14.5 | F.10.11 | +| f16fma | |check| | |check| | |check| | N/A | |check| | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h index d84619d5cc5c2..9a11ecc49307e 100644 --- a/libc/include/llvm-libc-macros/float16-macros.h +++ b/libc/include/llvm-libc-macros/float16-macros.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_MACROS_FLOAT16_MACROS_H #define LLVM_LIBC_MACROS_FLOAT16_MACROS_H -#include "llvm-libc-types/float128.h" +#include "../llvm-libc-types/float128.h" #if defined(__FLT16_MANT_DIG__) && \ (!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \ diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 0e347a91057d8..adac7d5932428 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -479,6 +479,7 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"f16fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16fmal", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16fmaf128", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, FunctionSpec<"fmod", RetValSpec, [ArgSpec, ArgSpec]>, diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 9ed843aaa5d93..3dfc4ac94827d 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -103,6 +103,7 @@ add_math_entrypoint_object(f16divf) add_math_entrypoint_object(f16fma) add_math_entrypoint_object(f16fmaf) +add_math_entrypoint_object(f16fmal) add_math_entrypoint_object(f16fmaf128) add_math_entrypoint_object(f16sqrtf) diff --git a/libc/src/math/f16fmal.h b/libc/src/math/f16fmal.h new file mode 100644 index 0000000000000..6f5dd33aa18f6 --- /dev/null +++ b/libc/src/math/f16fmal.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fmal -----------------------*- 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_F16FMAL_H +#define LLVM_LIBC_SRC_MATH_F16FMAL_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fmal(long double x, long double y, long double z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMAL_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 9dfee2d0f90a9..d7c9817fc457b 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3770,6 +3770,19 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + f16fmal + SRCS + f16fmal.cpp + HDRS + ../f16fmal.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( f16fmaf128 SRCS diff --git a/libc/src/math/generic/f16fmal.cpp b/libc/src/math/generic/f16fmal.cpp new file mode 100644 index 0000000000000..067483629a336 --- /dev/null +++ b/libc/src/math/generic/f16fmal.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16fmal 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/f16fmal.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fmal, + (long double x, long double y, long double z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index ab3b155f0f92b..62ffadd12f03b 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1933,6 +1933,21 @@ add_fp_unittest( libc.src.stdlib.srand ) +add_fp_unittest( + f16fmal_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16fmal_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmal + libc.src.stdlib.rand + libc.src.stdlib.srand +) + add_subdirectory(generic) add_subdirectory(smoke) diff --git a/libc/test/src/math/FmaTest.h b/libc/test/src/math/FmaTest.h index 53895e7d633c2..01143331d4ab5 100644 --- a/libc/test/src/math/FmaTest.h +++ b/libc/test/src/math/FmaTest.h @@ -45,9 +45,6 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { static constexpr InStorageType IN_MIN_SUBNORMAL_U = InFPBits::min_subnormal().uintval(); - OutConstants out; - InConstants in; - InStorageType get_random_bit_pattern() { InStorageType bits{0}; for (InStorageType i = 0; i < sizeof(InStorageType) / 2; ++i) { @@ -92,4 +89,14 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { } }; +#define LIST_FMA_TESTS(T, func) \ + using LlvmLibcFmaTest = FmaTestTemplate; \ + TEST_F(LlvmLibcFmaTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcFmaTest, NormalRange) { test_normal_range(&func); } + +#define LIST_NARROWING_FMA_TESTS(OutType, InType, func) \ + using LlvmLibcFmaTest = FmaTestTemplate; \ + TEST_F(LlvmLibcFmaTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcFmaTest, NormalRange) { test_normal_range(&func); } + #endif // LLVM_LIBC_TEST_SRC_MATH_FMATEST_H diff --git a/libc/test/src/math/f16fma_test.cpp b/libc/test/src/math/f16fma_test.cpp index d684c4f304fbc..2e46b5bdd4682 100644 --- a/libc/test/src/math/f16fma_test.cpp +++ b/libc/test/src/math/f16fma_test.cpp @@ -10,12 +10,4 @@ #include "src/math/f16fma.h" -using LlvmLibcF16fmaTest = FmaTestTemplate; - -TEST_F(LlvmLibcF16fmaTest, SubnormalRange) { - test_subnormal_range(&LIBC_NAMESPACE::f16fma); -} - -TEST_F(LlvmLibcF16fmaTest, NormalRange) { - test_normal_range(&LIBC_NAMESPACE::f16fma); -} +LIST_NARROWING_FMA_TESTS(float16, double, LIBC_NAMESPACE::f16fma) diff --git a/libc/test/src/math/f16fmaf_test.cpp b/libc/test/src/math/f16fmaf_test.cpp index e4ca88b8810e1..5e3aec768c191 100644 --- a/libc/test/src/math/f16fmaf_test.cpp +++ b/libc/test/src/math/f16fmaf_test.cpp @@ -10,12 +10,4 @@ #include "src/math/f16fmaf.h" -using LlvmLibcF16fmafTest = FmaTestTemplate; - -TEST_F(LlvmLibcF16fmafTest, SubnormalRange) { - test_subnormal_range(&LIBC_NAMESPACE::f16fmaf); -} - -TEST_F(LlvmLibcF16fmafTest, NormalRange) { - test_normal_range(&LIBC_NAMESPACE::f16fmaf); -} +LIST_NARROWING_FMA_TESTS(float16, float, LIBC_NAMESPACE::f16fmaf) diff --git a/libc/test/src/math/f16fmal_test.cpp b/libc/test/src/math/f16fmal_test.cpp new file mode 100644 index 0000000000000..5394268a9cd8f --- /dev/null +++ b/libc/test/src/math/f16fmal_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmal ---------------------------------------------===// +// +// 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 "FmaTest.h" + +#include "src/math/f16fmal.h" + +LIST_NARROWING_FMA_TESTS(float16, long double, LIBC_NAMESPACE::f16fmal) diff --git a/libc/test/src/math/fmaf_test.cpp b/libc/test/src/math/fmaf_test.cpp index 0e498d46ecfb0..09e9c504b942a 100644 --- a/libc/test/src/math/fmaf_test.cpp +++ b/libc/test/src/math/fmaf_test.cpp @@ -10,12 +10,4 @@ #include "src/math/fmaf.h" -using LlvmLibcFmafTest = FmaTestTemplate; - -TEST_F(LlvmLibcFmafTest, SubnormalRange) { - test_subnormal_range(&LIBC_NAMESPACE::fmaf); -} - -TEST_F(LlvmLibcFmafTest, NormalRange) { - test_normal_range(&LIBC_NAMESPACE::fmaf); -} +LIST_FMA_TESTS(float, LIBC_NAMESPACE::fmaf) diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 7ccff3467ead2..2362ee12bcf41 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3668,6 +3668,18 @@ add_fp_unittest( libc.src.math.f16fmaf ) +add_fp_unittest( + f16fmal_test + SUITE + libc-math-smoke-tests + SRCS + f16fmal_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmal +) + add_fp_unittest( f16fmaf128_test SUITE diff --git a/libc/test/src/math/smoke/f16fmal_test.cpp b/libc/test/src/math/smoke/f16fmal_test.cpp new file mode 100644 index 0000000000000..5394268a9cd8f --- /dev/null +++ b/libc/test/src/math/smoke/f16fmal_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmal ---------------------------------------------===// +// +// 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 "FmaTest.h" + +#include "src/math/f16fmal.h" + +LIST_NARROWING_FMA_TESTS(float16, long double, LIBC_NAMESPACE::f16fmal) From 5892e2ba49d7c6f24c55a991820a6b9772ad9ce4 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 16:29:15 +0200 Subject: [PATCH 6/8] fixup! [libc][math][c23] Add f16fmaf128 C23 math function --- libc/config/linux/aarch64/entrypoints.txt | 2 +- libc/config/linux/x86_64/entrypoints.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 3a53b8ad45ae1..086bd4e26cbf8 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -564,7 +564,7 @@ if(LIBC_TYPES_HAS_FLOAT16) if(LIBC_TYPES_HAS_FLOAT128) list(APPEND TARGET_LIBM_ENTRYPOINTS # math.h C23 mixed _Float16 and _Float128 entrypoints - libc.src.math.f16fma128 + libc.src.math.f16fmaf128 ) endif() endif() diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index defda2dd15a31..8125dcb7a5633 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -593,7 +593,7 @@ if(LIBC_TYPES_HAS_FLOAT16) if(LIBC_TYPES_HAS_FLOAT128) list(APPEND TARGET_LIBM_ENTRYPOINTS # math.h C23 mixed _Float16 and _Float128 entrypoints - libc.src.math.f16fma128 + libc.src.math.f16fmaf128 ) endif() endif() From 427873a7cb547fe1f8b9e328fc83ba1b6824704f Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 17:12:49 +0200 Subject: [PATCH 7/8] fixup! [libc][math][c23] Add f16fma C23 math function Change multiply_add.h to use FMA builtins directly. --- libc/src/__support/FPUtil/CMakeLists.txt | 2 -- .../FPUtil/generic_hardware/CMakeLists.txt | 10 ------- .../__support/FPUtil/generic_hardware/fma.h | 29 ------------------- libc/src/__support/FPUtil/multiply_add.h | 7 +++-- 4 files changed, 4 insertions(+), 44 deletions(-) delete mode 100644 libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt delete mode 100644 libc/src/__support/FPUtil/generic_hardware/fma.h diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 7b52872f5f5c3..84c5f802710c4 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -154,7 +154,6 @@ add_header_library( HDRS multiply_add.h DEPENDS - libc.src.__support.FPUtil.generic_hardware.fma libc.src.__support.common ) @@ -227,4 +226,3 @@ add_header_library( ) add_subdirectory(generic) -add_subdirectory(generic_hardware) diff --git a/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt b/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt deleted file mode 100644 index a094d7f8a6f00..0000000000000 --- a/libc/src/__support/FPUtil/generic_hardware/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_header_library( - fma - HDRS - fma.h - DEPENDS - libc.src.__support.common - libc.src.__support.macros.properties.cpu_features - FLAGS - FMA_OPT -) diff --git a/libc/src/__support/FPUtil/generic_hardware/fma.h b/libc/src/__support/FPUtil/generic_hardware/fma.h deleted file mode 100644 index f878728cd2de5..0000000000000 --- a/libc/src/__support/FPUtil/generic_hardware/fma.h +++ /dev/null @@ -1,29 +0,0 @@ -//===-- Generic hardware implementation of fused multiply-add ---*- 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 LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H -#define LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H - -#include "src/__support/common.h" -#include "src/__support/macros/properties/cpu_features.h" - -namespace LIBC_NAMESPACE::fputil::generic_hardware { - -#ifdef LIBC_TARGET_CPU_HAS_FMA -LIBC_INLINE float fma(float x, float y, float z) { - return __builtin_fmaf(x, y, z); -} - -LIBC_INLINE double fma(double x, double y, double z) { - return __builtin_fma(x, y, z); -} -#endif // LIBC_TARGET_CPU_HAS_FMA - -} // namespace LIBC_NAMESPACE::fputil::generic_hardware - -#endif // LIBC_SRC___SUPPORT_FPUTIL_GENERIC_HARDWARE_FMA_H diff --git a/libc/src/__support/FPUtil/multiply_add.h b/libc/src/__support/FPUtil/multiply_add.h index 9683c526aee72..1b9eee4ace62d 100644 --- a/libc/src/__support/FPUtil/multiply_add.h +++ b/libc/src/__support/FPUtil/multiply_add.h @@ -39,17 +39,18 @@ multiply_add(T x, T y, T z) { #if defined(LIBC_TARGET_CPU_HAS_FMA) // FMA instructions are available. -#include "src/__support/FPUtil/generic_hardware/fma.h" +// We use builtins directly instead of including FMA.h to avoid a circular +// dependency: multiply_add.h -> FMA.h -> generic/FMA.h -> dyadic_float.h. namespace LIBC_NAMESPACE { namespace fputil { LIBC_INLINE float multiply_add(float x, float y, float z) { - return generic_hardware::fma(x, y, z); + return __builtin_fmaf(x, y, z); } LIBC_INLINE double multiply_add(double x, double y, double z) { - return generic_hardware::fma(x, y, z); + return __builtin_fma(x, y, z); } } // namespace fputil From f0170f160f459b5b46f05fb738ce41981a17f851 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Thu, 27 Jun 2024 18:21:07 +0200 Subject: [PATCH 8/8] fixup! [libc][math][c23] Add f16fmal C23 math function --- .../__support/FPUtil/generic/CMakeLists.txt | 1 + libc/src/__support/FPUtil/generic/FMA.h | 45 ++++++++++++++++++- libc/utils/MPFRWrapper/MPFRUtils.cpp | 8 ++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt index 80af697903286..bd8af98473edf 100644 --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -24,6 +24,7 @@ add_header_library( libc.src.__support.CPP.bit libc.src.__support.CPP.limits libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.basic_operations libc.src.__support.FPUtil.dyadic_float libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h index 40a99fc6ca62e..d0a01c3092c42 100644 --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/bit.h" #include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/BasicOperations.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/FPUtil/rounding_mode.h" @@ -107,7 +108,9 @@ LIBC_INLINE cpp::enable_if_t && sizeof(OutType) <= sizeof(InType), OutType> fma(InType x, InType y, InType z) { - using InFPBits = fputil::FPBits; + using OutFPBits = FPBits; + using OutStorageType = typename OutFPBits::StorageType; + using InFPBits = FPBits; using InStorageType = typename InFPBits::StorageType; constexpr int IN_EXPLICIT_MANT_LEN = InFPBits::FRACTION_LEN + 1; @@ -116,6 +119,42 @@ fma(InType x, InType y, InType z) { using TmpResultType = UInt; using DyadicFloat = DyadicFloat; + InFPBits x_bits(x), y_bits(y), z_bits(z); + + if (LIBC_UNLIKELY(x_bits.is_nan() || y_bits.is_nan() || z_bits.is_nan())) { + if (x_bits.is_nan() || y_bits.is_nan()) { + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan() || + z_bits.is_signaling_nan()) + raise_except_if_required(FE_INVALID); + + if (x_bits.is_quiet_nan()) { + InStorageType x_payload = static_cast(getpayload(x)); + if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(x_bits.sign(), + static_cast(x_payload)) + .get_val(); + } + + if (y_bits.is_quiet_nan()) { + InStorageType y_payload = static_cast(getpayload(y)); + if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(y_bits.sign(), + static_cast(y_payload)) + .get_val(); + } + + if (z_bits.is_quiet_nan()) { + InStorageType z_payload = static_cast(getpayload(z)); + if ((z_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(z_bits.sign(), + static_cast(z_payload)) + .get_val(); + } + + return OutFPBits::quiet_nan().get_val(); + } + } + if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0)) return static_cast(x * y + z); @@ -137,7 +176,9 @@ fma(InType x, InType y, InType z) { z *= InType(InStorageType(1) << InFPBits::FRACTION_LEN); } - InFPBits x_bits(x), y_bits(y), z_bits(z); + x_bits = InFPBits(x); + y_bits = InFPBits(y); + z_bits = InFPBits(z); const Sign z_sign = z_bits.sign(); Sign prod_sign = (x_bits.sign() == y_bits.sign()) ? Sign::POS : Sign::NEG; x_exp += x_bits.get_biased_exponent(); diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index d1c814b6bf18f..97ce0f63b57fb 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -979,6 +979,10 @@ template void explain_ternary_operation_one_output_error( Operation, const TernaryInput &, float16, double, RoundingMode); template void explain_ternary_operation_one_output_error( Operation, const TernaryInput &, float16, double, RoundingMode); +template void +explain_ternary_operation_one_output_error(Operation, + const TernaryInput &, + float16, double, RoundingMode); #endif template @@ -1130,6 +1134,10 @@ template bool compare_ternary_operation_one_output(Operation, const TernaryInput &, float16, double, RoundingMode); +template bool +compare_ternary_operation_one_output(Operation, + const TernaryInput &, float16, + double, RoundingMode); #endif } // namespace internal