use std::arch::aarch64::{
uint8x16_t, vandq_u8, vdupq_n_u8, vget_lane_u64, vgetq_lane_u8, vld1q_u8, vmaxq_u8, vqtbl1q_u8,
vreinterpret_u64_u8, vreinterpretq_u16_u8, vshrn_n_u16, vshrq_n_u8, vtstq_u8,
};
use super::STEP;
use crate::lattice::Quotient;
use crate::shuffle::{self, CHUNK, IDENTITY, STRIDE, WAYS};
#[target_feature(enable = "neon")]
pub(crate) unsafe fn sweep_shuffle(q: &Quotient, hay: &[u8]) -> bool {
#[inline(always)]
unsafe fn sweep(
q: &Quotient,
block: &[u8],
stride: usize,
mut live: uint8x16_t,
) -> (uint8x16_t, u8) {
unsafe {
let identity = vld1q_u8(IDENTITY.as_ptr());
let mut compose = [identity; WAYS];
let mut high = [identity; WAYS];
for step in 0..stride {
for (way, (f, h)) in compose.iter_mut().zip(&mut high).enumerate() {
let byte = block[way * stride + step];
let row = vld1q_u8(q.rows[usize::from(byte)].as_ptr());
*f = vqtbl1q_u8(row, *f);
*h = vmaxq_u8(*h, *f);
}
}
let mut seen = live;
for (f, h) in compose.into_iter().zip(high) {
seen = vmaxq_u8(seen, vqtbl1q_u8(h, live));
live = vqtbl1q_u8(f, live);
}
(live, vgetq_lane_u8::<0>(seen))
}
}
unsafe {
let mut live = vdupq_n_u8(q.start);
let mut rest = hay;
while rest.len() >= CHUNK {
let (chunk, after) = rest.split_at(CHUNK);
let (next, seen) = sweep(q, chunk, STRIDE, live);
if seen >= q.threshold {
return false;
}
(live, rest) = (next, after);
}
let (paved, trailing) = rest.split_at(rest.len() / WAYS * WAYS);
let (live, seen) = sweep(q, paved, paved.len() / WAYS, live);
if seen >= q.threshold {
return false;
}
shuffle::walk(q, trailing, vgetq_lane_u8::<0>(live)).is_some()
}
}
#[target_feature(enable = "neon")]
pub(crate) unsafe fn classify(lo: &[u8; 16], hi: &[u8; 16], hay: &[u8]) -> Option<usize> {
unsafe {
let (lo_tbl, hi_tbl) = (vld1q_u8(lo.as_ptr()), vld1q_u8(hi.as_ptr()));
let nibble = vdupq_n_u8(0x0F);
for (i, block) in hay.chunks_exact(STEP).enumerate() {
let v = vld1q_u8(block.as_ptr());
let picked = vqtbl1q_u8(lo_tbl, vandq_u8(v, nibble));
let select = vqtbl1q_u8(hi_tbl, vshrq_n_u8::<4>(v));
let hit = vtstq_u8(picked, select);
let packed = vget_lane_u64::<0>(vreinterpret_u64_u8(vshrn_n_u16::<4>(
vreinterpretq_u16_u8(hit),
)));
if packed != 0 {
return Some(i * STEP + (packed.trailing_zeros() as usize >> 2));
}
}
crate::skip::wide::tail(lo, hi, hay)
}
}