llvm / llvm/llvm-project

AArch64 missed optimization: 32-bit narrowing prevents shifted-register EOR selection

Open
#199,813 2 comments 0 reactions 0 assignees View on GitHub
backend:AArch64 missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

It seems that premature 32-bit narrowing can prevent right shift and XOR operations from being combined into a single A64 instruction.

[Compile](https://godbolt.org/z/xhWP8s6ev) the following code with `clang -target arm64-apple-macosx15.0 -O3 -S tmp.cpp` (version `17.0.0`):

```C++
#include

using Bits = std::uint64_t;

Bits left_full(Bits bits) {
return ((bits << 30) ^ bits) & 0x100000000;
}

Bits right_full(Bits bits) {
return ((bits >> 30) ^ bits) & 0x100000000;
}

Bits left_opt(Bits bits) {
return ((bits << 30) ^ bits) & 0x10000000;
}

Bits right_opt(Bits bits) {
return ((bits >> 30) ^ bits) & 0x10000000;
}
```

The result is:

```asm
left_full(unsigned long):
eor x8, x0, x0, lsl #30
and x0, x8, #0x100000000
ret

right_full(unsigned long):
eor x8, x0, x0, lsr #30
and x0, x8, #0x100000000
ret

left_opt(unsigned long):
and x0, x0, #0x10000000
ret

right_opt(unsigned long):
lsr x8, x0, #30
eor w8, w8, w0
and x0, x8, #0x10000000
ret
```

The first two are OK; both left shift and right shift are folded into the XOR operation.

In the left-shift case, with the mask on bit 28 instead of bit 32, the compiler recognizes that the left-shifted value can’t contribute to the result, and rightly omits it.

In the right-shift case, both operands remain relevant. The compiler seems to realize that only the lower 32 bits of the XOR are needed, so it narrows the instruction to 32-bit. But that prevents it from folding the right-shift into it, because

```asm
eor w8, w0, w0, lsr #30
and x0, x8, #0x10000000
```

wouldn’t be valid: It would drop the high bits being shifted in; the narrowing can only happen after the shift. So it would have been more efficient to keep the XOR in 64-bit form:

```asm
eor x8, x0, x0, lsr #30
and x0, x8, #0x10000000
```

IR example: https://godbolt.org/z/hnzxjqszz

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.