#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
use super::super::rows::{matrix_tail, rows_resolved};
use super::super::{Affine8D, Blocked, Gfni, bfactor, bmul};
use crate::field::gf8b::Elem;
use crate::field::gf8d;
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix2_8b(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
terms: &[(&[Elem], &[u8])],
nt: bool,
lanes: usize,
) {
mul_into_matrix2_checked::<Gfni>(rows, row_len, terms, nt, lanes);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix2_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
terms: &[(&[gf8d::Elem], &[u8])],
nt: bool,
lanes: usize,
) {
mul_into_matrix2_checked::<Affine8D>(rows, row_len, terms, nt, lanes);
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn mul_into_matrix2_checked<S: Blocked>(
rows: &mut [u8],
row_len: usize,
terms: &[(&[S::Coeff], &[u8])],
nt: bool,
lanes: usize,
) {
assert!(
2usize
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"matrix_overwrite2: rows buffer does not hold two rows of {row_len} bytes"
);
for (coeffs, src) in terms {
assert_eq!(src.len(), row_len);
assert!(
coeffs.len() >= 2,
"matrix_overwrite2: term needs two coefficients"
);
}
if nt {
debug_assert_eq!(
rows.as_ptr() as usize % 32,
0,
"matrix_overwrite2: non-temporal stores need a 32-byte-aligned buffer"
);
debug_assert_eq!(
row_len % 32,
0,
"matrix_overwrite2: non-temporal stores need a 32-byte row"
);
}
let base = rows.as_mut_ptr();
unsafe {
let ptr0 = base;
let ptr1 = base.add(row_len);
match (nt, lanes) {
(false, 2) => matrix2_body::<S, false, 2>(ptr0, ptr1, row_len, terms),
(false, 3) => matrix2_body::<S, false, 3>(ptr0, ptr1, row_len, terms),
(false, 4) => matrix2_body::<S, false, 4>(ptr0, ptr1, row_len, terms),
(true, 2) => matrix2_body::<S, true, 2>(ptr0, ptr1, row_len, terms),
(true, 3) => matrix2_body::<S, true, 3>(ptr0, ptr1, row_len, terms),
(true, 4) => matrix2_body::<S, true, 4>(ptr0, ptr1, row_len, terms),
_ => panic!("matrix_overwrite2: lanes must be 2, 3, or 4"),
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn matrix2_body<S: Blocked, const NT: bool, const LANES: usize>(
ptr0: *mut u8,
ptr1: *mut u8,
row_len: usize,
terms: &[(&[S::Coeff], &[u8])],
) {
let step = 32 * LANES;
let mut tile = 0;
while tile + step <= row_len {
let mut a0 = [_mm256_setzero_si256(); LANES];
let mut a1 = [_mm256_setzero_si256(); LANES];
for (coeffs, src) in terms {
unsafe {
let f0 = bfactor::<S>(coeffs[0]);
let f1 = bfactor::<S>(coeffs[1]);
let sp = src.as_ptr().add(tile);
for l in 0..LANES {
let x = core::arch::x86_64::_mm256_loadu_si256(sp.add(32 * l).cast());
a0[l] = _mm256_xor_si256(a0[l], bmul::<S>(x, f0));
a1[l] = _mm256_xor_si256(a1[l], bmul::<S>(x, f1));
}
}
}
unsafe {
for l in 0..LANES {
crate::kernel::x86::store256::<NT>(ptr0.add(tile + 32 * l), a0[l]);
crate::kernel::x86::store256::<NT>(ptr1.add(tile + 32 * l), a1[l]);
}
}
tile += step;
}
while tile + 32 <= row_len {
let mut a0 = _mm256_setzero_si256();
let mut a1 = _mm256_setzero_si256();
for (coeffs, src) in terms {
unsafe {
let f0 = bfactor::<S>(coeffs[0]);
let f1 = bfactor::<S>(coeffs[1]);
let x = core::arch::x86_64::_mm256_loadu_si256(src.as_ptr().add(tile).cast());
a0 = _mm256_xor_si256(a0, bmul::<S>(x, f0));
a1 = _mm256_xor_si256(a1, bmul::<S>(x, f1));
}
}
unsafe {
core::arch::x86_64::_mm256_storeu_si256(ptr0.add(tile).cast(), a0);
core::arch::x86_64::_mm256_storeu_si256(ptr1.add(tile).cast(), a1);
}
tile += 32;
}
matrix_tail::<S, [(&[S::Coeff], &[u8])], true>(&[ptr0, ptr1], row_len, 0, tile, terms);
if NT {
_mm_sfence();
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix1_tile_8d(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
terms: &[(&[gf8d::Elem], &[u8])],
lanes: usize,
) {
assert!(
row_len <= rows.len(),
"matrix_overwrite1_tile: rows buffer does not hold one row of {row_len} bytes"
);
for (coeffs, src) in terms {
assert_eq!(src.len(), row_len);
assert!(
!coeffs.is_empty(),
"matrix_overwrite1_tile: term needs one coefficient"
);
}
let ptr = rows.as_mut_ptr();
match lanes {
3 => rows_resolved::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 3, true>(
[ptr],
row_len,
0,
terms,
),
4 => rows_resolved::<Affine8D, [(&[gf8d::Elem], &[u8])], 1, 4, true>(
[ptr],
row_len,
0,
terms,
),
_ => panic!("matrix_overwrite1_tile: lanes must be 3 or 4"),
}
}