auto-vectorization
You wrote an ordinary loop — for each i, c[i] = a[i] + b[i] — adding two arrays one element at a time, the way you would explain it to a friend. Auto-vectorization is the compiler quietly noticing that this loop does the same independent operation on each element, and rewriting it under the hood to use SIMD instructions: instead of one add per iteration, it emits one wide add per eight elements. You wrote scalar code; the compiler handed the CPU vector code. It is a translator that turns plain loops into the wide-lane stamping of SIMD without you touching the SIMD instructions yourself.
How does the compiler decide it is safe? It must prove the loop iterations are truly independent — that processing element i in a batch of eight cannot change the answer for element j in the same batch. To do that it analyzes the loop for data dependences (does iteration i+1 read what iteration i wrote?), checks that the array accesses are regular (ideally contiguous unit stride, so a single wide load fills a vector register), and handles the leftover tail when the array length is not a clean multiple of the vector width. If it can prove safety and profitability, it strip-mines the loop into wide chunks plus a scalar tail.
The honest centre of this entry is why auto-vectorization so often fails — because it is the most common disappointment beginners meet. The compiler must be conservative: if two pointers might alias (point into the same array, so a write could clobber a later read), it must assume the worst and refuse. Loop-carried dependences (sum += a[i] is a reduction the compiler must recognize specially; s[i] = s[i-1] + a[i] is a true chain it usually cannot vectorize), function calls inside the loop, complex branches, and irregular gather/scatter access patterns all block it. The practical upshot: clean, branch-light loops over contiguous arrays with no aliasing vectorize beautifully; tangled code does not, and the compiler silently leaves it scalar. Tools like restrict hints, simpler loop bodies, and reading the compiler's vectorization report are how real programmers coax it along.
for (i=0;i<n;i++) c[i]=a[i]+b[i]; vectorizes cleanly — no dependence, contiguous. But for (i=1;i<n;i++) a[i]=a[i-1]+b[i]; does not: each iteration needs the previous iteration's freshly-written a[i-1], a true loop-carried dependence, so the compiler keeps it scalar.
Independent, contiguous loops vectorize; loop-carried dependences and possible pointer aliasing force the compiler back to scalar code.
Auto-vectorization is not magic that always fires. Pointer aliasing, loop-carried dependences, branches, and function calls routinely defeat it, and the compiler fails silently — your loop still runs, just scalar. Check the vectorization report; do not assume it happened.