Re: [PATCH v3] match.pd: Simplify XORs of zero_one_valued comparisons

Shivam Gupta <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <CAHX=PX-Ln1EA1nF=6E6CNpdMVV=EUddAZnHUhtsJOymqa9zjmg@mail.gmail.com>
On Mon, 17 Aug 2026 at 3:09 PM, Shivam Gupta <[email protected]> wrote:

>
> On Mon, 17 Aug 2026 at 2:16 PM, Richard Biener <[email protected]>
> wrote:
>
>> On Sat, Aug 15, 2026 at 8:44 PM Shivam Gupta <[email protected]>
>> wrote:
>> >
>> > Recognize XOR patterns involving zero_one_valued operands compared
>> > against zero and simplify them to direct equality or inequality tests.
>> >
>> > Specifically:
>> >
>> > (a == 0) ^ (b != 0)  -> a == b
>> > (a != 0) ^ (b == 0)  -> a == b
>> > (a == 0) ^ (b == 0)  -> a != b
>> > (a != 0) ^ (b != 0)  -> a != b
>> >
>> > Also handle a specific case:
>> > (a == 0) ^ b -> a == b
>> >
>> > Extend the simplifications to handle the corresponding boolean
>> > equality forms as well:
>> > (a == 0) == (b != 0) -> a != b
>> > (a != 0) == (b == 0) -> a != b
>> > (a == 0) == (b == 0) -> a == b
>> > (a != 0) == (b != 0) -> a == b
>> >
>> > Regression tested on aarch64-linux-gnu with RUNTESTFLAGS="tree-ssa.exp".
>>
>> Note you need to bootstrap and run all regression tests.
>>
>> OK if you did and this showed no errors.
>>
>
> No, I have not had a bootstrap build. I can have it in few hours and will
> ping the thread.
>
> Thanks for reviewing and pointing that out.
>
> Regards,
> Shivam
>

Took a little longer time to get back. There is no regression with
bootstrap build too.

Please help me commit the change.

Thanks,
Shivam

>
>> Thanks,
>> Richard.
>>
>> > Changes since v1:
>> > * v3: Merge the op1 == op2 and op1 != op2 comparison patterns into a
>> >       single pattern using out_cmp.
>> >       Wrap the pattern inside (if (INTEGRAL_TYPE_P (type))) to
>> explicitly guard
>> >       against vector types instead of relying on zero_one_valued_p
>> internals.
>> >       Drop unnecessary ':s' tree flags and remove outer convert.
>> >       Update the regression test to check for the expected canonical
>> >       XOR form rather than the absence of comparisons against zero.
>> >
>> > * v2: Simplify (a == 0) ^ b to a == b.
>> >       Handle outer EQ as well as outer NE forms.
>> >       Use convert:type to handle differing operand types.
>> >
>> > gcc/ChangeLog:
>> >         * match.pd: Add simplifications for XORs and boolean
>> >         comparisons of zero_one_valued comparisons against zero.
>> >
>> > gcc/testsuite/ChangeLog:
>> >         * gcc.dg/tree-ssa/bool-eq-bitxor.c: Update expected number
>> >         of optimized XOR forms.
>> >         * gcc.dg/tree-ssa/bool-xor-zero-one-valued.c: New test.
>> >
>> > Signed-off-by: Shivam Gupta <[email protected]>
>> > ---
>> >  gcc/match.pd                                  | 21 +++++++++++
>> >  .../gcc.dg/tree-ssa/bool-eq-bitxor.c          |  5 +--
>> >  .../tree-ssa/bool-xor-zero-one-valued.c       | 36 +++++++++++++++++++
>> >  3 files changed, 58 insertions(+), 4 deletions(-)
>> >  create mode 100644
>> gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
>> >
>> > diff --git a/gcc/match.pd b/gcc/match.pd
>> > index 6addf8fee..edd6cd6a3 100644
>> > --- a/gcc/match.pd
>> > +++ b/gcc/match.pd
>> > @@ -3989,6 +3989,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>> >      (if (types_match (type, TREE_TYPE (@0)))
>> >       (bit_xor @0 { build_one_cst (type); } ))))))
>> >
>> > +/* For zero_one_valued operands:
>> > +   (a == 0) != b -> a == b.  */
>> > +(simplify
>> > + (ne:c (convert (eq zero_one_valued_p@0 integer_zerop))
>> > +       (convert zero_one_valued_p@1))
>> > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
>> > +      && types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
>> > +  (eq @0 @1)))
>> > +
>> > +/* For zero_one_valued operands:
>> > +   (a op1 0) cmp (b op2 0) -> a out_cmp b
>> > +   where out_cmp is cmp if op1 == op2, and the inverse of cmp
>> otherwise.  */
>> > +(if (INTEGRAL_TYPE_P (type))
>> > +  (for cmp     (ne ne eq eq ne ne eq eq)
>> > +       op1     (eq ne eq ne eq ne eq ne)
>> > +       op2     (eq ne eq ne ne eq ne eq)
>> > +       out_cmp (ne ne eq eq eq eq ne ne)
>> > +    (simplify
>> > +      (cmp:c (op1 zero_one_valued_p@0 integer_zerop)
>> > +             (op2 zero_one_valued_p@1 integer_zerop))
>> > +      (out_cmp (convert:type @0) (convert:type @1)))))
>> >
>> >  /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */
>> >  /* ((a ^ b) & c) cmp d && a == b --> (0 cmp d && a == b). */
>> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
>> > index bc263e809..bfb3fe06b 100644
>> > --- a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
>> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
>> > @@ -36,7 +36,4 @@ xor_ne_ne (u32 a, u32 b)
>> >  }
>> >
>> >  /* Verify all functions canonicalize to xor-mask tests.  */
>> > -/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^
>> b_\[0-9\]+\\(D\\)" 3 "optimized" } } */
>> > -
>> > -/* xor_eq_ne not optimized yet due to zero_one_valued_p
>> canonicalization.  */
>> > -/* { dg-final { scan-tree-dump-times "& 1" 2 "optimized" { xfail *-*-*
>> } } } */
>> > +/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^
>> b_\[0-9\]+\\(D\\)" 4 "optimized" } } */
>> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
>> b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
>> > new file mode 100644
>> > index 000000000..95b369299
>> > --- /dev/null
>> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
>> > @@ -0,0 +1,36 @@
>> > +/* { dg-do compile } */
>> > +/* { dg-options "-O1 -fdump-tree-optimized" } */
>> > +
>> > +_Bool
>> > +f1 (unsigned a, unsigned b)
>> > +{
>> > +  if (a != 0 && a != 1) __builtin_unreachable();
>> > +  if (b != 0 && b != 1) __builtin_unreachable();
>> > +  return (a == 0) ^ (b != 0);
>> > +}
>> > +
>> > +_Bool
>> > +f2 (unsigned a, unsigned b)
>> > +{
>> > +  if (a != 0 && a != 1) __builtin_unreachable();
>> > +  if (b != 0 && b != 1) __builtin_unreachable();
>> > +  return (a != 0) ^ (b == 0);
>> > +}
>> > +
>> > +_Bool
>> > +f3 (unsigned a, unsigned b)
>> > +{
>> > +  if (a != 0 && a != 1) __builtin_unreachable();
>> > +  if (b != 0 && b != 1) __builtin_unreachable();
>> > +  return (a == 0) ^ (b == 0);
>> > +}
>> > +
>> > +_Bool
>> > +f4 (unsigned a, unsigned b)
>> > +{
>> > +  if (a != 0 && a != 1) __builtin_unreachable();
>> > +  if (b != 0 && b != 1) __builtin_unreachable();
>> > +  return (a != 0) ^ (b != 0);
>> > +}
>> > +
>> > +/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^
>> b_\[0-9\]+\\(D\\)" 4 "optimized" } } */
>> > --
>> > 2.43.0
>> >
>>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.