1#![cfg_attr(
12 not(test),
13 warn(
14 clippy::panic,
15 clippy::unwrap_used,
16 clippy::expect_used,
17 clippy::undocumented_unsafe_blocks
18 )
19)]
20
21mod half;
22pub use half::Half;
23
24mod traits;
25pub use traits::{
26 DistanceFunction, DistanceFunctionMut, Norm, PreprocessedDistanceFunction, PureDistanceFunction,
27};
28
29mod value;
30pub use value::{MathematicalValue, SimilarityScore};
31
32mod unaligned;
33pub use unaligned::{AsUnaligned, UnalignedSlice};
34
35pub mod contains;
36pub mod conversion;
37pub mod distance;
38pub mod norm;
39pub mod sparse;
40
41#[cfg(any(
42 all(target_arch = "x86_64", target_feature = "avx2"),
43 target_arch = "aarch64",
44))]
45const CACHE_LINE_SIZE: usize = 64;
46
47#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))]
53#[inline(always)]
54pub unsafe fn prefetch_cache_line(_ptr: *const i8) {
55 #[cfg(not(miri))]
56 {
57 use std::arch::x86_64::*;
58 unsafe { _mm_prefetch(_ptr, _MM_HINT_T0) };
60 }
61}
62
63#[cfg(target_arch = "aarch64")]
69#[inline(always)]
70pub unsafe fn prefetch_cache_line(_ptr: *const i8) {
71 #[cfg(not(miri))]
72 {
73 unsafe {
75 std::arch::asm!(
76 "prfm pldl2keep, [{ptr}]",
77 ptr = in(reg) _ptr,
78 options(nostack, preserves_flags, readonly),
79 );
80 }
81 }
82}
83
84#[cfg(not(any(
90 all(target_arch = "x86_64", target_feature = "avx2"),
91 target_arch = "aarch64",
92)))]
93#[inline(always)]
94pub unsafe fn prefetch_cache_line(_ptr: *const i8) {}
95
96#[cfg(any(
97 all(target_arch = "x86_64", target_feature = "avx2"),
98 target_arch = "aarch64",
99))]
100#[inline(always)]
101unsafe fn prefetch_exactly<const N: usize>(ptr: *const i8) {
102 for i in 0..N {
103 unsafe { prefetch_cache_line(ptr.add(i * CACHE_LINE_SIZE)) };
105 }
106}
107
108#[cfg(any(
109 all(target_arch = "x86_64", target_feature = "avx2"),
110 target_arch = "aarch64",
111))]
112#[inline(always)]
113unsafe fn prefetch_at_most<const N: usize>(ptr: *const i8, bytes: usize) {
114 for i in 0..N {
115 if CACHE_LINE_SIZE * i >= bytes {
116 break;
117 }
118
119 unsafe { prefetch_cache_line(ptr.add(i * CACHE_LINE_SIZE)) };
121 }
122}
123
124#[cfg(any(
127 all(target_arch = "x86_64", target_feature = "avx2"),
128 target_arch = "aarch64",
129))]
130#[inline]
131pub fn prefetch_hint_max<const MAX_CACHE_LINES: usize, T>(vec: &[T]) {
132 let vecsize = std::mem::size_of_val(vec);
133 if vecsize >= MAX_CACHE_LINES * CACHE_LINE_SIZE {
134 unsafe { prefetch_exactly::<MAX_CACHE_LINES>(vec.as_ptr().cast()) }
136 } else {
137 unsafe { prefetch_at_most::<MAX_CACHE_LINES>(vec.as_ptr().cast(), vecsize) }
139 }
140}
141
142#[cfg(any(
145 all(target_arch = "x86_64", target_feature = "avx2"),
146 target_arch = "aarch64",
147))]
148#[inline]
149pub fn prefetch_hint_all<T>(vec: &[T]) {
150 let vecsize = std::mem::size_of_val(vec);
151 let num_prefetch_blocks = vecsize.div_ceil(CACHE_LINE_SIZE);
152 let vec_ptr = vec.as_ptr() as *const i8;
153 for d in 0..num_prefetch_blocks {
154 unsafe { prefetch_cache_line(vec_ptr.add(d * CACHE_LINE_SIZE)) };
156 }
157}
158
159#[cfg(not(any(
160 all(target_arch = "x86_64", target_feature = "avx2"),
161 target_arch = "aarch64",
162)))]
163pub fn prefetch_hint_max<const MAX_CACHE_LINES: usize, T>(_vec: &[T]) {}
164
165#[cfg(not(any(
166 all(target_arch = "x86_64", target_feature = "avx2"),
167 target_arch = "aarch64",
168)))]
169pub fn prefetch_hint_all<T>(_vec: &[T]) {}
170
171#[cfg(test)]
172mod test_util;