https://gcc.gnu.org/g:ca6ddc9ecd74b89284ecede2ed90f768f70d88a5

commit r17-5328-gca6ddc9ecd74b89284ecede2ed90f768f70d88a5
Author: Igor Shevlyakov <[email protected]>
Date:   Sun Oct 18 14:58:39 2026 -0700

    match.pd: Index BIT_FIELD_REF of VEC_PERM_EXPR inputs by their length
    
    The BIT_FIELD_REF <VEC_PERM_EXPR <a, b, sel>> fold takes its element
    count from the selector, i.e. from the result.  It then uses that count
    to reduce selector values, to choose between a and b, and to rebase
    indices into b.  A constant VEC_PERM_EXPR may have inputs with a
    different number of elements than its result.  When a and b are wider,
    an index into a at or above the result length is taken as an index
    into b: silent wrong code.  When they are narrower, an index into b is
    taken as an index past the end of a, which fails GIMPLE verification.
    Besides explicit element extraction, vector lowering produces such
    BIT_FIELD_REFs when it lowers an unsupported narrowing permute whose
    input is a narrowing permute the target supports, and forwprop then
    folds them.
    
    Use the element count of the inputs.
    
    gcc/ChangeLog:
    
            * match.pd (BIT_FIELD_REF (vec_perm ...)): Take the element count
            from the inputs, not the selector.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/torture/vec-perm-bitfield-ref-narrow-input-1.c: New test.
            * gcc.dg/torture/vec-perm-bitfield-ref-wide-input-1.c: New test.
    
    Signed-off-by: Igor Shevlyakov <[email protected]>

Diff:
---
 gcc/match.pd                                       |  5 +-
 .../torture/vec-perm-bitfield-ref-narrow-input-1.c | 53 ++++++++++++++++++++++
 .../torture/vec-perm-bitfield-ref-wide-input-1.c   | 53 ++++++++++++++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 629114591a2b..7bb9126065dc 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -11042,8 +11042,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     unsigned HOST_WIDE_INT nelts, idx;
     unsigned HOST_WIDE_INT nelts_op = 0;
   }
+  /* NELTS is the number of elements in each input, which may differ
+     from that of the result; the selector indexes their concatenation.  */
   (if (constant_multiple_p (tree_to_poly_uint64 (@rpos), elem_size, &idx)
-       && VECTOR_CST_NELTS (@3).is_constant (&nelts)
+       && VECTOR_CST_NELTS (@3).is_constant ()
+       && TYPE_VECTOR_SUBPARTS (TREE_TYPE (@1)).is_constant (&nelts)
        && (known_eq (size, elem_size)
           || (constant_multiple_p (size, elem_size, &nelts_op)
               && pow2p_hwi (nelts_op))))
diff --git 
a/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-narrow-input-1.c 
b/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-narrow-input-1.c
new file mode 100644
index 000000000000..43d4831b702c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-narrow-input-1.c
@@ -0,0 +1,53 @@
+/* BIT_FIELD_REF of a VEC_PERM_EXPR with inputs narrower than the result.  */
+/* { dg-do run } */
+/* { dg-additional-options "-fgimple -Wno-psabi" } */
+
+typedef short v8hi __attribute__((vector_size(16)));
+typedef short v4hi __attribute__((vector_size(8)));
+typedef short v2hi __attribute__((vector_size(4)));
+
+v4hi a, b;
+short s;
+v2hi r;
+
+/* One element.  */
+void __attribute__((noipa)) __GIMPLE() f1 ()
+{
+  v4hi a_; v4hi b_; v8hi c_; short e_;
+  a_ = a; b_ = b;
+  c_ = __VEC_PERM (a_, b_, _Literal (v8hi) { 0, 5, 2, 3, 4, 5, 6, 7 });
+  e_ = __BIT_FIELD_REF <short> (c_, 16, 16);
+  s = e_;
+}
+
+/* A subvector.  */
+void __attribute__((noipa)) __GIMPLE() f2 ()
+{
+  v4hi a_; v4hi b_; v8hi c_; v2hi e_;
+  a_ = a; b_ = b;
+  c_ = __VEC_PERM (a_, b_, _Literal (v8hi) { 0, 1, 6, 7, 4, 5, 2, 3 });
+  e_ = __BIT_FIELD_REF <v2hi> (c_, 32, 32);
+  r = e_;
+}
+
+int
+main ()
+{
+  for (int i = 0; i < 4; i++)
+    {
+      a[i] = i + 1;
+      b[i] = i + 101;
+    }
+
+  f1 ();
+  /* c[1] = b1.  */
+  if (s != 102)
+    __builtin_abort ();
+
+  f2 ();
+  /* c[2] = b2, c[3] = b3.  */
+  if (r[0] != 103 || r[1] != 104)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-wide-input-1.c 
b/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-wide-input-1.c
new file mode 100644
index 000000000000..deb7247ed654
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/vec-perm-bitfield-ref-wide-input-1.c
@@ -0,0 +1,53 @@
+/* BIT_FIELD_REF of a VEC_PERM_EXPR with inputs wider than the result.  */
+/* { dg-do run } */
+/* { dg-additional-options "-fgimple -Wno-psabi" } */
+
+typedef short v8hi __attribute__((vector_size(16)));
+typedef short v4hi __attribute__((vector_size(8)));
+typedef short v2hi __attribute__((vector_size(4)));
+
+v8hi a, b;
+short s;
+v2hi r;
+
+/* One element.  */
+void __attribute__((noipa)) __GIMPLE() f1 ()
+{
+  v8hi a_; v8hi b_; v4hi c_; short e_;
+  a_ = a; b_ = b;
+  c_ = __VEC_PERM (a_, b_, _Literal (v4hi) { 13, 6, 2, 9 });
+  e_ = __BIT_FIELD_REF <short> (c_, 16, 16);
+  s = e_;
+}
+
+/* A subvector.  */
+void __attribute__((noipa)) __GIMPLE() f2 ()
+{
+  v8hi a_; v8hi b_; v4hi c_; v2hi e_;
+  a_ = a; b_ = b;
+  c_ = __VEC_PERM (a_, b_, _Literal (v4hi) { 13, 2, 6, 7 });
+  e_ = __BIT_FIELD_REF <v2hi> (c_, 32, 32);
+  r = e_;
+}
+
+int
+main ()
+{
+  for (int i = 0; i < 8; i++)
+    {
+      a[i] = i + 1;
+      b[i] = i + 101;
+    }
+
+  f1 ();
+  /* c[1] = a6.  */
+  if (s != 7)
+    __builtin_abort ();
+
+  f2 ();
+  /* c[2] = a6, c[3] = a7.  */
+  if (r[0] != 7 || r[1] != 8)
+    __builtin_abort ();
+
+  return 0;
+}

Reply via email to