From: Kyrylo Tkachov <[email protected]>

A permute of two results of the same unary operation needs only one such
operation, applied to the permuted vector.  The selector and both vector
types are unchanged, so the permute itself costs the same, and the lanes
that the permute drops are no longer computed at all.

  typedef float v4f __attribute__((vector_size (16)));
  typedef int   v4i __attribute__((vector_size (16)));
  v4f f (v4f a, v4f b)
  {
    v4i m = { 3, 6, 1, 4 };
    return __builtin_shuffle (-a, -b, m);
  }

aarch64 -O2 before:

        fneg    v0.4s, v0.4s
        adrp    x0, .LANCHOR0
        fneg    v1.4s, v1.4s
        ldr     q29, [x0, #:lo12:.LANCHOR0]
        mov     v30.16b, v0.16b
        mov     v31.16b, v1.16b
        tbl     v0.16b, {v30.16b - v31.16b}, v29.16b

after:

        adrp    x0, .LANCHOR0
        ldr     q31, [x0, #:lo12:.LANCHOR0]
        tbl     v0.16b, {v0.16b - v1.16b}, v31.16b
        fneg    v0.4s, v0.4s

The two register-pair moves also go away, because the permute can now
take the incoming argument registers directly.

Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

        * match.pd (vec_perm of two identical unary operations): New
        simplification sinking the operation through the permute.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/vec-perm-unary-1.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/match.pd                                  |  9 ++++
 .../gcc.dg/tree-ssa/vec-perm-unary-1.c        | 44 +++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vec-perm-unary-1.c

diff --git a/gcc/match.pd b/gcc/match.pd
index ec00347a968..4fca75d6fb6 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12532,6 +12532,15 @@ and,
       && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
   (convert @0)))
 
+/* VEC_PERM_EXPR of two results of the same unary operation needs only one
+   such operation, applied to the permuted vector.  The selector and both
+   vector types are unchanged, so the permute itself costs the same, and
+   the lanes that the permute drops are no longer computed.  */
+(for uop (negate bit_not abs absu)
+ (simplify
+  (vec_perm (uop:s @0) (uop:s @1) @2)
+  (uop (vec_perm @0 @1 @2))))
+
 /* Optimize
    c1 = VEC_PERM_EXPR (a, a, mask)
    c2 = VEC_PERM_EXPR (b, b, mask)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vec-perm-unary-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vec-perm-unary-1.c
new file mode 100644
index 00000000000..7ff2498a6ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vec-perm-unary-1.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* A permute of two results of the same unary operation needs only one such
+   operation, applied to the permuted vector.  */
+
+typedef float v4f __attribute__((vector_size (16)));
+typedef int   v4i __attribute__((vector_size (16)));
+
+v4f
+f (v4f a, v4f b)
+{
+  v4i m = { 3, 6, 1, 4 };
+  return __builtin_shuffle (-a, -b, m);
+}
+
+v4i
+g (v4i a, v4i b)
+{
+  v4i m = { 0, 4, 1, 5 };
+  return __builtin_shuffle (~a, ~b, m);
+}
+
+v4i
+h (v4i a, v4i b)
+{
+  v4i m = { 0, 4, 1, 5 };
+  return __builtin_shuffle (-a, -b, m);
+}
+
+/* The absolute value written as a sign mask folds to ABS_EXPR first, so
+   this exercises the abs case of the same rule.  */
+v4i
+k (v4i a, v4i b)
+{
+  v4i m = { 0, 4, 1, 5 };
+  v4i sa = a >> 31, sb = b >> 31;
+  return __builtin_shuffle ((a ^ sa) - sa, (b ^ sb) - sb, m);
+}
+
+/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = -a" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = ~a" "optimized" } } */
-- 
2.50.1 (Apple Git-155)

Reply via email to