Skip to main content

kernel

Macro kernel 

Source
macro_rules! kernel {
    (
        $(#[$meta:meta])*
        $vis:vis fn $name:ident(
            $token:ident : $token_ty:ident $(, $arg:ident : $arg_ty:ty)* $(,)?
        ) $(-> $ret:ty)? {
            $($kernel_body:tt)*
        }
    ) => { ... };
    (
        $(#[$meta:meta])*
        $vis:vis fn $name:ident(
            $token:ident : $token_ty:ty $(, $arg:ident : $arg_ty:ty)* $(,)?
        ) $(-> $ret:ty)? {
            $($kernel_body:tt)*
        }
    ) => { ... };
}
Expand description

Creates a context where you can safely call intrinsics available at the SIMD level named by the function’s first argument.

This is useful if the portable abstractions are not enough, and you need to use platform-specific intrinsics for parts of the computation.

The first argument must be a SIMD token written as token: Neon, token: WasmSimd128, token: Sse4_2, or token: Avx2.

For levels with runtime-detected target features, the macro runs your body inside an inner function annotated with the appropriate #[target_feature] attributes. That makes platform-specific intrinsics from core::arch or std::arch safe to call in the body, as long as they do not have safety requirements beyond those target features.

§Example

use fearless_simd::{i32x8, prelude::*};
#[cfg(target_arch = "x86")]
use std::arch::x86::{__m256i, _mm256_add_epi32};
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::{__m256i, _mm256_add_epi32};

fearless_simd::kernel!(
    fn add_i32x8(avx2: Avx2, a: __m256i, b: __m256i) -> __m256i {
        _mm256_add_epi32(a, b)
    }
);

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
if let Some(avx2) = fearless_simd::Level::new().as_avx2() {
    let a: i32x8<_> = [1, 2, 3, 4, 5, 6, 7, 8].simd_into(avx2);
    let b: i32x8<_> = [10, 20, 30, 40, 50, 60, 70, 80].simd_into(avx2);
    let sum: i32x8<_> = add_i32x8(avx2, a.into(), b.into()).simd_into(avx2);

    assert_eq!(<[i32; 8]>::from(sum), [11, 22, 33, 44, 55, 66, 77, 88]);
}

See the sRGB example for an end-to-end use of kernel macros.

§Limitations

The macro only accepts a single plain, safe, non-generic function item with simple named parameters. However, the body of the function can be as complex as you like.

The SIMD token type must be written as a bare supported name: literally Neon, WasmSimd128, Sse4_2, or Avx2. No paths or aliases.

For soundness, this macro only accepts safe functions.

fearless_simd::kernel!(
    unsafe fn should_not_compile(avx2: Avx2) {}
);