use super::super::{ColumnWindow, RESOLVE_CHUNK, check_scattered, column_blocked, column_blocks};
use super::{bfactor_avx512, bmul_avx512, brem_half_avx512};
use crate::kernel::Matrix;
use crate::kernel::gf8::Prepared;
pub(crate) const MATRIX_PEEL_MIN: usize = 8192;
const MATRIX_RESOLVE_MIN: usize = 512;
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_avx512_with<M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V4xToken,
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_avx512: 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_avx512: term {term} source must span one row"
);
}
if terms.len() == 0 || row_len == 0 || nrows == 0 {
return;
}
mul_add_matrix_impl::<M, false>(rows, row_len, nrows, terms);
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_into_matrix_avx512_with<M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V4xToken,
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_avx512: 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_into_matrix_avx512: term {term} source must span one row"
);
}
if terms.len() == 0 {
if row_len != 0 && nrows != 0 {
rows[..nrows * row_len].fill(0);
}
return;
}
if row_len == 0 || nrows == 0 {
return;
}
mul_add_matrix_impl::<M, true>(rows, row_len, nrows, terms);
}
#[archmage::rite(v4x, import_intrinsics)]
fn mul_add_matrix_impl<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
if row_len < MATRIX_RESOLVE_MIN {
matrix_block::<M, OVERWRITE, true>(rows, row_len, 0, row_len, nrows, terms);
return;
}
matrix_long::<M, OVERWRITE>(rows, row_len, nrows, terms);
}
#[archmage::rite(v4x, import_intrinsics)]
#[inline(never)]
fn matrix_long<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
rows: &mut [u8],
row_len: usize,
nrows: usize,
terms: &M,
) {
if !column_blocked(nrows, row_len) {
matrix_block::<M, OVERWRITE, false>(rows, row_len, 0, row_len, nrows, terms);
return;
}
let head = aligned_head(rows.as_ptr(), row_len);
for (start, len) in column_blocks(row_len, head) {
let window = ColumnWindow::new(terms, start, len);
matrix_block::<_, OVERWRITE, false>(rows, row_len, start, len, nrows, &window);
}
}
fn aligned_head(first: *const u8, pitch: usize) -> usize {
if pitch.is_multiple_of(64) {
(first as usize).wrapping_neg() & 63
} else {
0
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_block<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool, const DIRECT: 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 + 4 <= nrows {
let ptrs = unsafe {
[
base.add(g * pitch + block_start),
base.add((g + 1) * pitch + block_start),
base.add((g + 2) * pitch + block_start),
base.add((g + 3) * pitch + block_start),
]
};
matrix_rows4::<M, OVERWRITE, DIRECT>(ptrs, block_len, g, terms);
g += 4;
}
if g + 2 <= nrows {
let ptrs = unsafe {
[
base.add(g * pitch + block_start),
base.add((g + 1) * pitch + block_start),
]
};
matrix_rows2::<M, OVERWRITE, DIRECT>(ptrs, block_len, g, terms);
g += 2;
}
if g < nrows {
let ptr = unsafe { base.add(g * pitch + block_start) };
matrix_rows1::<M, OVERWRITE, DIRECT>(ptr, block_len, g, terms);
}
}
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_rows4<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool, const DIRECT: bool>(
ptrs: [*mut u8; 4],
row_len: usize,
g: usize,
terms: &M,
) {
let head = (ptrs[0] as usize).wrapping_neg() & 63;
let head = if row_len >= MATRIX_PEEL_MIN && head < row_len && row_len.is_multiple_of(64) {
head
} else {
0
};
if head > 0 {
matrix_tail::<M, OVERWRITE>(&ptrs, head, 0, g, terms);
}
let vector_len = row_len & !63;
let tile = if DIRECT {
let mut tile = head;
while tile + 256 <= vector_len {
rows_tile4::<M, OVERWRITE>(ptrs, tile, g, terms);
tile += 256;
}
while tile + 64 <= vector_len {
rows_lane4::<M, OVERWRITE>(ptrs, tile, g, terms);
tile += 64;
}
tile
} else {
rows_resolved::<M, 4, OVERWRITE>(ptrs, head, vector_len, g, terms)
};
matrix_tail::<M, OVERWRITE>(&ptrs, row_len, tile, g, terms);
}
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_rows2<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool, const DIRECT: bool>(
ptrs: [*mut u8; 2],
row_len: usize,
g: usize,
terms: &M,
) {
let head = (ptrs[0] as usize).wrapping_neg() & 63;
let head = if row_len >= MATRIX_PEEL_MIN && head < row_len && row_len.is_multiple_of(64) {
head
} else {
0
};
if head > 0 {
matrix_tail::<M, OVERWRITE>(&ptrs, head, 0, g, terms);
}
let vector_len = row_len & !63;
let tile = if DIRECT {
let mut tile = head;
while tile + 256 <= vector_len {
rows_tile2::<M, OVERWRITE>(ptrs, tile, g, terms);
tile += 256;
}
while tile + 64 <= vector_len {
rows_lane2::<M, OVERWRITE>(ptrs, tile, g, terms);
tile += 64;
}
tile
} else {
rows_resolved::<M, 2, OVERWRITE>(ptrs, head, vector_len, g, terms)
};
matrix_tail::<M, OVERWRITE>(&ptrs, row_len, tile, g, terms);
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_rows1<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool, const DIRECT: bool>(
ptr: *mut u8,
row_len: usize,
g: usize,
terms: &M,
) {
let head = (ptr as usize).wrapping_neg() & 63;
let head = if row_len >= MATRIX_PEEL_MIN && head < row_len && row_len.is_multiple_of(64) {
head
} else {
0
};
if head > 0 {
matrix_tail::<M, OVERWRITE>(&[ptr], head, 0, g, terms);
}
let vector_len = row_len & !63;
let tile = if DIRECT {
let mut tile = head;
while tile + 256 <= vector_len {
rows_tile1::<M, OVERWRITE>(ptr, tile, g, terms);
tile += 256;
}
while tile + 64 <= vector_len {
rows_lane1::<M, OVERWRITE>(ptr, tile, g, terms);
tile += 64;
}
tile
} else {
rows_resolved::<M, 1, OVERWRITE>([ptr], head, vector_len, g, terms)
};
let tail = unsafe { core::slice::from_raw_parts_mut(ptr.add(tile), row_len - tile) };
if OVERWRITE {
tail.fill(0);
}
for term in 0..terms.len() {
let coeff = terms.coefficient(term, g);
if !coeff.is_zero() {
brem_half_avx512(tail, coeff, &terms.source(term)[tile..]);
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_tile4<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 4],
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = [[_mm512_setzero_si512(); 4]; 4];
if !OVERWRITE {
for (&ptr, slots) in ptrs.iter().zip(acc.iter_mut()) {
for (lane, slot) in slots.iter_mut().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile + 64 * lane), 64)
.as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
}
}
for term in 0..terms.len() {
let maps = [
terms.coefficient(term, g).affine,
terms.coefficient(term, g + 1).affine,
terms.coefficient(term, g + 2).affine,
terms.coefficient(term, g + 3).affine,
];
let f = [
bfactor_avx512(maps[0]),
bfactor_avx512(maps[1]),
bfactor_avx512(maps[2]),
bfactor_avx512(maps[3]),
];
let src = terms.source(term);
let (s, _) = src[tile..tile + 256].as_chunks::<64>();
let x = [
_mm512_loadu_si512(&s[0]),
_mm512_loadu_si512(&s[1]),
_mm512_loadu_si512(&s[2]),
_mm512_loadu_si512(&s[3]),
];
for (slots, &factor) in acc.iter_mut().zip(&f) {
for (slot, &value) in slots.iter_mut().zip(&x) {
*slot = _mm512_xor_si512(*slot, bmul_avx512(value, factor));
}
}
}
for (&ptr, slots) in ptrs.iter().zip(&acc) {
for (lane, &value) in slots.iter().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts_mut(ptr.add(tile + 64 * lane), 64)
.as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
}
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_lane4<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 4],
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = [_mm512_setzero_si512(); 4];
if !OVERWRITE {
for (&ptr, slot) in ptrs.iter().zip(acc.iter_mut()) {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile), 64).as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
}
for term in 0..terms.len() {
let src = terms.source(term);
let (s, _) = src[tile..tile + 64].as_chunks::<64>();
let x = _mm512_loadu_si512(&s[0]);
for (row, slot) in acc.iter_mut().enumerate() {
let map = terms.coefficient(term, g + row).affine;
*slot = _mm512_xor_si512(*slot, bmul_avx512(x, bfactor_avx512(map)));
}
}
for (&ptr, &value) in ptrs.iter().zip(&acc) {
{
let (rc, _) =
core::slice::from_raw_parts_mut(ptr.add(tile), 64).as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_tile2<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 2],
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = [[_mm512_setzero_si512(); 4]; 2];
if !OVERWRITE {
for (&ptr, slots) in ptrs.iter().zip(acc.iter_mut()) {
for (lane, slot) in slots.iter_mut().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile + 64 * lane), 64)
.as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
}
}
for term in 0..terms.len() {
let maps = [
terms.coefficient(term, g).affine,
terms.coefficient(term, g + 1).affine,
];
let f = [bfactor_avx512(maps[0]), bfactor_avx512(maps[1])];
let src = terms.source(term);
let (s, _) = src[tile..tile + 256].as_chunks::<64>();
let x = [
_mm512_loadu_si512(&s[0]),
_mm512_loadu_si512(&s[1]),
_mm512_loadu_si512(&s[2]),
_mm512_loadu_si512(&s[3]),
];
for (slots, &factor) in acc.iter_mut().zip(&f) {
for (slot, &value) in slots.iter_mut().zip(&x) {
*slot = _mm512_xor_si512(*slot, bmul_avx512(value, factor));
}
}
}
for (&ptr, slots) in ptrs.iter().zip(&acc) {
for (lane, &value) in slots.iter().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts_mut(ptr.add(tile + 64 * lane), 64)
.as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
}
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_lane2<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptrs: [*mut u8; 2],
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = [_mm512_setzero_si512(); 2];
if !OVERWRITE {
for (&ptr, slot) in ptrs.iter().zip(acc.iter_mut()) {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile), 64).as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
}
for term in 0..terms.len() {
let src = terms.source(term);
let (s, _) = src[tile..tile + 64].as_chunks::<64>();
let x = _mm512_loadu_si512(&s[0]);
for (row, slot) in acc.iter_mut().enumerate() {
let map = terms.coefficient(term, g + row).affine;
*slot = _mm512_xor_si512(*slot, bmul_avx512(x, bfactor_avx512(map)));
}
}
for (&ptr, &value) in ptrs.iter().zip(&acc) {
{
let (rc, _) =
core::slice::from_raw_parts_mut(ptr.add(tile), 64).as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_tile1<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptr: *mut u8,
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = [_mm512_setzero_si512(); 4];
if !OVERWRITE {
for (lane, slot) in acc.iter_mut().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile + 64 * lane), 64)
.as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
}
for term in 0..terms.len() {
let factor = bfactor_avx512(terms.coefficient(term, g).affine);
let src = terms.source(term);
let (s, _) = src[tile..tile + 256].as_chunks::<64>();
acc[0] = _mm512_xor_si512(acc[0], bmul_avx512(_mm512_loadu_si512(&s[0]), factor));
acc[1] = _mm512_xor_si512(acc[1], bmul_avx512(_mm512_loadu_si512(&s[1]), factor));
acc[2] = _mm512_xor_si512(acc[2], bmul_avx512(_mm512_loadu_si512(&s[2]), factor));
acc[3] = _mm512_xor_si512(acc[3], bmul_avx512(_mm512_loadu_si512(&s[3]), factor));
}
for (lane, &value) in acc.iter().enumerate() {
{
let (rc, _) = core::slice::from_raw_parts_mut(ptr.add(tile + 64 * lane), 64)
.as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_lane1<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptr: *mut u8,
tile: usize,
g: usize,
terms: &M,
) {
unsafe {
let mut acc = _mm512_setzero_si512();
if !OVERWRITE {
{
let (rc, _) = core::slice::from_raw_parts(ptr.add(tile), 64).as_chunks::<64>();
acc = _mm512_loadu_si512(&rc[0]);
}
}
for term in 0..terms.len() {
let factor = bfactor_avx512(terms.coefficient(term, g).affine);
let src = terms.source(term);
let (s, _) = src[tile..tile + 64].as_chunks::<64>();
acc = _mm512_xor_si512(acc, bmul_avx512(_mm512_loadu_si512(&s[0]), factor));
}
{
let (rc, _) = core::slice::from_raw_parts_mut(ptr.add(tile), 64).as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], acc);
}
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_resolved<M: Matrix<Prepared> + ?Sized, const ROWS: usize, const OVERWRITE: bool>(
ptrs: [*mut u8; ROWS],
head: usize,
vector_len: usize,
g: usize,
terms: &M,
) -> usize {
let end = head + ((vector_len - head) & !63);
if end == head {
return head;
}
let count = terms.len();
let mut start = 0;
let mut first = true;
loop {
let taken = (count - start).min(RESOLVE_CHUNK);
let mut maps: [core::mem::MaybeUninit<[u64; ROWS]>; RESOLVE_CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
let mut srcs: [core::mem::MaybeUninit<&[u8]>; RESOLVE_CHUNK] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for offset in 0..taken {
let term = start + offset;
let mut words = [0u64; ROWS];
for (row, word) in words.iter_mut().enumerate() {
*word = terms.coefficient(term, g + row).affine;
}
maps[offset].write(words);
let src = terms.source(term);
assert!(
src.len() >= end,
"matrix kernel: term {term} source is shorter than the row span"
);
srcs[offset].write(src);
}
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::<ROWS, true>(ptrs, head, end, maps, srcs);
} else {
rows_body::<ROWS, false>(ptrs, head, end, maps, srcs);
}
first = false;
start += taken;
if start >= count {
break;
}
}
end
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn rows_body<const ROWS: usize, const OVERWRITE: bool>(
ptrs: [*mut u8; ROWS],
head: usize,
end: usize,
maps: &[[u64; ROWS]],
srcs: &[&[u8]],
) {
let (map_pairs, map_odd) = maps.as_chunks::<2>();
let (src_pairs, src_odd) = srcs.as_chunks::<2>();
let mut tile = head;
while tile + 256 <= end {
let mut acc = [[_mm512_setzero_si512(); 4]; ROWS];
if !OVERWRITE {
for (&ptr, slots) in ptrs.iter().zip(acc.iter_mut()) {
let (rc, _) =
unsafe { core::slice::from_raw_parts(ptr.add(tile), 256) }.as_chunks::<64>();
for (slot, chunk) in slots.iter_mut().zip(rc) {
*slot = _mm512_loadu_si512(chunk);
}
}
}
for ([map0, map1], [src0, src1]) in map_pairs.iter().zip(src_pairs) {
let (s0, s1) = unsafe {
(
core::slice::from_raw_parts(src0.as_ptr().add(tile), 256),
core::slice::from_raw_parts(src1.as_ptr().add(tile), 256),
)
};
let (s0, _) = s0.as_chunks::<64>();
let (s1, _) = s1.as_chunks::<64>();
let x0 = [
_mm512_loadu_si512(&s0[0]),
_mm512_loadu_si512(&s0[1]),
_mm512_loadu_si512(&s0[2]),
_mm512_loadu_si512(&s0[3]),
];
let x1 = [
_mm512_loadu_si512(&s1[0]),
_mm512_loadu_si512(&s1[1]),
_mm512_loadu_si512(&s1[2]),
_mm512_loadu_si512(&s1[3]),
];
for ((slots, &word0), &word1) in acc.iter_mut().zip(map0).zip(map1) {
let (f0, f1) = (bfactor_avx512(word0), bfactor_avx512(word1));
for ((slot, &a), &b) in slots.iter_mut().zip(&x0).zip(&x1) {
let pair = _mm512_xor_si512(bmul_avx512(a, f0), bmul_avx512(b, f1));
*slot = _mm512_xor_si512(*slot, pair);
}
}
}
for (map, src) in map_odd.iter().zip(src_odd) {
let (s, _) = unsafe { core::slice::from_raw_parts(src.as_ptr().add(tile), 256) }
.as_chunks::<64>();
let x = [
_mm512_loadu_si512(&s[0]),
_mm512_loadu_si512(&s[1]),
_mm512_loadu_si512(&s[2]),
_mm512_loadu_si512(&s[3]),
];
for (slots, &word) in acc.iter_mut().zip(map) {
let f = bfactor_avx512(word);
for (slot, &value) in slots.iter_mut().zip(&x) {
*slot = _mm512_xor_si512(*slot, bmul_avx512(value, f));
}
}
}
for (&ptr, slots) in ptrs.iter().zip(&acc) {
let (rc, _) = unsafe { core::slice::from_raw_parts_mut(ptr.add(tile), 256) }
.as_chunks_mut::<64>();
for (chunk, &value) in rc.iter_mut().zip(slots) {
_mm512_storeu_si512(chunk, value);
}
}
tile += 256;
}
while tile + 64 <= end {
let mut acc = [_mm512_setzero_si512(); ROWS];
if !OVERWRITE {
for (&ptr, slot) in ptrs.iter().zip(acc.iter_mut()) {
let (rc, _) =
unsafe { core::slice::from_raw_parts(ptr.add(tile), 64) }.as_chunks::<64>();
*slot = _mm512_loadu_si512(&rc[0]);
}
}
for ([map0, map1], [src0, src1]) in map_pairs.iter().zip(src_pairs) {
let (s0, s1) = unsafe {
(
core::slice::from_raw_parts(src0.as_ptr().add(tile), 64),
core::slice::from_raw_parts(src1.as_ptr().add(tile), 64),
)
};
let x0 = _mm512_loadu_si512(&s0.as_chunks::<64>().0[0]);
let x1 = _mm512_loadu_si512(&s1.as_chunks::<64>().0[0]);
for ((slot, &word0), &word1) in acc.iter_mut().zip(map0).zip(map1) {
let pair = _mm512_xor_si512(
bmul_avx512(x0, bfactor_avx512(word0)),
bmul_avx512(x1, bfactor_avx512(word1)),
);
*slot = _mm512_xor_si512(*slot, pair);
}
}
for (map, src) in map_odd.iter().zip(src_odd) {
let (s, _) = unsafe { core::slice::from_raw_parts(src.as_ptr().add(tile), 64) }
.as_chunks::<64>();
let x = _mm512_loadu_si512(&s[0]);
for (slot, &word) in acc.iter_mut().zip(map) {
*slot = _mm512_xor_si512(*slot, bmul_avx512(x, bfactor_avx512(word)));
}
}
for (&ptr, &value) in ptrs.iter().zip(&acc) {
let (rc, _) =
unsafe { core::slice::from_raw_parts_mut(ptr.add(tile), 64) }.as_chunks_mut::<64>();
_mm512_storeu_si512(&mut rc[0], value);
}
tile += 64;
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_tail<M: Matrix<Prepared> + ?Sized, const OVERWRITE: bool>(
ptrs: &[*mut u8],
row_len: usize,
tile: usize,
g: usize,
terms: &M,
) {
if tile == row_len {
return;
}
for (slot, &row) in ptrs.iter().enumerate() {
let tail = unsafe { core::slice::from_raw_parts_mut(row.add(tile), row_len - tile) };
if OVERWRITE {
tail.fill(0);
}
for term in 0..terms.len() {
let coeff = terms.coefficient(term, g + slot);
if !coeff.is_zero() {
brem_half_avx512(tail, coeff, &terms.source(term)[tile..row_len]);
}
}
}
}
#[allow(clippy::used_underscore_binding)]
#[archmage::arcane(import_intrinsics)]
pub fn mul_add_matrix_at_avx512_with<M: Matrix<Prepared> + ?Sized>(
_token: archmage::X64V4xToken,
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
check_scattered("mul_add_matrix_at_avx512", dst.len(), row_len, row_starts);
for term in 0..terms.len() {
assert_eq!(
terms.source(term).len(),
row_len,
"mul_add_matrix_at_avx512: term {term} source must span one row"
);
}
if terms.len() == 0 || row_starts.is_empty() {
return;
}
mul_add_matrix_at_impl::<M>(dst, row_len, row_starts, terms);
}
#[archmage::rite(v4x, import_intrinsics)]
fn mul_add_matrix_at_impl<M: Matrix<Prepared> + ?Sized>(
dst: &mut [u8],
row_len: usize,
row_starts: &[usize],
terms: &M,
) {
if row_len < MATRIX_RESOLVE_MIN {
matrix_at_block::<M, true>(dst, row_len, 0, row_len, row_starts, terms);
return;
}
if !column_blocked(row_starts.len(), row_len) {
matrix_at_block::<M, false>(dst, row_len, 0, row_len, row_starts, terms);
return;
}
let head = aligned_head(dst.as_ptr().wrapping_add(row_starts[0]), row_len);
for (start, len) in column_blocks(row_len, head) {
let window = ColumnWindow::new(terms, start, len);
matrix_at_block::<_, false>(dst, row_len, start, len, row_starts, &window);
}
}
#[allow(unsafe_code)]
#[archmage::rite(v4x, import_intrinsics)]
fn matrix_at_block<M: Matrix<Prepared> + ?Sized, const DIRECT: bool>(
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 + 4 <= nrows {
let ptrs = unsafe {
[
base.add(row_starts[g] + block_start),
base.add(row_starts[g + 1] + block_start),
base.add(row_starts[g + 2] + block_start),
base.add(row_starts[g + 3] + block_start),
]
};
matrix_rows4::<M, false, DIRECT>(ptrs, block_len, g, terms);
g += 4;
}
if g + 2 <= nrows {
let ptrs = unsafe {
[
base.add(row_starts[g] + block_start),
base.add(row_starts[g + 1] + block_start),
]
};
matrix_rows2::<M, false, DIRECT>(ptrs, block_len, g, terms);
g += 2;
}
if g < nrows {
let ptr = unsafe { base.add(row_starts[g] + block_start) };
matrix_rows1::<M, false, DIRECT>(ptr, block_len, g, terms);
}
}