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.

Reply via email to