#![cfg_attr(
not(test),
warn(
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::undocumented_unsafe_blocks
)
)]
mod half;
pub use half::Half;
mod traits;
pub use traits::{
DistanceFunction, DistanceFunctionMut, Norm, PreprocessedDistanceFunction, PureDistanceFunction,
};
mod value;
pub use value::{MathematicalValue, SimilarityScore};
mod unaligned;
pub use unaligned::{AsUnaligned, UnalignedSlice};
pub mod contains;
pub mod conversion;
pub mod distance;
pub mod norm;
pub mod sparse;
#[cfg(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
))]
const CACHE_LINE_SIZE: usize = 64;
#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))]
#[inline(always)]
pub unsafe fn prefetch_cache_line(_ptr: *const i8) {
#[cfg(not(miri))]
{
use std::arch::x86_64::*;
unsafe { _mm_prefetch(_ptr, _MM_HINT_T0) };
}
}
#[cfg(target_arch = "aarch64")]
#[inline(always)]
pub unsafe fn prefetch_cache_line(_ptr: *const i8) {
#[cfg(not(miri))]
{
unsafe {
std::arch::asm!(
"prfm pldl2keep, [{ptr}]",
ptr = in(reg) _ptr,
options(nostack, preserves_flags, readonly),
);
}
}
}
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
)))]
#[inline(always)]
pub unsafe fn prefetch_cache_line(_ptr: *const i8) {}
#[cfg(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
))]
#[inline(always)]
unsafe fn prefetch_exactly<const N: usize>(ptr: *const i8) {
for i in 0..N {
unsafe { prefetch_cache_line(ptr.add(i * CACHE_LINE_SIZE)) };
}
}
#[cfg(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
))]
#[inline(always)]
unsafe fn prefetch_at_most<const N: usize>(ptr: *const i8, bytes: usize) {
for i in 0..N {
if CACHE_LINE_SIZE * i >= bytes {
break;
}
unsafe { prefetch_cache_line(ptr.add(i * CACHE_LINE_SIZE)) };
}
}
#[cfg(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
))]
#[inline]
pub fn prefetch_hint_max<const MAX_CACHE_LINES: usize, T>(vec: &[T]) {
let vecsize = std::mem::size_of_val(vec);
if vecsize >= MAX_CACHE_LINES * CACHE_LINE_SIZE {
unsafe { prefetch_exactly::<MAX_CACHE_LINES>(vec.as_ptr().cast()) }
} else {
unsafe { prefetch_at_most::<MAX_CACHE_LINES>(vec.as_ptr().cast(), vecsize) }
}
}
#[cfg(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
))]
#[inline]
pub fn prefetch_hint_all<T>(vec: &[T]) {
let vecsize = std::mem::size_of_val(vec);
let num_prefetch_blocks = vecsize.div_ceil(CACHE_LINE_SIZE);
let vec_ptr = vec.as_ptr() as *const i8;
for d in 0..num_prefetch_blocks {
unsafe { prefetch_cache_line(vec_ptr.add(d * CACHE_LINE_SIZE)) };
}
}
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
)))]
pub fn prefetch_hint_max<const MAX_CACHE_LINES: usize, T>(_vec: &[T]) {}
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "avx2"),
target_arch = "aarch64",
)))]
pub fn prefetch_hint_all<T>(_vec: &[T]) {}
#[cfg(test)]
mod test_util;