On Tue, 13 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.
>
> 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));
I think the naming is now confusing, result_mode would be d_mode,
op_mode is ab_mode and since the comment does not show the VIEW_CONVERT
c and c_op mode do not match anything.
I would suggest to use op{0,1,2}_mode to match the capture IDs
and to adjust the comment to mention the VIEW_CONVERT and replace
a,b,c,d with op{0,1,2} and result.
OK with that change or whatever similar change to make this more
obvious.
Richard.
> 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" } } */
>
--
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)