🚀Go deeper — read the bookHigh-Performance Computing in C++— runnable code & full walkthrough →

hpc · advanced

SIMD & Auto-Vectorization

SIMD (Single Instruction, Multiple Data) executes one operation across a vector of elements — 8 floats per AVX instruction, 16 with AVX-512. Compilers auto-vectorize clean, countable, dependency-free loops at -O3 -march=native, emitting a packed body plus a scalar remainder. The biggest lever is data layout: Struct-of-Arrays gives the unit-stride access the vectorizer needs, while interleaved Array-of-Structs forces strided gathers that block it. Pointer aliasing and loop-carried dependencies silently defeat it too — annotate with __restrict, prefer reductions, and confirm with -fopt-info-vec / -fopt-info-vec-missed.

🔑 Key line

SIMD does one operation on many elements per instruction; -O3 -march=native auto-vectorizes simple unit-stride loops, but AoS layouts, loop-carried dependencies and pointer aliasing block it — use SoA, __restrict and reductions, and verify with -fopt-info-vec.

The code

// Scalar: the CPU adds ONE pair of floats per instruction
for (int i = 0; i < n; ++i)
c[i] = a[i] + b[i];
// With -O3 the compiler AUTO-VECTORIZES this into SIMD:
// one AVX instruction adds 8 floats at once (256 bits / 32).
struct P {
float x, y, z;
}; // AoS: x,y,z interleaved -> strided
struct S {
float *x, *y, *z;
}; // SoA: each axis contiguous -> vectorizes
void add(float* __restrict c, // __restrict: 'these don't alias',
const float* a, const float* b); // so it's safe to vectorize

What this lesson walks through

  1. 01Scalar baseline — one add per instruction
  2. 02-O3 auto-vectorizes — 8 lanes in ONE instruction
  3. 03Data layout decides it — SoA beats AoS
  4. 04Why it silently fails — aliasing

Written naively, the CPU processes one pair of floats per instruction: c[0]=a[0]+b[0], then c[1]=a[1]+b[1]… One lane at a time.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of SIMD & Auto-Vectorization and 100+ animated C++ interview lessons.

← Previous
Branch Prediction & Branchless Code
Next →
OpenMP: shared-memory parallelism