https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128161
Bug ID: 128161
Summary: [17 Regression] wrong code at -O2: (signed
char)(svcntb() * 4) > 0 is true on 256-bit and wider
SVE
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: yuki.tanaka at defaultcase dot de
Target Milestone: ---
#include <arm_sve.h>
__attribute__((noipa)) int a(void)
{
return (signed char)(svcntb() * 4) > 0;
}
int main(void)
{
if (svcntb() >= 32 && a())
__builtin_abort();
return 0;
}
$ build-aarch64/gcc/xgcc -B build-aarch64/gcc -O2 -march=armv8.2-a+sve -c
polycast.c -o polycast.o
$ aarch64-linux-gnu-gcc -static polycast.s -o polycast
$ qemu-aarch64 -cpu max,sve128=on ./polycast; echo $?
0
$ qemu-aarch64 -cpu max,sve256=on ./polycast; echo $?
qemu: uncaught target signal 6 (Aborted) - core dumped
Aborted qemu-aarch64 -cpu max,sve256=on ./polycast
134
On a 256-bit SVE machine (e.g. Neoverse V1) svcntb() is 32, so svcntb() * 4 is
128 and (signed char) 128 is -128; on 512-bit and wider SVE the conversion
gives 0. The comparison must therefore be false whenever the vector length is
256 bits or more. Instead a returns 1 and main aborts.
Compiler Explore:
https://godbolt.org/z/3Yvc5ac1x
GCC 17:
a:
mov w0, 1
ret
GCC 16.1 computes the value at run time (cntb x0, all, mul #4; sxtb; cmp; cset
gt) and gives the correct result. GCC 17 also folds the comparison to 1 at -O1
and with -march=armv9-a. With -fwrapv, the generated code is correct.
Possibly related to r17-3518-g1dd02e1deff ("middle-end: Teach ranger about
POLY_INT_CST ranges for VRP.").