https://gcc.gnu.org/g:73824bffde7a2226a864313546f8f0bd127a22b7

commit r16-5896-g73824bffde7a2226a864313546f8f0bd127a22b7
Author: Daniel Barboza <[email protected]>
Date:   Thu Nov 27 22:03:18 2025 -0300

    match.pd: x&c ?(x op c):(x|c) -> x^c [PR122615, PR122616]
    
    Add a single pattern to reduce these patterns to "x ^ c":
    
    x & c ? (x - c) | (x | c)
    x & c ? (x & ~c) | (x | c)
    
    As long as "c" has a single bit set.
    
            PR tree-optimization/122615
            PR tree-optimization/122616
    
    gcc/ChangeLog:
    
            * match.pd (`x & c ? (x - c) | (x | c)`): New pattern.
            (`x & c ? (x & ~c) | (x | c)`): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/torture/pr122615.c: New test.
            * gcc.dg/torture/pr122616.c: Likewise.
    
    Co-authored-by: Jeff Law <[email protected]>
    Signed-off-by: Daniel Barboza <[email protected]>

Diff:
---
 gcc/match.pd                            | 16 ++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr122615.c | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr122616.c | 22 ++++++++++++++++++++++
 3 files changed, 60 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index f164ec591008..bf410a75f5f8 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6617,6 +6617,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        (convert (minus { arg; } (convert:type1 @0))))))))))
 #endif
 
+/* X & C1 ? (X + -C1) : (X | C1) -> X ^ C1
+   X & C1 ? (X & ~C1) : (X | C1) -> X ^ C1
+   when C1 has a single bit set.  */
+(for op (plus bit_and)
+ (simplify
+  (cond (ne (bit_and @0 INTEGER_CST@1) integer_zerop)
+            (op @0 INTEGER_CST@2) (bit_ior @0 @1))
+   (with {
+     auto c1 = wi::to_wide (@1);
+     auto c2 = wi::to_wide (@2);
+    }
+    (if (wi::popcount (c1) == 1
+         && ((op == PLUS_EXPR && wi::eq_p (wi::neg (c2), c1))
+              || (op == BIT_AND_EXPR && wi::eq_p (wi::bit_not (c2), c1))))
+         (bit_xor @0 @1)))))
+
 (simplify
  (convert (cond@0 @1 INTEGER_CST@2 INTEGER_CST@3))
  (if (INTEGRAL_TYPE_P (type)
diff --git a/gcc/testsuite/gcc.dg/torture/pr122615.c 
b/gcc/testsuite/gcc.dg/torture/pr122615.c
new file mode 100644
index 000000000000..9f4f3c49a016
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr122615.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+int f1 (int x)
+{
+  return x & 1 ? (x & ~1) : (x | 1);
+}
+
+int f2 (int x)
+{
+  return x & 2 ? (x & ~2) : (x | 2);
+}
+
+int f3 (int x)
+{
+  return x & 3 ? (x & ~3) : (x | 3);
+}
+
+/* { dg-final { scan-tree-dump-times "x \\^ 1" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "x \\^ 2" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "x \\^ 3" 0 "original" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr122616.c 
b/gcc/testsuite/gcc.dg/torture/pr122616.c
new file mode 100644
index 000000000000..77d364ef2f47
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr122616.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-original" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+int f1 (int x)
+{
+  return x & 1 ? (x - 1) : (x | 1);
+}
+
+int f2 (int x)
+{
+  return x & 2 ? (x - 2) : (x | 2);
+}
+
+int f3 (int x)
+{
+  return x & 3 ? (x - 3) : (x | 3);
+}
+
+/* { dg-final { scan-tree-dump-times "x \\^ 1" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "x \\^ 2" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "x \\^ 3" 0 "original" } } */

Reply via email to