diff --git a/libc/shared/math.h b/libc/shared/math.h index f7fa175234296..eec3c31ae1035 100644 --- a/libc/shared/math.h +++ b/libc/shared/math.h @@ -87,6 +87,7 @@ #include "math/rsqrtf16.h" #include "math/sin.h" #include "math/sinf.h" +#include "math/sinhf.h" #include "math/tan.h" #include "math/tanf.h" diff --git a/libc/shared/math/sinhf.h b/libc/shared/math/sinhf.h new file mode 100644 index 0000000000000..fac98fc60c13c --- /dev/null +++ b/libc/shared/math/sinhf.h @@ -0,0 +1,23 @@ +//===-- Shared sinhf function -----------------------------------*- 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_SHARED_MATH_SINHF_H +#define LLVM_LIBC_SHARED_MATH_SINHF_H + +#include "shared/libc_common.h" +#include "src/__support/math/sinhf.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::sinhf; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_SINHF_H diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index d37dbe6be6864..f7875527d1f9d 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -1276,6 +1276,19 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + sinhf + HDRS + sinhf.h + DEPENDS + .sinhfcoshf_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + add_header_library( dfmal HDRS diff --git a/libc/src/__support/math/sinhf.h b/libc/src/__support/math/sinhf.h new file mode 100644 index 0000000000000..e8efc29aeac79 --- /dev/null +++ b/libc/src/__support/math/sinhf.h @@ -0,0 +1,88 @@ +//===-- Single-precision sinh 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H + +#include "sinhfcoshf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float sinhf(float x) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + uint32_t x_abs = xbits.abs().uintval(); + + // When |x| >= 90, or x is inf or nan + if (LIBC_UNLIKELY(x_abs >= 0x42b4'0000U || x_abs <= 0x3da0'0000U)) { + // |x| <= 0.078125 + if (x_abs <= 0x3da0'0000U) { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // |x| = 0.0005589424981735646724700927734375 + if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { + if (fputil::fenv_is_round_to_nearest()) + return x; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // |x| <= 2^-26 + if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { + return static_cast( + LIBC_UNLIKELY(x_abs == 0) ? x : (x + 0.25 * x * x * x)); + } + + double xdbl = x; + double x2 = xdbl * xdbl; + // Sollya: fpminimax(sinh(x),[|3,5,7|],[|D...|],[-1/16-1/64;1/16+1/64],x); + // Sollya output: x * (0x1p0 + x^0x1p1 * (0x1.5555555556583p-3 + x^0x1p1 + // * (0x1.111110d239f1fp-7 + // + x^0x1p1 * 0x1.a02b5a284013cp-13))) + // Therefore, output of Sollya = x * pe; + double pe = fputil::polyeval(x2, 0.0, 0x1.5555555556583p-3, + 0x1.111110d239f1fp-7, 0x1.a02b5a284013cp-13); + return static_cast(fputil::multiply_add(xdbl, pe, xdbl)); + } + + if (xbits.is_nan()) + return x + 1.0f; // sNaN to qNaN + signal + + if (xbits.is_inf()) + return x; + + int rounding = fputil::quick_get_round(); + if (xbits.is_neg()) { + if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) + return -FPBits::max_normal().get_val(); + } else { + if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) + return FPBits::max_normal().get_val(); + } + + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW); + + return x + FPBits::inf(xbits.sign()).get_val(); + } + + // sinh(x) = (e^x - e^(-x)) / 2. + return static_cast( + math::sinhfcoshf_internal::exp_pm_eval(x)); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 11b87ca93a97c..d7abbc5564245 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -4134,10 +4134,7 @@ add_entrypoint_object( HDRS ../sinhf.h DEPENDS - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.macros.optimization - libc.src.__support.math.sinhfcoshf_utils + libc.src.__support.math.sinhf ) add_entrypoint_object( diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp index 5f2d0b5d9c71c..a8f8c715019a8 100644 --- a/libc/src/math/generic/sinhf.cpp +++ b/libc/src/math/generic/sinhf.cpp @@ -7,74 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sinhf.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/math/sinhfcoshf_utils.h" +#include "src/__support/math/sinhf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { - using FPBits = typename fputil::FPBits; - FPBits xbits(x); - uint32_t x_abs = xbits.abs().uintval(); - - // When |x| >= 90, or x is inf or nan - if (LIBC_UNLIKELY(x_abs >= 0x42b4'0000U || x_abs <= 0x3da0'0000U)) { - // |x| <= 0.078125 - if (x_abs <= 0x3da0'0000U) { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // |x| = 0.0005589424981735646724700927734375 - if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { - if (fputil::fenv_is_round_to_nearest()) - return x; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // |x| <= 2^-26 - if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { - return static_cast( - LIBC_UNLIKELY(x_abs == 0) ? x : (x + 0.25 * x * x * x)); - } - - double xdbl = x; - double x2 = xdbl * xdbl; - // Sollya: fpminimax(sinh(x),[|3,5,7|],[|D...|],[-1/16-1/64;1/16+1/64],x); - // Sollya output: x * (0x1p0 + x^0x1p1 * (0x1.5555555556583p-3 + x^0x1p1 - // * (0x1.111110d239f1fp-7 - // + x^0x1p1 * 0x1.a02b5a284013cp-13))) - // Therefore, output of Sollya = x * pe; - double pe = fputil::polyeval(x2, 0.0, 0x1.5555555556583p-3, - 0x1.111110d239f1fp-7, 0x1.a02b5a284013cp-13); - return static_cast(fputil::multiply_add(xdbl, pe, xdbl)); - } - - if (xbits.is_nan()) - return x + 1.0f; // sNaN to qNaN + signal - - if (xbits.is_inf()) - return x; - - int rounding = fputil::quick_get_round(); - if (xbits.is_neg()) { - if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) - return -FPBits::max_normal().get_val(); - } else { - if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) - return FPBits::max_normal().get_val(); - } - - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - - return x + FPBits::inf(xbits.sign()).get_val(); - } - - // sinh(x) = (e^x - e^(-x)) / 2. - return static_cast( - math::sinhfcoshf_internal::exp_pm_eval(x)); -} +LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { return math::sinhf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index ef472992fea40..63037e45dd995 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -84,6 +84,7 @@ add_fp_unittest( libc.src.__support.math.rsqrtf16 libc.src.__support.math.sin libc.src.__support.math.sinf + libc.src.__support.math.sinhf libc.src.__support.math.tan libc.src.__support.math.tanf ) diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp index 45a7934a83621..e27c1d6c95ea8 100644 --- a/libc/test/shared/shared_math_test.cpp +++ b/libc/test/shared/shared_math_test.cpp @@ -78,6 +78,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) { EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::expm1f(0.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::hypotf(0.0f, 0.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::logf(1.0f)); + EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::sinhf(0.0f)); EXPECT_FP_EQ_ALL_ROUNDING(0.75f, LIBC_NAMESPACE::shared::frexpf(24.0f, &exponent)); diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 09b0a5a8e584a..1bb2397e27294 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -3521,6 +3521,19 @@ libc_support_library( ], ) +libc_support_library( + name = "__support_math_sinhf", + hdrs = ["src/__support/math/sinhf.h"], + deps = [ + ":__support_fputil_fenv_impl", + ":__support_fputil_fp_bits", + ":__support_fputil_rounding_mode", + ":__support_macros_config", + ":__support_macros_optimization", + ":__support_math_sinhfcoshf_utils", + ], +) + libc_support_library( name = "__support_math_tan", hdrs = ["src/__support/math/tan.h"], @@ -5135,14 +5148,7 @@ libc_math_function( libc_math_function( name = "sinhf", additional_deps = [ - ":__support_fputil_fma", - ":__support_fputil_multiply_add", - ":__support_fputil_nearest_integer", - ":__support_fputil_polyeval", - ":__support_fputil_rounding_mode", - ":__support_macros_optimization", - ":__support_math_sinhfcoshf_utils", - ":__support_math_common_constants", + ":__support_math_sinhf", ], )