https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128080
Bug ID: 128080
Summary: [14/15/16/17 Regression] wrong code merging
VEC_PERM_EXPRs when the merged indices do not fit the
mask element type
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 following is miscompiled at -O1 and above since GCC 14:
typedef signed char V __attribute__((vector_size (256)));
/* 255, 254, ..., 0. */
#define R1(n) (255 - (n))
#define R4(n) R1 (n), R1 (n + 1), R1 (n + 2), R1 (n + 3)
#define R16(n) R4 (n), R4 (n + 4), R4 (n + 8), R4 (n + 12)
#define R64(n) R16 (n), R16 (n + 16), R16 (n + 32), R16 (n + 48)
V x, b, r;
__attribute__((noipa)) void
f (void)
{
/* c[i] = b[255 - i]. */
V c = __builtin_shufflevector (b, b, R64 (0), R64 (64), R64 (128), R64
(192));
/* Index -1 selects element 511 of { x, c }, i.e. c[255] = b[0]. */
V m = { 0, -1 };
r = __builtin_shuffle (x, c, m);
}
int
main ()
{
for (int i = 0; i < 256; i++)
{
x[i] = 1;
b[i] = 2;
}
f ();
if (r[0] != 1 || r[1] != 2)
__builtin_abort ();
return 0;
}
$ gcc -O2 pr.c && ./a.out
Aborted
forwprop1 merges the two permutes into
_4 = VEC_PERM_EXPR <x.2_3, x.2_3, { 0, 0, 0, ... }>;
so b is gone. The merged selector refers to element 256 of { x, b }
(b[0]), but it is built with the element type of the outer mask:
vec_perm_indices_to_tree (TREE_TYPE (@4), sel2) uses build_int_cst
on a signed char, so 256 becomes 0, which selects x[0]. With 256
lanes the indices of a two-input permute range over 0..511, which an
8-bit element only represents modulo 256. The original masks were
fine because the user can only write indices that fit; it is the
composition that produces 256..383 (and the equivalent ranges in the
other patterns).
The same conversion is done by all three VEC_PERM_EXPR merge
patterns in match.pd (line numbers as of r17-5471-g77b872105c0):
12961 new_vcst = vec_perm_indices_to_tree (TREE_TYPE (@5), new_sel);
(VEC_PERM <VIEW_CONVERT? <VEC_PERM <a, b>>, same>)
13030 op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2);
(VEC_PERM <x, VEC_PERM <a, b>>)
13096 op0 = vec_perm_indices_to_tree (TREE_TYPE (@4), sel2);
(VEC_PERM <VEC_PERM <a, b>, x>)
pr.c goes through 13030. pr2.c (attached) is miscompiled through
12904/12961 on trunk at -O2, where a one-operand __builtin_shuffle of
a two-input __builtin_shufflevector result folds to
VEC_PERM_EXPR <x, x, { 1, 0, ... }> instead of reading b[1]; older
releases get pr2.c wrong even at -O0, which looks like a separate,
already fixed problem, so pr2.c is only useful against trunk.
The two-input merges came with r14-3571 (PR111228) and the
view-convert one with r15-818; GCC 13 has neither and gets pr.c
right.
It needs a byte element type and at least 256 lanes, so it can be hit
with generic vectors and with fixed-length SVE at 2048 bits
(-march=armv8.2-a+sve -msve-vector-bits=2048 gives the same bad
VEC_PERM_EXPR <x, x, { 0, 0, ... }>), and presumably with RVV at large
VLEN.
Possible fixes: punt when the mask element type cannot represent
2 * nelts - 1, or, since verify_gimple accepts any integer element
type for a constant mask, build the merged mask with a wider element
type when the original one is too narrow.