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)
