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" } } */

Reply via email to