Rust
Simd<T, N>
Use the Simd<T, N> vector type.
Simd<T, N>
The basic type in std::simd is Simd<T, N>: element type T and lane count N (a const generic). f32x4 is in fact an alias for Simd<f32, 4>. Operators (+, *, -) are defined lane-wise:
use std::simd::Simd;
let a: Simd<f32, 8> = Simd::splat(1.0); // all lanes 1.0
let b = Simd::<f32, 8>::splat(2.0);
let c = a + b; // 8 lanes of 3.0
The right lane count depends on the processor: SSE is 128 bits (4×f32), AVX2 256 bits (8×f32), AVX-512 512 bits (16×f32).
Your own lane type
We can imitate the same interface in stable Rust with const generics and the Add trait:
#[derive(Clone, Copy)]
struct Seritler<const N: usize>([f32; N]);
impl<const N: usize> Seritler<N> {
fn yay(x: f32) -> Self { Seritler([x; N]) }
}
impl<const N: usize> std::ops::Add for Seritler<N> {
type Output = Self;
fn add(self, o: Self) -> Self {
Seritler(std::array::from_fn(|i| self.0[i] + o.0[i]))
}
}
Having the lane count in the type prevents accidentally adding vectors of different widths at compile time.
Exercise Eight lanes
Write the Seritler<const N: usize> type above with yay and Add. Print the lane count of Seritler::<8>::yay(1.0) + Seritler::<8>::yay(2.0) and the sum of its lanes, separated by a space.
Show example solution
#[derive(Clone, Copy)]
struct Seritler<const N: usize>([f32; N]);
impl<const N: usize> Seritler<N> {
fn yay(x: f32) -> Self {
Seritler([x; N])
}
}
impl<const N: usize> std::ops::Add for Seritler<N> {
type Output = Self;
fn add(self, o: Self) -> Self {
Seritler(std::array::from_fn(|i| self.0[i] + o.0[i]))
}
}
fn main() {
let c = Seritler::<8>::yay(1.0) + Seritler::<8>::yay(2.0);
let toplam: f32 = c.0.iter().sum();
println!("{} {}", c.0.len(), toplam);
}
Test yourself
-
What does <code>Simd::splat(1.0)</code> produce?
- A single-element vector
- An empty vector
- The bits of 1.0
- A vector with all lanes 1.0
Show answer
A vector with all lanes 1.0 — splat "spreads" a value over all lanes; it's used in operations like multiplying by a constant.
-
Addition operator
impl<const N: usize> std::ops::____ for Seritler<N> {
type Output = Self;
fn add(self, o: Self) -> Self { .. }
}
Show answer
impl<const N: usize> std::ops::Add for Seritler<N> {
type Output = Self;
fn add(self, o: Self) -> Self { .. }
}
-
Width and lane count (f32)
- SSE (128 bit)
- 4
- AVX2 (256 bit)
- 8
- AVX-512 (512 bit)
- 16
- NEON (128 bit)
- 4 lanes (ARM)
Next lesson: Mask