blob: 848b9647dd6126f64bb7ee60d3a144629262c124 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the implemenation for single-precision SIMD exp2.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXP2F_H
#define LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXP2F_H
#include "expf_utils.h"
#include "src/__support/CPP/simd.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/common.h"
namespace LIBC_NAMESPACE_DECL {
namespace mathvec {
template <size_t N>
LIBC_INLINE static cpp::simd<double, N> inline_exp2(cpp::simd<double, N> x) {
constexpr cpp::simd<double, N> shift = 0x1.800000000ffc0p+46;
// Rounds n to be x to the nearest multiple of 1/64
// While preparing z to be used as an index for the lookup in eval_exp
cpp::simd<double, N> z = x + shift;
cpp::simd<double, N> n = z - shift;
// ln(2), with a bias of +768 FP64 ULP, which is enough to remove the
// hard to round cases when casting back to FP32.
constexpr cpp::simd<double, N> biased_ln2 = 0x1.62e42fefa3cefp-1;
// Using 2^x = e^(x * ln2),
// Reduces x into r as:
// r = (x - n) * ln(2), with |r| <= ln2/128.
// then computes 2^x = 2^n * exp(r).
cpp::simd<double, N> r = (x - n) * biased_ln2;
return eval_exp(r, z);
}
template <size_t N>
LIBC_INLINE cpp::simd<float, N> exp2f(cpp::simd<float, N> x) {
using FPBits = typename fputil::FPBits<float>;
cpp::simd<bool, N> is_inf = x >= 0x1p7;
cpp::simd<bool, N> is_zero = x <= -0x1.2cp7f;
cpp::simd<bool, N> is_special = is_inf | is_zero;
cpp::simd<float, N> special_res = is_inf ? FPBits::inf().get_val() : 0.0f;
cpp::simd<double, N> x_d = cpp::simd_cast<double, float, N>(x);
cpp::simd<double, N> y = inline_exp2(x_d);
cpp::simd<float, N> ret = cpp::simd_cast<float, double, N>(y);
return is_special ? special_res : ret;
}
} // namespace mathvec
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXP2F_H