C Mastery / SIMD: SSE, AVX, NEON, SVE, Intrinsics
Part 9 — Performance

SIMD: SSE, AVX, NEON, SVE, Intrinsics

This chapter covers SIMD (single instruction, multiple data): the instruction sets (SSE, AVX, NEON, SVE) and how to use them from C via intrinsics.

Why This Matters

SIMD processes multiple data elements per instruction, giving 2x–16x speedups on data-parallel work. It is the backbone of graphics, audio, numerical, and machine-learning kernels.

Prerequisites

Core Concept

SIMD instructions operate on vector registers holding multiple lanes of the same type (e.g., 4 floats in an SSE register, 8 in AVX). A single instruction adds/multiplies all lanes in parallel.

ISAWidthCommon platform
SSE128-bitx86/x86-64
AVX256-bitx86-64
AVX-512512-bitx86-64 (server)
NEON128-bitARM/ARM64
SVEscalableARM64

Using SIMD from C

Auto-vectorization

The compiler may vectorize simple, dependency-free loops (c.opt.3). Add restrict and aligned, contiguous access to help it.

Intrinsics

Intrinsics map directly to SIMD instructions:

#include <immintrin.h>   /* x86 SIMD */

void add4(float *a, float *b, float *c)
{
    __m128 va = _mm_loadu_ps(a);
    __m128 vb = _mm_loadu_ps(b);
    __m128 vc = _mm_add_ps(va, vb);
    _mm_storeu_ps(c, vc);
}

ARM NEON uses <arm_neon.h> with float32x4_t and vaddq_f32.

Examples

SSE sum of four floats

#include <immintrin.h>

float sum4(const float *a)
{
    __m128 v = _mm_loadu_ps(a);
    v = _mm_hadd_ps(v, v);
    v = _mm_hadd_ps(v, v);
    return _mm_cvtss_f32(v);
}

Alignment

Aligned loads (_mm_load_ps) require 16-byte alignment; unaligned loads (_mm_loadu_ps) work anywhere but may be slower on older hardware.

How It Works

The CPU has wide vector registers (XMM/YMM/ZMM on x86, V/Q on ARM). A SIMD instruction performs the same operation on each lane simultaneously. Intrinsics compile to these instructions with the right register allocation.

Variations

Masked and gather/scatter (AVX-512/SVE)

Advanced SIMD supports predication (masked lanes) and gather/scatter (loading non-contiguous elements), useful for sparse/irregular data.

Portable SIMD wrappers

Libraries or _Generic can abstract over SSE/NEON, but raw intrinsics are architecture-specific.

Common Mistakes

_mm_load_ps).

Undefined Behavior

Portability

or use a portable wrapper.

Under the Hood

The compiler lowers intrinsics to the matching instruction. Vectorization requires data-parallel, dependency-free loops and often alignment/restrict.

Practical Usage

AVX/AVX-512.

Exercises

1. Write an SSE function to add two float arrays and verify results. 2. Vectorize a dot product with intrinsics. 3. Compare auto-vectorized vs. intrinsics code for the same loop.

Deep Challenge

Implement a vectorized matrix-vector multiply (float) using AVX intrinsics, handling arbitrary sizes with a scalar remainder. Explain your data layout and alignment choices.

References

Verification

HARDWARE/COMPILER-SPECIFIC

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.perf.simd06