Re: [PATCH] match.pd: sink a unary operation through a vector permute
Andrea Pinski <[email protected]> Tue, 4 Aug 2026 18:30:27 -0700
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcANZbfYcSvi3_86jKrbKhEQroYFtGQ3-Fa8zzCmDS-M0A@mail.gmail.com> |
On Tue, Aug 4, 2026 at 2:50=E2=80=AFAM <[email protected]> wrote: > > 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 =3D { 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 o= ne > + such operation, applied to the permuted vector. The selector and bot= h > + 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)))) Hmm, abs and negate might introduce new undefined behavior here for the signed integer case. (abs and negate is fine for fp since they don't trap). So this needs more handling for that case. See the fp handling. Note I think the already existing pattern: ``` (for op (plus minus mult bit_and bit_ior bit_xor lshift rshift) (simplify (op (vec_perm @0 @0 @2) (vec_perm @1 @1 @2)) (if (VECTOR_INTEGER_TYPE_P (type)) (vec_perm (op@3 @0 @1) @3 @2)))) ``` Has the same issue of maybe introducing undefined behavior. This means we should fix that too. > + > /* Optimize > c1 =3D VEC_PERM_EXPR (a, a, mask) > c2 =3D VEC_PERM_EXPR (b, b, mask) > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vec-perm-unary-1.c b/gcc/tests= uite/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 s= uch > + 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 =3D { 3, 6, 1, 4 }; > + return __builtin_shuffle (-a, -b, m); > +} > + > +v4i > +g (v4i a, v4i b) > +{ > + v4i m =3D { 0, 4, 1, 5 }; > + return __builtin_shuffle (~a, ~b, m); > +} > + > +v4i > +h (v4i a, v4i b) > +{ > + v4i m =3D { 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 =3D { 0, 4, 1, 5 }; > + v4i sa =3D a >> 31, sb =3D 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 " =3D -a" "optimized" } } */ > +/* { dg-final { scan-tree-dump-not " =3D ~a" "optimized" } } */ > -- > 2.50.1 (Apple Git-155) >