xref: /aosp_15_r20/external/llvm-libc/src/math/generic/coshf16.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Half-precision cosh(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/coshf16.h"
10 #include "expxf16.h"
11 #include "hdr/errno_macros.h"
12 #include "hdr/fenv_macros.h"
13 #include "src/__support/FPUtil/FEnvImpl.h"
14 #include "src/__support/FPUtil/FPBits.h"
15 #include "src/__support/FPUtil/except_value_utils.h"
16 #include "src/__support/FPUtil/rounding_mode.h"
17 #include "src/__support/common.h"
18 #include "src/__support/macros/config.h"
19 #include "src/__support/macros/optimization.h"
20 
21 namespace LIBC_NAMESPACE_DECL {
22 
23 static constexpr fputil::ExceptValues<float16, 9> COSHF16_EXCEPTS_POS = {{
24     // x = 0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ)
25     {0x29a8U, 0x3c00U, 1U, 0U, 1U},
26     // x = 0x1.8c4p+0, coshf16(x) = 0x1.3a8p+1 (RZ)
27     {0x3e31U, 0x40eaU, 1U, 0U, 0U},
28     // x = 0x1.994p+0, coshf16(x) = 0x1.498p+1 (RZ)
29     {0x3e65U, 0x4126U, 1U, 0U, 0U},
30     // x = 0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ)
31     {0x3ed8U, 0x41b6U, 1U, 0U, 1U},
32     // x = 0x1.aap+1, coshf16(x) = 0x1.be8p+3 (RZ)
33     {0x42a8U, 0x4afaU, 1U, 0U, 1U},
34     // x = 0x1.cc4p+1, coshf16(x) = 0x1.23cp+4 (RZ)
35     {0x4331U, 0x4c8fU, 1U, 0U, 0U},
36     // x = 0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ)
37     {0x44a2U, 0x526dU, 1U, 0U, 0U},
38     // x = 0x1.958p+2, coshf16(x) = 0x1.1a4p+8 (RZ)
39     {0x4656U, 0x5c69U, 1U, 0U, 0U},
40     // x = 0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ)
41     {0x497cU, 0x7715U, 1U, 0U, 1U},
42 }};
43 
44 static constexpr fputil::ExceptValues<float16, 4> COSHF16_EXCEPTS_NEG = {{
45     // x = -0x1.6ap-5, coshf16(x) = 0x1p+0 (RZ)
46     {0xa9a8U, 0x3c00U, 1U, 0U, 1U},
47     // x = -0x1.b6p+0, coshf16(x) = 0x1.6d8p+1 (RZ)
48     {0xbed8U, 0x41b6U, 1U, 0U, 1U},
49     // x = -0x1.288p+2, coshf16(x) = 0x1.9b4p+5 (RZ)
50     {0xc4a2U, 0x526dU, 1U, 0U, 0U},
51     // x = -0x1.5fp+3, coshf16(x) = 0x1.c54p+14 (RZ)
52     {0xc97cU, 0x7715U, 1U, 0U, 1U},
53 }};
54 
55 LLVM_LIBC_FUNCTION(float16, coshf16, (float16 x)) {
56   using FPBits = fputil::FPBits<float16>;
57   FPBits x_bits(x);
58 
59   uint16_t x_u = x_bits.uintval();
60   uint16_t x_abs = x_u & 0x7fffU;
61 
62   // When |x| >= acosh(2^16), or x is NaN.
63   if (LIBC_UNLIKELY(x_abs >= 0x49e5U)) {
64     // cosh(NaN) = NaN
65     if (x_bits.is_nan()) {
66       if (x_bits.is_signaling_nan()) {
67         fputil::raise_except_if_required(FE_INVALID);
68         return FPBits::quiet_nan().get_val();
69       }
70 
71       return x;
72     }
73 
74     // When |x| >= acosh(2^16).
75     if (x_abs >= 0x49e5U) {
76       // cosh(+/-inf) = +inf
77       if (x_bits.is_inf())
78         return FPBits::inf().get_val();
79 
80       switch (fputil::quick_get_round()) {
81       case FE_TONEAREST:
82       case FE_UPWARD:
83         fputil::set_errno_if_required(ERANGE);
84         fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
85         return FPBits::inf().get_val();
86       default:
87         return FPBits::max_normal().get_val();
88       }
89     }
90   }
91 
92   if (x_bits.is_pos()) {
93     if (auto r = COSHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
94       return r.value();
95   } else {
96     if (auto r = COSHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
97       return r.value();
98   }
99 
100   return eval_sinh_or_cosh</*IsSinh=*/false>(x);
101 }
102 
103 } // namespace LIBC_NAMESPACE_DECL
104