NEON and Scalar Tails¶
Vectorizing a loop adds a new boundary: the last elements may not fill a vector. Start with an exact integer operation and test every tail length before discussing speed.
Course examples on GitHub
Before you start¶
Complete the checked array project. You can state input/output range and aliasing contracts.
Outcome: implement four-lane addition with a scalar tail and compare every output with C. Use a fresh Pi practice directory. The native Raspberry Pi 4 used for course checks supports these Advanced SIMD instructions; check your actual target before running.
Understand the lanes¶
The SIMD/FP register bank has v0–v31, separate from x0–x30. v0.4s interprets 128 bits as four 32-bit lanes. LD1 fills those lanes; ADD performs separate modulo-2^32 additions; ST1 writes the vector. Carries do not flow between lanes.
This routine computes output[i] = input[i] + 1 modulo 2^32. The caller supplies n readable/writable elements, with non-overlapping input and output. n=0 permits null pointers because neither range is accessed.
Implement vector and tail paths¶
No vector access occurs unless at least four elements remain. The 16-byte pointer advance is four elements, not 16 elements. This leaf uses only caller-clobbered vector registers and makes no calls.
Guard words detect writes outside the intended output, not all possible input overreads. The instruction/control-flow reasoning is still needed. The output is ordinary memory, not a device buffer.
Common traps¶
Do not round n up and read past its range. Do not interpret a .4s operation as four 64-bit elements. Do not generalize exact integer equivalence to floating-point reductions: reassociation, rounding and NaNs need a separate policy.
If the target rejects an instruction at assembly time, check the configured architecture. If execution raises illegal instruction, check hardware and execution support instead of adding speculative compiler flags.
Correct does not mean faster¶
A scalar compiler loop may already be vectorized. This lesson performs no timing comparison and makes no speed claim. A useful comparison must use the same operation, valid inputs, optimization options and tail policy. The final lesson separates correctness tests from measurement.
Check your understanding¶
For n=7, how many vector and scalar iterations run? What protects the eighth input element from being read?
Compare your reasoning
One vector iteration consumes four, then three scalar iterations consume the remaining elements. Both paths test remaining count before their access.
Continue the course¶
Previous: A Checked Array Project · Course roadmap · Next: Extended Inline Assembly