unbounded-shiftA right shift whose input cannot be bounded
Reported by --explain after a verdict.
mettle explain unbounded-shift
Integer lanes are 32 bits wide. + - * & | ^ << are congruent mod 2^32, so the low 32 bits of a result depend only on the low 32 bits of its inputs and a lane reproduces them whatever width the scalar code used. >> is the exception: it reads bits back DOWN, so a lane that wrapped where the scalar did not would shift different bits in.
The kernel takes a right shift only where the shifted value is provably inside int32, and a multiply is not provable on its own. This is refused:
dst[i] = (r[i]*77 + g[i]*150 + b[i]*29) >> 8;
Masking bounds it, at the cost of one op per lane, and this vectorizes:
dst[i] = ((r[i]*77 + g[i]*150 + b[i]*29) & 65535) >> 8;
Keep the destination int32. Narrowing the store to a uint8* puts the loop outside the kernels for a separate reason, so masking alone will not move it.
Related
- call-in-bodyThe loop body calls a function
- extern-call-in-bodyThe loop body calls an external function
- indirect-callThe loop body calls through a function pointer
- alloc-in-bodyThe loop body allocates
- inline-asmThe loop body contains inline assembly
- control-flowThe loop body branches
- early-exitThe loop can leave before its trip count
- int16-elements16-bit integer elements have no kernel