#![allow(unsafe_code)]
pub(crate) mod gf16;
pub(crate) mod gf8;
#[cfg(feature = "internals")]
pub mod proven;
use core::arch::aarch64::*;
use crate::kernel::scalar;
pub(crate) fn xor_neon(dst: &mut [u8], src: &[u8]) {
assert_eq!(dst.len(), src.len());
unsafe { xor_neon_impl(dst, src) }
}
#[target_feature(enable = "neon")]
unsafe fn xor_neon_impl(dst: &mut [u8], src: &[u8]) {
let len = dst.len() & !15;
let (dst_ptr, src_ptr) = (dst.as_mut_ptr(), src.as_ptr());
let mut offset = 0;
while offset < len {
unsafe {
let d = vld1q_u8(dst_ptr.add(offset));
let s = vld1q_u8(src_ptr.add(offset));
vst1q_u8(dst_ptr.add(offset), veorq_u8(d, s));
}
offset += 16;
}
scalar::xor(&mut dst[len..], &src[len..]);
}
#[cfg(any(test, feature = "internals"))]
const NEON_ROW_TILE: usize = 4 * 16;
#[cfg(any(test, feature = "internals"))]
pub(crate) fn xor_rows_neon(dst: &mut [u8], src: &[u8], row_len: usize) {
assert_eq!(dst.len(), src.len());
assert!(dst.len().is_multiple_of(row_len));
debug_assert_ne!(row_len, 0);
unsafe { xor_rows_neon_impl(dst.as_mut_ptr(), src.as_ptr(), dst.len() / row_len, row_len) }
}
#[cfg(any(test, feature = "internals"))]
#[target_feature(enable = "neon")]
unsafe fn xor_rows_neon_impl(dst: *mut u8, src: *const u8, rows: usize, row_len: usize) {
let fours = rows / 4;
let twos = (rows % 4) / 2;
unsafe {
let (mut d, mut s) = (dst, src);
if fours > 0 {
xor_streams_neon::<4>(d, s, fours, row_len);
d = d.add(fours * 4 * row_len);
s = s.add(fours * 4 * row_len);
}
if twos > 0 {
xor_streams_neon::<2>(d, s, twos, row_len);
d = d.add(2 * row_len);
s = s.add(2 * row_len);
}
if rows % 2 == 1 {
let tail = core::slice::from_raw_parts_mut(d, row_len);
let tail_src = core::slice::from_raw_parts(s, row_len);
xor_neon_impl(tail, tail_src);
}
}
}
#[cfg(any(test, feature = "internals"))]
#[target_feature(enable = "neon")]
unsafe fn xor_streams_neon<const W: usize>(
dst: *mut u8,
src: *const u8,
groups: usize,
row_len: usize,
) {
for group in 0..groups {
let (base_d, base_s) =
unsafe { (dst.add(group * W * row_len), src.add(group * W * row_len)) };
let mut offset = 0;
while offset + NEON_ROW_TILE <= row_len {
for r in 0..W {
unsafe {
let d = base_d.add(r * row_len + offset);
let s = base_s.add(r * row_len + offset);
for v in 0..NEON_ROW_TILE / 16 {
let dv = vld1q_u8(d.add(v * 16));
let sv = vld1q_u8(s.add(v * 16));
vst1q_u8(d.add(v * 16), veorq_u8(dv, sv));
}
}
}
offset += NEON_ROW_TILE;
}
while offset + 16 <= row_len {
for r in 0..W {
unsafe {
let d = base_d.add(r * row_len + offset);
let s = base_s.add(r * row_len + offset);
vst1q_u8(d, veorq_u8(vld1q_u8(d), vld1q_u8(s)));
}
}
offset += 16;
}
if offset < row_len {
for r in 0..W {
let tail =
unsafe { core::slice::from_raw_parts_mut(base_d.add(r * row_len), row_len) };
let tail_src =
unsafe { core::slice::from_raw_parts(base_s.add(r * row_len), row_len) };
scalar::xor(&mut tail[offset..], &tail_src[offset..]);
}
}
}
}