https://gcc.gnu.org/g:3db0edb7331f01233dc3b4d1e32b094c7b4ba678

commit r17-5216-g3db0edb7331f01233dc3b4d1e32b094c7b4ba678
Author: Igor Shevlyakov <[email protected]>
Date:   Wed Oct 14 14:35:13 2026 -0700

    match.pd: Fix mode queries of VEC_PERM merge through view-convert [PR127882]
    
    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.  Rename the modes and selectors
            and show the VIEW_CONVERT_EXPR in the comment.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/i386/pr127882.c: New test.
    
    Signed-off-by: Igor Shevlyakov <[email protected]>

Diff:
---
 gcc/match.pd                             | 44 ++++++++++++++++++--------------
 gcc/testsuite/gcc.target/i386/pr127882.c | 27 ++++++++++++++++++++
 2 files changed, 52 insertions(+), 19 deletions(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 6984af445825..1cb710974f7e 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12865,10 +12865,13 @@ and,
 
 
 /* Merge
-     c = VEC_PERM_EXPR <a, b, VCST0>;
-     d = VEC_PERM_EXPR <c, c, VCST1>;
+     inner = VEC_PERM_EXPR <op2, op3, sel4>;
+     vc = VIEW_CONVERT_EXPR <inner>;  (optional)
+     result = VEC_PERM_EXPR <vc, vc, sel5>;
    to
-     d = VEC_PERM_EXPR <a, b, NEW_VCST>;  */
+     result = VIEW_CONVERT_EXPR <VEC_PERM_EXPR <op2, op3, new_sel>>;
+   The VIEW_CONVERT_EXPR may change the element type but not the element
+   count.  */
 
 (simplify
  (vec_perm (view_convert?@0 (vec_perm@1 @2 @3 VECTOR_CST@4)) @0 VECTOR_CST@5)
@@ -12876,37 +12879,40 @@ and,
   (with
    {
      machine_mode result_mode = TYPE_MODE (type);
-     machine_mode op_mode = TYPE_MODE (TREE_TYPE (@2));
+     machine_mode vc_mode = TYPE_MODE (TREE_TYPE (@0));
+     machine_mode inner_mode = TYPE_MODE (TREE_TYPE (@1));
+     machine_mode op2_mode = TYPE_MODE (TREE_TYPE (@2));
      int nelts = TYPE_VECTOR_SUBPARTS (type).to_constant ();
-     vec_perm_indices sel0, sel1;
+     vec_perm_indices sel4, sel5;
    }
-   (if (tree_to_vec_perm_indices (&sel0, @2, @3, @4)
-       && tree_to_vec_perm_indices (&sel1, @0, @0, @5)
+   (if (tree_to_vec_perm_indices (&sel4, @2, @3, @4)
+       && tree_to_vec_perm_indices (&sel5, @0, @0, @5)
        && TYPE_SIZE (TREE_TYPE (TREE_TYPE (@0)))
           == TYPE_SIZE (TREE_TYPE (TREE_TYPE (@1))))
     (with
      {
-       vec_perm_builder builder2 (nelts, nelts, 1);
+       vec_perm_builder new_builder (nelts, nelts, 1);
        for (int i = 0; i < nelts; i++)
-        builder2.quick_push (sel0[sel1[i].to_constant ()]);
+        new_builder.quick_push (sel4[sel5[i].to_constant ()]);
 
-       vec_perm_indices sel2 (builder2, 2, nelts);
+       vec_perm_indices new_sel (new_builder, 2, nelts);
 
-       tree op0 = NULL_TREE;
+       tree new_vcst = NULL_TREE;
        /* If the new VEC_PERM_EXPR can't be handled but both
          original VEC_PERM_EXPRs can, punt.
          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)
+         number of VEC_PERM_EXPRs that can't be handled.
+         The new VEC_PERM_EXPR has the type of op2.  */
+       if (can_vec_perm_const_p (op2_mode, op2_mode, new_sel, 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)))
-        op0 = vec_perm_indices_to_tree (TREE_TYPE (@5), sel2);
+              ? (!can_vec_perm_const_p (inner_mode, op2_mode, sel4, true)
+                 || !can_vec_perm_const_p (result_mode, vc_mode, sel5, true))
+              : !can_vec_perm_const_p (result_mode, vc_mode, sel5, true)))
+        new_vcst = vec_perm_indices_to_tree (TREE_TYPE (@5), new_sel);
      }
-     (if (op0)
-      (view_convert (vec_perm @2 @3 { op0; }))))))))
+     (if (new_vcst)
+      (view_convert (vec_perm @2 @3 { new_vcst; }))))))))
 
 /* Merge
      c = VEC_PERM_EXPR <a, b, VCST0>;
diff --git a/gcc/testsuite/gcc.target/i386/pr127882.c 
b/gcc/testsuite/gcc.target/i386/pr127882.c
new file mode 100644
index 000000000000..531a30b3c455
--- /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" } } */

Reply via email to