Optimization Reports and SIMD Intrinsics (Optional)
Advanced Concurrency, SIMD, and Performance

9.9 Optimization Reports and SIMD Intrinsics (Optional)

Auto-vectorization is invisible until you look at compiler output or generated assembly. This optional lesson connects Lesson 9.8 to the measurement workflow from Lesson 0.4.

Reading GCC vectorization reports

GCC can print vectorization decisions when you pass optimization and info flags:

# c++ -std=c++23 -O3 -march=native -fopt-info-vec-optimized loop.cpp
Ask GCC whether a loop was vectorized.

Look for lines such as vectorized or not vectorized with a reason (data dependency, unknown trip count, function call inside the loop). Clang offers similar diagnostics with -Rpass=loop-vectorize and related flags.

Compiler Explorer workflow

Paste the same loop into Compiler Explorer with -O3 -std=c++23 and inspect the assembly pane. A vectorized loop on x86_64 often shows packed instructions (addps, vmovups, vpaddd) instead of one scalar add per element. If you only see scalar add in a tight numeric loop, the compiler kept the loop scalar, check the report for the reason before rewriting by hand.

A minimal intrinsic example (SSE2)

Intrinsics name vector registers and instructions explicitly. The example below uses SSE2 (__m128), available on essentially all x86_64 targets. AVX2 (__m256) follows the same pattern but typically requires -mavx2 at compile time.

#include <immintrin.h>
#include <cstring>

void addFour(const float* a, const float* b, float* out) {
    __m128 va{_mm_loadu_ps(a)};
    __m128 vb{_mm_loadu_ps(b)};
    __m128 sum{_mm_add_ps(va, vb)};
    _mm_storeu_ps(out, sum);
}

int main() {
    alignas(16) float a[4]{1, 2, 3, 4};
    alignas(16) float b[4]{10, 20, 30, 40};
    alignas(16) float out[4]{};
    addFour(a, b, out);
    return out[0] == 11.0f && out[3] == 44.0f ? 0 : 1;
}
Add four floats with SSE2 intrinsics.
Note

Prefer intrinsics only after profiling shows a hot loop and the compiler will not vectorize it safely. Maintain a scalar fallback path or gate AVX code behind CPU feature detection on shipped binaries.

When not to hand-write SIMD

If the compiler already vectorizes the loop, intrinsics usually add portability cost without benefit. If the loop has gathers, branches, or irregular memory access, SIMD may not apply at all. Measure before and after, and keep the scalar version in tests for correctness.

Chapter 9 Knowledge CheckQuestion 1 of 6

Which statement about std::atomic and mutexes is correct?

Finished reading this lesson?