Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc][math][c23] Add asinhf16 function #131351

Merged
merged 9 commits into from
Mar 29, 2025
Merged

[libc][math][c23] Add asinhf16 function #131351

merged 9 commits into from
Mar 29, 2025

Conversation

meltq
Copy link
Contributor

@meltq meltq commented Mar 14, 2025

Implement asinh for Float16 along with tests. Closes #131001

@llvmbot llvmbot added the libc label Mar 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 14, 2025

@llvm/pr-subscribers-libc

Author: Tejas Vipin (meltq)

Changes

Implement asinh for Float16 along with tests. Closes #131001


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

11 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+1)
  • (modified) libc/docs/headers/math/index.rst (+1-1)
  • (modified) libc/include/math.yaml (+7)
  • (modified) libc/src/math/CMakeLists.txt (+1)
  • (added) libc/src/math/asinhf16.h (+21)
  • (modified) libc/src/math/generic/CMakeLists.txt (+20)
  • (added) libc/src/math/generic/asinhf16.cpp (+85)
  • (modified) libc/test/src/math/CMakeLists.txt (+12)
  • (added) libc/test/src/math/asinhf16_test.cpp (+42)
  • (modified) libc/test/src/math/smoke/CMakeLists.txt (+12)
  • (added) libc/test/src/math/smoke/asinhf16_test.cpp (+35)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a29478898fe70..85263a0dce24b 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.atanf
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index 5b855ce4881c3..b3ac6a9732da7 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 a66f981030864..a124a1cf3e946 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -52,6 +52,13 @@ functions:
     return_type: float
     arguments:
       - type: float
+  - name: asinhf16
+    standards:
+      - stdc
+    return_type: _Float16
+    arguments:
+      - type: _Float16
+    guard: LIBC_TYPES_HAS_FLOAT16
   - name: atan2
     standards:
       - stdc
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index f18a73d46f9aa..fe6d0d520e207 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -53,6 +53,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 3114289bad486..3b982af2b7a2d 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3959,6 +3959,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<float16, N_EXCEPTS> 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<float16>;
+  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<float16>(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<float16>(fputil::multiply_add(x_d, p, 0.0f));
+  }
+
+  // General case: asinh(x) = ln(x + sqrt(x^2 + 1))
+  float sqrt_term = fputil::sqrt<float>(fputil::multiply_add(x_d, x_d, 1.0f));
+  return fputil::cast<float16>(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 53ddd301900c0..01b802ff4c943 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2160,6 +2160,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<float16>;
+
+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 6f94440d826d9..bb304f0beff1f 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3933,6 +3933,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<float16>;
+
+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);
+}

Copy link

github-actions bot commented Mar 14, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@meltq
Copy link
Contributor Author

meltq commented Mar 14, 2025

@lntue @overmighty Requesting review.

@overmighty overmighty self-requested a review March 14, 2025 18:14
@meltq
Copy link
Contributor Author

meltq commented Mar 15, 2025

Failing checks seem to be because of the recent tj-actions issue.

@meltq
Copy link
Contributor Author

meltq commented Mar 17, 2025

All suggested changes have been made except for 1 formatting change not allowed by clang-format and the logic regarding the Sollya polynomial which requires further clarification.

@meltq
Copy link
Contributor Author

meltq commented Mar 18, 2025

@overmighty dc07f52 that I just pushed implements the change you suggested for ASINHF16_EXCEPTS but clang-format does seem to flag it. This is the diff I get after running clang-format locally

diff --git a/libc/src/math/generic/asinhf16.cpp b/libc/src/math/generic/asinhf16.cpp
index 7110d1f5cc96..52e46bfc6267 100644
--- a/libc/src/math/generic/asinhf16.cpp
+++ b/libc/src/math/generic/asinhf16.cpp
@@ -22,26 +22,25 @@ namespace LIBC_NAMESPACE_DECL {
 #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
 static constexpr size_t N_EXCEPTS = 8;
 
-static constexpr fputil::ExceptValues<float16, N_EXCEPTS> 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<float16, N_EXCEPTS> 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}}};
 #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS

@overmighty
Copy link
Member

-    {0xcc9b, 0xc336, 0, 1, 1}
-}};

You need to add a trailing comma. I tested exactly this with both Clang-Format 18.1.8 and 19.1.7 and it didn't get formatted differently:

static constexpr fputil::ExceptValues<float16, N_EXCEPTS> 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},
}};

@meltq
Copy link
Contributor Author

meltq commented Mar 18, 2025

You need to add a trailing comma. I tested exactly this with both Clang-Format 18.1.8 and 19.1.7 and it didn't get formatted differently:

whoops :) fixed

@meltq meltq changed the title [libc][math][c23] Add asinhf16() function [libc][math][c23] Add asinhf16 function Mar 25, 2025
@meltq
Copy link
Contributor Author

meltq commented Mar 26, 2025

Added suggested changes and resolved merge conflict.

@meltq
Copy link
Contributor Author

meltq commented Mar 26, 2025

Added all requested changes.

@overmighty overmighty merged commit d22e35b into llvm:main Mar 29, 2025
17 checks passed
@meltq meltq deleted the asinhf16 branch March 29, 2025 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc][math][c23] Implement C23 math function asinhf16
3 participants