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

Jakub Jelinek <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <amu_X4xamrm8llta@tucnak>
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?

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.