use core::arch::aarch64::{
self, uint32x4_t, vaddq_u32, vandq_u32, vdupq_n_u32, vhaddq_u32, vminq_u32, vmlsq_n_u32,
vtstq_u32,
};
use crate::{PackedMontyParameters, TwoAdicData};
#[inline(always)]
pub(crate) fn halve_neon<PMP: PackedMontyParameters>(input: uint32x4_t) -> uint32x4_t {
unsafe {
let one = vdupq_n_u32(1);
let is_odd_mask = vtstq_u32(input, one);
let to_add = vandq_u32(PMP::PACKED_P, is_odd_mask);
vhaddq_u32(input, to_add)
}
}
#[inline(always)]
pub unsafe fn mul_2exp_neg_n_neon<TAD: TwoAdicData + PackedMontyParameters, const N: i32>(
input: uint32x4_t,
) -> uint32x4_t {
const {
assert!(N <= TAD::TWO_ADICITY as i32);
}
unsafe {
let mask = aarch64::vdupq_n_u32((1u32 << N) - 1);
let lo = aarch64::vandq_u32(input, mask);
let hi = aarch64::vshrq_n_u32::<N>(input);
let n_prime = TAD::TWO_ADICITY as i32 - N;
let res = vmlsq_n_u32(hi, lo, (TAD::ODD_FACTOR as u32) << n_prime);
let u = aarch64::vaddq_u32(res, TAD::PACKED_P);
aarch64::vminq_u32(res, u)
}
}
#[inline(always)]
pub unsafe fn mul_2exp_neg_two_adicity_neon<
TAD: TwoAdicData + PackedMontyParameters,
const N: i32,
const N_PRIME: i32,
>(
input: uint32x4_t,
) -> uint32x4_t {
const {
assert!(N == TAD::TWO_ADICITY as i32);
assert!(N + N_PRIME == 31);
}
unsafe {
let mask = vdupq_n_u32((1u32 << N) - 1);
let lo = vandq_u32(input, mask);
let hi_plus_lo = aarch64::vsraq_n_u32::<N>(lo, input);
let lo_shft = aarch64::vshlq_n_u32::<N_PRIME>(lo);
let res = aarch64::vsubq_u32(hi_plus_lo, lo_shft);
let u = vaddq_u32(res, TAD::PACKED_P);
vminq_u32(res, u)
}
}