m03 · Burst · drill · 50 min
Make three stubborn loops vectorize
Why this is a drill and not a lab
The vectorization lab gave you a loop and walked you to the finding. That proves the mechanism and teaches you to read the viewer.
This is the version where nobody tells you what is wrong. Three loops, three distinct blockers, and the only evidence available is the assembly — which is exactly the situation ADR-007 argued this module had to prepare you for. The distinction the whole module rests on is between “did it vectorize?” and “why 2-wide and not 8?”, and only the second is testable without a walkthrough.
You are also writing the broken loops yourself. That is deliberate: constructing a specific failure is the fastest way to learn to recognise it.
The three failures
Build one loop for each category. The module named them; the mapping from category to code is yours to make.
Loop A — a provable-overlap problem. Two pointers the compiler cannot separate, so it must assume a write through one might disturb a read through the other.
Loop B — a dependency problem. Nothing to do with aliasing. The loop body
makes iteration i+1 depend on iteration i in a way that forbids computing
them simultaneously.
Loop C — a control-flow or unsupported-operation problem. The loop contains something the vectorizer cannot express in packed form, so it falls back entirely.
Each must be a plausible piece of code — something you could believe someone wrote on purpose. A contrived loop that could never appear in real work teaches you to recognise a shape you will never meet.
| Constraint | The shortcut it closes |
|---|---|
| Diagnosis evidenced by ASM | “It got faster so I fixed it” — which is true of a cache accident too |
| No speculative [NoAlias] | Sprinkling attributes until it vectorizes, having promised something unverified |
| Three different reasons | Diagnosing all three as aliasing because aliasing is the one you remember |
| Say when float results change | Silent numerical drift as a side effect of an optimisation |
| No changing what the loop computes | Winning by computing less |
The second constraint is the important one and it connects to the whole course.
[NoAlias] is a promise, structurally identical to [ReadOnly] in Module 4
and to a tracked baker read in Module 5: the compiler optimises on your
declaration and cannot detect a false one. Applying it to see if it helps is
lying to the compiler and hoping.
How to work it
Milestones, not steps.
- Write the three loops and confirm each is genuinely scalar in the ASM before doing anything else. If one accidentally vectorized, you built the wrong bug — good, that is a finding, and it means you should ask why.
- Predict, in writing, which blocker each has. Then check.
- Fix one at a time, re-reading the ASM after each. Never fix two and measure once.
- Record the vector width achieved for each. Compare against what the element type theoretically allows.
- Explain any gap. A
floatloop that vectorized 4-wide when the target supports 8 is a finding with a cause. - Revert each fix individually to confirm it was the cause. This is the control, and it is the step people skip.
When you are done
Answer without checking your notes:
- For each loop, what instruction in the before-ASM proved it was scalar?
- Which of the three did you misdiagnose on first prediction, and what misled you?
- What vector width did each achieve, and for any that fell short of the type’s maximum, what specifically prevented the wider form?
- For the loop you fixed with a promise-style attribute, what is the invariant that makes the promise true, and where in your code would it be violated if someone reused the job carelessly?
- One of your loops has a scalar remainder. At what element count does that remainder stop being negligible?
- Which fix would you be least comfortable applying to a colleague’s code without asking them a question first, and what is the question?
If one of your loops turns out to be un-vectorizable for a legitimate reason — the dependency is real and the algorithm genuinely requires it — that is a correct outcome. Recognising a loop that should not vectorize is as valuable as fixing one that should, and considerably rarer.