Fearless SIMD v1.0 launches with safe, performant Rust abstractions
Eight years after its prototype, Fearless SIMD reaches stable release, eliminating unsafe code while maintaining hardware performance.
What to know
- Fearless SIMD v1.0 reaches stable after 8 years, offering memory-safe SIMD programming for Rust without ad-hoc unsafe code blocks.
- The library achieves safety through the kernel! macro and safe transmute module, requiring security audits of only two core components.
- Performance is preserved through multiple abstraction levels—from portable operations to direct platform intrinsic access—and state-of-the-art compiler optimizations.
Fearless SIMD project Library developerLinebender Host/publisher
How it unfolded 1 development · click the chart to see its coverage posts
-
1
Fearless SIMD balances performance with portability
The library provides both precise variants (identical across platforms) and fast variants (platform-dependent) for operations with different edge-case behavior. It enables algorithms to leverage hardware's native vector size while also supporting fixed vector sizes, and allows safe fallback to platform intrinsics with no overhead when portable abstractions are insufficient.
“A common criticism leveled at portable SIMD abstractions is that they aren't performant enough, so we've put a lot of effort into making sure that Fearless SIMD never holds you back.”
— Fearless SIMD developers -
For context, fearless_simd works by creating implementations of the `Simd` trait for different SIMD levels, and then your function gets invoked as `double_u32s(Avx512, values)` or similar, using a different type for [AVX-512](https://docs.rs/fearless_simd/1.0.0/fearless_simd/struct.Avx512.html) vs…
2 more of the top 3 · 9 posts in this stretch
-
I was checking the docs on Crates.io, and the usage doesn't seem straightforward. 3 things stand out; I'm not a Rust expert, so forgive me if the answers are obvious. The first example has this code: ``` #[simd] fn double_u32s(_: S, values: &mut [u32]) { for value in values { *value = *value * 2; } } ``` Which takes an unused SIMD parameter; what…
-
Such a type doesn't tell you what SIMD instructions are available on the current machine, just what data widths you want to operate on. fearless_simd does in fact have types like this, albeit they don't make the width a generic parameter because const generics in rust kinda suck at the moment, so the types are `u8x16`, `u16x32` and so on. The…
-
-
background
Fearless SIMD eliminates unsafe code through kernel! macro and safe transmute — Unlike other SIMD abstractions containing thousands of unsafe blocks, Fearless SIMD is engineered to avoid ad-hoc unsafe code. It achieves this through the kernel! macro (which invokes most SIMD intrinsics without unsafe by leveraging target feature v1.1) and a safe transmute module inspired by crates like bytemuck and zerocopy. Only two small, self-contained building blocks require safety auditing.
-
background
Fearless SIMD reaches v1.0 stable release — After 8 years of development since the original prototype, Fearless SIMD v1.0 launches alongside fearless_simd_macros v0.1. The library offers multiple levels of abstraction for SIMD programming: autovectorization and multiversioning, portable SIMD abstractions, or safe access to intrinsics.
What people are saying 6 voices from 1 site · best of 9 · verbatim
- Sep 22
-
> In the case of strlen, though, aren't you paying an indirect call anyway? Not necessarily, sometimes the [compiler inlines libc calls](https://godbolt.org/z/5n3P6M7hd). Though admittedly, not for strlen in my experience, so not a great example, sorry. And there are ifunc's for a lot of GLIBC functions, so clearly indirect calls are worth it in…
-
> I guess I was thinking more about situations like strlen In the case of strlen, though, aren't you paying an indirect call anyway? Most of this: > It nearly always means at least an indirect function call, you lose any function inlining or outlining benefits, and the code size increase can hurt performance as you get worse cache locality. will…
-
Yeah fair enough, it sounds like you’re in a situation where you know you have high loop counts where I agree that this is an effective solution, and those overheads can easily be amortised. I guess I was thinking more about situations like strlen where the loop counts is very unknown and balancing performance of small loop counts and high loop…
-
It's actual runtime dispatch. Inside the `dispatch!` macro there's effectively a `match` on the detected SIMD level, with each arm calling the right specialized impl. This isn't exposed in the public API, so fearless_simd could technically switch up the dispatch strategy later. But yes, there's definitely a small overhead for the runtime dispatch…
-
What if there were a SIMD type parameterised over type and length, with all SIMD operations defined on this type? `double_u32s` could just take this type and operate on it. This is close to how [SIMD in Mojo works](https://mojolang.org/nightly/docs/std/simd/SIMD/). It does mean that you need to write infra code to specialise to the best SIMD…
-
Hmm interesting! It doesn't handle any scalable SIMD architectures (aarch64 SVE or riscv's vector extension) which are far more challenging from an API point of view so I’d be interested to see how it handles those challenges (or if it can). It’s also a little unclear to me when the function dispatching happens?…