#![allow(unsafe_code)]
#![cfg_attr(
all(
target_arch = "aarch64",
feature = "crc32",
not(any(feature = "crc16", feature = "crc24", feature = "crc64", test))
),
allow(dead_code, unused_imports)
)]
#[cfg(target_arch = "x86_64")]
pub const LARGE_BLOCK_DISTANCE: usize = 1024;
#[cfg(target_arch = "aarch64")]
pub const LARGE_BLOCK_DISTANCE: usize = 768;
#[cfg(target_arch = "x86_64")]
mod x86_64_impl {
use core::arch::x86_64::{_MM_HINT_T0, _mm_prefetch};
#[inline(always)]
pub(crate) unsafe fn prefetch_read_l1(ptr: *const u8) {
unsafe {
_mm_prefetch(ptr.cast::<i8>(), _MM_HINT_T0);
}
}
}
#[cfg(target_arch = "aarch64")]
mod aarch64_impl {
#[inline(always)]
pub(crate) unsafe fn prefetch_read_l1(ptr: *const u8) {
unsafe {
core::arch::asm!(
"prfm pldl1keep, [{ptr}]",
ptr = in(reg) ptr,
options(nostack, preserves_flags)
);
}
}
}
#[cfg(target_arch = "aarch64")]
pub(crate) use aarch64_impl::prefetch_read_l1;
#[cfg(target_arch = "x86_64")]
pub(crate) use x86_64_impl::prefetch_read_l1;
#[cfg(all(not(any(target_arch = "x86_64", target_arch = "aarch64")), test))]
pub const LARGE_BLOCK_DISTANCE: usize = 512;
#[cfg(all(not(any(target_arch = "x86_64", target_arch = "aarch64")), test))]
#[inline(always)]
pub(crate) unsafe fn prefetch_read_l1(_ptr: *const u8) {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prefetch_distance_is_cache_line_aligned() {
assert_eq!(LARGE_BLOCK_DISTANCE % 64, 0);
}
#[test]
#[cfg_attr(miri, ignore)] fn prefetch_does_not_crash_on_null() {
unsafe {
prefetch_read_l1(core::ptr::null());
}
}
#[test]
#[cfg_attr(miri, ignore)] fn prefetch_does_not_crash_on_unaligned() {
let data = [0u8; 256];
unsafe {
prefetch_read_l1(data.as_ptr().add(1));
prefetch_read_l1(data.as_ptr().add(7));
prefetch_read_l1(data.as_ptr().add(63));
}
}
}