| 1 | //===-- Implementation of tanbf16 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 | #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H |
| 10 | #define LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H |
| 11 | |
| 12 | #include "hdr/errno_macros.h" |
| 13 | #include "hdr/fenv_macros.h" |
| 14 | #include "sincosf_utils.h" |
| 15 | #include "src/__support/FPUtil/FEnvImpl.h" |
| 16 | #include "src/__support/FPUtil/FPBits.h" |
| 17 | #include "src/__support/FPUtil/bfloat16.h" |
| 18 | #include "src/__support/FPUtil/cast.h" |
| 19 | #include "src/__support/FPUtil/multiply_add.h" |
| 20 | #include "src/__support/macros/optimization.h" |
| 21 | |
| 22 | namespace LIBC_NAMESPACE_DECL { |
| 23 | |
| 24 | namespace math { |
| 25 | |
| 26 | LIBC_INLINE bfloat16 tanbf16(bfloat16 x) { |
| 27 | |
| 28 | using FPBits = fputil::FPBits<bfloat16>; |
| 29 | FPBits xbits(x); |
| 30 | |
| 31 | uint16_t x_u = xbits.uintval(); |
| 32 | uint16_t x_abs = x_u & 0x7fff; |
| 33 | float xf = x; |
| 34 | |
| 35 | // NaN or -/+ INF |
| 36 | if (x_abs >= 0x7F80) { |
| 37 | // NaN |
| 38 | if (xbits.is_nan()) { |
| 39 | if (xbits.is_signaling_nan()) { |
| 40 | fputil::raise_except_if_required(FE_INVALID); |
| 41 | return FPBits::quiet_nan().get_val(); |
| 42 | } |
| 43 | return x; |
| 44 | } |
| 45 | //|x| is +/- INF |
| 46 | fputil::set_errno_if_required(EDOM); |
| 47 | fputil::raise_except_if_required(FE_INVALID); |
| 48 | return x + FPBits::quiet_nan().get_val(); |
| 49 | } |
| 50 | |
| 51 | // Through Exhaustive testing - |
| 52 | // The last value where tan(x) ~ x is 0x3db8 |
| 53 | if (LIBC_UNLIKELY(x_abs <= 0x3db8)) { |
| 54 | // |x| = {0} |
| 55 | if (LIBC_UNLIKELY(x_abs == 0)) { |
| 56 | return x; |
| 57 | } |
| 58 | return fputil::cast<bfloat16>(x: fputil::multiply_add(x: xf, y: 0x1.0p-11f, z: xf)); |
| 59 | } |
| 60 | |
| 61 | double xd = static_cast<double>(xf); |
| 62 | uint32_t x_abs_f = fputil::FPBits<float>(xf).uintval() & 0x7fffffff; |
| 63 | double sin_k, cos_k, sin_y, cosm1_y; |
| 64 | |
| 65 | // TODO: Use bfloat16 version for inv_trigf_utils_internals after they are |
| 66 | // available |
| 67 | // Tracking issue : |
| 68 | // https://github.com/llvm/llvm-project/issues/202079 |
| 69 | sincosf_utils_internal::sincosf_eval(xd, x_abs: x_abs_f, sin_k, cos_k, sin_y, |
| 70 | cosm1_y); |
| 71 | |
| 72 | return fputil::cast<bfloat16>( |
| 73 | x: fputil::multiply_add(x: sin_y, y: cos_k, |
| 74 | z: fputil::multiply_add(x: cosm1_y, y: sin_k, z: sin_k)) / |
| 75 | fputil::multiply_add(x: sin_y, y: -sin_k, |
| 76 | z: fputil::multiply_add(x: cosm1_y, y: cos_k, z: cos_k))); |
| 77 | } |
| 78 | |
| 79 | } // namespace math |
| 80 | |
| 81 | } // namespace LIBC_NAMESPACE_DECL |
| 82 | |
| 83 | #endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H |
| 84 | |