4 ms·
You can get well-defined behavior at 0 cost (for x86-64 and ARM64, which covers most everything not very obscure/embedded) on both GCC and LLVM by explicitly ad
by orlp 3y ago
You can get well-defined behavior at 0 cost (for x86-64 and ARM64, which covers most everything not very obscure/embedded) on both GCC and LLVM by explicitly adding a modulo operator:
uint32_t foo(uint32_t x, int s) {
return x << (s % 32);
}
foo(unsigned int, int):
shlx eax, edi, esi
ret
- Someone 3y agoIs that well defined for foo(0x12345678, -1) ? I think that, in modern C -1 % 32 == -1 (% computes the remainder, not the modulo) it would try to compute x << -1 and AFAIK that’s undefined behavior. Even if it is well-defined, it possibly is not what you want. If you were to call foo(0x12345678, 32) I think the most logical result would be zero, but the code you give returns 0x12345678.
- dzaima 3y agoYeah, to be well-defined it should be 's & 31', or use an unsigned type for s; compiler explorer comparing those under ubsan shows the original having the possibility of UB: https://godbolt.org/z/eT9q871bY https://godbolt.org/z/eT9q871bY
- orlp 3y agoYou're right I was sloppy in defining s to be an int, it should've been an unsigned type. My point was more about getting consistent behavior across platforms at (most often) zero cost, not to support arbitrary negative shifts.