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

            Bug ID: 127558
           Summary: [loongarch64] wrong code at -O2: a live sign-extension
                    replaced with a copy
           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: ---
            Target: loongarch64

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

A value narrowed to int keeps its upper 32 bits from -O2 up, because the
sign-extension that produces it is deleted while those bits are still live.
$ cat t1.c
#include <stdio.h>
volatile long A;
long B = 0x80000001;
long D = 1;
long m[2];
long e = 1;
unsigned long long t;
int main(void) {
  int z = 0;
  _BitInt(17) g = A;
  for (; A; z = (int)B)
    ;
  t = (int)(D ? B : -g) ^ (_BitInt(7))e;
  m[0] = m[(unsigned)B & 1] / B;
  int r = 0 == z ? 2 * B : 0;
  printf("%llu\n", r * t);
}

A is zero, so the loop does not run and z stays 0, and g is 0. D is 1, so the
ternary gives B, and (int)B must wrap 0x80000001 to -2147483647; xor with 1
gives -2147483648, so t is 2^64-2^31. r is (int)(2*B) == 2, so r*t must be
    2 * (2^64 - 2^31) mod 2^64 == 2^64 - 2^32 == 18446744069414584320.

$ loongarch64-unknown-linux-gnu-gcc -O1 -static t1.c -o t1 && qemu-loongarch64
./t1
18446744069414584320                (correct)
$ loongarch64-unknown-linux-gnu-gcc -O2 -static t1.c -o t1 && qemu-loongarch64
./t1
4294967296                          (wrong)
4294967296 is 2 * (2147483649), so I guess the (int) never happened.

  16.1.0                wrong
  trunk (4015b65b)      wrong
  trunk (20260920)      wrong
  trunk (20260922)      wrong

-O0, -O1 and -Os are correct; -O2 and -O3 are wrong. x86-64 is correct at every
level.

Reply via email to