[aarch64] [missed-opt] Irrelevant subtraction pessimizes llvm.uadd/usub.with.overflow
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
[Godbolt](https://godbolt.org/z/948EWPoqM)
```cpp
#include
uint64_t f(uint64_t x, uint64_t y) {
uint64_t sum;
if (__builtin_uaddl_overflow(x, y, &sum)) {
return sum - 100;
} else {
return 0;
}
}
uint64_t g(uint64_t x, uint64_t y) {
uint64_t sum;
if (__builtin_uaddl_overflow(x, y, &sum)) {
return sum - 100;
} else {
return sum;
}
}
```
```asm
f(unsigned long, unsigned long):
adds x8, x0, x1
sub x8, x8, #100
cmn x0, x1
csel x0, x8, xzr, hs
ret
g(unsigned long, unsigned long):
adds x8, x0, x1
sub x8, x8, #100
adds x9, x0, x1
csel x0, x8, x9, hs
ret
```
In `f`, note `adds` computing the sum and having its output flag is ignored and recomputed with `cmn`. In `g`, note `adds` being run twice.
This problem affects `__builtin_uaddl_overflow` and `__builtin_usubl_overflow` equally.
Replacing `- 100` with `+ 100` miraculously fixes the lowering, but obviously changes semantics.
Contributor guide
Research direction
Start with the Godbolt reproducer and compare the AArch64 lowering of f and g for the overflow builtins. Trace the lowering of llvm.uadd.with.overflow and llvm.usub.with.overflow to determine why subtraction causes redundant flag computation or addition. Done means the generated AArch64 avoids the unnecessary recomputation while preserving the subtraction semantics for both functions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100