fearless_simd 0.3.0

Safer and easier SIMD
Documentation

Fearless SIMD

Safer and easier SIMD

Latest published version. Documentation build status. Apache 2.0 or MIT license.
Linebender Zulip, #simd channel. GitHub Actions CI status. Dependency staleness status.

[!CAUTION] Fearless SIMD is in extremely early experimental development. As such, there are no stability guarantees, APIs are incomplete, and architectures have missing implementations. Fearless SIMD is being developed in conjunction with the Vello Sparse Strips renderer.

A helper library to make SIMD more friendly.

Fearless SIMD exposes safe SIMD with ergonomic multi-versioning in Rust.

Fearless SIMD uses "marker values" which serve as proofs of which target features are available on the current CPU. These each implement the Simd trait, which exposes a core set of SIMD operations which are implemented as efficiently as possible on each target platform.

Additionally, there are types for packed vectors of a specific width and element type (such as f32x4). Fearless SIMD does not currently support vectors of less than 128 bits. These vector types implement some standard arithmetic traits (i.e. they can be added together using +, multiplied by a scalar using *, among others), which are implemented as efficiently as possible using SIMD instructions. These can be created in a SIMD context using the SimdFrom trait, or the from_slice associated function.

To call a function with the best available target features and get the associated Simd implementation, use the [dispatch!()] macro:

use fearless_simd::{Level, Simd, dispatch};

#[inline(always)]
fn sigmoid<S: Simd>(simd: S, x: &[f32], out: &mut [f32]) { /* ... */ }

// The stored level, which you should only construct once in your application.
let level = Level::new();

dispatch!(level, simd => sigmoid(simd, &[/*...*/], &mut [/*...*/]));

A few things to note:

  1. sigmoid is generic over any Simd type.
  2. The dispatch macro is used to invoke the given function with the target features associated with the supplied Level.
  3. The function or closure passed to [dispatch!()] should be #[inline(always)]. The performance of the SIMD implementation may be poor if that isn't the case. See the section on inlining for details

The first parameter to [dispatch!()] is the Level. If you are writing an application, you should create this once (using Level::new), and pass it to any function which wants to use SIMD. This type stores which instruction sets are available for the current process, which is used in the macro to dispatch to the most optimal variant of the supplied function for this process.

Inlining

Fearless SIMD relies heavily on Rust's inlining support to create functions which have the given target features enabled. As such, most functions which you write when using Fearless SIMD should have the #[inline(always)] attribute.

Webassembly

WASM SIMD doesn't have feature detection, and so you need to compile two versions of your bundle for WASM, one with SIMD and one without, then select the appropriate one for your user's browser. TODO: Expand on this.

Credits

This crate was inspired by pulp, std::simd, among others in the Rust ecosystem, though makes many decisions differently. It benefited from conversations with Luca Versari, though he is not responsible for any of the mistakes or bad decisions.

Feature Flags

The following crate feature flags are available:

  • std (enabled by default): Get floating point functions from the standard library (likely using your target's libc). Also allows using Level::new on all platforms, to detect which target features are enabled.
  • libm: Use floating point implementations from libm.
  • safe_wrappers: Include safe wrappers for (some) target feature specific intrinsics, beyond the basic SIMD operations abstracted on all platforms.

At least one of std and libm is required; std overrides libm.

Minimum supported Rust Version (MSRV)

This version of Fearless SIMD has been verified to compile with Rust 1.86 and later.

Future versions of Fearless SIMD might increase the Rust version requirement. It will not be treated as a breaking change and as such can even happen with small patch releases.

Community

Linebender Zulip, #simd channel.

Discussion of Fearless SIMD development happens in the Linebender Zulip, specifically in #simd. All public content can be read without logging in.

Contributions are welcome by pull request. The Rust code of conduct applies.

License

Licensed under either of

at your option.