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

            Bug ID: 128583
           Summary: x86_64: wrong code at -O2: v == (_BitInt(33))(-2 & g)
                    is compiled as v << 31 == 0
           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/3c6Yxa6Ys

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

static volatile int a;
_BitInt(65) g;
_BitInt(65) *p = &g;

int main(void) {
  int w = 0;
  _BitInt(2) v = a ? -1 : 0;
  *p = 2;
  for (; w < (v == (_BitInt(33))(-2 & g)); w++)
    if (g <= 0)
      break;
  printf("%d\n", w);
}

a is 0, so v is 0, and g is 2 after the store through p, so (_BitInt(33))(-2 &
g) is 2 and v == 2 is false: the loop does not run and the program should print
0.

$ gcc -O1 t1.c -o t1 && ./t1
0                                   (correct)
$ gcc -O2 t1.c -o t1 && ./t1
1                                   (wrong)

  x86-64 trunk (d5444af5d693)       wrong at -O2, -O3, -Os
  x86-64 16.2.0, 15.3.0             wrong at -O2, -O3, -Os
  x86-64 14.4.0                     wrong at -O2

-O0 and -O1 are correct. -fdisable-rtl-combine, -fno-tree-ter or
-fno-expensive-optimizations each make it print 0. aarch64 and loongarch64
trunk print 0, and so does clang.

Notes:
At -O2 the comparison is emitted without its right-hand side, as v << 31 == 0:

        sbbq    %rcx, %rcx              # v
        ...
        salq    $31, %rcx
        sete    %sil                    # v == (_BitInt(33))(-2 & g)

while -O1 computes (_BitInt(33))(-2 & g) and compares with it:

        andq    $-2, %rsi
        salq    $31, %rsi
        sarq    $31, %rsi
        cmpq    %rsi, %rcx
        sete    %sil

Reply via email to