https://gcc.gnu.org/g:c40a4cc2d943d8572a62f21d3eb1d4171e51d5ac

commit r16-577-gc40a4cc2d943d8572a62f21d3eb1d4171e51d5ac
Author: Andrew MacLeod <amacl...@redhat.com>
Date:   Thu May 8 20:28:11 2025 -0400

    Remove negative ranges using trailing zero masks.
    
    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.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/vrp124.c | 31 ++++++++++++++++++
 gcc/tree-ssanames.cc                   |  2 +-
 gcc/value-range.cc                     | 57 +++++++++++++++++++++++++---------
 3 files changed, 74 insertions(+), 16 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
new file mode 100644
index 000000000000..789b550f88d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp124.c
@@ -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" } } */
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index de7b9b79f948..fd2abfe0745d 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -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);
 }
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index a770b41b474a..d2c14e7900df 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -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

Reply via email to