use super::super::{ColumnWindow, RESOLVE_CHUNK, check_scattered, column_blocked, column_blocks};
use super::rows::{MAX_GROUP_ROWS, group_rows, matrix_group};
use crate::kernel::Matrix;
use crate::kernel::gf8::Prepared;
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_gfni_with<const NATIVE: bool, M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_add_matrix_gfni: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 {
return;
}
mul_add_matrix_impl::<NATIVE, M, false>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_gfni_with<const NATIVE: bool, M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
assert!(
nrows
.checked_mul(row_len)
.is_some_and(|needed| needed <= rows.len()),
"mul_into_matrix_gfni: rows buffer does not hold {nrows} rows of {row_len} bytes"
);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
mul_add_matrix_impl::<NATIVE, M, true>(rows, row_len, nrows, terms);
}
#[archmage::rite(v3_gfni_crypto)]
fn mul_add_matrix_impl<const NATIVE: bool, M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
if !gfni_column_blocked(nrows, row_len, terms.len()) {
matrix_block::<NATIVE, M, OVERWRITE>(rows, row_len, 0, row_len, nrows, terms);
return;
}
for (start, len) in column_blocks(row_len, 0) {
let window = ColumnWindow::new(terms, start, len);
matrix_block::<NATIVE, _, OVERWRITE>(rows, row_len, start, len, nrows, &window);
}
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn matrix_block<const NATIVE: bool, M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
rows: &mut [u8],
pitch: usize,
block_start: usize,
block_len: usize,
nrows: usize,
terms: &M,
) {
debug_assert!(block_start + block_len <= pitch);
let base = rows.as_mut_ptr();
let mut g = 0;
while g < nrows {
let width = group_rows(nrows, g, terms.len());
let mut ptrs = [core::ptr::null_mut::<u8>(); MAX_GROUP_ROWS];
for (j, slot) in ptrs[..width].iter_mut().enumerate() {
*slot = unsafe { base.add((g + j) * pitch + block_start) };
}
matrix_group::<NATIVE, M, OVERWRITE>(&ptrs[..width], block_len, g, terms);
g += width;
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_gfni_with<const NATIVE: bool, M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V3GfniCryptoToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
check_scattered("mul_add_matrix_at_gfni", dst.len(), row_len, row_starts);
for term in 0..terms.len() {
assert_eq!(terms.source(term).len(), row_len);
}
if terms.len() == 0 || row_starts.is_empty() {
return;
}
mul_add_matrix_at_impl::<NATIVE, M>(dst, row_len, row_starts, terms);
}
#[archmage::rite(v3_gfni_crypto)]
fn mul_add_matrix_at_impl<const NATIVE: bool, M: Matrix<Prepared> + ?Sized>(
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
if !gfni_column_blocked(row_starts.len(), row_len, terms.len()) {
matrix_at_block::<NATIVE, M>(dst, row_len, 0, row_len, row_starts, terms);
return;
}
for (start, len) in column_blocks(row_len, 0) {
let window = ColumnWindow::new(terms, start, len);
matrix_at_block::<NATIVE, _>(dst, row_len, start, len, row_starts, &window);
}
}
fn gfni_column_blocked(nrows: usize, row_len: usize, nterms: usize) -> bool {
nterms > RESOLVE_CHUNK && column_blocked(nrows, row_len)
}
#[allow(unsafe_code)]
#[archmage::rite(v3_gfni_crypto)]
fn matrix_at_block<const NATIVE: bool, M: Matrix<Prepared> + ?Sized>(
dst: &mut [u8],
row_len: usize,
block_start: usize,
block_len: usize,
row_starts: &[usize],
terms: &M,
) {
debug_assert!(block_start + block_len <= row_len);
let base = dst.as_mut_ptr();
let nrows = row_starts.len();
let mut g = 0;
while g < nrows {
let width = group_rows(nrows, g, terms.len());
let mut ptrs = [core::ptr::null_mut::<u8>(); MAX_GROUP_ROWS];
for (j, slot) in ptrs[..width].iter_mut().enumerate() {
*slot = unsafe { base.add(row_starts[g + j] + block_start) };
}
matrix_group::<NATIVE, M, false>(&ptrs[..width], block_len, g, terms);
g += width;
}
}