If you need to use hardware-specific intrinsics (like NEON or AVX), use the kernel! macro. This macro creates a function where you can safely call raw intrinsics by passing a hardware-specific token (e.g., Neon). You can then check for support at runtime using level.as_neon() (or the relevant architecture method) and dispatch to the kernel.
use fearless_simd::{prelude::*, Level, u32x4};
fearless_simd::kernel!(
fn double_u32s_neon(neon: Neon, values: &mut [u32]) {
use core::arch::aarch64::*;
let mut chunks = values.chunks_exact_mut(4);
for chunk in &mut chunks {
let v: uint32x4_t = u32x4::from_slice(neon, chunk).into(); // safe load
let doubled = vmulq_u32(v, vdupq_n_u32(2)); // safe access to a NEON intrinsic
let doubled: u32x4<_> = doubled.simd_into(neon);
doubled.store_slice(chunk);
}
for value in chunks.into_remainder() {
*value = *value * 2;
}
}
);
#[cfg(target_arch = "aarch64")]
{
let level = Level::new();
if let Some(neon) = level.as_neon() {
let mut values = [1, 2, 3, 4, 5];
double_u32s_neon(neon, &mut values);
assert_eq!(values, [2, 4, 6, 8, 10]);
}
}