Macro memchr::arch::x86_64::memchr::unsafe_ifunc

source ·
macro_rules! unsafe_ifunc {
    (
        $memchrty:ident,
        $memchrfind:ident,
        $fnty:ty,
        $retty:ty,
        $hay_start:ident,
        $hay_end:ident,
        $($needle:ident),+
    ) => { ... };
}
Expand description

Provides a way to run a memchr-like function while amortizing the cost of runtime CPU feature detection.

This works by loading a function pointer from an atomic global. Initially, this global is set to a function that does CPU feature detection. For example, if AVX2 is enabled, then the AVX2 implementation is used. Otherwise, at least on x86_64, the SSE2 implementation is used. (And in some niche cases, if SSE2 isn’t available, then the architecture independent fallback implementation is used.)

After the first call to this function, the atomic global is replaced with the specific AVX2, SSE2 or fallback routine chosen. Subsequent calls then will directly call the chosen routine instead of needing to go through the CPU feature detection branching again.

This particular macro is specifically written to provide the implementation of functions with the following signature:

fn memchr(needle1: u8, start: *const u8, end: *const u8) -> Option<usize>;

Where you can also have memchr2 and memchr3, but with needle2 and needle3, respectively. The start and end parameters correspond to the start and end of the haystack, respectively.

We use raw pointers here instead of the more obvious haystack: &[u8] so that the function is compatible with our lower level iterator logic that operates on raw pointers. We use this macro to implement “raw” memchr routines with the signature above, and then define memchr routines using regular slices on top of them.

Note that we use #[cfg(target_feature = "sse2")] below even though it shouldn’t be strictly necessary because without it, it seems to cause the compiler to blow up. I guess it can’t handle a function pointer being created with a sse target feature? Dunno. See the build-for-x86-64-but-non-sse-target CI job if you want to experiment with this.

§Safety

Primarily callers must that $fnty is a correct function pointer type and not something else.

Callers must also ensure that $memchrty::$memchrfind corresponds to a routine that returns a valid function pointer when a match is found. That is, a pointer that is >= start and < end.

Callers must also ensure that the $hay_start and $hay_end identifiers correspond to valid pointers.