Skip to content

Commit d22e35b

Browse files
authored
[libc][math][c23] Add asinhf16 function (#131351)
Implement asinh for Float16 along with tests. Closes #131001
1 parent 1d0005a commit d22e35b

File tree

11 files changed

+259
-2
lines changed

11 files changed

+259
-2
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,10 @@ endif()
653653
if(LIBC_TYPES_HAS_FLOAT16)
654654
list(APPEND TARGET_LIBM_ENTRYPOINTS
655655
# math.h C23 _Float16 entrypoints
656-
libc.src.math.asinf16
657656
libc.src.math.acosf16
658657
libc.src.math.acoshf16
658+
libc.src.math.asinf16
659+
libc.src.math.asinhf16
659660
libc.src.math.canonicalizef16
660661
libc.src.math.ceilf16
661662
libc.src.math.copysignf16

libc/docs/headers/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ Higher Math Functions
257257
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
258258
| asin | |check| | | | |check| | | 7.12.4.2 | F.10.1.2 |
259259
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
260-
| asinh | |check| | | | | | 7.12.5.2 | F.10.2.2 |
260+
| asinh | |check| | | | |check| | | 7.12.5.2 | F.10.2.2 |
261261
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
262262
| asinpi | | | | | | 7.12.4.9 | F.10.1.9 |
263263
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/include/math.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ functions:
5959
return_type: float
6060
arguments:
6161
- type: float
62+
- name: asinhf16
63+
standards:
64+
- stdc
65+
return_type: _Float16
66+
arguments:
67+
- type: _Float16
68+
guard: LIBC_TYPES_HAS_FLOAT16
6269
- name: atan
6370
standards:
6471
- stdc

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ add_math_entrypoint_object(asinf16)
5454

5555
add_math_entrypoint_object(asinh)
5656
add_math_entrypoint_object(asinhf)
57+
add_math_entrypoint_object(asinhf16)
5758

5859
add_math_entrypoint_object(atan)
5960
add_math_entrypoint_object(atanf)

libc/src/math/asinhf16.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for asinhf16 ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception.
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_MATH_ASINHF16_H
10+
#define LLVM_LIBC_SRC_MATH_ASINHF16_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include "src/__support/macros/properties/types.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
float16 asinhf16(float16 x);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_MATH_ASINHF16_H

libc/src/math/generic/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,6 +3980,27 @@ add_entrypoint_object(
39803980
libc.src.__support.macros.optimization
39813981
)
39823982

3983+
add_entrypoint_object(
3984+
asinhf16
3985+
SRCS
3986+
asinhf16.cpp
3987+
HDRS
3988+
../asinhf16.h
3989+
DEPENDS
3990+
.explogxf
3991+
libc.hdr.fenv_macros
3992+
libc.src.__support.FPUtil.cast
3993+
libc.src.__support.FPUtil.except_value_utils
3994+
libc.src.__support.FPUtil.fenv_impl
3995+
libc.src.__support.FPUtil.fp_bits
3996+
libc.src.__support.FPUtil.multiply_add
3997+
libc.src.__support.FPUtil.polyeval
3998+
libc.src.__support.FPUtil.rounding_mode
3999+
libc.src.__support.FPUtil.sqrt
4000+
libc.src.__support.macros.optimization
4001+
libc.src.__support.macros.properties.types
4002+
)
4003+
39834004
add_entrypoint_object(
39844005
atanhf
39854006
SRCS

libc/src/math/generic/asinhf16.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===-- Half-precision asinh(x) function ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception.
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/math/asinhf16.h"
10+
#include "explogxf.h"
11+
#include "hdr/fenv_macros.h"
12+
#include "src/__support/FPUtil/FEnvImpl.h"
13+
#include "src/__support/FPUtil/FPBits.h"
14+
#include "src/__support/FPUtil/PolyEval.h"
15+
#include "src/__support/FPUtil/cast.h"
16+
#include "src/__support/FPUtil/except_value_utils.h"
17+
#include "src/__support/FPUtil/multiply_add.h"
18+
#include "src/__support/FPUtil/rounding_mode.h"
19+
#include "src/__support/FPUtil/sqrt.h"
20+
#include "src/__support/common.h"
21+
#include "src/__support/macros/config.h"
22+
#include "src/__support/macros/optimization.h"
23+
24+
namespace LIBC_NAMESPACE_DECL {
25+
26+
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
27+
static constexpr size_t N_EXCEPTS = 8;
28+
29+
static constexpr fputil::ExceptValues<float16, N_EXCEPTS> ASINHF16_EXCEPTS{{
30+
// (input, RZ output, RU offset, RD offset, RN offset)
31+
32+
// x = 0x1.da4p-2, asinhf16(x) = 0x1.ca8p-2 (RZ)
33+
{0x3769, 0x372a, 1, 0, 1},
34+
// x = 0x1.d6cp-1, asinhf16(x) = 0x1.a58p-1 (RZ)
35+
{0x3b5b, 0x3a96, 1, 0, 0},
36+
// x = 0x1.c7cp+3, asinhf16(x) = 0x1.accp+1 (RZ)
37+
{0x4b1f, 0x42b3, 1, 0, 0},
38+
// x = 0x1.26cp+4, asinhf16(x) = 0x1.cd8p+1 (RZ)
39+
{0x4c9b, 0x4336, 1, 0, 1},
40+
// x = -0x1.da4p-2, asinhf16(x) = -0x1.ca8p-2 (RZ)
41+
{0xb769, 0xb72a, 0, 1, 1},
42+
// x = -0x1.d6cp-1, asinhf16(x) = -0x1.a58p-1 (RZ)
43+
{0xbb5b, 0xba96, 0, 1, 0},
44+
// x = -0x1.c7cp+3, asinhf16(x) = -0x1.accp+1 (RZ)
45+
{0xcb1f, 0xc2b3, 0, 1, 0},
46+
// x = -0x1.26cp+4, asinhf16(x) = -0x1.cd8p+1 (RZ)
47+
{0xcc9b, 0xc336, 0, 1, 1},
48+
}};
49+
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
50+
51+
LLVM_LIBC_FUNCTION(float16, asinhf16, (float16 x)) {
52+
using FPBits = fputil::FPBits<float16>;
53+
FPBits xbits(x);
54+
55+
uint16_t x_u = xbits.uintval();
56+
uint16_t x_abs = x_u & 0x7fff;
57+
58+
if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) {
59+
if (xbits.is_signaling_nan()) {
60+
fputil::raise_except_if_required(FE_INVALID);
61+
return FPBits::quiet_nan().get_val();
62+
}
63+
64+
return x;
65+
}
66+
67+
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
68+
// Handle exceptional values
69+
if (auto r = ASINHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
70+
return r.value();
71+
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
72+
73+
float xf = x;
74+
const float SIGN[2] = {1.0f, -1.0f};
75+
float x_sign = SIGN[x_u >> 15];
76+
77+
// |x| <= 0.25
78+
if (LIBC_UNLIKELY(x_abs <= 0x3400)) {
79+
// when |x| < 0x1.718p-5, asinhf16(x) = x. Adjust by 1 ULP for certain
80+
// rounding types.
81+
if (LIBC_UNLIKELY(x_abs < 0x29c6)) {
82+
int rounding = fputil::quick_get_round();
83+
if ((rounding == FE_UPWARD || rounding == FE_TOWARDZERO) && xf < 0)
84+
return fputil::cast<float16>(xf + 0x1p-24f);
85+
if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && xf > 0)
86+
return fputil::cast<float16>(xf - 0x1p-24f);
87+
return fputil::cast<float16>(xf);
88+
}
89+
90+
float x_sq = xf * xf;
91+
// Generated by Sollya with:
92+
// > P = fpminimax(asinh(x)/x, [|0, 2, 4, 6, 8|], [|SG...|], [0, 2^-2]);
93+
// The last coefficient 0x1.bd114ep-6f has been changed to 0x1.bd114ep-5f
94+
// for better accuracy.
95+
float p = fputil::polyeval(x_sq, 1.0f, -0x1.555552p-3f, 0x1.332f6ap-4f,
96+
-0x1.6c53dep-5f, 0x1.bd114ep-5f);
97+
98+
return fputil::cast<float16>(xf * p);
99+
}
100+
101+
// General case: asinh(x) = ln(x + sqrt(x^2 + 1))
102+
float sqrt_term = fputil::sqrt<float>(fputil::multiply_add(xf, xf, 1.0f));
103+
return fputil::cast<float16>(
104+
x_sign * log_eval(fputil::multiply_add(xf, x_sign, sqrt_term)));
105+
}
106+
107+
} // namespace LIBC_NAMESPACE_DECL

libc/test/src/math/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,17 @@ add_fp_unittest(
21752175
libc.src.__support.FPUtil.fp_bits
21762176
)
21772177

2178+
add_fp_unittest(
2179+
asinhf16_test
2180+
NEED_MPFR
2181+
SUITE
2182+
libc-math-unittests
2183+
SRCS
2184+
asinhf16_test.cpp
2185+
DEPENDS
2186+
libc.src.math.asinhf16
2187+
)
2188+
21782189
add_fp_unittest(
21792190
acoshf_test
21802191
NEED_MPFR

libc/test/src/math/asinhf16_test.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===-- Exhaustive test for asinhf16 --------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/math/asinhf16.h"
10+
#include "test/UnitTest/FPMatcher.h"
11+
#include "test/UnitTest/Test.h"
12+
#include "utils/MPFRWrapper/MPFRUtils.h"
13+
14+
using LlvmLibcAsinhf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
15+
16+
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
17+
18+
// Range: [0, Inf]
19+
static constexpr uint16_t POS_START = 0x0000U;
20+
static constexpr uint16_t POS_STOP = 0x7c00U;
21+
22+
// Range: [-Inf, 0]
23+
static constexpr uint16_t NEG_START = 0x8000U;
24+
static constexpr uint16_t NEG_STOP = 0xfc00U;
25+
26+
TEST_F(LlvmLibcAsinhf16Test, PositiveRange) {
27+
for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
28+
float16 x = FPBits(v).get_val();
29+
30+
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, x,
31+
LIBC_NAMESPACE::asinhf16(x), 0.5);
32+
}
33+
}
34+
35+
TEST_F(LlvmLibcAsinhf16Test, NegativeRange) {
36+
for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
37+
float16 x = FPBits(v).get_val();
38+
39+
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinh, x,
40+
LIBC_NAMESPACE::asinhf16(x), 0.5);
41+
}
42+
}

libc/test/src/math/smoke/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,17 @@ add_fp_unittest(
39463946
libc.src.__support.FPUtil.fp_bits
39473947
)
39483948

3949+
add_fp_unittest(
3950+
asinhf16_test
3951+
SUITE
3952+
libc-math-smoke-tests
3953+
SRCS
3954+
asinhf16_test.cpp
3955+
DEPENDS
3956+
libc.src.errno.errno
3957+
libc.src.math.asinhf16
3958+
)
3959+
39493960
add_fp_unittest(
39503961
acoshf_test
39513962
SUITE
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===-- Unittests for asinhf16 --------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/errno/libc_errno.h"
10+
#include "src/math/asinhf16.h"
11+
#include "test/UnitTest/FPMatcher.h"
12+
#include "test/UnitTest/Test.h"
13+
14+
using LlvmLibcAsinhf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
15+
16+
TEST_F(LlvmLibcAsinhf16Test, SpecialNumbers) {
17+
LIBC_NAMESPACE::libc_errno = 0;
18+
EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinhf16(aNaN));
19+
EXPECT_MATH_ERRNO(0);
20+
21+
EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::asinhf16(sNaN), FE_INVALID);
22+
EXPECT_MATH_ERRNO(0);
23+
24+
EXPECT_FP_EQ(zero, LIBC_NAMESPACE::asinhf16(zero));
25+
EXPECT_MATH_ERRNO(0);
26+
27+
EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::asinhf16(neg_zero));
28+
EXPECT_MATH_ERRNO(0);
29+
30+
EXPECT_FP_EQ(inf, LIBC_NAMESPACE::asinhf16(inf));
31+
EXPECT_MATH_ERRNO(0);
32+
33+
EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::asinhf16(neg_inf));
34+
EXPECT_MATH_ERRNO(0);
35+
}

0 commit comments

Comments
 (0)