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]>
---
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" } } */
--
2.56.0