https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97555

--- Comment #4 from Aldy Hernandez <aldyh at gcc dot gnu.org> ---
The problem here is we're trying to add 1 to a -1 in a signed 1-bit field.

Signed 1-bits are annoying because you can't really add or subtract one,
because the one is unrepresentable.  For invert() we have a special
subtract_one() function that handles 1-bit signed fields.  We need a
corresponding add_one() here.

The untested patch below should do it. 

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index ee62f103598..74ab2e57fde 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3680,15 +3680,28 @@ range_tests ()
   // Test 1-bit signed integer union.
   // [-1,-1] U [0,0] = VARYING.
   tree one_bit_type = build_nonstandard_integer_type (1, 0);
+  tree one_bit_min = vrp_val_min (one_bit_type);
+  tree one_bit_max = vrp_val_max (one_bit_type);
   {
-    tree one_bit_min = vrp_val_min (one_bit_type);
-    tree one_bit_max = vrp_val_max (one_bit_type);
     int_range<2> min (one_bit_min, one_bit_min);
     int_range<2> max (one_bit_max, one_bit_max);
     max.union_ (min);
     ASSERT_TRUE (max.varying_p ());
   }

+  // Test inversion of 1-bit signed integers.
+  {
+    int_range<2> min (one_bit_min, one_bit_min);
+    int_range<2> max (one_bit_max, one_bit_max);
+    int_range<2> t;
+    t = min;
+    t.invert ();
+    ASSERT_TRUE (t == max);
+    t = max;
+    t.invert ();
+    ASSERT_TRUE (t == min);
+  }
+
   // Test that NOT(255) is [0..254] in 8-bit land.
   int_range<1> not_255 (UCHAR (255), UCHAR (255), VR_ANTI_RANGE);
   ASSERT_TRUE (not_255 == int_range<1> (UCHAR (0), UCHAR (254)));
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 7847104050c..f45a342605a 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1772,18 +1772,29 @@ irange::irange_intersect (const irange &r)
     verify_range ();
 }

+// Signed 1-bits are strange.  You can't subtract 1, because you can't
+// represent the number 1.  This works around that for the invert routine.
+
 static wide_int inline
 subtract_one (const wide_int &x, tree type, wi::overflow_type &overflow)
 {
-  // A signed 1-bit bit-field, has a range of [-1,0] so subtracting +1
-  // overflows, since +1 is unrepresentable.  This is why we have an
-  // addition of -1 here.
   if (TYPE_SIGN (type) == SIGNED)
-    return wi::add (x, -1 , SIGNED, &overflow);
+    return wi::add (x, -1, SIGNED, &overflow);
   else
     return wi::sub (x, 1, UNSIGNED, &overflow);
 }

+// The analogous function for adding 1.
+
+static wide_int inline
+add_one (const wide_int &x, tree type, wi::overflow_type &overflow)
+{
+  if (TYPE_SIGN (type) == SIGNED)
+    return wi::sub (x, -1, SIGNED, &overflow);
+  else
+    return wi::add (x, 1, TYPE_SIGN (type), &overflow);
+}
+
 /* Return the inverse of a range.  */

 void
@@ -1881,7 +1892,7 @@ irange::invert ()
   // set the overflow bit.
   if (type_max != wi::to_wide (orig_range.m_base[i]))
     {
-      tmp = wi::add (wi::to_wide (orig_range.m_base[i]), 1, sign, &ovf);
+      tmp = add_one (wi::to_wide (orig_range.m_base[i]), ttype, ovf);
       m_base[nitems++] = wide_int_to_tree (ttype, tmp);
       m_base[nitems++] = wide_int_to_tree (ttype, type_max);
       if (ovf)

Reply via email to