#![cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
#[target_feature(enable = "avx2")]
pub(crate) unsafe fn avx2_text_run_len(bytes: &[u8]) -> usize {
let mut off = 0usize;
let len = bytes.len();
while off < len {
let chunk = if len - off >= 32 {
_mm256_loadu_si256(bytes.as_ptr().add(off) as *const __m256i)
} else {
return off + scalar_tail(&bytes[off..]);
};
let run = classify32(chunk);
if run != 32 {
return off + run;
}
off += 32;
}
len
}
#[target_feature(enable = "avx2")]
unsafe fn classify32(chunk: __m256i) -> usize {
let lt = _mm256_cmpeq_epi8(_mm256_min_epu8(chunk, _mm256_set1_epi8(0x1F)), chunk);
let gt = _mm256_cmpeq_epi8(_mm256_max_epu8(chunk, _mm256_set1_epi8(0x7F)), chunk);
let eq_lt = _mm256_cmpeq_epi8(chunk, _mm256_set1_epi8(b'<' as i8));
let eq_amp = _mm256_cmpeq_epi8(chunk, _mm256_set1_epi8(b'&' as i8));
let eq_rb = _mm256_cmpeq_epi8(chunk, _mm256_set1_epi8(b']' as i8));
let stop = _mm256_or_si256(
_mm256_or_si256(_mm256_or_si256(lt, gt), _mm256_or_si256(eq_lt, eq_amp)),
eq_rb,
);
let mask = _mm256_movemask_epi8(stop) as u32;
let first = mask.trailing_zeros() as usize;
if first < 32 {
first
} else {
32
}
}
#[target_feature(enable = "avx512f,avx512bw")]
pub(crate) unsafe fn avx512_text_run_len(bytes: &[u8]) -> usize {
let mut off = 0usize;
let len = bytes.len();
while off < len {
if len - off >= 64 {
let chunk = _mm512_loadu_si512(bytes.as_ptr().add(off) as *const __m512i);
let run = classify64(chunk);
if run != 64 {
return off + run;
}
off += 64;
} else {
return off + scalar_tail(&bytes[off..]);
}
}
len
}
#[target_feature(enable = "avx512f,avx512bw")]
unsafe fn classify64(chunk: __m512i) -> usize {
let lt = _mm512_cmplt_epu8_mask(chunk, _mm512_set1_epi8(0x20));
let gt = _mm512_cmpgt_epu8_mask(chunk, _mm512_set1_epi8(0x7E));
let eq_lt = _mm512_cmpeq_epi8_mask(chunk, _mm512_set1_epi8(b'<' as i8));
let eq_amp = _mm512_cmpeq_epi8_mask(chunk, _mm512_set1_epi8(b'&' as i8));
let eq_rb = _mm512_cmpeq_epi8_mask(chunk, _mm512_set1_epi8(b']' as i8));
let stop = lt | gt | eq_lt | eq_amp | eq_rb;
let first = stop.trailing_zeros() as usize;
if first < 64 {
first
} else {
64
}
}
fn scalar_tail(bytes: &[u8]) -> usize {
super::scalar::scalar_text_run_len(bytes)
}