Godbolt
#include <stdint.h>
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;
}
}
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.