← Concepts

阅读中文版本

Auto-Vectorization

Auto-vectorization lets compilers transform loops into SIMD instructions operating on multiple elements at once — when dependencies, alignment, and aliasing checks allow it to prove safety.

performance

Definition

Vectorization rewrites scalar loops into SIMD form where one instruction processes 4 to 16 lanes. Compilers auto-vectorize only when they can prove absence of dependencies, handle alignment, and resolve aliasing; small changes in code shape — bounds, strides, function calls — flip vectorization on and off silently.

Context and scope

Relevant in numeric kernels, parsing, image processing, and JSON hot paths. Verified via compiler reports (-Rpass, opt-viewer) and SIMD counters in profilers.

Common misconceptions

  • Vectorization is automatic, so it just happens — proving safety is conservative; a function call or ambiguous pointer silently kills the loop transform
  • SIMD gives linear speedup by lane count — memory-bound loops gain little beyond bandwidth saturation; compute-bound kernels scale closer to lanes
  • Hand-written intrinsics always beat the compiler — modern auto-vectorizers frequently match or beat naive intrinsics; measure before hand-unrolling

Anti-patterns

  • Hiding the loop trip count behind a function call boundary and losing vectorization across it
  • Interleaving stores and loads through pointers the compiler cannot prove disjoint
  • Reading generated assembly once and assuming the same code shape still vectorizes after refactors

Related concepts

Authoritative source

https://llvm.org/docs/Vectorizers.html

What it is

A scalar loop adds one element per iteration; a vectorized one adds four to sixteen with the same instruction. The compiler performs this transform autonomously when the code admits a proof.

How it works

The vectorizer checks loop-carried dependencies, aliasing between arrays, alignment, and trip counts, then emits wide loads, stores, and arithmetic with tail handling. Inlining matters: a multiply in another function blocks the transform until inlined. Compiler reports name the loops that failed and the exact reason.

When to care

Numeric kernels, checksums, base64 and UTF conversion, and any per-element loop over large buffers. Structure code for the prover: pure loops, local bounds, restrict-qualified pointers, and no early exits.

Pitfalls

Vectorization is brittle: innocent refactors disable it with no warning. Tail handling adds overhead that hurts small arrays. Wide instructions raise register pressure and can spill. Verify in CI with compiler vectorization reports so silent regressions surface as test failures.