use crate::decoding::simd_copy;
use crate::encoding::fastpath::FastpathKernel;
use crate::encoding::workspace::RegionVec;
use super::RawSequence;
const LITERAL_INLINE_COPY_MAX: usize = 2048;
pub(super) fn gather_literals(
kernel: FastpathKernel,
block: &[u8],
sequences: &[RawSequence],
tail: usize,
dst: &mut RegionVec<u8>,
) {
if dst.capacity() - dst.len() < block.len() {
crate::encoding::workspace::capacity_exhausted();
}
match kernel {
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "kernel-avx2"
))]
FastpathKernel::Avx2Bmi2 => unsafe { gather_avx2(block, sequences, tail, dst) },
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "kernel-sse"
))]
FastpathKernel::Sse2 | FastpathKernel::Sse42 => unsafe {
gather_sse2(block, sequences, tail, dst)
},
#[cfg(all(
target_arch = "aarch64",
target_endian = "little",
feature = "kernel-neon"
))]
FastpathKernel::Neon => gather_neon(block, sequences, tail, dst),
#[cfg(all(
target_arch = "wasm32",
target_feature = "simd128",
feature = "kernel-simd128"
))]
FastpathKernel::Simd128 => gather_simd128(block, sequences, tail, dst),
_ => gather_scalar(block, sequences, tail, dst),
}
}
const WILDCOPY_SLACK: usize = 32;
macro_rules! gather_body {
($block:expr, $sequences:expr, $tail:expr, $dst:expr, $medium:path, $wild:path, $chunk:expr) => {{
let block: &[u8] = $block;
let dst: &mut RegionVec<u8> = $dst;
let src = block.as_ptr();
let src_len = block.len();
let start = dst.len();
let out = unsafe { dst.as_mut_ptr().add(start) };
let mut written = 0usize;
let mut pos = 0usize;
macro_rules! copy_run {
($len:expr) => {{
let len = $len;
let room = src_len - pos;
unsafe {
let s = src.add(pos);
let d = out.add(written);
if room >= WILDCOPY_SLACK && len <= room - WILDCOPY_SLACK {
if len < LITERAL_INLINE_COPY_MAX {
if len != 0 {
$wild(s, d, len.next_multiple_of($chunk));
}
} else {
core::ptr::copy_nonoverlapping(s, d, len);
}
} else {
assert!(len <= room, "sequences reach past the block they describe");
if len <= 32 {
if len != 0 {
simd_copy::copy_exact_small(s, d, len);
}
} else if len < LITERAL_INLINE_COPY_MAX {
$medium(s, d, len);
} else {
core::ptr::copy_nonoverlapping(s, d, len);
}
}
}
written += len;
}};
}
for seq in $sequences {
let ll = seq.ll as usize;
copy_run!(ll);
pos += ll;
let ml = seq.ml as usize;
assert!(
ml <= src_len - pos,
"sequences reach past the block they describe"
);
pos += ml;
}
copy_run!($tail);
assert_eq!(pos + $tail, src_len, "sequences must cover the block");
unsafe { dst.set_len(start + written) };
}};
}
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "kernel-avx2"
))]
#[target_feature(enable = "avx2")]
unsafe fn gather_avx2(
block: &[u8],
sequences: &[RawSequence],
tail: usize,
dst: &mut RegionVec<u8>,
) {
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_avx2,
simd_copy::copy_avx2,
32
)
}
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
feature = "kernel-sse"
))]
#[target_feature(enable = "sse2")]
unsafe fn gather_sse2(
block: &[u8],
sequences: &[RawSequence],
tail: usize,
dst: &mut RegionVec<u8>,
) {
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_sse2,
simd_copy::copy_sse2,
16
)
}
#[cfg(all(
target_arch = "aarch64",
target_endian = "little",
feature = "kernel-neon"
))]
fn gather_neon(block: &[u8], sequences: &[RawSequence], tail: usize, dst: &mut RegionVec<u8>) {
#[cfg(target_feature = "neon")]
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_neon,
simd_copy::copy_neon,
16
);
#[cfg(not(target_feature = "neon"))]
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_u64,
simd_copy::copy_scalar,
core::mem::size_of::<usize>()
);
}
#[cfg(all(
target_arch = "wasm32",
target_feature = "simd128",
feature = "kernel-simd128"
))]
fn gather_simd128(block: &[u8], sequences: &[RawSequence], tail: usize, dst: &mut RegionVec<u8>) {
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_simd128,
simd_copy::copy_simd128,
16
)
}
fn gather_scalar(block: &[u8], sequences: &[RawSequence], tail: usize, dst: &mut RegionVec<u8>) {
gather_body!(
block,
sequences,
tail,
dst,
simd_copy::copy_exact_u64,
simd_copy::copy_scalar,
core::mem::size_of::<usize>()
)
}