use core::arch::x86_64::{self, __m256i};
use core::mem::transmute;
use crate::{MontyParameters, MontyParametersAVX2, TwoAdicData};
#[inline(always)]
pub(crate) fn halve_avx2<MP: MontyParameters>(input: __m256i) -> __m256i {
unsafe {
const ONE: __m256i = unsafe { transmute([1u32; 8]) };
let half = x86_64::_mm256_set1_epi32((MP::PRIME as i32 + 1) / 2);
let least_bit = x86_64::_mm256_and_si256(input, ONE); let t = x86_64::_mm256_srli_epi32::<1>(input);
let maybe_half = x86_64::_mm256_sign_epi32(half, least_bit);
x86_64::_mm256_add_epi32(t, maybe_half)
}
}
#[inline(always)]
pub(crate) unsafe fn signed_add_avx2<MPAVX2: MontyParametersAVX2>(
lhs: __m256i,
rhs: __m256i,
) -> __m256i {
unsafe {
let pos_neg_p = x86_64::_mm256_sign_epi32(MPAVX2::PACKED_P, rhs);
let sum = x86_64::_mm256_add_epi32(lhs, rhs);
let sum_corr = x86_64::_mm256_sub_epi32(sum, pos_neg_p);
x86_64::_mm256_min_epu32(sum, sum_corr)
}
}
#[inline(always)]
pub unsafe fn mul_2exp_neg_n_avx2<TAD: TwoAdicData, const N: i32, const N_PRIME: i32>(
input: __m256i,
) -> __m256i {
unsafe {
const {
assert!(N + N_PRIME == TAD::TWO_ADICITY as i32);
}
let odd_factor = x86_64::_mm256_set1_epi32(TAD::ODD_FACTOR); let mask = x86_64::_mm256_set1_epi32((1_i32 << N) - 1_i32);
let hi = x86_64::_mm256_srli_epi32::<N>(input);
let val_lo = x86_64::_mm256_and_si256(input, mask);
let lo_x_r = x86_64::_mm256_madd_epi16(val_lo, odd_factor);
let lo = x86_64::_mm256_slli_epi32::<N_PRIME>(lo_x_r);
x86_64::_mm256_sub_epi32(hi, lo)
}
}
#[inline(always)]
pub unsafe fn mul_neg_2exp_neg_n_avx2<TAD: TwoAdicData, const N: i32, const N_PRIME: i32>(
input: __m256i,
) -> __m256i {
unsafe {
const {
assert!(N + N_PRIME == TAD::TWO_ADICITY as i32);
}
let odd_factor = x86_64::_mm256_set1_epi32(TAD::ODD_FACTOR); let mask = x86_64::_mm256_set1_epi32((1_i32 << N) - 1_i32);
let hi = x86_64::_mm256_srli_epi32::<N>(input);
let lo = x86_64::_mm256_and_si256(input, mask);
let lo_x_r = x86_64::_mm256_madd_epi16(lo, odd_factor);
let lo_shft = x86_64::_mm256_slli_epi32::<N_PRIME>(lo_x_r);
x86_64::_mm256_sub_epi32(lo_shft, hi)
}
}
#[inline(always)]
pub unsafe fn mul_2exp_neg_8_avx2<TAD: TwoAdicData, const N_PRIME: i32>(input: __m256i) -> __m256i {
unsafe {
const {
assert!(8 + N_PRIME == TAD::TWO_ADICITY as i32);
}
let odd_factor = x86_64::_mm256_set1_epi32(TAD::ODD_FACTOR);
let hi = x86_64::_mm256_srli_epi32::<8>(input);
let lo_x_r = x86_64::_mm256_maddubs_epi16(input, odd_factor);
let lo_shft = x86_64::_mm256_slli_epi32::<N_PRIME>(lo_x_r);
x86_64::_mm256_sub_epi32(hi, lo_shft)
}
}
#[inline(always)]
pub unsafe fn mul_neg_2exp_neg_8_avx2<TAD: TwoAdicData, const N_PRIME: i32>(
input: __m256i,
) -> __m256i {
unsafe {
const {
assert!(8 + N_PRIME == TAD::TWO_ADICITY as i32);
}
let odd_factor = x86_64::_mm256_set1_epi32(TAD::ODD_FACTOR);
let hi = x86_64::_mm256_srli_epi32::<8>(input);
let lo_x_r = x86_64::_mm256_maddubs_epi16(input, odd_factor);
let lo_shft = x86_64::_mm256_slli_epi32::<N_PRIME>(lo_x_r);
x86_64::_mm256_sub_epi32(lo_shft, hi)
}
}
#[inline(always)]
pub unsafe fn mul_2exp_neg_two_adicity_avx2<TAD: TwoAdicData, const N: i32, const N_PRIME: i32>(
input: __m256i,
) -> __m256i {
unsafe {
const {
assert!(N == TAD::TWO_ADICITY as i32);
assert!(N + N_PRIME == 31);
}
let mask = x86_64::_mm256_set1_epi32((1_i32 << N) - 1_i32); let hi = x86_64::_mm256_srli_epi32::<N>(input);
let lo = x86_64::_mm256_and_si256(input, mask);
let lo_shft = x86_64::_mm256_slli_epi32::<N_PRIME>(lo);
let lo_plus_hi = x86_64::_mm256_add_epi32(lo, hi);
x86_64::_mm256_sub_epi32(lo_plus_hi, lo_shft)
}
}
#[inline(always)]
pub unsafe fn mul_neg_2exp_neg_two_adicity_avx2<
TAD: TwoAdicData,
const N: i32,
const N_PRIME: i32,
>(
input: __m256i,
) -> __m256i {
unsafe {
const {
assert!(N == TAD::TWO_ADICITY as i32);
assert!(N + N_PRIME == 31);
}
let mask = x86_64::_mm256_set1_epi32((1_i32 << N) - 1_i32); let hi = x86_64::_mm256_srli_epi32::<N>(input);
let lo = x86_64::_mm256_and_si256(input, mask);
let lo_shft = x86_64::_mm256_slli_epi32::<N_PRIME>(lo);
let lo_plus_hi = x86_64::_mm256_add_epi32(lo, hi);
x86_64::_mm256_sub_epi32(lo_shft, lo_plus_hi)
}
}