On Wed, Aug 19, 2026 at 9:12 PM Shivam Gupta <[email protected]> wrote:
>
>
>
> 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.

Pushed.

Richard.

> 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
>>> >

Reply via email to