Re: [PATCH] match.pd: merge two masked equality tests of one value
Andrea Pinski <[email protected]> Tue, 4 Aug 2026 13:19:09 -0700
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcB_r5hmkiO7TPANxPgF63mKY6F0X3RDZUFcOeU3kP3tkA@mail.gmail.com> |
On Tue, Aug 4, 2026 at 3:39=E2=80=AFAM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > Two masked tests of the same value examine one set of bits, so one mask a= nd > one comparison do the whole job: > > ((X & C1) =3D=3D C2) & ((X & C3) =3D=3D C4) > -> (X & (C1 | C3)) =3D=3D (C2 | C4) when C2 and C4 agree on the bit= s both > masks select > -> false when they disagree > > and the inclusive or of the two inequalities is the De Morgan dual. > > int f (unsigned x) { return ((x & 5) =3D=3D 5) & ((x & 24) =3D=3D 24); = } > > aarch64 -O2 before: > > and w1, w0, 5 > and w0, w0, 24 > cmp w1, 5 > cset w1, eq > cmp w0, 24 > cset w0, eq > and w0, w0, w1 > > after: > > and w0, w0, 29 > cmp w0, 29 > cset w0, eq > > A test whose constant has a bit outside its own mask is decided already a= nd > is left to the rules that decide it. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? No because Daniel already submitted a more complete patch and Richi reviewed it here: https://gcc.gnu.org/pipermail/gcc-patches/2026-May/716820.html Also see starting at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D93131#c14 . Which is the same review Richi gave earlier. Thanks, Andrea > Thanks, > Kyrill > > gcc/ChangeLog: > > * match.pd (((X & C1) =3D=3D C2) &/| ((X & C3) =3D=3D C4)): New > simplification. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/maskcmp-merge-1.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match.pd | 28 +++++++++++++++++++ > .../gcc.dg/tree-ssa/maskcmp-merge-1.c | 26 +++++++++++++++++ > 2 files changed, 54 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 41acf869f9c..fa3856fc50e 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -3939,6 +3939,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > { constant_boolean_node (true, type); }) > )))))) > > +/* Merge two masked equality tests of the same value. > + > + ((X & C1) =3D=3D C2) & ((X & C3) =3D=3D C4) > + -> (X & (C1 | C3)) =3D=3D (C2 | C4) when C2 and C4 agree on the= bits > + both masks select > + -> false when they disagree > + > + and the inclusive or of the two inequalities is the De Morgan dual. = Two > + masked tests of one value examine one set of bits, so one mask and one > + comparison do the whole job. */ > +(for cmp (eq ne) > + bitop (bit_and bit_ior) > + (simplify > + (bitop (cmp:s (bit_and:s @0 INTEGER_CST@1) INTEGER_CST@2) > + (cmp:s (bit_and:s @0 INTEGER_CST@3) INTEGER_CST@4)) > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))) > + (with { wide_int m1 =3D wi::to_wide (@1), v1 =3D wi::to_wide (@2); > + wide_int m2 =3D wi::to_wide (@3), v2 =3D wi::to_wide (@4); > + tree t0 =3D TREE_TYPE (@0); } > + /* A test whose constant has a bit outside its mask is decided alrea= dy > + and is left to the rules that decide it. */ > + (if (wi::bit_and_not (v1, m1) =3D=3D 0 > + && wi::bit_and_not (v2, m2) =3D=3D 0) > + (if ((m1 & m2 & (v1 ^ v2)) =3D=3D 0) > + (cmp (bit_and @0 { wide_int_to_tree (t0, m1 | m2); }) > + { wide_int_to_tree (t0, v1 | v2); }) > + { constant_boolean_node (cmp =3D=3D NE_EXPR, 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 > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c b/gcc/testsu= ite/gcc.dg/tree-ssa/maskcmp-merge-1.c > new file mode 100644 > index 00000000000..9509afce27e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/maskcmp-merge-1.c > @@ -0,0 +1,26 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > + > +typedef unsigned int u; > + > +/* Two masked tests of one value examine one set of bits, so one mask an= d > + one comparison do the whole job. */ > + > +int a1 (u x) { return ((x & 5) =3D=3D 5) & ((x & 24) =3D=3D 24); } > +int a2 (u x) { return ((x & 5) =3D=3D 1) & ((x & 24) =3D=3D 16); } > +int a3 (u x) { return ((x & 5) =3D=3D 0) & ((x & 24) =3D=3D 24); } > +int a4 (u x) { return ((x & 12) =3D=3D 12) & ((x & 20) =3D=3D 4); } > + > +/* The De Morgan dual. */ > +int b1 (u x) { return ((x & 5) !=3D 5) | ((x & 24) !=3D 24); } > +int b2 (u x) { return ((x & 5) !=3D 1) | ((x & 24) !=3D 16); } > + > +/* Bit 2 is selected by both masks and the two tests disagree on it, so = the > + conjunction is false and the disjunction is true. */ > +int c1 (u x) { return ((x & 6) =3D=3D 6) & ((x & 12) =3D=3D 8); } > +int c2 (u x) { return ((x & 6) !=3D 6) | ((x & 12) !=3D 8); } > + > +/* { dg-final { scan-tree-dump-times " & 29" 5 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times " & 28" 1 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "return 0;" 1 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "return 1;" 1 "optimized" } } */ > -- > 2.50.1 (Apple Git-155) >