NEON (bin/02_neon.s, vadd): fixed 128-bit q registers, a scalar tail
loop for the remainder:
...ldp q0, q1 ... fadd v0.4s ... stp ... (vector body, 8 floats per step)
.LBB0_4: fadd s0, s0, s1 ; subs x8, x8, #1 ; b.ne .LBB0_4 (scalar remainder: up to 7 elements)
SVE (bin/02_sve.s, vadd, default epilogue): the main loop uses z
registers with an unpredicated ptrue body and an epilogue.
SVE with tail folding (bin/02_sve_tail, -mllvm -prefer-predicate-over-epilogue=predicate-dont-vectorize):
whilelo p0.s, xzr, x3 // p0[lane] = (lane < n)
.LBB0_4:
ld1w { z0.s }, p0/z, [x1, x10, lsl #2] // load active lanes, zero the rest
ld1w { z1.s }, p0/z, [x2, x10, lsl #2]
fadd z0.s, z0.s, z1.s
st1w { z0.s }, p0, [x0, x10, lsl #2] // store active lanes only
whilelo p0.s, x10, x9 // recompute the predicate for the next block
No remainder loop at all: the final iteration simply has a partially
true predicate. And no vector length appears anywhere in the code.