Skip to content

Commit eadda81

Browse files
committed
[libc][math][c23] Add tanhf16 C23 math function
Part of #95250.
1 parent 9102fa2 commit eadda81

File tree

12 files changed

+386
-1
lines changed

12 files changed

+386
-1
lines changed

libc/config/gpu/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
551551
libc.src.math.setpayloadf16
552552
libc.src.math.setpayloadsigf16
553553
libc.src.math.sinhf16
554+
libc.src.math.tanhf16
554555
libc.src.math.totalorderf16
555556
libc.src.math.totalordermagf16
556557
libc.src.math.truncf16

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
662662
libc.src.math.setpayloadf16
663663
libc.src.math.setpayloadsigf16
664664
libc.src.math.sinhf16
665+
libc.src.math.tanhf16
665666
libc.src.math.totalorderf16
666667
libc.src.math.totalordermagf16
667668
libc.src.math.truncf16

libc/docs/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ Higher Math Functions
344344
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
345345
| tan | |check| | |check| | | | | 7.12.4.7 | F.10.1.7 |
346346
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
347-
| tanh | |check| | | | | | 7.12.5.6 | F.10.2.6 |
347+
| tanh | |check| | | | |check| | | 7.12.5.6 | F.10.2.6 |
348348
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
349349
| tanpi | | | | | | 7.12.4.14 | F.10.1.14 |
350350
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/spec/stdc.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@ def StdC : StandardSpec<"stdc"> {
712712
GuardedFunctionSpec<"sinhf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
713713

714714
FunctionSpec<"tanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
715+
GuardedFunctionSpec<"tanhf16", RetValSpec<Float16Type>, [ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
715716

716717
FunctionSpec<"acosf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
717718

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ add_math_entrypoint_object(tanf)
483483

484484
add_math_entrypoint_object(tanh)
485485
add_math_entrypoint_object(tanhf)
486+
add_math_entrypoint_object(tanhf16)
486487

487488
add_math_entrypoint_object(tgamma)
488489
add_math_entrypoint_object(tgammaf)

libc/src/math/generic/CMakeLists.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4154,6 +4154,28 @@ add_entrypoint_object(
41544154
-O3
41554155
)
41564156

4157+
add_entrypoint_object(
4158+
tanhf16
4159+
SRCS
4160+
tanhf16.cpp
4161+
HDRS
4162+
../tanhf16.h
4163+
DEPENDS
4164+
.expxf16
4165+
libc.hdr.fenv_macros
4166+
libc.src.__support.CPP.array
4167+
libc.src.__support.FPUtil.except_value_utils
4168+
libc.src.__support.FPUtil.fenv_impl
4169+
libc.src.__support.FPUtil.fp_bits
4170+
libc.src.__support.FPUtil.multiply_add
4171+
libc.src.__support.FPUtil.nearest_integer
4172+
libc.src.__support.FPUtil.polyeval
4173+
libc.src.__support.FPUtil.rounding_mode
4174+
libc.src.__support.macros.optimization
4175+
COMPILE_OPTIONS
4176+
-O3
4177+
)
4178+
41574179
add_entrypoint_object(
41584180
acoshf
41594181
SRCS

libc/src/math/generic/tanhf16.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//===-- Half-precision tanh(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/tanhf16.h"
10+
#include "expxf16.h"
11+
#include "hdr/fenv_macros.h"
12+
#include "src/__support/CPP/array.h"
13+
#include "src/__support/FPUtil/FEnvImpl.h"
14+
#include "src/__support/FPUtil/FPBits.h"
15+
#include "src/__support/FPUtil/PolyEval.h"
16+
#include "src/__support/FPUtil/except_value_utils.h"
17+
#include "src/__support/FPUtil/multiply_add.h"
18+
#include "src/__support/FPUtil/nearest_integer.h"
19+
#include "src/__support/FPUtil/rounding_mode.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+
static constexpr fputil::ExceptValues<float16, 2> TANHF16_EXCEPTS = {{
27+
// x = 0x1.f54p+0, tanhf16(x) = 0x1.ecp-1 (RZ)
28+
{0x3fd5U, 0x3bb0U, 1U, 0U, 0U},
29+
// x = -0x1.f54p+0, tanhf16(x) = -0x1.ecp-1 (RZ)
30+
{0xbfd5U, 0xbbb0U, 0U, 1U, 0U},
31+
}};
32+
33+
LLVM_LIBC_FUNCTION(float16, tanhf16, (float16 x)) {
34+
using FPBits = fputil::FPBits<float16>;
35+
FPBits x_bits(x);
36+
37+
uint16_t x_u = x_bits.uintval();
38+
uint16_t x_abs = x_u & 0x7fffU;
39+
40+
// When -2^(-14) <= x <= -2^(-9), or |x| <= 0x1.d2p-4,
41+
// or |x| >= atanh(1 - 2^(-11)), or x is NaN.
42+
if (LIBC_UNLIKELY((x_u >= 0x8400U && x_u <= 0x9800U) || x_abs <= 0x2f48U ||
43+
x_abs >= 0x4429U)) {
44+
// tanh(NaN) = NaN
45+
if (x_bits.is_nan()) {
46+
if (x_bits.is_signaling_nan()) {
47+
fputil::raise_except_if_required(FE_INVALID);
48+
return FPBits::quiet_nan().get_val();
49+
}
50+
51+
return x;
52+
}
53+
54+
// When -2^(-14) <= x <= -2^(-9).
55+
if (x_u >= 0x8400U && x_u <= 0x9800U) {
56+
switch (fputil::quick_get_round()) {
57+
case FE_TONEAREST:
58+
case FE_DOWNWARD:
59+
return x;
60+
default:
61+
return FPBits(static_cast<uint16_t>(x_u - 1U)).get_val();
62+
}
63+
}
64+
65+
// When |x| <= 0x1.d2p-4.
66+
if (x_abs <= 0x2f48U) {
67+
float xf = x;
68+
float xf_sq = xf * xf;
69+
// Degree-7 Taylor expansion generated by Sollya with the following
70+
// commands:
71+
// > taylor(tanh(x), 7, 0);
72+
// > display = hexadecimal;
73+
// > // For each coefficient:
74+
// > round(/* put coefficient here */, SG, RN);
75+
return static_cast<float16>(
76+
xf * fputil::polyeval(xf_sq, 0x1p+0f, -0x1.555556p-2f, 0x1.111112p-3f,
77+
-0x1.ba1ba2p-5f));
78+
}
79+
80+
// tanh(+/-inf) = +/-1
81+
if (x_bits.is_inf())
82+
return FPBits::one(x_bits.sign()).get_val();
83+
84+
// When |x| >= atanh(1 - 2^(-11)).
85+
fputil::raise_except_if_required(FE_INEXACT);
86+
87+
int rounding_mode = fputil::quick_get_round();
88+
if ((rounding_mode == FE_TONEAREST && x_abs >= 0x4482U) ||
89+
(rounding_mode == FE_UPWARD && x_bits.is_pos()) ||
90+
(rounding_mode == FE_DOWNWARD && x_bits.is_neg())) {
91+
return FPBits::one(x_bits.sign()).get_val();
92+
}
93+
if (x_bits.is_pos())
94+
return static_cast<float16>(0x1.ffcp-1);
95+
return static_cast<float16>(-0x1.ffcp-1);
96+
}
97+
98+
if (auto r = TANHF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
99+
return r.value();
100+
101+
// For atanh(-1 + 2^(-11)) < x < atanh(1 - 2^(-11)), to compute tanh(x), we
102+
// perform the following range reduction: find hi, mid, lo, such that:
103+
// x = (hi + mid) * log(2) * 0.5 + lo, in which
104+
// hi is an integer,
105+
// mid * 2^5 is an integer,
106+
// -2^(-5) <= lo < 2^(-5).
107+
// In particular,
108+
// hi + mid = round(x * log2(e) * 2 * 2^5) * 2^(-5).
109+
// Then,
110+
// tanh(x) = sinh(x)/cosh(x)
111+
// = (e^x - e^(-x)) / (e^x + e^(-x))
112+
// = (e^(2x) - 1) / (e^(2x) + 1)
113+
// = (2^(hi + mid) * e^(2*lo) - 1) / (2^(hi + mid) * e^(2*lo) + 1)
114+
// = (e^(2*lo) - 2^(-hi - mid)) / (e^(2*lo) + 2^(-hi - mid))
115+
// We store 2^(-mid) in the lookup table EXP2_MID_5_BITS, and compute
116+
// 2^(-hi - mid) by adding -hi to the exponent field of 2^(-mid).
117+
// e^lo is computed using a degree-3 minimax polynomial generated by Sollya.
118+
119+
float xf = x;
120+
float kf = fputil::nearest_integer(xf * (LOG2F_E * 2.0f * 0x1.0p+5f));
121+
int x_hi_mid = -static_cast<int>(kf);
122+
int x_hi = x_hi_mid >> 5;
123+
int x_mid = x_hi_mid & 0x1f;
124+
// lo = x - (hi + mid)
125+
// = round(x * log2(e) * 2 * 2^5) * log(2) * 0.5 * (-2^(-5)) + x
126+
float lo = fputil::multiply_add(kf, LOGF_2 * 0.5f * -0x1.0p-5f, xf);
127+
128+
uint32_t exp2_hi_mid_bits =
129+
EXP2_MID_5_BITS[x_mid] +
130+
static_cast<uint32_t>(x_hi << fputil::FPBits<float>::FRACTION_LEN);
131+
// exp2_hi_mid = 2^(-hi - mid)
132+
float exp2_hi_mid = fputil::FPBits<float>(exp2_hi_mid_bits).get_val();
133+
// Degree-3 minimax polynomial generated by Sollya with the following
134+
// commands:
135+
// > display = hexadecimal;
136+
// > P = fpminimax(expm1(2*x)/x, 2, [|SG...|], [-2^-5, 2^-5]);
137+
// > 1 + x * P;
138+
float exp_2lo =
139+
fputil::polyeval(lo, 0x1p+0f, 0x1p+1f, 0x1.001p+1f, 0x1.555ddep+0f);
140+
return static_cast<float16>((exp_2lo - exp2_hi_mid) /
141+
(exp_2lo + exp2_hi_mid));
142+
}
143+
144+
} // namespace LIBC_NAMESPACE_DECL

libc/src/math/tanhf16.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for tanhf16 -----------------------*- 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_TANHF16_H
10+
#define LLVM_LIBC_SRC_MATH_TANHF16_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 tanhf16(float16 x);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_MATH_TANHF16_H

libc/test/src/math/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,17 @@ add_fp_unittest(
19551955
libc.src.__support.FPUtil.fp_bits
19561956
)
19571957

1958+
add_fp_unittest(
1959+
tanhf16_test
1960+
NEED_MPFR
1961+
SUITE
1962+
libc-math-unittests
1963+
SRCS
1964+
tanhf16_test.cpp
1965+
DEPENDS
1966+
libc.src.math.tanhf16
1967+
)
1968+
19581969
add_fp_unittest(
19591970
atanhf_test
19601971
NEED_MPFR

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3626,6 +3626,18 @@ add_fp_unittest(
36263626
libc.src.__support.FPUtil.fp_bits
36273627
)
36283628

3629+
add_fp_unittest(
3630+
tanhf16_test
3631+
SUITE
3632+
libc-math-smoke-tests
3633+
SRCS
3634+
tanhf16_test.cpp
3635+
DEPENDS
3636+
libc.hdr.fenv_macros
3637+
libc.src.errno.errno
3638+
libc.src.math.tanhf16
3639+
)
3640+
36293641
add_fp_unittest(
36303642
atanhf_test
36313643
SUITE

0 commit comments

Comments
 (0)