https://gcc.gnu.org/g:ac55655ce45a237a6a01e0cce50211841603c2ec
commit r16-665-gac55655ce45a237a6a01e0cce50211841603c2ec Author: Andrew MacLeod <amacl...@redhat.com> Date: Wed May 14 11:32:58 2025 -0400 Enhance bitwise_and::op1_range Any known bits from the LHS range can be used to specify known bits in the non-mask operand. PR tree-optimization/116546 gcc/ * range-op.cc (operator_bitwise_and::op1_range): Utilize bitmask from the LHS to improve op1's bitmask. gcc/testsuite/ * gcc.dg/pr116546.c: New. Diff: --- gcc/range-op.cc | 22 +++++++++++++++++++- gcc/testsuite/gcc.dg/pr116546.c | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 06d357f5199f..e2b9c82bc7b7 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3716,14 +3716,34 @@ operator_bitwise_and::op1_range (irange &r, tree type, return true; } + if (!op2.singleton_p (mask)) + return true; + // For 0 = op1 & MASK, op1 is ~MASK. - if (lhs.zero_p () && op2.singleton_p ()) + if (lhs.zero_p ()) { wide_int nz = wi::bit_not (op2.get_nonzero_bits ()); int_range<2> tmp (type); tmp.set_nonzero_bits (nz); r.intersect (tmp); } + + irange_bitmask lhs_bm = lhs.get_bitmask (); + // given [5,7] mask 0x3 value 0x4 = N & [7, 7] mask 0x0 value 0x7 + // Nothing is known about the bits not specified in the mask value (op2), + // Start with the mask, 1's will occur where values were masked. + wide_int op1_mask = ~mask; + // Any bits that are unknown on the LHS are also unknown in op1, + // so union the current mask with the LHS mask. + op1_mask |= lhs_bm.mask (); + // The resulting zeros correspond to known bits in the LHS mask, and + // the LHS value should tell us what they are. Mask off any + // extraneous values thats are not convered by the mask. + wide_int op1_value = lhs_bm.value () & ~op1_mask; + irange_bitmask op1_bm (op1_value, op1_mask); + // INtersect this mask with anything already known about the value. + op1_bm.intersect (r.get_bitmask ()); + r.update_bitmask (op1_bm); return true; } diff --git a/gcc/testsuite/gcc.dg/pr116546.c b/gcc/testsuite/gcc.dg/pr116546.c new file mode 100644 index 000000000000..b82dc27f4522 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr116546.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +extern long foo (void); +extern long bar (void); + +long +test1 (long n) +{ + n &= 7; + if (n == 4) { + if (n & 4) + return foo (); + else + return bar (); + } + return 0; +} + +long +test2 (long n) +{ + n &= 7; + if (n > 4) { + if (n & 4) + return foo (); + else + return bar (); + } + return 0; +} + +long +test3 (long n) +{ + n &= 7; + if (n >= 4) { + if (n & 4) + return foo (); + else + return bar (); + } + return 0; +} + +/* { dg-final { scan-tree-dump-not "bar" "evrp" } } */