use crate::kernel::Matrix;
mod avx2;
#[cfg(feature = "simd512")]
mod avx512;
mod gfni;
mod ssse3;
pub use avx2::{
mul_add_avx2, mul_add_gather_avx2, mul_add_matrix_avx2_with, mul_add_scatter_avx2,
mul_assign_avx2, mul_elementwise_assign_avx2, mul_elementwise_avx2, mul_into_avx2,
multiply_vectors_avx2,
};
#[cfg(feature = "simd512")]
#[cfg(test)]
pub(crate) use avx512::{GATHER_PEEL_MIN, MATRIX_PEEL_MIN, SCATTER_PEEL_MIN};
#[cfg(feature = "simd512")]
pub use avx512::{
mul_add_avx512, mul_add_gather_avx512, mul_add_matrix_at_avx512_with,
mul_add_matrix_avx512_with, mul_add_scatter_avx512, mul_assign_avx512,
mul_elementwise_assign_avx512, mul_elementwise_avx512, mul_into_avx512,
mul_into_matrix_avx512_with,
};
#[cfg(test)]
pub(crate) use gfni::MATRIX_PREFETCH_MIN;
pub use gfni::{
mul_add_gather_gfni, mul_add_gfni, mul_add_matrix_at_gfni_with, mul_add_matrix_gfni_with,
mul_add_scatter_gfni, mul_assign_gfni, mul_elementwise_assign_gfni, mul_elementwise_gfni,
mul_into_gfni, mul_into_matrix_gfni_with,
};
pub use ssse3::{
mul_add_gather_ssse3, mul_add_matrix_ssse3_with, mul_add_scatter_ssse3, mul_add_ssse3,
mul_assign_ssse3, mul_elementwise_assign_ssse3, mul_elementwise_ssse3, mul_into_ssse3,
multiply_vectors_ssse3,
};
pub(in crate::kernel::x86::gf8) trait BodySite:
body_site::Sealed
{
}
pub(in crate::kernel::x86::gf8) struct EntryBody;
pub(in crate::kernel::x86::gf8) struct PeelBody;
impl BodySite for EntryBody {}
impl BodySite for PeelBody {}
mod body_site {
pub trait Sealed {}
impl Sealed for super::EntryBody {}
impl Sealed for super::PeelBody {}
}
pub(crate) const RESOLVE_CHUNK: usize = 32;
fn check_gather(name: &str, dst: &[u8], coeffs: usize, srcs: &[&[u8]]) {
assert_eq!(coeffs, srcs.len(), "{name}: one coefficient per source");
for (index, &src) in srcs.iter().enumerate() {
assert_eq!(
src.len(),
dst.len(),
"{name}: source {index} does not match the destination length"
);
}
}
fn check_scattered(name: &str, dst_len: usize, row_len: usize, row_starts: &[usize]) {
for (j, &start) in row_starts.iter().enumerate() {
let end = start
.checked_add(row_len)
.unwrap_or_else(|| panic!("{name}: row offset plus length overflows"));
assert!(
end <= dst_len,
"{name}: row {j} spans {start}..{end} but dst is {dst_len} bytes"
);
}
for (a, &sa) in row_starts.iter().enumerate() {
for &sb in &row_starts[a + 1..] {
let (lo, hi) = if sa <= sb { (sa, sb) } else { (sb, sa) };
assert!(
hi - lo >= row_len,
"{name}: rows at {sa} and {sb} overlap for {row_len}-byte rows"
);
}
}
}
pub(crate) const MATRIX_COLUMN_BLOCK: usize = 4096;
fn column_blocked(nrows: usize, row_len: usize) -> bool {
(nrows == 3 || nrows > 4) && row_len > 2 * MATRIX_COLUMN_BLOCK
}
fn column_blocks(row_len: usize, head: usize) -> impl Iterator<Item = (usize, usize)> {
let mut start = 0;
let mut end = if head == 0 { MATRIX_COLUMN_BLOCK } else { head };
core::iter::from_fn(move || {
if start >= row_len {
return None;
}
let stop = end.min(row_len);
let block = (start, stop - start);
start = stop;
end = stop.saturating_add(MATRIX_COLUMN_BLOCK);
Some(block)
})
}
struct ColumnWindow<'a, M: ?Sized> {
inner: &'a M,
start: usize,
len: usize,
}
impl<'a, M: ?Sized> ColumnWindow<'a, M> {
fn new(inner: &'a M, start: usize, len: usize) -> Self {
Self { inner, start, len }
}
}
impl<C, M: Matrix<C> + ?Sized> Matrix<C> for ColumnWindow<'_, M> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
#[inline]
fn coefficient(&self, term: usize, row: usize) -> C {
self.inner.coefficient(term, row)
}
#[inline]
fn source(&self, term: usize) -> &[u8] {
&self.inner.source(term)[self.start..self.start + self.len]
}
}