use core::arch::x86_64::*;
pub(crate) fn bignum_aff_point_select_p384(z: &mut [u64; 12], table: &[u64], index: u8) {
select::<12, 3>(z, table, index)
}
pub(crate) fn bignum_aff_point_select_p521(z: &mut [u64; 18], table: &[u64], index: u8) {
select::<18, 4>(z, table, index)
}
fn select<const N: usize, const V: usize>(z: &mut [u64; N], table: &[u64], index: u8) {
const { assert!(N == 4 * V || N == 4 * V + 2) };
unsafe { _select::<N, V>(z, table, index) }
}
#[target_feature(enable = "avx,avx2")]
fn _select<const N: usize, const V: usize>(z: &mut [u64; N], table: &[u64], index: u8) {
super::cpu::prefetch(table, N);
let mut acc = [_mm256_setzero_si256(); V];
let mut tail = _mm_setzero_si128();
let desired_index = _mm256_set1_epi32(index as i32);
let ones = _mm256_set1_epi32(1);
let mut index = ones;
let (rows, _) = table.as_chunks::<N>();
for row in rows {
let mask = _mm256_cmpeq_epi32(index, desired_index);
index = _mm256_add_epi32(index, ones);
for (i, acc) in acc.iter_mut().enumerate() {
let word = unsafe { _mm256_loadu_si256(row.as_ptr().add(4 * i).cast()) };
*acc = _mm256_xor_si256(*acc, _mm256_and_si256(word, mask));
}
if N > 4 * V {
let word = unsafe { _mm_loadu_si128(row.as_ptr().add(4 * V).cast()) };
tail = _mm_xor_si128(tail, _mm_and_si128(word, _mm256_castsi256_si128(mask)));
}
}
for (i, acc) in acc.iter().enumerate() {
unsafe { _mm256_storeu_si256(z.as_mut_ptr().add(4 * i).cast(), *acc) };
}
if N > 4 * V {
unsafe { _mm_storeu_si128(z.as_mut_ptr().add(4 * V).cast(), tail) };
}
}