]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Improve contains_p and intersect with bitmasks.
authorAndrew MacLeod <amacleod@redhat.com>
Wed, 28 May 2025 20:27:16 +0000 (16:27 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Wed, 18 Jun 2025 17:49:20 +0000 (13:49 -0400)
Improve the way contains_p (wide_int) and intersect behave wioth
singletons and bitmasks.  Also fix a buglet in bitmask_intersect when the
result is a singleton which is not in the current range.

PR tree-optimization/119039
gcc/
* value-range.cc (irange::contains_p): Call wide_int version of
contains_p for singleton ranges.
(irange::intersect): If either range is a singleton, use
contains_p.

gcc/testsuite/
* gcc.dg/pr119039-2.c: New.

gcc/testsuite/gcc.dg/pr119039-2.c [new file with mode: 0644]
gcc/value-range.cc

diff --git a/gcc/testsuite/gcc.dg/pr119039-2.c b/gcc/testsuite/gcc.dg/pr119039-2.c
new file mode 100644 (file)
index 0000000..634b400
--- /dev/null
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+extern void good (void);
+extern void bad (void);
+
+/* Switch simplification should remove 'case 2:' because 'i' will always
+ * have its 0th bit set (odd). */
+
+void bitmask_elimination_1(int i)
+{
+  i = i | 1;
+
+  switch (i)
+    {
+    case 1:
+      good ();
+      break;
+
+    // This case should be removed;
+    case 2:
+      bad ();
+      break;
+
+    case 3:
+      good ();
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* Switch simplification should remove 'case 20-28:' because 'i' will always
+ * be a multiple of 16.  */
+void bitmask_elimination_2 (int i)
+{
+  int masked_val = i & 0xF0; // This zeroes out the lower 4 bits of 'i'
+
+  switch (masked_val)
+  {
+    case 0:
+      good (); // Reachable.
+      break;
+
+    // This entire cased should be removed;
+    case 20 ... 28:
+      bad ();
+      break;
+
+    case 32:
+      good (); // Reachable.
+      break;
+
+    default:
+      good ();
+      break;
+  }
+}
+/* { dg-final { scan-tree-dump-not "bad" "evrp" } } */
index 5e97fdb76919df23dc5ad54b5e1073626ca06759..348c68ec902e348f35594b0646b6a765da171a72 100644 (file)
@@ -1628,10 +1628,8 @@ irange::contains_p (const wide_int &cst) const
   if (undefined_p ())
     return false;
 
-  // See if we can exclude CST based on the known 0 bits.
-  if (!m_bitmask.unknown_p ()
-      && cst != 0
-      && wi::bit_and (m_bitmask.get_nonzero_bits (), cst) == 0)
+  // Check is the known bits in bitmask exclude CST.
+  if (!m_bitmask.member_p (cst))
     return false;
 
   signop sign = TYPE_SIGN (type ());
@@ -1899,12 +1897,17 @@ irange::irange_contains_p (const irange &r) const
   gcc_checking_assert (!undefined_p () && !varying_p ());
   gcc_checking_assert (!r.undefined_p () && !varying_p ());
 
+  // Check singletons directly which will include any bitmasks.
+  wide_int rl;
+  if (r.singleton_p (rl))
+    return contains_p (rl);
+
   // In order for THIS to fully contain R, all of the pairs within R must
   // be fully contained by the pairs in this object.
   signop sign = TYPE_SIGN (m_type);
   unsigned ri = 0;
   unsigned i = 0;
-  wide_int rl = r.m_base[0];
+  rl = r.m_base[0];
   wide_int ru = r.m_base[1];
   wide_int l = m_base[0];
   wide_int u = m_base[1];
@@ -1973,6 +1976,16 @@ irange::intersect (const vrange &v)
       return res;
     }
 
+  // If either range is a singleton and the other range does not contain
+  // it, the result is undefined.
+  wide_int val;
+  if ((singleton_p (val) && !r.contains_p (val))
+      || (r.singleton_p (val) && !contains_p (val)))
+    {
+      set_undefined ();
+      return true;
+    }
+
   // If R fully contains this, then intersection will change nothing.
   if (r.irange_contains_p (*this))
     return intersect_bitmask (r);