From 6de44fa8970a4e045a17bb0dc9fc1f4afd837cf8 Mon Sep 17 00:00:00 2001 From: meltq Date: Fri, 14 Mar 2025 21:33:04 +0530 Subject: [PATCH 1/9] Add asinhf16 function --- libc/config/linux/x86_64/entrypoints.txt | 1 + libc/docs/headers/math/index.rst | 2 +- libc/include/math.yaml | 7 ++ libc/src/math/CMakeLists.txt | 1 + libc/src/math/asinhf16.h | 21 ++++++ libc/src/math/generic/CMakeLists.txt | 20 +++++ libc/src/math/generic/asinhf16.cpp | 85 ++++++++++++++++++++++ libc/test/src/math/CMakeLists.txt | 12 +++ libc/test/src/math/asinhf16_test.cpp | 42 +++++++++++ libc/test/src/math/smoke/CMakeLists.txt | 12 +++ libc/test/src/math/smoke/asinhf16_test.cpp | 35 +++++++++ 11 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 libc/src/math/asinhf16.h create mode 100644 libc/src/math/generic/asinhf16.cpp create mode 100644 libc/test/src/math/asinhf16_test.cpp create mode 100644 libc/test/src/math/smoke/asinhf16_test.cpp diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index ac281e8d39066..7f436651be2dc 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -411,6 +411,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acoshf libc.src.math.asinf libc.src.math.asinhf + libc.src.math.asinhf16 libc.src.math.atan2 libc.src.math.atan2f libc.src.math.atan diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst index 16903a40c03fa..23d010e2ab5d7 100644 --- a/libc/docs/headers/math/index.rst +++ b/libc/docs/headers/math/index.rst @@ -257,7 +257,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | asin | |check| | | | |check| | | 7.12.4.2 | F.10.1.2 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| asinh | |check| | | | | | 7.12.5.2 | F.10.2.2 | +| asinh | |check| | | | |check| | | 7.12.5.2 | F.10.2.2 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | asinpi | | | | | | 7.12.4.9 | F.10.1.9 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/include/math.yaml b/libc/include/math.yaml index bd29eb0213c4f..3a06bcfc4f43e 100644 --- a/libc/include/math.yaml +++ b/libc/include/math.yaml @@ -59,6 +59,13 @@ functions: return_type: float arguments: - type: float + - name: asinhf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: atan standards: - stdc diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 92c80a1053c9e..9fec978ece2bd 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -54,6 +54,7 @@ add_math_entrypoint_object(asinf16) add_math_entrypoint_object(asinh) add_math_entrypoint_object(asinhf) +add_math_entrypoint_object(asinhf16) add_math_entrypoint_object(atan) add_math_entrypoint_object(atanf) diff --git a/libc/src/math/asinhf16.h b/libc/src/math/asinhf16.h new file mode 100644 index 0000000000000..2969a3498164f --- /dev/null +++ b/libc/src/math/asinhf16.h @@ -0,0 +1,21 @@ +//===-- Implementation header for asinhf16 -----------------------*- 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_ASINHF16_H +#define LLVM_LIBC_SRC_MATH_ASINHF16_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 asinhf16(float16 x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_ASINHF16_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 77c6244c5e5da..4217c58656b7b 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3980,6 +3980,26 @@ add_entrypoint_object( libc.src.__support.macros.optimization ) +add_entrypoint_object( + asinhf16 + SRCS + asinhf16.cpp + HDRS + ../asinhf16.h + DEPENDS + .explogxf + libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types +) + add_entrypoint_object( atanhf SRCS diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp new file mode 100644 index 0000000000000..d8a6058623514 --- /dev/null +++ b/libc/src/math/generic/asinhf16.cpp @@ -0,0 +1,85 @@ +//===-- Half-precision asinhf16(x) 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/asinhf16.h" +#include "src/math/generic/explogxf.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/generic/sqrt.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +static constexpr size_t N_EXCEPTS = 8; + +static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ + // (input, RZ output, RU offset, RD offset, RN offset) + {0x3769, 0x372A, 1, 0, 1}, + {0x3B5B, 0x3A96, 1, 0, 0}, + {0x4B1F, 0x42B3, 1, 0, 0}, + {0x4C9B, 0x4336, 1, 0, 1}, + {0xB769, 0xB72A, 0, 1, 1}, + {0xBB5B, 0xBA96, 0, 1, 0}, + {0xCB1F, 0xC2B3, 0, 1, 0}, + {0xCC9B, 0xC336, 0, 1, 1} +}}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { + using FPBits = fputil::FPBits; + FPBits xbits(x); + + float x_d = x; + uint16_t x_u = xbits.uintval(); + uint16_t x_abs = x_u & 0x7fff; + + if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + return x; + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Handle exceptional values + if (auto r = ASINHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + const float SIGN[2] = {1.0f, -1.0f}; + float x_sign = SIGN[x_u >> 15]; + + // |x| <= 0.25 + if (LIBC_UNLIKELY(x_abs <= 0x3400)) { + if (LIBC_UNLIKELY(x_abs == 0)) + return x; + if (LIBC_UNLIKELY((fputil::get_round() == FE_UPWARD) && + (x_u >= 0x8401) && (x_u <= 0x90E6))) + return static_cast(x_d + 0x1p-24f); + + float x_sq = x_d * x_d; + // Generated by Sollya with: + // > P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8|], [|SG...|],[0, 2^-2]); + float p = fputil::polyeval(x_sq, 1.0f, -0x1.555556p-3f, 0x1.3334dep-4f, + -0x1.6f3e2p-5f, 0x1.51d012p-5f); + + return static_cast(fputil::multiply_add(x_d, p, 0.0f)); + } + + // General case: asinh(x) = ln(x + sqrt(x^2 + 1)) + float sqrt_term = fputil::sqrt(fputil::multiply_add(x_d, x_d, 1.0f)); + return fputil::cast(x_sign * log_eval( + fputil::multiply_add(x_d, x_sign, sqrt_term))); +} +} diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 6ca4163f07949..71d8080acda70 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -2175,6 +2175,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) + +add_fp_unittest( + asinhf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + asinhf16_test.cpp + DEPENDS + libc.src.math.asinhf16 +) + add_fp_unittest( acoshf_test NEED_MPFR diff --git a/libc/test/src/math/asinhf16_test.cpp b/libc/test/src/math/asinhf16_test.cpp new file mode 100644 index 0000000000000..32f3aa141d685 --- /dev/null +++ b/libc/test/src/math/asinhf16_test.cpp @@ -0,0 +1,42 @@ +//===-- Exhaustive test for asinhf16 ---------------------------------------===// +// +// 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/asinhf16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcAsinhf16Test = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// 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(LlvmLibcAsinhf16Test, PositiveRange) { + for (uint16_t v = POS_START; v <= POS_STOP; ++v) { + float16 x = FPBits(v).get_val(); + + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, x, + LIBC_NAMESPACE::asinhf16(x), 0.5); + } +} + +TEST_F(LlvmLibcAsinhf16Test, NegativeRange) { + for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { + float16 x = FPBits(v).get_val(); + + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, x, + LIBC_NAMESPACE::asinhf16(x), 0.5); + } +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 660b68687d63c..406b6a85cee7b 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3946,6 +3946,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + asinhf16_test + SUITE + libc-math-smoke-tests + SRCS + asinhf16_test.cpp + DEPENDS + libc.src.errno.errno + libc.src.math.asinhf16 + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( acoshf_test SUITE diff --git a/libc/test/src/math/smoke/asinhf16_test.cpp b/libc/test/src/math/smoke/asinhf16_test.cpp new file mode 100644 index 0000000000000..6faac38067ca8 --- /dev/null +++ b/libc/test/src/math/smoke/asinhf16_test.cpp @@ -0,0 +1,35 @@ +//===-- Unittests for asinhf16 ----------------------------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/math/asinhf16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcAsinhf16Test = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcAsinhf16Test, SpecialNumbers) { + LIBC_NAMESPACE::libc_errno = 0; + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinhf16(aNaN)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::asinhf16(sNaN), FE_INVALID); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf16(0.0f)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(-0.0f, LIBC_NAMESPACE::asinhf16(-0.0f)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(inf, LIBC_NAMESPACE::asinhf16(inf)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::asinhf16(neg_inf)); + EXPECT_MATH_ERRNO(0); +} From 3b73ed7da49d4a7d90ecbc5cbd07bf6b49b6c583 Mon Sep 17 00:00:00 2001 From: meltq Date: Fri, 14 Mar 2025 22:29:35 +0530 Subject: [PATCH 2/9] Fixed format errors --- libc/src/math/asinhf16.h | 2 +- libc/src/math/generic/asinhf16.cpp | 35 +++++++++++----------- libc/test/src/math/asinhf16_test.cpp | 2 +- libc/test/src/math/smoke/asinhf16_test.cpp | 2 +- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/libc/src/math/asinhf16.h b/libc/src/math/asinhf16.h index 2969a3498164f..b6893416d46b8 100644 --- a/libc/src/math/asinhf16.h +++ b/libc/src/math/asinhf16.h @@ -1,4 +1,4 @@ -//===-- Implementation header for asinhf16 -----------------------*- C++ -*-===// +//===-- Implementation header for asinhf16 -----------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index d8a6058623514..7591a8bf9b633 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -1,4 +1,4 @@ -//===-- Half-precision asinhf16(x) function --------------------------------===// +//===-- Half-precision asinhf16(x) function--------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,30 +8,29 @@ //===----------------------------------------------------------------------===// #include "src/math/asinhf16.h" -#include "src/math/generic/explogxf.h" #include "src/__support/FPUtil/except_value_utils.h" #include "src/__support/FPUtil/generic/sqrt.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/types.h" +#include "src/math/generic/explogxf.h" namespace LIBC_NAMESPACE_DECL { #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS static constexpr size_t N_EXCEPTS = 8; -static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ - // (input, RZ output, RU offset, RD offset, RN offset) - {0x3769, 0x372A, 1, 0, 1}, - {0x3B5B, 0x3A96, 1, 0, 0}, - {0x4B1F, 0x42B3, 1, 0, 0}, - {0x4C9B, 0x4336, 1, 0, 1}, - {0xB769, 0xB72A, 0, 1, 1}, - {0xBB5B, 0xBA96, 0, 1, 0}, - {0xCB1F, 0xC2B3, 0, 1, 0}, - {0xCC9B, 0xC336, 0, 1, 1} -}}; +static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{ + {// (input, RZ output, RU offset, RD offset, RN offset) + {0x3769, 0x372A, 1, 0, 1}, + {0x3B5B, 0x3A96, 1, 0, 0}, + {0x4B1F, 0x42B3, 1, 0, 0}, + {0x4C9B, 0x4336, 1, 0, 1}, + {0xB769, 0xB72A, 0, 1, 1}, + {0xBB5B, 0xBA96, 0, 1, 0}, + {0xCB1F, 0xC2B3, 0, 1, 0}, + {0xCC9B, 0xC336, 0, 1, 1}}}; #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { @@ -64,8 +63,8 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { if (LIBC_UNLIKELY(x_abs <= 0x3400)) { if (LIBC_UNLIKELY(x_abs == 0)) return x; - if (LIBC_UNLIKELY((fputil::get_round() == FE_UPWARD) && - (x_u >= 0x8401) && (x_u <= 0x90E6))) + if (LIBC_UNLIKELY((fputil::get_round() == FE_UPWARD) && (x_u >= 0x8401) && + (x_u <= 0x90E6))) return static_cast(x_d + 0x1p-24f); float x_sq = x_d * x_d; @@ -79,7 +78,7 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { // General case: asinh(x) = ln(x + sqrt(x^2 + 1)) float sqrt_term = fputil::sqrt(fputil::multiply_add(x_d, x_d, 1.0f)); - return fputil::cast(x_sign * log_eval( - fputil::multiply_add(x_d, x_sign, sqrt_term))); -} + return fputil::cast( + x_sign * log_eval(fputil::multiply_add(x_d, x_sign, sqrt_term))); } +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/math/asinhf16_test.cpp b/libc/test/src/math/asinhf16_test.cpp index 32f3aa141d685..6673251c5db16 100644 --- a/libc/test/src/math/asinhf16_test.cpp +++ b/libc/test/src/math/asinhf16_test.cpp @@ -1,4 +1,4 @@ -//===-- Exhaustive test for asinhf16 ---------------------------------------===// +//===-- Exhaustive test for asinhf16---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/test/src/math/smoke/asinhf16_test.cpp b/libc/test/src/math/smoke/asinhf16_test.cpp index 6faac38067ca8..efa088f6e1437 100644 --- a/libc/test/src/math/smoke/asinhf16_test.cpp +++ b/libc/test/src/math/smoke/asinhf16_test.cpp @@ -1,4 +1,4 @@ -//===-- Unittests for asinhf16 ----------------------------------------------===// +//===-- Unittests for asinhf16---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. From 674b9288198edc799d1b9d084e2e6c8c662c6bf3 Mon Sep 17 00:00:00 2001 From: meltq Date: Sat, 15 Mar 2025 23:43:15 +0530 Subject: [PATCH 3/9] Removed repeated dependency in CMakeLists --- libc/src/math/generic/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 4217c58656b7b..a3513859a17c5 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3992,7 +3992,6 @@ add_entrypoint_object( libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.polyeval libc.src.__support.FPUtil.sqrt From c9e63d23963221dffcbbfe5b30001aa9b309ac7d Mon Sep 17 00:00:00 2001 From: meltq Date: Mon, 17 Mar 2025 14:59:41 +0530 Subject: [PATCH 4/9] Suggested changes --- libc/config/linux/x86_64/entrypoints.txt | 2 +- libc/src/math/asinhf16.h | 2 +- libc/src/math/generic/asinhf16.cpp | 77 +++++++++++++--------- libc/test/src/math/asinhf16_test.cpp | 2 +- libc/test/src/math/smoke/CMakeLists.txt | 1 - libc/test/src/math/smoke/asinhf16_test.cpp | 6 +- 6 files changed, 53 insertions(+), 37 deletions(-) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 7f436651be2dc..ebc9ff44af8fd 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -411,7 +411,6 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acoshf libc.src.math.asinf libc.src.math.asinhf - libc.src.math.asinhf16 libc.src.math.atan2 libc.src.math.atan2f libc.src.math.atan @@ -654,6 +653,7 @@ if(LIBC_TYPES_HAS_FLOAT16) list(APPEND TARGET_LIBM_ENTRYPOINTS # math.h C23 _Float16 entrypoints libc.src.math.asinf16 + libc.src.math.asinhf16 libc.src.math.acosf16 libc.src.math.acoshf16 libc.src.math.canonicalizef16 diff --git a/libc/src/math/asinhf16.h b/libc/src/math/asinhf16.h index b6893416d46b8..bb40e208d7ee3 100644 --- a/libc/src/math/asinhf16.h +++ b/libc/src/math/asinhf16.h @@ -1,4 +1,4 @@ -//===-- Implementation header for asinhf16 -----------------------*- C++-*-===// +//===-- Implementation header for asinhf16 ----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index 7591a8bf9b633..2a5fbd5a6102b 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -1,43 +1,50 @@ -//===-- Half-precision asinhf16(x) function--------------------------------===// +//===-- Half-precision asinh(x) 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/asinhf16.h" +#include "explogxf.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/generic/sqrt.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/sqrt.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/properties/types.h" -#include "src/math/generic/explogxf.h" +#include "src/__support/macros/optimization.h" namespace LIBC_NAMESPACE_DECL { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS static constexpr size_t N_EXCEPTS = 8; static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{ {// (input, RZ output, RU offset, RD offset, RN offset) - {0x3769, 0x372A, 1, 0, 1}, - {0x3B5B, 0x3A96, 1, 0, 0}, - {0x4B1F, 0x42B3, 1, 0, 0}, - {0x4C9B, 0x4336, 1, 0, 1}, - {0xB769, 0xB72A, 0, 1, 1}, - {0xBB5B, 0xBA96, 0, 1, 0}, - {0xCB1F, 0xC2B3, 0, 1, 0}, - {0xCC9B, 0xC336, 0, 1, 1}}}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // x = 0x1.da4p-2, asinhf16(x) = 0x1.ca8p-2 (RZ) + {0x3769, 0x372a, 1, 0, 1}, + // x = 0x1.d6cp-1, asinhf16(x) = 0x1.a58p-1 (RZ) + {0x3b5b, 0x3a96, 1, 0, 0}, + // x = 0x1.c7cp+3, asinhf16(x) = 0x1.accp+1 (RZ) + {0x4b1f, 0x42b3, 1, 0, 0}, + // x = 0x1.26cp+4, asinhf16(x) = 0x1.cd8p+1 (RZ) + {0x4c9b, 0x4336, 1, 0, 1}, + // x = -0x1.da4p-2, asinhf16(x) = -0x1.ca8p-2 (RZ) + {0xb769, 0xb72a, 0, 1, 1}, + // x = -0x1.d6cp-1, asinhf16(x) = -0x1.a58p-1 (RZ) + {0xbb5b, 0xba96, 0, 1, 0}, + // x = -0x1.c7cp+3, asinhf16(x) = -0x1.accp+1 (RZ) + {0xcb1f, 0xc2b3, 0, 1, 0}, + // x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ) + {0xcc9b, 0xc336, 0, 1, 1}}}; LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { using FPBits = fputil::FPBits; FPBits xbits(x); - float x_d = x; uint16_t x_u = xbits.uintval(); uint16_t x_abs = x_u & 0x7fff; @@ -50,35 +57,45 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { return x; } -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS // Handle exceptional values if (auto r = ASINHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + float xf = x; const float SIGN[2] = {1.0f, -1.0f}; float x_sign = SIGN[x_u >> 15]; // |x| <= 0.25 if (LIBC_UNLIKELY(x_abs <= 0x3400)) { - if (LIBC_UNLIKELY(x_abs == 0)) - return x; - if (LIBC_UNLIKELY((fputil::get_round() == FE_UPWARD) && (x_u >= 0x8401) && - (x_u <= 0x90E6))) - return static_cast(x_d + 0x1p-24f); - float x_sq = x_d * x_d; + // when |x| < 0x1.718p-5, asinhf16(x) = x. Adjust by 1 ULP for certain + // rounding types. + if (LIBC_UNLIKELY(x_abs < 0x29c6)) { + if (((fputil::get_round() == FE_UPWARD) || + (fputil::get_round() == FE_TOWARDZERO)) && + xf < 0) + return fputil::cast(xf + 0x1p-24f); + if (((fputil::get_round() == FE_DOWNWARD) || + (fputil::get_round() == FE_TOWARDZERO)) && + xf > 0) + return fputil::cast(xf - 0x1p-24f); + return fputil::cast(xf); + } + + float x_sq = xf * xf; // Generated by Sollya with: - // > P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8|], [|SG...|],[0, 2^-2]); - float p = fputil::polyeval(x_sq, 1.0f, -0x1.555556p-3f, 0x1.3334dep-4f, - -0x1.6f3e2p-5f, 0x1.51d012p-5f); + // > P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8|], [|SG...|], [0, 2^-2]); + // The last coefficient 0x1.bd114ep-6f has been changed to 0x1.bd114ep-5f + // for better accuracy. + float p = fputil::polyeval(x_sq, 1.0f, -0x1.555552p-3f, 0x1.332f6ap-4f, + -0x1.6c53dep-5f, 0x1.bd114ep-5f); - return static_cast(fputil::multiply_add(x_d, p, 0.0f)); + return fputil::cast(xf * p); } // General case: asinh(x) = ln(x + sqrt(x^2 + 1)) - float sqrt_term = fputil::sqrt(fputil::multiply_add(x_d, x_d, 1.0f)); + float sqrt_term = fputil::sqrt(fputil::multiply_add(xf, xf, 1.0f)); return fputil::cast( - x_sign * log_eval(fputil::multiply_add(x_d, x_sign, sqrt_term))); + x_sign * log_eval(fputil::multiply_add(xf, x_sign, sqrt_term))); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/math/asinhf16_test.cpp b/libc/test/src/math/asinhf16_test.cpp index 6673251c5db16..929d13713d197 100644 --- a/libc/test/src/math/asinhf16_test.cpp +++ b/libc/test/src/math/asinhf16_test.cpp @@ -1,4 +1,4 @@ -//===-- Exhaustive test for asinhf16---------------------------------------===// +//===-- Exhaustive test for asinhf16 --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 406b6a85cee7b..b7601735c1109 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3955,7 +3955,6 @@ add_fp_unittest( DEPENDS libc.src.errno.errno libc.src.math.asinhf16 - libc.src.__support.FPUtil.fp_bits ) add_fp_unittest( diff --git a/libc/test/src/math/smoke/asinhf16_test.cpp b/libc/test/src/math/smoke/asinhf16_test.cpp index efa088f6e1437..dcaab217331c7 100644 --- a/libc/test/src/math/smoke/asinhf16_test.cpp +++ b/libc/test/src/math/smoke/asinhf16_test.cpp @@ -1,4 +1,4 @@ -//===-- Unittests for asinhf16---------------------------------------------===// +//===-- Unittests for asinhf16 --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,10 +21,10 @@ TEST_F(LlvmLibcAsinhf16Test, SpecialNumbers) { EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::asinhf16(sNaN), FE_INVALID); EXPECT_MATH_ERRNO(0); - EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf16(0.0f)); + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::asinhf16(zero)); EXPECT_MATH_ERRNO(0); - EXPECT_FP_EQ(-0.0f, LIBC_NAMESPACE::asinhf16(-0.0f)); + EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::asinhf16(neg_zero)); EXPECT_MATH_ERRNO(0); EXPECT_FP_EQ(inf, LIBC_NAMESPACE::asinhf16(inf)); From 458c120cfd5adf2c5c9ad1dc06e0bc4ad36f8fe0 Mon Sep 17 00:00:00 2001 From: meltq Date: Tue, 18 Mar 2025 12:47:41 +0530 Subject: [PATCH 5/9] Format LUT --- libc/src/math/generic/asinhf16.cpp | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index 2a5fbd5a6102b..e7b3ebd20f0f3 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -21,25 +21,26 @@ namespace LIBC_NAMESPACE_DECL { static constexpr size_t N_EXCEPTS = 8; -static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{ - {// (input, RZ output, RU offset, RD offset, RN offset) - - // x = 0x1.da4p-2, asinhf16(x) = 0x1.ca8p-2 (RZ) - {0x3769, 0x372a, 1, 0, 1}, - // x = 0x1.d6cp-1, asinhf16(x) = 0x1.a58p-1 (RZ) - {0x3b5b, 0x3a96, 1, 0, 0}, - // x = 0x1.c7cp+3, asinhf16(x) = 0x1.accp+1 (RZ) - {0x4b1f, 0x42b3, 1, 0, 0}, - // x = 0x1.26cp+4, asinhf16(x) = 0x1.cd8p+1 (RZ) - {0x4c9b, 0x4336, 1, 0, 1}, - // x = -0x1.da4p-2, asinhf16(x) = -0x1.ca8p-2 (RZ) - {0xb769, 0xb72a, 0, 1, 1}, - // x = -0x1.d6cp-1, asinhf16(x) = -0x1.a58p-1 (RZ) - {0xbb5b, 0xba96, 0, 1, 0}, - // x = -0x1.c7cp+3, asinhf16(x) = -0x1.accp+1 (RZ) - {0xcb1f, 0xc2b3, 0, 1, 0}, - // x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ) - {0xcc9b, 0xc336, 0, 1, 1}}}; +static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ + // (input, RZ output, RU offset, RD offset, RN offset) + + // x = 0x1.da4p-2, asinhf16(x) = 0x1.ca8p-2 (RZ) + {0x3769, 0x372a, 1, 0, 1}, + // x = 0x1.d6cp-1, asinhf16(x) = 0x1.a58p-1 (RZ) + {0x3b5b, 0x3a96, 1, 0, 0}, + // x = 0x1.c7cp+3, asinhf16(x) = 0x1.accp+1 (RZ) + {0x4b1f, 0x42b3, 1, 0, 0}, + // x = 0x1.26cp+4, asinhf16(x) = 0x1.cd8p+1 (RZ) + {0x4c9b, 0x4336, 1, 0, 1}, + // x = -0x1.da4p-2, asinhf16(x) = -0x1.ca8p-2 (RZ) + {0xb769, 0xb72a, 0, 1, 1}, + // x = -0x1.d6cp-1, asinhf16(x) = -0x1.a58p-1 (RZ) + {0xbb5b, 0xba96, 0, 1, 0}, + // x = -0x1.c7cp+3, asinhf16(x) = -0x1.accp+1 (RZ) + {0xcb1f, 0xc2b3, 0, 1, 0}, + // x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ) + {0xcc9b, 0xc336, 0, 1, 1} +}}; LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { using FPBits = fputil::FPBits; From 0c2cb4ab0f8006a34bd7168e879eba9dc1297ddf Mon Sep 17 00:00:00 2001 From: meltq Date: Tue, 18 Mar 2025 12:53:47 +0530 Subject: [PATCH 6/9] Add back LIBC_MATH_HAS_SKIP_ACCURATE_PASS check --- libc/src/math/generic/asinhf16.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index e7b3ebd20f0f3..7110d1f5cc963 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -19,6 +19,7 @@ namespace LIBC_NAMESPACE_DECL { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS static constexpr size_t N_EXCEPTS = 8; static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ @@ -41,6 +42,7 @@ static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ // x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ) {0xcc9b, 0xc336, 0, 1, 1} }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { using FPBits = fputil::FPBits; @@ -58,9 +60,11 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { return x; } +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS // Handle exceptional values if (auto r = ASINHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS float xf = x; const float SIGN[2] = {1.0f, -1.0f}; From e7ef314947a3c2998402c171b14fa51da1efb56b Mon Sep 17 00:00:00 2001 From: meltq Date: Tue, 18 Mar 2025 17:53:00 +0530 Subject: [PATCH 7/9] Added trailing comma --- libc/src/math/generic/asinhf16.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index 7110d1f5cc963..3b5d12562b658 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -40,7 +40,7 @@ static constexpr fputil::ExceptValues ASINHF16_EXCEPTS{{ // x = -0x1.c7cp+3, asinhf16(x) = -0x1.accp+1 (RZ) {0xcb1f, 0xc2b3, 0, 1, 0}, // x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ) - {0xcc9b, 0xc336, 0, 1, 1} + {0xcc9b, 0xc336, 0, 1, 1}, }}; #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS From e79d2cec04d393dafd6676ed3fbc48209495a42e Mon Sep 17 00:00:00 2001 From: meltq Date: Wed, 26 Mar 2025 08:43:56 +0530 Subject: [PATCH 8/9] Cleaned up rounding logic --- libc/src/math/generic/asinhf16.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index 3b5d12562b658..f85a522a76929 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -12,6 +12,7 @@ #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/FPUtil/sqrt.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" @@ -76,13 +77,10 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { // when |x| < 0x1.718p-5, asinhf16(x) = x. Adjust by 1 ULP for certain // rounding types. if (LIBC_UNLIKELY(x_abs < 0x29c6)) { - if (((fputil::get_round() == FE_UPWARD) || - (fputil::get_round() == FE_TOWARDZERO)) && - xf < 0) + int rounding = fputil::quick_get_round(); + if ((rounding == FE_UPWARD || rounding == FE_TOWARDZERO) && xf < 0) return fputil::cast(xf + 0x1p-24f); - if (((fputil::get_round() == FE_DOWNWARD) || - (fputil::get_round() == FE_TOWARDZERO)) && - xf > 0) + if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && xf > 0) return fputil::cast(xf - 0x1p-24f); return fputil::cast(xf); } @@ -103,4 +101,5 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { return fputil::cast( x_sign * log_eval(fputil::multiply_add(xf, x_sign, sqrt_term))); } + } // namespace LIBC_NAMESPACE_DECL From 1d866f72a9bb7faf2ff048351fe66c3df7b80c99 Mon Sep 17 00:00:00 2001 From: meltq Date: Wed, 26 Mar 2025 22:14:36 +0530 Subject: [PATCH 9/9] Formatting changes --- libc/config/linux/x86_64/entrypoints.txt | 4 ++-- libc/src/math/generic/CMakeLists.txt | 2 ++ libc/src/math/generic/asinhf16.cpp | 4 +++- libc/test/src/math/CMakeLists.txt | 1 - 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index ebc9ff44af8fd..948a0b648e20a 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -652,10 +652,10 @@ endif() if(LIBC_TYPES_HAS_FLOAT16) list(APPEND TARGET_LIBM_ENTRYPOINTS # math.h C23 _Float16 entrypoints - libc.src.math.asinf16 - libc.src.math.asinhf16 libc.src.math.acosf16 libc.src.math.acoshf16 + libc.src.math.asinf16 + libc.src.math.asinhf16 libc.src.math.canonicalizef16 libc.src.math.ceilf16 libc.src.math.copysignf16 diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index a3513859a17c5..d3454803df377 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3990,10 +3990,12 @@ add_entrypoint_object( .explogxf libc.hdr.fenv_macros libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.except_value_utils libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode libc.src.__support.FPUtil.sqrt libc.src.__support.macros.optimization libc.src.__support.macros.properties.types diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp index f85a522a76929..78786320b5f71 100644 --- a/libc/src/math/generic/asinhf16.cpp +++ b/libc/src/math/generic/asinhf16.cpp @@ -9,6 +9,9 @@ #include "src/math/asinhf16.h" #include "explogxf.h" #include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" #include "src/__support/FPUtil/multiply_add.h" @@ -73,7 +76,6 @@ LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) { // |x| <= 0.25 if (LIBC_UNLIKELY(x_abs <= 0x3400)) { - // when |x| < 0x1.718p-5, asinhf16(x) = x. Adjust by 1 ULP for certain // rounding types. if (LIBC_UNLIKELY(x_abs < 0x29c6)) { diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 71d8080acda70..9a73f9fe07597 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -2175,7 +2175,6 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) - add_fp_unittest( asinhf16_test NEED_MPFR