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

            Bug ID: 128562
           Summary: [17 Regression] arm: vaddq_s8(b, c) >> 1 is compiled
                    to vhadd.s8 and does not wrap
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: yuki.tanaka at defaultcase dot de
  Target Milestone: ---

#include <arm_neon.h>
#include <stdint.h>

__attribute__((noipa)) int8x16_t a(int8x16_t b, int8x16_t c)
{
  return vaddq_s8(b, c) >> 1;
}

int main(void)
{
  int8_t d[16] = {100, 127, 64, 1, 0, -1, -100, -128, 63, 65, 90, -90, 2, 50,
51, 20};
  int8_t e[16] = {100, 127, 64, 2, 0, -1, -100, -128, 64, 63, 38, -38, 3, 78,
77, 10};
  int8x16_t r = a(vld1q_s8(d), vld1q_s8(e));

  for (int i = 0; i < 16; i++)
    {
      int8_t p = (int8_t)(uint8_t)(d[i] + e[i]);

      if (r[i] != p >> 1)
        __builtin_abort();
    }

  return 0;
}

vaddq_s8 wraps to 8 bits. For lane 0, 100 + 100 = 200 wraps to -56, and -56 >>
1 = -28. The program must return normally.

With -O1 and above (-mcpu=cortex-a15 -mfpu=neon-vfpv4) trunk compiles a to a
single vhadd.s8, which adds without truncating to 8 bits: lane 0 becomes (100 +
100) >> 1 = 100, and the program aborts. GCC 16.1.0 and 15.2.0 generate vadd.i8
followed by vshr.s8 and pass. -fwrapv avoids the problem.

Compiler Explorer:
https://godbolt.org/z/cdErsKKoE

Reply via email to