>From 5e592f98e7cd79b3097bedeb2d39bd8e448adf4e Mon Sep 17 00:00:00 2001
From: Kael Andrew Alonzo Franco <[email protected]>
Date: Wed, 8 Jul 2026 18:43:32 -0400
Subject: [PATCH] match: Fold (X + C) + (Y & ~C) to X + (Y | C) [PR126173]
Since `Y & ~C` clears all bits set in C, adding C cannot generate carry
through those bits and is equivalent to setting them with `or`.
Bootstrapped and tested on x86_64-pc-linux-gnu.
PR tree-optimization/126173
gcc/ChangeLog:
* match.pd: Fold (X + C) + (Y & ~C) to X + (Y | C).
gcc/testsuite/ChangeLog:
* gcc.dg/pr126173.c: New test.
Signed-off-by: Kael Franco <[email protected]>
---
gcc/match.pd | 6 ++++++
gcc/testsuite/gcc.dg/pr126173.c | 12 ++++++++++++
2 files changed, 18 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr126173.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 4520a23a026..1e1885d16d4 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1952,6 +1952,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op:c (bit_and @0 @1) (bit_xor @0 @1))
(bit_ior @0 @1)))
+/* (y & ~c) + (x + c) -> ((y | c) + x) */
+(simplify
+ (plus:c (bit_and @1 INTEGER_CST@3) (plus @0 INTEGER_CST@2))
+ (if (wi::eq_p (wi::bit_not (wi::to_wide (@3)), wi::to_wide (@2)))
+ (plus (bit_ior @1 @2) @0)))
+
/* (x & y) + (x | y) -> x + y */
(simplify
(plus:c (bit_and @0 @1) (bit_ior @0 @1))
diff --git a/gcc/testsuite/gcc.dg/pr126173.c b/gcc/testsuite/gcc.dg/pr126173.c
new file mode 100644
index 00000000000..9d5d9e86849
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126173.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#define C 10
+
+_Bool
+x_plus_c_plus_y_and_not_c (int X, int Y)
+{
+ return ((X + C) + (Y & ~C)) == (X + (Y | C));
+}
+
+/* { dg-final { scan-tree-dump-times "return 1;" 1 "optimized" } } */
--
2.55.0