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