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


Reply via email to