use crate::field::gf16::Elem;
use crate::kernel::gf16::Prepared;
use crate::kernel::tables::{ScaleTable, TowerCoeff, TowerTables};
use super::{PREFETCH_AHEAD, gf8, nt_split, peel_to_align, prefetch_dst, prefetch_tile, store256};
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
mod elementwise;
mod gather;
mod gfni;
mod matrix;
mod nibble;
mod scatter;
#[inline]
fn check_elements(name: &str, bytes: usize) {
assert!(
bytes.is_multiple_of(2),
"{name}: buffer of {bytes} bytes ends with a partial GF(2^16) element",
);
}
pub use elementwise::{mul_elementwise_avx2, mul_elementwise_gfni, mul_elementwise_ssse3};
#[allow(unused_imports)]
pub use gather::{mul_add_gather_avx2, mul_add_gather_gfni, mul_add_gather_ssse3};
pub use gfni::{mul_add_gfni, mul_assign_gfni, mul_into_gfni};
#[allow(unused_imports)]
pub use matrix::{
mul_add_matrix_avx2, mul_add_matrix_gfni, mul_add_matrix_gfni_with, mul_add_matrix_ssse3,
mul_add_matrix_ssse3_with,
};
pub use nibble::{
mul_add_avx2, mul_add_ssse3, mul_assign_avx2, mul_assign_ssse3, mul_into_avx2, mul_into_ssse3,
};
pub use scatter::{mul_add_scatter_avx2, mul_add_scatter_gfni, mul_add_scatter_ssse3};
pub(crate) use nibble::{
NibbleAvx2, NibbleSsse3, lookup_avx2, nibble_avx2, nibble_ssse3, scale_avx2, scale_ssse3,
split_avx2,
};
pub trait TableCoefficient {
fn coefficient(&self) -> Elem;
fn with_tables<R>(&self, consume: impl FnOnce(&TowerTables) -> R) -> R;
}
impl TableCoefficient for Elem {
#[inline]
fn coefficient(&self) -> Elem {
*self
}
#[inline]
fn with_tables<R>(&self, consume: impl FnOnce(&TowerTables) -> R) -> R {
consume(&TowerTables::new(*self))
}
}
impl TableCoefficient for Prepared {
#[inline]
fn coefficient(&self) -> Elem {
self.coeff()
}
#[inline]
fn with_tables<R>(&self, consume: impl FnOnce(&TowerTables) -> R) -> R {
match self {
Prepared::Tables(tables) => consume(tables),
other => consume(&TowerTables::new(other.coeff())),
}
}
}
const SWAP_ADJACENT: [u8; 16] = [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14];
const SWAP_ADJACENT_WIDE: [u8; 32] = {
let mut wide = [0u8; 32];
let mut i = 0;
while i < 32 {
wide[i] = SWAP_ADJACENT[i & 15];
i += 1;
}
wide
};
#[inline]
fn broadcast_words(coeff: TowerCoeff) -> (i16, i16) {
(
i16::from_ne_bytes(coeff.same.to_ne_bytes()),
i16::from_ne_bytes(coeff.cross.to_ne_bytes()),
)
}
#[archmage::rite(v3, import_intrinsics)]
fn swap_mask256() -> __m256i {
_mm256_loadu_si256(&SWAP_ADJACENT_WIDE)
}
#[archmage::rite(v2, import_intrinsics)]
fn swap_mask128() -> __m128i {
_mm_loadu_si128(&SWAP_ADJACENT)
}
#[archmage::rite(v3_gfni_crypto)]
fn scale_gfni(src: __m256i, swapped: __m256i, same: __m256i, cross: __m256i) -> __m256i {
_mm256_xor_si256(
_mm256_gf2p8mul_epi8(src, same),
_mm256_gf2p8mul_epi8(swapped, cross),
)
}
const TERM_TILE: usize = 8;
struct LaneAvx2 {
nibble: __m256i,
even: __m256i,
swap: __m256i,
}
#[archmage::rite(v3)]
fn lane_avx2() -> LaneAvx2 {
LaneAvx2 {
nibble: _mm256_set1_epi8(0x0f),
even: _mm256_set1_epi16(0x00ff),
swap: swap_mask256(),
}
}
struct SplitAvx2 {
direct: (__m256i, __m256i),
crossed: (__m256i, __m256i),
}
#[archmage::rite(v3)]
fn split_source_avx2(src: __m256i, lanes: &LaneAvx2) -> SplitAvx2 {
SplitAvx2 {
direct: split_avx2(src, lanes.nibble),
crossed: split_avx2(_mm256_shuffle_epi8(src, lanes.swap), lanes.nibble),
}
}
#[archmage::rite(v3, import_intrinsics)]
fn lookup_bank_avx2(factor: &ScaleTable, split: (__m256i, __m256i)) -> __m256i {
let lo = _mm256_broadcastsi128_si256(_mm_loadu_si128(&factor.lo));
let hi = _mm256_broadcastsi128_si256(_mm_loadu_si128(&factor.hi));
lookup_avx2(lo, hi, split)
}
#[archmage::rite(v3)]
fn scale_split_avx2(
split: &SplitAvx2,
factors: &[&'static ScaleTable; 4],
even_mask: __m256i,
) -> __m256i {
let even = _mm256_xor_si256(
lookup_bank_avx2(factors[0], split.direct),
lookup_bank_avx2(factors[2], split.crossed),
);
let odd = _mm256_xor_si256(
lookup_bank_avx2(factors[1], split.direct),
lookup_bank_avx2(factors[3], split.crossed),
);
_mm256_xor_si256(
_mm256_and_si256(even, even_mask),
_mm256_andnot_si256(even_mask, odd),
)
}