Re: [PATCH] match.pd: Fix (a & b) == (a ^ b) -> !(a | b) simplification [PR126490]

Richard Biener <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>

> Am 30.07.2026 um 23:18 schrieb Jakub Jelinek <[email protected]>:
> 
> Hi!
> 
> The following testcase is miscompiled.
> We have 2 different simplifications
> (a & b) ^ (a == b) -> !(a | b)
> (a & b) == (a ^ b) -> !(a | b)
> where both a and b are truth_valued_p.  That doesn't mean they have
> boolean type, it means that either they have integral type with one bit
> precision (boolean, unsigned or signed) or they are result of comparisons
> etc.
> Now, because both a and b appear as operands of the same &, they necessarily
> have the same or uselessly compatible type.  For the first case, the a == b
> comparison necessarily has to have the same type too and so type is the same
> type as well.
> For the second case that is not the case, e.g. in the problematic
> testcase both a and b are unsigned _BitInt(1) while == has int type, but
> it could very well be also that a and b are results of comparisons etc.
> and have int type.
> Now, the comment properly uses ! for the replacement, but the replacement
> of the simplification actually uses bit_not, so ~.  ~ is fine for 1-bit
> precision, but not for wider ones.
> The following patch differentiates between the case when a and b have
> 1-bit precision type, then it ensures ~ is done in that type and only
> then it is converted to type, while for other cases it does ^ 1 instead.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?

Ok

Richard 

> 2026-07-30  Jakub Jelinek  <[email protected]>
> 
>    PR tree-optimization/126490
>    * match.pd ((a & b) == (a ^ b) -> !(a | b)): If @0 has
>    integral one bit precision type, use (convert:type ...) around the
>    bit_not just in case the comparison has a different result type
>    from the type of its operands.  Otherwise do that too but with
>    bit_not replaced with bit_xor with one of the appropriate type.
> 
>    * gcc.dg/torture/bitint-104.c: New test.
> 
> --- gcc/match.pd.jj    2026-07-30 10:30:26.284706405 +0200
> +++ gcc/match.pd    2026-07-30 16:14:57.423126308 +0200
> @@ -2720,7 +2720,10 @@ (define_operator_list SYNC_FETCH_AND_AND
>      second_op (eq bit_xor)
>  (simplify
>   (first_op:c (bit_and:c truth_valued_p@0 truth_valued_p@1) (second_op @0 @1))
> -    (bit_not (bit_ior @0 @1))))
> +   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
> +    && TYPE_PRECISION (TREE_TYPE (@0)) == 1)
> +    (convert:type (bit_not (bit_ior @0 @1)))
> +    (convert:type (bit_xor (bit_ior @0 @1) { build_one_cst (TREE_TYPE (@0)); })))))
> 
> /* Convert ~ (A - 1) or ~ (A + -1) to -A.  */
> (simplify
> --- gcc/testsuite/gcc.dg/torture/bitint-104.c.jj    2026-07-30 15:53:51.605133318 +0200
> +++ gcc/testsuite/gcc.dg/torture/bitint-104.c    2026-07-30 15:53:15.097577105 +0200
> @@ -0,0 +1,78 @@
> +/* PR tree-optimization/126490 */
> +/* { dg-do run { target bitint } } */
> +
> +typedef unsigned _BitInt(1) T;
> +
> +[[gnu::noipa]] int
> +foo (T a, T b)
> +{
> +  return ((a & b) == (a ^ b)) + 1;
> +}
> +
> +[[gnu::noipa]] int
> +bar (T a, T b)
> +{
> +  return ((a & b) == (a ^ b)) != 0;
> +}
> +
> +[[gnu::noipa]] int
> +baz (T a, T b)
> +{
> +  return ((a & b) == (a ^ b)) == 0;
> +}
> +
> +[[gnu::noipa]] int
> +qux (T a, T b)
> +{
> +  return ((a & b) == (a ^ b)) < 1;
> +}
> +
> +[[gnu::noipa]] int
> +corge (int a, int b)
> +{
> +  return (a & b) == (a ^ b);
> +}
> +
> +[[gnu::noipa]] int
> +garply (T a, T b)
> +{
> +  return ((a & b) ^ (a == b)) + 1;
> +}
> +
> +[[gnu::noipa]] int
> +fred (T a, T b)
> +{
> +  return ((a & b) ^ (a == b)) != 0;
> +}
> +
> +[[gnu::noipa]] int
> +xyzzy (T a, T b)
> +{
> +  return ((a & b) ^ (a == b)) == 0;
> +}
> +
> +[[gnu::noipa]] int
> +waldo (T a, T b)
> +{
> +  return ((a & b) ^ (a == b)) < 1;
> +}
> +
> +int
> +main ()
> +{
> +  for (int i = 0; i < 4; ++i)
> +    {
> +      int a = i & 1;
> +      int b = i >> 1;
> +      int c = corge (a, b);
> +      if (foo (a, b) != c + 1
> +          || bar (a, b) != (c != 0)
> +          || baz (a, b) != (c == 0)
> +          || qux (a, b) != (c < 1)
> +      || garply (a, b) != c + 1
> +          || fred (a, b) != (c != 0)
> +          || xyzzy (a, b) != (c == 0)
> +          || waldo (a, b) != (c < 1))
> +    __builtin_abort ();
> +    }
> +}
> 
>    Jakub
>
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.