[PATCH] match.pd: sink a unary operation through a vector permute
<[email protected]> Tue, 4 Aug 2026 11:48:56 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
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)