Re: [PATCH] match.pd: combine a pair of vector comparisons against zero
Andrea Pinski <[email protected]> Tue, 4 Aug 2026 17:48:14 -0700
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcB_3iL7hxe6-f0WF_eYA0Q5431sPhUM0xswOe8_uyo9GQ@mail.gmail.com> |
On Tue, Aug 4, 2026 at 2:53=E2=80=AFAM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > A lane of A | B is zero exactly when the corresponding lanes of A and of = B > are both zero, so > > (A =3D=3D 0) & (B =3D=3D 0) -> (A | B) =3D=3D 0 > > and the De Morgan dual for the inequality. One vector comparison goes > away. Reassociation performs this for scalars, but it never runs on > vector masks, so the vector form is left alone today. > > typedef int v4si __attribute__((vector_size (16))); > v4si f (v4si a, v4si b) { v4si z =3D {0,0,0,0}; return (a =3D=3D z) & (= b =3D=3D z); } > > aarch64 -O3 before: > > cmeq v0.4s, v0.4s, #0 > cmeq v1.4s, v1.4s, #0 > and v0.16b, v0.16b, v1.16b > > after: > > orr v0.16b, v0.16b, v1.16b > cmeq v0.4s, v0.4s, #0 > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > gcc/ChangeLog: > > * match.pd ((A =3D=3D 0) & (B =3D=3D 0), (A !=3D 0) | (B !=3D 0))= : New > simplifications for vector operands. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/vec-mask-zero-1.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match.pd | 14 ++++++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c | 12 ++++++++++++ > 2 files changed, 26 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 22202af2cc1..fc81dfc5e66 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -3823,6 +3823,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > { constant_boolean_node (true, type); }) > )))))) > > +/* Combine two vector comparisons against zero into one: > + (A =3D=3D 0) & (B =3D=3D 0) --> (A | B) =3D=3D 0 > + (A !=3D 0) | (B !=3D 0) --> (A | B) !=3D 0 > + Reassociation does this for scalars only, it never runs on vector > + masks. */ > +(for eqne (eq ne) > + bitop (bit_and bit_ior) > + (simplify > + (bitop (eqne:s @0 integer_zerop) (eqne:s @1 integer_zerop)) > + (if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (@0)) > + && types_match (TREE_TYPE (@0), TREE_TYPE (@1))) > + (eqne (bit_ior @0 @1) > + { build_zero_cst (TREE_TYPE (@0)); })))) So I think you should be able to combine it with these patterns instead: ``` (for bitop (bit_and bit_ior) cmp (eq ne) /* PR35691: Transform (x =3D=3D 0 & y =3D=3D 0) -> (x | typeof(x)(y)) =3D=3D 0. (x !=3D 0 | y !=3D 0) -> (x | typeof(x)(y)) !=3D 0. */ (simplify (bitop (cmp @0 integer_zerop@2) (cmp @1 integer_zerop)) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE (@1)) && TYPE_PRECISION (TREE_TYPE (@0)) =3D=3D TYPE_PRECISION (TREE_TYPE= (@1))) (cmp (bit_ior @0 (convert @1)) @2))) /* Transform: (x =3D=3D -1 & y =3D=3D -1) -> (x & typeof(x)(y)) =3D=3D -1. (x !=3D -1 | y !=3D -1) -> (x & typeof(x)(y)) !=3D -1. */ (simplify (bitop (cmp @0 integer_all_onesp@2) (cmp @1 integer_all_onesp)) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE (@1)) && TYPE_PRECISION (TREE_TYPE (@0)) =3D=3D TYPE_PRECISION (TREE_TYPE= (@1))) (cmp (bit_and @0 (convert @1)) @2)))) ``` Instead of convert, use view_convert and instead of TYPE_PRECISION check you need something more like: ``` (if (VECTOR_TYPE_P (type) && VECTOR_TYPE_P (TREE_TYPE (@0)) && known_eq (TYPE_VECTOR_SUBPARTS (type), TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0))) && tree_nop_conversion_p (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (@0)= ))))) ``` Which might make sense to make in a helper function and use that also in nop_convert match pattern; maybe vector_nop_conversion_p. And then also add a testcase for -1. > + > /* Optimize (a CMP b) ^ (a CMP b) */ > /* Optimize (a CMP b) !=3D (a CMP b) */ > (for op (bit_xor ne) > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c b/gcc/testsu= ite/gcc.dg/tree-ssa/vec-mask-zero-1.c > new file mode 100644 > index 00000000000..f8c669636fd > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vec-mask-zero-1.c > @@ -0,0 +1,12 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > +/* A lane of A | B is zero exactly when both lanes are, so a pair of vec= tor > + comparisons against zero becomes one. Reassociation does this for > + scalars but never runs on vector masks. */ > +typedef int v4si __attribute__((vector_size (16))); > +v4si f (v4si a, v4si b) { v4si z =3D {0,0,0,0}; return (a =3D=3D z) & (b= =3D=3D z); } > +v4si g (v4si a, v4si b) { v4si z =3D {0,0,0,0}; return (a !=3D z) | (b != =3D z); } > +/* { dg-final { scan-tree-dump-times " =3D=3D " 1 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times " !=3D " 1 "optimized" } } */ > +/* Each function keeps one OR and one comparison. */ > +/* { dg-final { scan-tree-dump-times " \\| " 2 "optimized" } } */ > -- > 2.50.1 (Apple Git-155) >