On Sun, May 17, 2026 at 6:26 AM Shivam Gupta <[email protected]> wrote:
>
> This is a follow-up to the -O1 patch for PR112533.
>
> At -O2, GCC lowers (~a & 1) == (~b & 1) via inlining into:
> _14 = ~a;
> _12 = (bool) _14;
> _13 = ~b;
> _9 = (bool) _13;
> _8 = _9 == _12;
>
> At -O2, the ne case of (bool)(~x) != (bool)(~y) is already handled
> by CCP1 before forwprop runs.
> However the eq case was missing from match.pd.
>
> Add match.pd rule for the eq form:
>
> (bool)(~x) == (bool)(~y) -> (bool)(~(x ^ y))
>
> The NOTs cancel on both sides, reducing the equality comparison
> to XNOR.
>
> Bootstrapped and regression tested on aarch64-linux-gnu with
> RUNTESTFLAGS="tree-ssa.exp".
>
> PR tree-optimization/112533
>
> gcc/ChangeLog:
> * match.pd: Add eq case for (bool)(~x)==(bool)(~y),
> the ne case was already handled by CCP1.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/tree-ssa/bool-eq-simplify-O2.c: New test.
>
> Signed-off-by: Shivam Gupta <[email protected]>
> ---
> gcc/match.pd | 8 +++++
> .../gcc.dg/tree-ssa/bool-eq-simplify-O2.c | 30 +++++++++++++++++++
> 2 files changed, 38 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O2.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index ff13a07ea94..85a8d1cba50 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2033,6 +2033,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> && element_precision (type) <= element_precision (TREE_TYPE (@1)))
> (bit_xor (convert @0) (convert @1))))
>
> +/* (bool)(~X) == (bool)(~Y) -> (bool)(~(X ^ Y)). */
> +(simplify
> + (eq (convert (bit_not @0))
> + (convert (bit_not @1)))
> + (if (TREE_CODE (type) == BOOLEAN_TYPE
> + && types_match (@0, @1))
> + (convert (bit_not (bit_xor @0 @1)))))
I think we can do better and be more generic here.
Take:
```
int f(int a, int b)
{
// a = ~a;
// b = ~b;
short sa = a;
short sb = b;
return sa == sb;
}
```
This should just be:
```
int f(int a, int b)
{
// a = ~a;
// b = ~b;
int t = a ^ b;
short t1 = t;
return t1 == 0;
}
```
Which means adding another case to the simplify pattern for `(cmp
(convert@0 @00) (convert?@1 @10))`
I think it only works for eq/ne. Here we already handle outer > inner
precision. We need to add outer < inner.
And the result becomes `(cmp (convert (bit_xor @00 @10)) 0)` and that
will optimize the rest of the way to what you have above.
Thanks,
Andrea
> +
> /* Convert ~X ^ C to X ^ ~C. */
> (simplify
> (bit_xor (convert? (bit_not @0)) INTEGER_CST@1)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O2.c
> b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O2.c
> new file mode 100644
> index 00000000000..7e096828be8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-simplify-O2.c
> @@ -0,0 +1,30 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +/* Verify the fix for PR112533 at -O2:
> + (~a & 1) == (~b & 1) is lowered to (bool)(~a) == (bool)(~b)
> + which should be simplified to (bool)(~(a ^ b)). */
> +
> +typedef unsigned int u32;
> +
> +/* Source-level form from the bug report. */
> +static _Bool
> +is_even (u32 a)
> +{
> + return a % 2 == 0;
> +}
> +
> +_Bool
> +same_evenness (u32 a, u32 b)
> +{
> + return is_even (a) == is_even (b);
> +}
> +
> +_Bool
> +diff_evenness (u32 a, u32 b)
> +{
> + return is_even (a) != is_even (b);
> +}
> +
> +/* Verify the XOR form is produced. */
> +/* { dg-final { scan-tree-dump-times "\\\^" 2 "optimized" } } */
> --
> 2.34.1
>