blob: a7307af4f85dc644d941e36d9887501f11c0fd81 [file] [edit]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#ifndef EIGEN_NEON_SPECIALFUNCTIONS_H
#define EIGEN_NEON_SPECIALFUNCTIONS_H
namespace Eigen {
namespace internal {
#if EIGEN_ARCH_ARM
// For x = n * 2^-149, n < 2^23, erf(x) = (2/sqrt(pi))*x to float precision.
// round((2/sqrt(pi))*2^31) = 2423175810; the coefficient error contributes < 0.000319 ULP.
// Integer rounding avoids ARMv7 NEON's input/output flushing. The result bits also cover the first normal binade.
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2i perf_subnormal_significands(const Packet2i& n) {
return vreinterpret_s32_u32(vrshrn_n_u64(vmull_u32(vreinterpret_u32_s32(n), vdup_n_u32(2423175810u)), 31));
}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4i perf_subnormal_significands(const Packet4i& n) {
return vcombine_s32(perf_subnormal_significands(Packet2i(vget_low_s32(n))),
perf_subnormal_significands(Packet2i(vget_high_s32(n))));
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet perf_neon(const Packet& x) {
using PacketI = typename unpacket_traits<Packet>::integer_packet;
const Packet result = generic_fast_erf<float>::run(x);
const PacketI bits = preinterpret<PacketI>(x);
const PacketI magnitude = pand(bits, pset1<PacketI>(0x7fffffff));
const PacketI sign = pxor(bits, magnitude);
const PacketI subnormal = pcmp_lt(magnitude, pset1<PacketI>(0x00800000));
const PacketI recovered = por(perf_subnormal_significands(magnitude), sign);
return pselect(preinterpret<Packet>(subnormal), preinterpret<Packet>(recovered), result);
}
template <>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet2f perf<Packet2f>(const Packet2f& x) {
return perf_neon(x);
}
template <>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4f perf<Packet4f>(const Packet4f& x) {
return perf_neon(x);
}
#endif
#if EIGEN_ARCH_ARM64 && EIGEN_HAS_ARM64_FP16
#define NEON_HALF_TO_FLOAT_FUNCTIONS(METHOD) \
template <> \
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf METHOD<Packet8hf>(const Packet8hf& x) { \
const Packet4f lo = METHOD<Packet4f>(vcvt_f32_f16(vget_low_f16(x))); \
const Packet4f hi = METHOD<Packet4f>(vcvt_f32_f16(vget_high_f16(x))); \
return vcombine_f16(vcvt_f16_f32(lo), vcvt_f16_f32(hi)); \
} \
\
template <> \
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf METHOD<Packet4hf>(const Packet4hf& x) { \
return vcvt_f16_f32(METHOD<Packet4f>(vcvt_f32_f16(x))); \
}
NEON_HALF_TO_FLOAT_FUNCTIONS(perf)
NEON_HALF_TO_FLOAT_FUNCTIONS(pndtri)
#undef NEON_HALF_TO_FLOAT_FUNCTIONS
#endif // EIGEN_ARCH_ARM64 && EIGEN_HAS_ARM64_FP16
EIGEN_INSTANTIATE_SPECIAL_FUNCS_BF16(Packet4f, Packet4bf)
EIGEN_INSTANTIATE_SPECIAL_FUNCS_BF16_WITH(BF16_PACKET_FUNCTION_HALVES, Packet4f, Packet8bf)
} // namespace internal
} // namespace Eigen
#endif // EIGEN_NEON_SPECIALFUNCTIONS_H