[X86] LLVM -Oz generates 8-byte move for small constants
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
In certain cases, Clang -Oz generates a full 8 byte move for loading single byte constants. This does not seem to affect -Os or any other levels.
Test case (https://godbolt.org/z/G3EfdKxMs):
```
#include
#include
#include
size_t test(uint64_t p[6], size_t index) {
uint64_t p2[6];
memcpy(p2, p, sizeof(p2));
for (size_t i = 0; i < 6; i++) {
if ((p2[i] & (1ULL << index)) != 0) {
return i;
}
}
return 6;
}
```
This generates with Clang 21.1.0
```
test:
mov rcx, rsi
movups xmm0, xmmword ptr [rdi]
movups xmm1, xmmword ptr [rdi + 16]
movups xmm2, xmmword ptr [rdi + 32]
movaps xmmword ptr [rsp - 24], xmm2
movaps xmmword ptr [rsp - 40], xmm1
movaps xmmword ptr [rsp - 56], xmm0
movabs rdx, 1
shl rdx, cl
xor eax, eax
.LBB0_1:
cmp rax, 6
je .LBB0_4
test qword ptr [rsp + 8*rax - 56], rdx
jne .LBB0_4
inc rax
jmp .LBB0_1
.LBB0_4:
ret
```
where, `movabs rdx, 1` is used instead of `mov edx, 1` or `push 1/pop rdx`. A similar reproducer can be made in Zig as well. The issue does not appear if the `memcpy` is removed.
Additionally in this case, there are other missed optimisations as the `memcpy` can be eliminated (which happens with -O2), and `i` can be demoted to 32 bits.
Contributor guide
Assessment
This issue has not been assessed yet.