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

Reply via email to