]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Remove negative ranges using trailing zero masks.
authorAndrew MacLeod <amacleod@redhat.com>
Fri, 9 May 2025 00:28:11 +0000 (20:28 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Tue, 13 May 2025 00:10:34 +0000 (20:10 -0400)
When there are trailing 0's in the bitmask, set_range_from_bitmask () removes
the lower positive ranges which do not match the value.  This reworks it to
provide the same functionailty for the negative ranges in signed types.
If the lower 4 bits are all 0:
  int [-INF, +INF] MASK 0xfffffff0 VALUE 0x0
becomes:
  int [-INF,  -16][0, 0][16, 2147483632] MASK 0xfffffff0 VALUE 0x0

gcc/
* tree-ssanames.cc (set_bitmask): Use int_range_max for temps.
* value-range.cc (irange::set_range_from_bitmask): Handle all
trailing zero values.

gcc/testsuite/
* gcc.dg/tree-ssa/vrp124.c: New.

gcc/testsuite/gcc.dg/tree-ssa/vrp124.c [new file with mode: 0644]
gcc/tree-ssanames.cc
gcc/value-range.cc

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
new file mode 100644 (file)
index 0000000..789b550
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+/* Test removal of trailing zero mask ranges from signed values. */
+/* Mask off the lower 4 bits of an integer. */
+#define MASK 0XF
+
+void dead (int c);
+void keep();
+
+/* A signed character should have a range something like : */
+/* int [-INF, -16][0, 0][16, 2147483632] MASK 0xfffffff0 VALUE 0x0 */
+
+int
+foo2 (int c)
+{
+  c = c & ~MASK;
+  if (c == 0)
+    return 0;
+  if (c > -16)
+    {
+      keep ();
+      if (c < 16)
+       dead (c);
+    }
+  if (c > (__INT_MAX__ & ~MASK))
+    dead (c);
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "dead" "evrp" } } */
index de7b9b79f948640cba515bbc3ff61d4279ab8830..fd2abfe0745dc47799bddfed1bb524630e71f94c 100644 (file)
@@ -488,7 +488,7 @@ set_bitmask (tree name, const wide_int &value, const wide_int &mask)
 {
   gcc_assert (!POINTER_TYPE_P (TREE_TYPE (name)));
 
-  int_range<2> r (TREE_TYPE (name));
+  int_range_max r (TREE_TYPE (name));
   r.update_bitmask (irange_bitmask (value, mask));
   set_range_info (name, r);
 }
index a770b41b474ae77bf8449b207f621773c8fdc630..d2c14e7900dff260371365218f138853d5660467 100644 (file)
@@ -2286,7 +2286,7 @@ irange::set_range_from_bitmask ()
       if (has_zero)
        {
          int_range<2> zero;
-         zero.set_zero (type ());
+         zero.set_zero (m_type);
          union_ (zero);
        }
       if (flag_checking)
@@ -2295,31 +2295,58 @@ irange::set_range_from_bitmask ()
     }
   else if (popcount == 0)
     {
-      set_zero (type ());
+      set_zero (m_type);
       return true;
     }
 
-  // If the mask doesn't have any trailing zero, return.
+  // If the mask doesn't have a trailing zero, theres nothing to filter.
   int z = wi::ctz (m_bitmask.mask ());
   if (!z)
     return false;
 
-  // Remove trailing ranges that this bitmask indicates can't exist.
-  int_range_max mask_range;
-  int prec = TYPE_PRECISION (type ());
-  wide_int ub = (wi::one (prec) << z) - 1;
-  mask_range = int_range<2> (type (), wi::zero (prec), ub);
+  int prec = TYPE_PRECISION (m_type);
+  wide_int value = m_bitmask.value ();
+  wide_int mask = m_bitmask.mask ();
 
-  // Then remove the specific value these bits contain from the range.
-  wide_int value = m_bitmask.value () & ub;
-  mask_range.intersect (int_range<2> (type (), value, value, VR_ANTI_RANGE));
+  // Remove the [0, X] values which the trailing-zero mask rules out.
+  // For example, if z == 4, the mask is 0xFFF0, and the lowest 4 bits
+  // define the range [0, 15]. Only one of which (value & low_mask) is allowed.
+  wide_int ub = (wi::one (prec) << z) - 1;  // Upper bound of affected range.
+  int_range_max mask_range (m_type, wi::zero (prec), ub);
 
-  // Inverting produces a list of ranges which can be valid.
+  // Remove the one valid value from the excluded range and form an anti-range.
+  wide_int allow = value & ub;
+  mask_range.intersect (int_range<2> (m_type, allow, allow, VR_ANTI_RANGE));
+
+  // Invert it to get the allowed values and intersect it with the main range.
   mask_range.invert ();
+  bool changed = intersect (mask_range);
 
-  // And finally select R from only those valid values.
-  intersect (mask_range);
-  return true;
+  // Now handle the rest of the domain — the upper side for positive values,
+  // or [-X, -1] for signed negatives.
+  // Compute the maximum value representable under the mask/value constraint.
+  ub = mask | value;
+
+  // If value is non-negative, adjust the upper limit to remove values above
+  // UB that conflict with known fixed bits.
+  if (TYPE_SIGN (m_type) == UNSIGNED || wi::clz (ub) > 0)
+    mask_range = int_range<1> (m_type, wi::zero (prec), ub);
+  else
+    {
+      // For signed negative values, find the lowest value with trailing zeros.
+      // This forms a range such as [-512, -1] for z=9.
+      wide_int lb = -(wi::one (prec) << z);
+      mask_range = int_range<2> (m_type, lb, wi::minus_one (prec));
+
+      // Remove the one allowed value from that set.
+      allow = value | lb;
+      mask_range.intersect (int_range<2> (m_type, allow, allow, VR_ANTI_RANGE));
+      mask_range.invert ();
+    }
+
+  // Make sure we call intersect, so do it first.
+  changed = intersect (mask_range) | changed;
+  return changed;
 }
 
 void