https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128142
Bug ID: 128142
Summary: [16/17 Regression] Vector (x + y) >> 1 folded to
.AVG_FLOOR although the signed sum can wrap with
-fwrapv
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ishevlyakov at gcc dot gnu.org
Target Milestone: ---
The match.pd fold of a vector (x + y) >> 1 into IFN_AVG_FLOOR (x, y),
added in r16-1112-g7bb1933c1fc, checks that each element of x and y has
a leading zero bit. For an unsigned type that keeps x + y from
wrapping. For a signed type whose overflow is defined (-fwrapv) it
does not: two nonnegative values can add up to a negative one, and the
shift then gives a negative result, while IFN_AVG_FLOOR adds without
truncation and gives a positive one.
typedef int v4si __attribute__ ((vector_size (16)));
__attribute__ ((noipa)) v4si
f (v4si a, v4si b)
{
return ((a & 0x7fffffff) + (b & 0x7fffffff)) >> 1;
}
int
main ()
{
v4si a = { 0x7fffffff, 0x7fffffff, 0x40000000, 3 };
v4si b = { 0x7fffffff, 1, 0x40000000, 4 };
v4si r = f (a, b);
if (r[0] != -1 || r[1] != -0x40000000 || r[2] != -0x40000000 || r[3] != 3)
__builtin_abort ();
return 0;
}
With -O2 -fwrapv, trunk compiles f for aarch64 to
bic v1.4s, #128, lsl #24
bic v0.4s, #128, lsl #24
shadd v0.4s, v0.4s, v1.4s
ret
so r[0] is 0x7fffffff instead of -1, and r[1] and r[2] are 0x40000000
instead of -0x40000000. The optimized dump shows .AVG_FLOOR. GCC 15
keeps the add and the arithmetic shift.
Without -fwrapv the fold is valid, since a wrapping signed sum would be
undefined. With -fwrapv, a signed type needs two leading zero bits in
each operand for x + y not to wrap.