]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Enhance bitwise_and::op1_range
authorAndrew MacLeod <amacleod@redhat.com>
Wed, 14 May 2025 15:32:58 +0000 (11:32 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Thu, 15 May 2025 17:07:34 +0000 (13:07 -0400)
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.

gcc/range-op.cc
gcc/testsuite/gcc.dg/pr116546.c [new file with mode: 0644]

index 06d357f5199f15fa099ceaa04e1be3df3f1528ec..e2b9c82bc7b77126722028842611e8e7bed7bf5c 100644 (file)
@@ -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 (file)
index 0000000..b82dc27
--- /dev/null
@@ -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" } } */