|
| 1 | +//===-- Implementation header for rsqrtf ------------------------*- 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___SUPPORT_MATH_RSQRTF_H |
| 10 | +#define LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H |
| 11 | + |
| 12 | +#include "hdr/errno_macros.h" |
| 13 | +#include "hdr/fenv_macros.h" |
| 14 | +#include "src/__support/FPUtil/FEnvImpl.h" |
| 15 | +#include "src/__support/FPUtil/FPBits.h" |
| 16 | +#include "src/__support/FPUtil/cast.h" |
| 17 | +#include "src/__support/FPUtil/sqrt.h" |
| 18 | +#include "src/__support/macros/optimization.h" |
| 19 | + |
| 20 | +namespace LIBC_NAMESPACE_DECL { |
| 21 | +namespace math { |
| 22 | + |
| 23 | +LIBC_INLINE static constexpr float rsqrtf(float x) { |
| 24 | + using FPBits = fputil::FPBits<float>; |
| 25 | + FPBits xbits(x); |
| 26 | + |
| 27 | + uint32_t x_u = xbits.uintval(); |
| 28 | + uint32_t x_abs = x_u & 0x7fff'ffffU; |
| 29 | + |
| 30 | + constexpr uint32_t INF_BITS = FPBits::inf().uintval(); |
| 31 | + |
| 32 | + // x is 0, inf/nan, or negative. |
| 33 | + if (LIBC_UNLIKELY(x_u == 0 || x_u >= INF_BITS)) { |
| 34 | + // x is NaN |
| 35 | + if (x_abs > INF_BITS) { |
| 36 | + if (xbits.is_signaling_nan()) { |
| 37 | + fputil::raise_except_if_required(FE_INVALID); |
| 38 | + return FPBits::quiet_nan().get_val(); |
| 39 | + } |
| 40 | + return x; |
| 41 | + } |
| 42 | + |
| 43 | + // |x| = 0 |
| 44 | + if (x_abs == 0) { |
| 45 | + fputil::raise_except_if_required(FE_DIVBYZERO); |
| 46 | + fputil::set_errno_if_required(ERANGE); |
| 47 | + return FPBits::inf(xbits.sign()).get_val(); |
| 48 | + } |
| 49 | + |
| 50 | + // -inf <= x < 0 |
| 51 | + if (x_u > 0x7fff'ffffU) { |
| 52 | + fputil::raise_except_if_required(FE_INVALID); |
| 53 | + fputil::set_errno_if_required(EDOM); |
| 54 | + return FPBits::quiet_nan().get_val(); |
| 55 | + } |
| 56 | + |
| 57 | + // x = +inf => rsqrt(x) = 0 |
| 58 | + return FPBits::zero(xbits.sign()).get_val(); |
| 59 | + } |
| 60 | + |
| 61 | + // TODO: add float based approximation when |
| 62 | + // LIBC_TARGET_CPU_HAS_FPU_DOUBLE is not defined |
| 63 | + double result = 1.0 / fputil::sqrt<double>(fputil::cast<double>(x)); |
| 64 | + |
| 65 | + return fputil::cast<float>(result); |
| 66 | +} |
| 67 | + |
| 68 | +} // namespace math |
| 69 | +} // namespace LIBC_NAMESPACE_DECL |
| 70 | + |
| 71 | +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H |
0 commit comments