Skip to main content

Crate lightweight_simd

Crate lightweight_simd 

Source
Expand description

Lightweight generic fixed-array vector types.

This crate provides Simd, a fixed-lane vector type Simd<T, N> over [T; N], with lane-wise arithmetic (vector/vector and vector/scalar), multiply-add (fused where the target has hardware FMA; see below), float functions, comparisons producing masks, mask selection, horizontal reductions, and slice load/store — all implemented without intrinsics and without runtime instruction dispatch.

Performance relies on the compiler auto-vectorizing this portable code; build with -C target-cpu=native (or a similar target-cpu setting) to obtain SIMD-level efficiency. Correctness does not depend on it.

Element categories are expressed by trait bounds rather than by distinct types: arithmetic requires num_traits::Num, the float functions require num_traits::Float, multiply-add requires num_traits::MulAdd where the target has hardware FMA and core::ops::Mul with core::ops::Add otherwise, and bitwise operations require the element’s own core::ops implementations. bool is a valid element, and Simd<bool, N> doubles as the mask type. The lane count N is an arbitrary const generic.

A full one-file map of the API surface — written for users and AI coding agents — lives in the guide module (kept as src/guide.md in the repository).

Concrete aliases such as f64x8 are enforced-alignment types (Aligned64<f64, 8>): array-backed siblings of Simd that share one implementation — every operation is defined once for Simd and the five aligned types together. The alignment is the vector’s byte size rounded up to a power of two, capped at 64 bytes; conversions between plain and aligned vectors are From/.0/to_simd. Masks (Simd<bool, N> and the maskN aliases) carry no enforced alignment; per-lane selection is mask_select on the value (available on every vector type), or Simd::select on the mask for plain vectors.

§Multiply-add semantics

mul_add and fma_from follow the compilation target (see docs/adr/0005 in the repository for the measured trade-off):

  • targets with hardware FMA — x86 built with -C target-cpu of x86-64-v3 or higher (including native), and all aarch64: the element’s fused num_traits::MulAdd, a single rounding per lane, one FMA instruction per register, no extra flags.
  • targets without — generic x86-64, x86-64-v2, and architectures the predicate does not know: a separated multiply and add (two roundings per lane) that never degrades into the slow software-fused libm fma calls (~4.6x slower than separated there). Under -C llvm-args=-fp-contract=fast this form still fuses into a hardware FMA instruction on capable targets.
  • the non-default cargo feature use_libm_fma pins the fused form on every target, accepting the libm software fma where hardware is absent — use it when results must be bit-identical across build targets.

§Example

Same example as the README; kept as a doctest so it is verified by CI.

use lightweight_simd::{f64x8, Simd};

// typed aliases (enforced alignment) or the generic Simd<T, N>
let a = f64x8::from([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
let b = f64x8::splat(2.0);

let c = a.mul_add(b, f64x8::one()); // a*b + 1, fused on FMA targets
assert_eq!(c.reduce_sum(), 80.0);

let mask = a.simd_gt(f64x8::splat(4.0)); // comparisons -> masks
assert_eq!(a.mask_select(mask, b).to_array(), [2.0, 2.0, 2.0, 2.0, 5.0, 6.0, 7.0, 8.0]);

let mut buf = [0.0; 8];
a.store_slice(&mut buf); // slice load/store

// any element type and lane count
let u = Simd::from([10u32, 20, 30]);
assert_eq!((u * 3).to_array(), [30, 60, 90]);

Re-exports§

pub use aligned::Aligned4;
pub use aligned::Aligned8;
pub use aligned::Aligned16;
pub use aligned::Aligned32;
pub use aligned::Aligned64;

Modules§

aligned
Enforced-alignment vector types.
guide
Dummy doc-only module: renders src/guide.md (the one-file API overview, also linked from the README) into the rustdoc output.

Structs§

Simd
A fixed-length vector of N lanes of element type T.

Type Aliases§

f32x2
Alias of Simd<f32, 2> with enforced alignment (Aligned8).
f32x4
Alias of Simd<f32, 4> with enforced alignment (Aligned16).
f32x8
Alias of Simd<f32, 8> with enforced alignment (Aligned32).
f32x16
Alias of Simd<f32, 16> with enforced alignment (Aligned64).
f64x2
Alias of Simd<f64, 2> with enforced alignment (Aligned16).
f64x4
Alias of Simd<f64, 4> with enforced alignment (Aligned32).
f64x8
Alias of Simd<f64, 8> with enforced alignment (Aligned64).
f64x16
Alias of Simd<f64, 16> with enforced alignment (Aligned64).
i8x8
Alias of Simd<i8, 8> with enforced alignment (Aligned8).
i8x16
Alias of Simd<i8, 16> with enforced alignment (Aligned16).
i8x32
Alias of Simd<i8, 32> with enforced alignment (Aligned32).
i8x64
Alias of Simd<i8, 64> with enforced alignment (Aligned64).
i16x4
Alias of Simd<i16, 4> with enforced alignment (Aligned8).
i16x8
Alias of Simd<i16, 8> with enforced alignment (Aligned16).
i16x16
Alias of Simd<i16, 16> with enforced alignment (Aligned32).
i16x32
Alias of Simd<i16, 32> with enforced alignment (Aligned64).
i32x4
Alias of Simd<i32, 4> with enforced alignment (Aligned16).
i32x8
Alias of Simd<i32, 8> with enforced alignment (Aligned32).
i32x16
Alias of Simd<i32, 16> with enforced alignment (Aligned64).
i64x2
Alias of Simd<i64, 2> with enforced alignment (Aligned16).
i64x4
Alias of Simd<i64, 4> with enforced alignment (Aligned32).
i64x8
Alias of Simd<i64, 8> with enforced alignment (Aligned64).
i64x16
Alias of Simd<i64, 16> with enforced alignment (Aligned64).
mask4
Plain (unaligned) mask alias of Simd<bool, 4>.
mask8
Plain (unaligned) mask alias of Simd<bool, 8>.
mask16
Plain (unaligned) mask alias of Simd<bool, 16>.
mask32
Plain (unaligned) mask alias of Simd<bool, 32>.