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