https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120231
Bug ID: 120231
Summary: GCC fails to notice that (double)u64 is non-negative
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: acoplan at gcc dot gnu.org
Target Milestone: ---
For the following function:
_Bool f(unsigned long u64)
{
return (double)u64 >= 0.0;
}
at -O3 on AArch64, GCC generates:
f:
ucvtf d31, x0
fcmpe d31, #0.0
cset w0, ge
ret
whereas LLVM gives:
f:
mov w0, #1
ret
i.e. it folds the comparison to constant true. GCC should do the same. This
would be useful in the context of code like the following:
unsigned long sqrtint(unsigned long a) {
return __builtin_sqrt(a);
}
for which GCC currently generates:
sqrtint:
ucvtf d0, x0
fcmp d0, #0.0
bpl .L5
stp x29, x30, [sp, -16]!
mov x29, sp
bl sqrt
ldp x29, x30, [sp], 16
fcvtzu x0, d0
ret
.L5:
fsqrt d0, d0
fcvtzu x0, d0
ret
i.e. it tests if the input is non-negative so that errno can be set correctly,
but the test is redundant since the input is necessarily non-negative. Indeed
LLVM generates:
sqrtint:
ucvtf d0, x0
fsqrt d0, d0
fcvtzu x0, d0
ret
for this case.