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

            Bug ID: 127550
           Summary: [16/17 Regression][loongarch64] wrong code at -O2: AND
                    with a mask wider than 32 bits on a sign-extended int
                    is treated as AND with 0xffffffff
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: shimizu2486 at gmail dot com
  Target Milestone: ---

Live Reproducer: https://godbolt.org/z/v66ojxP3j

Masking a sign-extended int with a constant wider than 32 bits gives the wrong
value from -O2 up, and the comparison that uses it is folded to a constant so
the branch disappears.

$ cat t1.c
#include <stdio.h>

static volatile int V = 1;
int v, d;

int main(void) {
  int *p = V ? &v : &d;
  *p = -1;
  if ((unsigned)v >= ((unsigned long long)v & 0x1ffffffffULL))
    printf("ge\n");
  else
    printf("lt\n");
}

V is nonzero, so p points at v and the store puts -1 there. (unsigned)v is then
2^32-1 and v & 0x1ffffffff is 2^33-1, so the >= is false and the program must
print lt.

$ loongarch64-unknown-linux-gnu-gcc -O1 -static t1.c -o t1 && qemu-loongarch64
./t1
lt                                  (correct)
$ loongarch64-unknown-linux-gnu-gcc -O2 -static t1.c -o t1 && qemu-loongarch64
./t1
ge                                  (wrong)

-O1 computes both operands and branches:

        bstrpick.d      $r13,$r12,31,0      # (unsigned)v
        bstrpick.d      $r12,$r12,32,0      # v & 0x1ffffffff
        bltu            $r13,$r12,.L3

-O2 emits neither the compare nor the branch: .LC0 ("ge") is loaded
unconditionally and the "lt" block is gone.

Any mask wider than 32 bits shows it, and the width of the extra bits does not
matter:

So the AND behaves as if the mask were 0xffffffff, i.e. the bits of the sign
extension above bit 31 are dropped.

  12.2.0 .. 15.2.0      correct
  16.1.0                wrong
  trunk (02535f61)      wrong

-O0 and -O1 are correct; -O2, -O3 and -Os are wrong. riscv64, x86-64 and
aarch64 trunk are all correct on this file, so it looks loongarch64-only.
  • [Bug rtl-optimization/127550] Ne... shimizu2486 at gmail dot com via Gcc-bugs

Reply via email to