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