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.

Reply via email to