Add two patterns to eliminate mispredicts in the following bit ops
scenarios:

- checking if a bitmask is not set, and in this case set it: always set
  the bitmask;
- checking if a bitmask is set, and in this case clear it: always clear
  the bitmask.

Bootstrapped and tested with x86_64-pc-linux-gnu.

        PR tree-optimization/64567

gcc/ChangeLog:

        * match.pd (`cond (bit_and A IMM) (bit_or A IMM) A`): New
        pattern.
        (`cond (bit_and A IMM) (bit_and A ~IMM) A`): New pattern.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/PR64567.c: New test.
---

Changes from v1:
- changed approach from phiopt to match.pd
- renamed new test from "PR64567.c" to "pr64567.c"
- v1 link: https://gcc.gnu.org/pipermail/gcc-patches/2026-February/708492.html

 gcc/match.pd                            | 21 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr64567.c | 23 +++++++++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr64567.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 8910591a04b..d1831e90472 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6316,6 +6316,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
               && !expand_vec_cond_expr_p (TREE_TYPE (@1), TREE_TYPE (@0)))))
    (vec_cond @0 (op!:type @3 @1) (op!:type @3 @2)))))
 
+/* If we have a "if a bitmask is not set, set it" case,
+   just set the bitmask all the time (see PR 64567).  */
+(simplify
+ (cond (eq (bit_and @0 @1) integer_zerop) (bit_ior@2 @0 @1) @0)
+ @2)
+
+/* A clear bit version of the above: "if a bitmask is
+   set, clear it". In this case always clear the bitmask
+   (see PR 64567).  */
+(simplify
+ (cond (ne (bit_and @0 INTEGER_CST@1) integer_zerop)
+       (bit_and@3 @0 INTEGER_CST@2) @0)
+  (with
+    {
+      wide_int cond_imm = wi::to_wide (@1);
+      wide_int mid_imm = wi::to_wide (@2);
+    }
+   (if (wi::ltu_p (cond_imm, mid_imm)
+       && wi::eq_p (mid_imm, wi::bit_not (cond_imm)))
+    @3)))
+
 #if GIMPLE
 (match (nop_atomic_bit_test_and_p @0 @1 @4)
  (bit_and (convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64567.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr64567.c
new file mode 100644
index 00000000000..09e8cee62ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64567.c
@@ -0,0 +1,23 @@
+/* { dg-additional-options -O2 } */
+/* { dg-additional-options -fdump-tree-phiopt } */
+
+#define F1 0x04
+#define F2 0x08
+
+int bar(unsigned flags);
+
+int foo(unsigned flags)
+{
+  if (flags & (F1 | F2))
+    flags &= ~(F1 | F2);
+  return bar(flags);
+}
+
+int baz(unsigned flags)
+{
+  if (!(flags & F1))
+    flags |= F1;
+  return bar(flags);
+}
+
+/* { dg-final { scan-tree-dump-times " PHI " 0 phiopt2 } } */
-- 
2.43.0

Reply via email to