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 >