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.").

Reply via email to