CodeBlanks Logo Icon CodeBlanks

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.

Practice 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.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
#[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);
}

Expected output

8 24

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 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 Correct answer

Explanation: splat "spreads" a value over all lanes; it's used in operations like multiplying by a constant.

2 Addition operator

Question
impl<const N: usize> std::ops::____ for Seritler<N> {
    type Output = Self;
    fn add(self, o: Self) -> Self { .. }
}
Answer
impl<const N: usize> std::ops::Add for Seritler<N> {
    type Output = Self;
    fn add(self, o: Self) -> Self { .. }
}

Explanation: std::ops::Add defines the + operator.

3 Width and lane count (f32)

Term Meaning
SSE (128 bit) 4
AVX2 (256 bit) 8
AVX-512 (512 bit) 16
NEON (128 bit) 4 lanes (ARM)

All lessons in Expert