#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
use super::{Blocked, bmul, brem, factor_word, wfactor};
use crate::kernel::Matrix;
pub(super) const RESOLVE_CHUNK: usize = 32;
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn rows_body<
S: Blocked,
const ROWS: usize,
const LANES: usize,
const OVERWRITE: bool,
>(
ptrs: [*mut u8; ROWS],
vector_len: usize,
maps: &[[u64; ROWS]],
srcs: &[&[u8]],
) {
let step = 32 * LANES;
let mut tile = 0;
while tile + step <= vector_len {
let mut acc = [[_mm256_setzero_si256(); LANES]; ROWS];
if !OVERWRITE {
unsafe {
for (&ptr, slots) in ptrs.iter().zip(acc.iter_mut()) {
for (lane, slot) in slots.iter_mut().enumerate() {
*slot = _mm256_loadu_si256(ptr.add(tile + 32 * lane).cast());
}
}
}
}
for (map, src) in maps.iter().zip(srcs) {
let mut factor = [_mm256_setzero_si256(); ROWS];
for (slot, &word) in factor.iter_mut().zip(map) {
*slot = wfactor::<S>(word);
}
unsafe {
let sp = src.as_ptr().add(tile);
let mut x = [_mm256_setzero_si256(); LANES];
for (lane, slot) in x.iter_mut().enumerate() {
*slot = _mm256_loadu_si256(sp.add(32 * lane).cast());
}
for (slots, &f) in acc.iter_mut().zip(&factor) {
for (slot, &value) in slots.iter_mut().zip(&x) {
*slot = _mm256_xor_si256(*slot, bmul::<S>(value, f));
}
}
}
}
unsafe {
for (&ptr, slots) in ptrs.iter().zip(&acc) {
for (lane, &value) in slots.iter().enumerate() {
_mm256_storeu_si256(ptr.add(tile + 32 * lane).cast(), value);
}
}
}
tile += step;
}
while tile + 32 <= vector_len {
let mut acc = [_mm256_setzero_si256(); ROWS];
if !OVERWRITE {
unsafe {
for (&ptr, slot) in ptrs.iter().zip(acc.iter_mut()) {
*slot = _mm256_loadu_si256(ptr.add(tile).cast());
}
}
}
for (map, src) in maps.iter().zip(srcs) {
unsafe {
let x = _mm256_loadu_si256(src.as_ptr().add(tile).cast());
for (slot, &word) in acc.iter_mut().zip(map) {
*slot = _mm256_xor_si256(*slot, bmul::<S>(x, wfactor::<S>(word)));
}
}
}
unsafe {
for (&ptr, &value) in ptrs.iter().zip(&acc) {
_mm256_storeu_si256(ptr.add(tile).cast(), value);
}
}
tile += 32;
}
}
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn rows_resolved<
S: Blocked,
M: Matrix<S::Coeff> + ?Sized,
const ROWS: usize,
const LANES: usize,
const OVERWRITE: bool,
>(
ptrs: [*mut u8; ROWS],
row_len: usize,
g: usize,
terms: &M,
) {
rows_resolved_chunked::<S, M, ROWS, LANES, OVERWRITE, RESOLVE_CHUNK, false>(
ptrs, row_len, g, terms,
);
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn rows_resolved_chunked<
S: Blocked,
M: Matrix<S::Coeff> + ?Sized,
const ROWS: usize,
const LANES: usize,
const OVERWRITE: bool,
const CHUNK: usize,
const FULL_INIT: bool,
>(
ptrs: [*mut u8; ROWS],
row_len: usize,
g: usize,
terms: &M,
) {
let vector_len = row_len & !31;
let count = terms.len();
let mut start = 0;
let mut first = true;
loop {
let taken = (count - start).min(CHUNK);
let mut maps: [core::mem::MaybeUninit<[u64; ROWS]>; CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
let mut srcs: [core::mem::MaybeUninit<&[u8]>; CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
if FULL_INIT {
for (words, src) in maps.iter_mut().zip(srcs.iter_mut()) {
words.write([0u64; ROWS]);
src.write(&[]);
}
}
for offset in 0..taken {
let term = start + offset;
let mut words = [0u64; ROWS];
for (row, word) in words.iter_mut().enumerate() {
*word = factor_word::<S>(*terms.coefficient(term, g + row));
}
maps[offset].write(words);
srcs[offset].write(terms.source(term));
}
let (maps, srcs): (&[[u64; ROWS]], &[&[u8]]) = unsafe {
(
core::slice::from_raw_parts(maps.as_ptr().cast::<[u64; ROWS]>(), taken),
core::slice::from_raw_parts(srcs.as_ptr().cast::<&[u8]>(), taken),
)
};
if OVERWRITE && first {
rows_body::<S, ROWS, LANES, true>(ptrs, vector_len, maps, srcs);
} else {
rows_body::<S, ROWS, LANES, false>(ptrs, vector_len, maps, srcs);
}
first = false;
start += taken;
if start >= count {
break;
}
}
matrix_tail::<S, M, OVERWRITE>(&ptrs, row_len, g, vector_len, terms);
}
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn matrix_rows4<S: Blocked, M: Matrix<S::Coeff> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 4],
row_len: usize,
g: usize,
terms: &M,
) {
rows_resolved::<S, M, 4, 2, OVERWRITE>(ptrs, row_len, g, terms);
}
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn matrix_rows2<S: Blocked, M: Matrix<S::Coeff> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 2],
row_len: usize,
g: usize,
terms: &M,
) {
rows_resolved::<S, M, 2, 4, OVERWRITE>(ptrs, row_len, g, terms);
}
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn matrix_rows1<S: Blocked, M: Matrix<S::Coeff> + ?Sized, const OVERWRITE: bool>(
ptr: *mut u8,
row_len: usize,
g: usize,
terms: &M,
) {
rows_resolved::<S, M, 1, 4, OVERWRITE>([ptr], row_len, g, terms);
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
pub(super) fn matrix_tail<S: Blocked, M: Matrix<S::Coeff> + ?Sized, const OVERWRITE: bool>(
ptrs: &[*mut u8],
row_len: usize,
g: usize,
tile: usize,
terms: &M,
) {
if tile == row_len {
return;
}
let remaining = row_len - tile;
for (slot, &row) in ptrs.iter().enumerate() {
let tail = unsafe { core::slice::from_raw_parts_mut(row.add(tile), remaining) };
if OVERWRITE {
tail.fill(0);
}
for term in 0..terms.len() {
let src = terms.source(term);
let coeff = *terms.coefficient(term, g + slot);
if S::byte(coeff) != 0 {
brem::<S>(tail, coeff, &src[tile..]);
}
}
}
}