https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67736

            Bug ID: 67736
           Summary: Wrong optimization with -fexpensive-optimizations on
                    mips64el
           Product: gcc
           Version: 5.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: aurelien at aurel32 dot net
  Target Milestone: ---
              Host: mips64el-unknown-linux-gnu
            Target: mips64el-unknown-linux-gnu
             Build: mips64el-unknown-linux-gnu

The following code is wrongly compiled on a mips64el target when using
-fexpensive-optimizations:

#include <inttypes.h>
#include <stdio.h>

int compare(uint64_t state, uint32_t *last, uint8_t buf)
{
    if (*last == ((state | buf) & 0xFFFFFFFF)) {
        printf("B %"PRIx64" %"PRIx32"\n", state, *last);
        return 0;
    }
    return 1;
}

It produces the following code:

00000000000009a0 <compare>:
 9a0:   30c200ff        andi    v0,a2,0xff
 9a4:   8ca60000        lw      a2,0(a1)
 9a8:   00441025        or      v0,v0,a0
 9ac:   10460004        beq     v0,a2,9c0 <compare+0x20>
 9b0:   24020001        li      v0,1
 9b4:   03e00008        jr      ra
 9b8:   00000000        nop
 9bc:   00000000        nop
...

Note how the comparison is done incorrectly, dropping the & 0xFFFFFFFF and
sign-extending the value when loading *last.

Using -fno-expensive-optimizations produces the following valid code:
00000000000009a0 <compare>:
 9a0:   30c200ff        andi    v0,a2,0xff
 9a4:   8ca60000        lw      a2,0(a1)
 9a8:   00441025        or      v0,v0,a0
 9ac:   7cc3f803        dext    v1,a2,0x0,0x20
 9b0:   7c42f803        dext    v0,v0,0x0,0x20
 9b4:   10620004        beq     v1,v0,9c8 <compare+0x28>
 9b8:   24020001        li      v0,1
 9bc:   03e00008        jr      ra
 9c0:   00000000        nop
 9c4:   00000000        nop
 9c8:   67bdfff0        daddiu  sp

Here both values are zero extended to 32-bit before the comparison.

Alternatively, when removing the line with the printf, GCC also produces
correct code, which is more optimized:

0000000000000960 <compare>:
 960:   30c600ff        andi    a2,a2,0xff
 964:   00c42025        or      a0,a2,a0
 968:   9ca20000        lwu     v0,0(a1)
 96c:   7c86f803        dext    a2,a0,0x0,0x20
 970:   00c21026        xor     v0,a2,v0
 974:   03e00008        jr      ra
 978:   0002102b        sltu    v0,zero,v0
 97c:   00000000        nop

Note that at least gcc 4.8.5, 4.9.3 and 5.2.1 are affected.

Reply via email to