1macro_rules! unsafe_ifunc {
59 (
60 $memchrty:ident,
61 $memchrfind:ident,
62 $fnty:ty,
63 $retty:ty,
64 $hay_start:ident,
65 $hay_end:ident,
66 $($needle:ident),+
67 ) => {{
68 #![allow(unused_unsafe)]
69
70 use core::sync::atomic::{AtomicPtr, Ordering};
71
72 type Fn = *mut ();
73 type RealFn = $fnty;
74 static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
75
76 #[cfg(target_feature = "sse2")]
77 #[target_feature(enable = "sse2", enable = "avx2")]
78 unsafe fn find_avx2(
79 $($needle: u8),+,
80 $hay_start: *const u8,
81 $hay_end: *const u8,
82 ) -> $retty {
83 use crate::arch::x86_64::avx2::memchr::$memchrty;
84 $memchrty::new_unchecked($($needle),+)
85 .$memchrfind($hay_start, $hay_end)
86 }
87
88 #[cfg(target_feature = "sse2")]
89 #[target_feature(enable = "sse2")]
90 unsafe fn find_sse2(
91 $($needle: u8),+,
92 $hay_start: *const u8,
93 $hay_end: *const u8,
94 ) -> $retty {
95 use crate::arch::x86_64::sse2::memchr::$memchrty;
96 $memchrty::new_unchecked($($needle),+)
97 .$memchrfind($hay_start, $hay_end)
98 }
99
100 unsafe fn find_fallback(
101 $($needle: u8),+,
102 $hay_start: *const u8,
103 $hay_end: *const u8,
104 ) -> $retty {
105 use crate::arch::all::memchr::$memchrty;
106 $memchrty::new($($needle),+).$memchrfind($hay_start, $hay_end)
107 }
108
109 unsafe fn detect(
110 $($needle: u8),+,
111 $hay_start: *const u8,
112 $hay_end: *const u8,
113 ) -> $retty {
114 let fun = {
115 #[cfg(not(target_feature = "sse2"))]
116 {
117 debug!(
118 "no sse2 feature available, using fallback for {}",
119 stringify!($memchrty),
120 );
121 find_fallback as RealFn
122 }
123 #[cfg(target_feature = "sse2")]
124 {
125 use crate::arch::x86_64::{sse2, avx2};
126 if avx2::memchr::$memchrty::is_available() {
127 debug!("chose AVX2 for {}", stringify!($memchrty));
128 find_avx2 as RealFn
129 } else if sse2::memchr::$memchrty::is_available() {
130 debug!("chose SSE2 for {}", stringify!($memchrty));
131 find_sse2 as RealFn
132 } else {
133 debug!("chose fallback for {}", stringify!($memchrty));
134 find_fallback as RealFn
135 }
136 }
137 };
138 FN.store(fun as Fn, Ordering::Relaxed);
139 fun($($needle),+, $hay_start, $hay_end)
145 }
146
147 unsafe {
152 let fun = FN.load(Ordering::Relaxed);
153 core::mem::transmute::<Fn, RealFn>(fun)(
154 $($needle),+,
155 $hay_start,
156 $hay_end,
157 )
158 }
159 }};
160}
161
162#[inline(always)]
174pub(crate) fn memchr_raw(
175 n1: u8,
176 start: *const u8,
177 end: *const u8,
178) -> Option<*const u8> {
179 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn = unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::One;
One::new_unchecked(n1).find_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::One;
One::new_unchecked(n1).find_raw(start, end)
}
unsafe fn find_fallback(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::all::memchr::One;
One::new(n1).find_raw(start, end)
}
unsafe fn detect(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::One::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::One::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, start, end)
}
}unsafe_ifunc!(
181 One,
182 find_raw,
183 unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>,
184 Option<*const u8>,
185 start,
186 end,
187 n1
188 )
189}
190
191#[inline(always)]
197pub(crate) fn memrchr_raw(
198 n1: u8,
199 start: *const u8,
200 end: *const u8,
201) -> Option<*const u8> {
202 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn = unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::One;
One::new_unchecked(n1).rfind_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::One;
One::new_unchecked(n1).rfind_raw(start, end)
}
unsafe fn find_fallback(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::all::memchr::One;
One::new(n1).rfind_raw(start, end)
}
unsafe fn detect(n1: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::One::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::One::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, start, end)
}
}unsafe_ifunc!(
204 One,
205 rfind_raw,
206 unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>,
207 Option<*const u8>,
208 start,
209 end,
210 n1
211 )
212}
213
214#[inline(always)]
220pub(crate) fn memchr2_raw(
221 n1: u8,
222 n2: u8,
223 start: *const u8,
224 end: *const u8,
225) -> Option<*const u8> {
226 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn =
unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::Two;
Two::new_unchecked(n1, n2).find_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::Two;
Two::new_unchecked(n1, n2).find_raw(start, end)
}
unsafe fn find_fallback(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::all::memchr::Two;
Two::new(n1, n2).find_raw(start, end)
}
unsafe fn detect(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::Two::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::Two::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, n2, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, n2, start, end)
}
}unsafe_ifunc!(
228 Two,
229 find_raw,
230 unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>,
231 Option<*const u8>,
232 start,
233 end,
234 n1,
235 n2
236 )
237}
238
239#[inline(always)]
245pub(crate) fn memrchr2_raw(
246 n1: u8,
247 n2: u8,
248 start: *const u8,
249 end: *const u8,
250) -> Option<*const u8> {
251 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn =
unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::Two;
Two::new_unchecked(n1, n2).rfind_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::Two;
Two::new_unchecked(n1, n2).rfind_raw(start, end)
}
unsafe fn find_fallback(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
use crate::arch::all::memchr::Two;
Two::new(n1, n2).rfind_raw(start, end)
}
unsafe fn detect(n1: u8, n2: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::Two::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::Two::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, n2, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, n2, start, end)
}
}unsafe_ifunc!(
253 Two,
254 rfind_raw,
255 unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>,
256 Option<*const u8>,
257 start,
258 end,
259 n1,
260 n2
261 )
262}
263
264#[inline(always)]
270pub(crate) fn memchr3_raw(
271 n1: u8,
272 n2: u8,
273 n3: u8,
274 start: *const u8,
275 end: *const u8,
276) -> Option<*const u8> {
277 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn =
unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::Three;
Three::new_unchecked(n1, n2, n3).find_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::Three;
Three::new_unchecked(n1, n2, n3).find_raw(start, end)
}
unsafe fn find_fallback(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::all::memchr::Three;
Three::new(n1, n2, n3).find_raw(start, end)
}
unsafe fn detect(n1: u8, n2: u8, n3: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::Three::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::Three::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, n2, n3, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, n2, n3, start, end)
}
}unsafe_ifunc!(
279 Three,
280 find_raw,
281 unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>,
282 Option<*const u8>,
283 start,
284 end,
285 n1,
286 n2,
287 n3
288 )
289}
290
291#[inline(always)]
297pub(crate) fn memrchr3_raw(
298 n1: u8,
299 n2: u8,
300 n3: u8,
301 start: *const u8,
302 end: *const u8,
303) -> Option<*const u8> {
304 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn =
unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::x86_64::avx2::memchr::Three;
Three::new_unchecked(n1, n2, n3).rfind_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::x86_64::sse2::memchr::Three;
Three::new_unchecked(n1, n2, n3).rfind_raw(start, end)
}
unsafe fn find_fallback(n1: u8, n2: u8, n3: u8, start: *const u8,
end: *const u8) -> Option<*const u8> {
use crate::arch::all::memchr::Three;
Three::new(n1, n2, n3).rfind_raw(start, end)
}
unsafe fn detect(n1: u8, n2: u8, n3: u8, start: *const u8, end: *const u8)
-> Option<*const u8> {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::Three::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::Three::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, n2, n3, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, n2, n3, start, end)
}
}unsafe_ifunc!(
306 Three,
307 rfind_raw,
308 unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>,
309 Option<*const u8>,
310 start,
311 end,
312 n1,
313 n2,
314 n3
315 )
316}
317
318#[inline(always)]
324pub(crate) fn count_raw(n1: u8, start: *const u8, end: *const u8) -> usize {
325 {
#![allow(unused_unsafe)]
use core::sync::atomic::{AtomicPtr, Ordering};
type Fn = *mut ();
type RealFn = unsafe fn(u8, *const u8, *const u8) -> usize;
static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn);
#[target_feature(enable = "sse2", enable = "avx2")]
unsafe fn find_avx2(n1: u8, start: *const u8, end: *const u8) -> usize {
use crate::arch::x86_64::avx2::memchr::One;
One::new_unchecked(n1).count_raw(start, end)
}
#[target_feature(enable = "sse2")]
unsafe fn find_sse2(n1: u8, start: *const u8, end: *const u8) -> usize {
use crate::arch::x86_64::sse2::memchr::One;
One::new_unchecked(n1).count_raw(start, end)
}
unsafe fn find_fallback(n1: u8, start: *const u8, end: *const u8)
-> usize {
use crate::arch::all::memchr::One;
One::new(n1).count_raw(start, end)
}
unsafe fn detect(n1: u8, start: *const u8, end: *const u8) -> usize {
let fun =
{
{
use crate::arch::x86_64::{sse2, avx2};
if avx2::memchr::One::is_available() {
;
find_avx2 as RealFn
} else if sse2::memchr::One::is_available() {
;
find_sse2 as RealFn
} else { ; find_fallback as RealFn }
}
};
FN.store(fun as Fn, Ordering::Relaxed);
fun(n1, start, end)
}
unsafe {
let fun = FN.load(Ordering::Relaxed);
core::mem::transmute::<Fn, RealFn>(fun)(n1, start, end)
}
}unsafe_ifunc!(
327 One,
328 count_raw,
329 unsafe fn(u8, *const u8, *const u8) -> usize,
330 usize,
331 start,
332 end,
333 n1
334 )
335}