On 7/29/2026 2:56 AM, Avinal Kumar wrote:
The expression (A | C) == A tests if all the bits in C are already set
in A. When C is a power of 2, this is equivalent to (A & C) != 0 which
avoids OR and compares against 0 instead of original value thus
optimizing the comparison.
Similarly (A | C) != A can be optimized to (A & C) == 0.
PR tree-optimization/101650
gcc/ChangeLog:
* match.pd: Simplify (A | C) == A to (A & C) != 0 when C is
power of 2.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/bitcmp-7.c: New test.
Signed-off-by: Avinal Kumar <[email protected]>
---
Bootstrapped and ran full test suite on x86_64 Fedora Linux.
Output for this particular patch test:
cat gcc/testsuite/gcc/gcc.sum | grep bitcmp-7
PASS: gcc.dg/tree-ssa/bitcmp-7.c (test for excess errors)
PASS: gcc.dg/tree-ssa/bitcmp-7.c scan-tree-dump-not optimized "\\| 4"
PASS: gcc.dg/tree-ssa/bitcmp-7.c scan-tree-dump-times optimized " & 4" 2
I also included some whitespace changes in some comments. Please let me know
if they should be a separate change.
In general formatting fixes should be distinct changes unless they're
directly in the space you're working. These cases touch independent
patterns so an independent patch would be better. This policy is mostly
to make it easier to review by avoiding unnecessary diffs. It's also
the case that many formatting changes can go in without review under our
trivial/obvious guidelines. But I don't think it's worth splitting
these out this time. This is mostly a note for future contributions.
@@ -8270,6 +8270,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp (bit_and@2 @0 integer_pow2p@1) @1)
(icmp @2 { build_zero_cst (TREE_TYPE (@0)); })))
+/* If we have (A | C) == A where C is a power of 2, convert this into
+ (A & C) != 0. Similarly for NE_EXPR. */
+(for cmp (eq ne)
+ icmp (ne eq)
+ (simplify
+ (cmp:c (bit_ior @0 integer_pow2p@1) @0)
+ (icmp (bit_and @0 @1) { build_zero_cst (TREE_TYPE (@0)); })))
+
So this is going to result in generating more bit test instructions
rather than generalized comparisons on targets which support bit
testing. On targets without bit test, we'll generate an eq/ne test
against zero which often encodes more efficiently than a test against an
arbitrary constant. So definitely a good transformation IMHO.
It would initially seem this is redundant with this pattern earlier in
match.pd:
|/* (X | Y) == Y becomes (X & ~Y) == 0. */ (simplify (cmp:c (bit_ior:c
@0 @1) @1) (cmp (bit_and @0 (bit_not! @1)) { build_zero_cst (TREE_TYPE
(@0)); }))|
So the main question/concern I have is why didn't the existing earlier
rule in match.pd fire? Presumably the "!" modifier on the bit_not is
rejecting the rewritten pattern?
Overall it looks good, I just want to make sure we're not utilizing the
more general pattern for a good reason.
jeff