Padding (Preferred): Ensure all inputs/outputs are padded so the loop can always process full vectors.
for (size_t i = 0; i < count; i += N) LoopBody<false>(d, i, 0);
Idempotent Overlap: Process whole vectors and include previously processed elements in the last vector. This is preferred if count >= N and LoopBody is idempotent.
for (size_t i = 0; i < count; i += N) LoopBody<false>(d, HWY_MIN(i, count - N), 0);
Transform Functions: Use Transform* functions from hwy/contrib/algo/transform-inl.h. This handles the loop and remainder automatically via a lambda or functor.
Transform1(d, x, n, y, [](auto d, const auto v, const auto v1) HWY_ATTR {
return MulAdd(Set(d, alpha), v, v1);
});
Scalar Remainder Loop: Process whole vectors until the remainder is less than N, then use a standard scalar loop.
size_t i = 0;
for (; i + N <= count; i += N) LoopBody<false>(d, i, 0);
for (; i < count; ++i) LoopBody<false>(CappedTag<T, 1>(), i, 0);
Masked Remainder (Best for non-padded data): Process whole vectors, then use a single call to a modified LoopBody with masking for the remaining elements. This is safe only if #if !HWY_MEM_OPS_MIGHT_FAULT is true.
size_t i = 0;
for (; i + N <= count; i += N) {
LoopBody<false>(d, i, 0);
}
if (i < count) {
LoopBody<true>(d, i, count - i);
}
Inside LoopBody<true>, use BlendedStore(v, FirstN(d, num_remaining), d, pointer); or MaskedLoad(FirstN(d, num_remaining), d, pointer); to handle the partial vector.