The pattern that merges c = VEC_PERM_EXPR <a, b> into
d = VEC_PERM_EXPR <c, c> also matches when c is view-converted before d
uses it.  It asks can_vec_perm_const_p about the new permute and about
both original ones with d's mode as the result mode and a's mode as the
input mode.  When the conversion changes the element type, e.g. from
short to _Float16, that is a permute between two different modes, which
the pattern never emits and no target supports.  All three queries then
fail, "one of the original permutes can't be handled" holds, and the
permutes are merged even when both are supported and the merged one is
not.  Vector lowering then expands the result element by element: on
x86_64 with SSE2 the testcase goes from 3 to 13 instructions.

Query each permute with its own modes instead: the new one has a's
type (it is view-converted to d's type afterwards), the inner one
produces c from a and b, and the outer one produces d from the
converted c.

Assisted-by: Claude Opus 5.5

        PR middle-end/127882

gcc/ChangeLog:

        * match.pd (vec_perm (view_convert? (vec_perm)) merge): Query
        each permute with its own modes.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/pr127882.c: New test.

Signed-off-by: Igor Shevlyakov <[email protected]>
---
 gcc/match.pd                             | 13 ++++++++----
 gcc/testsuite/gcc.target/i386/pr127882.c | 27 ++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr127882.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 6984af44582..fcb67a8dcc0 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12875,7 +12875,11 @@ and,
  (if (TYPE_VECTOR_SUBPARTS (type).is_constant ())
   (with
    {
+     /* c may be view-converted before d uses it, so query each permute
+       with its own modes.  The new permute has the type of a.  */
      machine_mode result_mode = TYPE_MODE (type);
+     machine_mode c_op_mode = TYPE_MODE (TREE_TYPE (@0));
+     machine_mode c_mode = TYPE_MODE (TREE_TYPE (@1));
      machine_mode op_mode = TYPE_MODE (TREE_TYPE (@2));
      int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
      vec_perm_indices sel0, sel1;
@@ -12898,11 +12902,12 @@ and,
          If one or both of the original VEC_PERM_EXPRs can't be
          handled and the new one can't be either, don't increase
          number of VEC_PERM_EXPRs that can't be handled.  */
-       if (can_vec_perm_const_p (result_mode, op_mode, sel2, false)
+       if (can_vec_perm_const_p (op_mode, op_mode, sel2, false)
           || (single_use (@0)
-              ? (!can_vec_perm_const_p (result_mode, op_mode, sel0, true)
-                 || !can_vec_perm_const_p (result_mode, op_mode, sel1, true))
-              : !can_vec_perm_const_p (result_mode, op_mode, sel1, true)))
+              ? (!can_vec_perm_const_p (c_mode, op_mode, sel0, true)
+                 || !can_vec_perm_const_p (result_mode, c_op_mode, sel1,
+                                           true))
+              : !can_vec_perm_const_p (result_mode, c_op_mode, sel1, true)))
         op0 = vec_perm_indices_to_tree (TREE_TYPE (@5), sel2);
      }
      (if (op0)
diff --git a/gcc/testsuite/gcc.target/i386/pr127882.c 
b/gcc/testsuite/gcc.target/i386/pr127882.c
new file mode 100644
index 00000000000..531a30b3c45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr127882.c
@@ -0,0 +1,27 @@
+/* PR middle-end/127882 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2 -mno-ssse3 -fdump-tree-optimized" } */
+
+typedef short v8hi __attribute__((vector_size(16)));
+typedef _Float16 v8hf __attribute__((vector_size(16)));
+
+/* Both permutes are supported, but the merged one is not: keep them, also
+   with a VIEW_CONVERT_EXPR between them.  */
+
+v8hi
+f1 (v8hi a, v8hi b)
+{
+  v8hi c = __builtin_shufflevector (a, b, 8, 0, 9, 1, 10, 2, 11, 3);
+  return __builtin_shufflevector (c, c, 1, 1, 0, 0, 4, 5, 7, 7);
+}
+
+v8hf
+f2 (v8hi a, v8hi b)
+{
+  v8hi c = __builtin_shufflevector (a, b, 8, 0, 9, 1, 10, 2, 11, 3);
+  v8hf e = (v8hf) c;
+  return __builtin_shufflevector (e, e, 1, 1, 0, 0, 4, 5, 7, 7);
+}
+
+/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "BIT_FIELD_REF" "optimized" } } */
-- 
2.56.0


Reply via email to