auto-vectorization
A normal instruction does one thing at a time: add these two numbers, store this one value. But modern processors also have wide SIMD instructions (Single Instruction, Multiple Data) that do the same operation to a whole batch of values at once — add eight pairs of floats in one go. Auto-vectorization is the compiler automatically rewriting a scalar loop, one that works on one element per iteration, into one that uses these wide instructions to process several elements per iteration.
Concretely, take a loop that adds two arrays element by element: for (i = 0; i < n; i++) c[i] = a[i] + b[i];. If the processor's SIMD unit handles 8 floats at a time, the compiler can transform this into a loop that loads 8 values of a, 8 of b, adds all 8 pairs with one SIMD instruction, and stores 8 results — then loops n/8 times, with a scalar remainder loop for the tail. The win can be several times faster for the right code. But vectorizing is only legal when the iterations are independent: the result for element i must not depend on the result for element i-1, and the memory regions must not secretly overlap.
It matters because it is how you get SIMD speed without writing intrinsics by hand, but it is also famously fragile, and a careful engineer should understand WHY it fails. Two killers dominate. Dependencies: if c[i] = c[i-1] + a[i], each iteration needs the previous one's result, so the batch cannot run in parallel. Aliasing: in C, if a, b, and c are plain pointers, the compiler cannot assume they point to non-overlapping memory — c might alias a — so it must assume the worst and refuse to vectorize, unless you promise otherwise with the restrict qualifier. Other blockers include function calls in the loop, complex control flow, and non-contiguous memory access. The honest summary: auto-vectorization is best-effort, not guaranteed; check the compiler's vectorization report rather than assuming it happened.
void add(float *a, float *b, float *c, int n) { for (int i = 0; i < n; i++) c[i] = a[i] + b[i]; } // may NOT vectorize: c could alias a or b. Fix the promise with restrict: void add(float * restrict a, float * restrict b, float * restrict c, int n) { ... }
Without restrict, the compiler must assume the arrays may overlap and may refuse SIMD; restrict promises they do not.
Auto-vectorization is best-effort, not guaranteed: loop-carried dependencies make it impossible, and pointer aliasing makes it unprovable, so the compiler silently keeps the scalar loop — read the vectorization report (e.g. -Rpass=loop-vectorize) instead of assuming it fired.