On Wed, 14 Oct 2026, Igor Shevlyakov wrote:

> 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.

This is OK, I have pushed it.

Richard.

> 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]>
> ---
>  gcc/match.pd                             | 44 ++++++++++++++----------
>  gcc/testsuite/gcc.target/i386/pr127882.c | 27 +++++++++++++++
>  2 files changed, 52 insertions(+), 19 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr127882.c
> 
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 6984af44582..1cb710974f7 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 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" } } */
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to