use super::*;
#[inline(always)]
pub fn neon_rcp_f32(v: float32x4_t) -> float32x4_t {
unsafe {
let e = vrecpeq_f32(v);
vmulq_f32(e, vrecpsq_f32(v, e))
}
}
#[inline(always)]
pub fn neon_rcp_f64(v: float64x2_t) -> float64x2_t {
unsafe {
let e = vrecpeq_f64(v);
vmulq_f64(e, vrecpsq_f64(v, e))
}
}
#[inline(always)]
pub fn neon_rsqrt_f32(v: float32x4_t) -> float32x4_t {
unsafe {
let e = vrsqrteq_f32(v);
vmulq_f32(e, vrsqrtsq_f32(vmulq_f32(v, e), e))
}
}
#[inline(always)]
pub fn neon_rsqrt_f64(v: float64x2_t) -> float64x2_t {
unsafe {
let e = vrsqrteq_f64(v);
vmulq_f64(e, vrsqrtsq_f64(vmulq_f64(v, e), e))
}
}
macro_rules! stamp_mulhi {
($($name:ident: $s:ident/$w:ident, $ty:ty, $get_lo:ident, $uzp:ident, $re:ident);* $(;)?) => {$(paste::paste! {
#[inline(always)]
pub fn $name(a: $ty, b: $ty) -> $ty {
unsafe {
let lo = [<vmull_ $s>]($get_lo(a), $get_lo(b));
let hi = [<vmull_high_ $s>](a, b);
$uzp($re(lo), $re(hi))
}
}
})*};
}
stamp_mulhi! {
neon_mulhi_s8: s8/s16, int8x16_t, vget_low_s8, vuzp2q_s8, vreinterpretq_s8_s16;
neon_mulhi_s16: s16/s32, int16x8_t, vget_low_s16, vuzp2q_s16, vreinterpretq_s16_s32;
neon_mulhi_s32: s32/s64, int32x4_t, vget_low_s32, vuzp2q_s32, vreinterpretq_s32_s64;
neon_mulhi_u8: u8/u16, uint8x16_t, vget_low_u8, vuzp2q_u8, vreinterpretq_u8_u16;
neon_mulhi_u16: u16/u32, uint16x8_t, vget_low_u16, vuzp2q_u16, vreinterpretq_u16_u32;
neon_mulhi_u32: u32/u64, uint32x4_t, vget_low_u32, vuzp2q_u32, vreinterpretq_u32_u64;
}
#[inline(always)]
pub fn neon_mullo_u64(a: uint64x2_t, b: uint64x2_t) -> uint64x2_t {
unsafe {
let a32 = vreinterpretq_u32_u64(a);
let b32 = vreinterpretq_u32_u64(b);
let cross = vmulq_u32(a32, vrev64q_u32(b32));
let cross = vshlq_n_u64::<32>(vpaddlq_u32(cross));
vmlal_u32(cross, vmovn_u64(a), vmovn_u64(b))
}
}