use crate::{AUX_NONE, AUX_SLASH, Blk, lead_run};
use core::arch::aarch64::*;
const POW: [u8; 16] = [1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128];
#[inline(always)]
unsafe fn mm64(v: [uint8x16_t; 4], pow: uint8x16_t) -> u64 {
unsafe {
let ab = vpaddq_u8(vandq_u8(v[0], pow), vandq_u8(v[1], pow));
let cd = vpaddq_u8(vandq_u8(v[2], pow), vandq_u8(v[3], pow));
let x = vpaddq_u8(ab, cd);
vgetq_lane_u64::<0>(vreinterpretq_u64_u8(vpaddq_u8(x, x)))
}
}
#[target_feature(enable = "neon")]
pub(crate) unsafe fn eq64(text: &[u8], base: usize, b: u8) -> u64 {
unsafe {
let pow = vld1q_u8(POW.as_ptr());
let n = vdupq_n_u8(b);
mm64(
[
vceqq_u8(vld1q_u8(text.as_ptr().add(base)), n),
vceqq_u8(vld1q_u8(text.as_ptr().add(base + 16)), n),
vceqq_u8(vld1q_u8(text.as_ptr().add(base + 32)), n),
vceqq_u8(vld1q_u8(text.as_ptr().add(base + 48)), n),
],
pow,
)
}
}
#[target_feature(enable = "neon")]
pub(crate) unsafe fn any64(text: &[u8], base: usize, b: u8) -> bool {
unsafe {
let n = vdupq_n_u8(b);
let p = text.as_ptr().add(base);
let a = vorrq_u8(vceqq_u8(vld1q_u8(p), n), vceqq_u8(vld1q_u8(p.add(16)), n));
let c = vorrq_u8(
vceqq_u8(vld1q_u8(p.add(32)), n),
vceqq_u8(vld1q_u8(p.add(48)), n),
);
vmaxvq_u8(vorrq_u8(a, c)) != 0
}
}
#[target_feature(enable = "neon")]
pub(crate) unsafe fn build64<const AUX: u8, const P3: bool>(
text: &[u8],
tags: &[u8],
base: usize,
lut: &[u8; 64],
cur_code: u8,
cur_aux: bool,
) -> (Blk, u8) {
unsafe {
let pow = vld1q_u8(POW.as_ptr());
let seven = vdupq_n_u8(7);
let tbl = uint8x16x4_t(
vld1q_u8(lut.as_ptr()),
vld1q_u8(lut.as_ptr().add(16)),
vld1q_u8(lut.as_ptr().add(32)),
vld1q_u8(lut.as_ptr().add(48)),
);
let mut isc = [vdupq_n_u8(0); 4];
let mut cd = [vdupq_n_u8(0); 4];
let mut prev = vdupq_n_u8(cur_code);
for k in 0..4 {
let raw = vqtbl4q_u8(tbl, vld1q_u8(tags.as_ptr().add(base + k * 16)));
isc[k] = vceqq_u8(raw, seven);
let c = vbslq_u8(isc[k], vextq_u8::<15>(prev, raw), raw);
let c = vbslq_u8(vceqq_u8(c, seven), vextq_u8::<14>(prev, c), c);
prev = c;
cd[k] = c;
}
let last_code = vgetq_lane_u8::<15>(prev);
let plane = |bit: u8| {
let d = vdupq_n_u8(bit);
mm64(
[
vtstq_u8(cd[0], d),
vtstq_u8(cd[1], d),
vtstq_u8(cd[2], d),
vtstq_u8(cd[3], d),
],
pow,
)
};
let mut b = Blk {
cont: mm64(isc, pow),
p0: plane(1),
p1: plane(2),
p2: plane(4),
p3: if P3 { plane(8) } else { 0 },
aux: 0,
};
if AUX == AUX_NONE {
return (b, last_code);
}
let ntext = text.len();
let tv = [
vld1q_u8(text.as_ptr().add(base)),
vld1q_u8(text.as_ptr().add(base + 16)),
vld1q_u8(text.as_ptr().add(base + 32)),
vld1q_u8(text.as_ptr().add(base + 48)),
];
if AUX == AUX_SLASH {
let sl = vdupq_n_u8(b'/');
b.aux = mm64(
[
vceqq_u8(tv[0], sl),
vceqq_u8(tv[1], sl),
vceqq_u8(tv[2], sl),
vceqq_u8(tv[3], sl),
],
pow,
);
return (b, last_code);
}
let e3e9 = |v| vcleq_u8(vsubq_u8(v, vdupq_n_u8(0xE3)), vdupq_n_u8(6));
let any = vmaxvq_u8(vorrq_u8(
vorrq_u8(e3e9(tv[0]), e3e9(tv[1])),
vorrq_u8(e3e9(tv[2]), e3e9(tv[3])),
));
if any != 0 {
let tail = {
let mut buf = [0u8; 16];
let off = base + 64;
let avail = text.len().saturating_sub(off).min(16);
buf[..avail].copy_from_slice(&text[off..off + avail]);
vld1q_u8(buf.as_ptr())
};
let cjkv = |v: uint8x16_t, nx: uint8x16_t| {
let (b1, b2) = (vextq_u8::<1>(v, nx), vextq_u8::<2>(v, nx));
let e9 = vandq_u8(
vceqq_u8(v, vdupq_n_u8(0xE9)),
vorrq_u8(
vcltq_u8(b1, vdupq_n_u8(0xBE)),
vandq_u8(
vceqq_u8(b1, vdupq_n_u8(0xBE)),
vcleq_u8(b2, vdupq_n_u8(0xA5)),
),
),
);
vorrq_u8(
vorrq_u8(
vandq_u8(
vceqq_u8(v, vdupq_n_u8(0xE3)),
vcleq_u8(vsubq_u8(b1, vdupq_n_u8(0x81)), vdupq_n_u8(2)),
),
vandq_u8(
vceqq_u8(v, vdupq_n_u8(0xE4)),
vcgeq_u8(b1, vdupq_n_u8(0xB8)),
),
),
vorrq_u8(vcleq_u8(vsubq_u8(v, vdupq_n_u8(0xE5)), vdupq_n_u8(3)), e9),
)
};
let mut leads = mm64(
[
cjkv(tv[0], tv[1]),
cjkv(tv[1], tv[2]),
cjkv(tv[2], tv[3]),
cjkv(tv[3], tail),
],
pow,
);
let lim = ntext.saturating_sub(base + 2);
if lim < 64 {
leads &= (1u64 << lim) - 1;
}
b.aux = leads | (leads << 1) | (leads << 2);
}
if cur_aux {
b.aux |= lead_run(b.cont, !0);
}
(b, last_code)
}
}