PR82547: Undetected overflow for UNSIGNED wide_ints
authorRichard Sandiford <richard.sandiford@linaro.org>
Wed, 22 Nov 2017 13:58:57 +0000 (13:58 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 22 Nov 2017 13:58:57 +0000 (13:58 +0000)
wi::add_large and wi::sub_large weren't setting the overflow bit
correctly for unsigned operations if the result needed fewer HWIs
than the precision.

2017-11-22  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
PR middle-end/82547
* wide-int.cc (wi::add_large, wi::sub_large): Fix overflow detection
for unsigned values with fewer HWIs than the precision.
(test_overflow): New function.
(wide_int_cc_tests): Call it.

From-SVN: r255059

gcc/ChangeLog
gcc/wide-int.cc

index ed0dc478547642119bfdf88a7ac52aff3f137943..e4efc762016ebdf763f544c52eb56696a400a15e 100644 (file)
@@ -1,3 +1,11 @@
+2017-11-22  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       PR middle-end/82547
+       * wide-int.cc (wi::add_large, wi::sub_large): Fix overflow detection
+       for unsigned values with fewer HWIs than the precision.
+       (test_overflow): New function.
+       (wide_int_cc_tests): Call it.
+
 2017-11-22  Richard Sandiford  <richard.sandiford@linaro.org>
 
        * emit-rtl.c (init_derived_machine_modes): Make sure ptr_mode
index ba0fd25b093fdf688e19c5f8583ed0189206ba23..ec4d1f36a3ce53892674c61ba5269776dac70b2c 100644 (file)
@@ -1158,7 +1158,7 @@ wi::add_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
       val[len] = mask0 + mask1 + carry;
       len++;
       if (overflow)
-       *overflow = false;
+       *overflow = (sgn == UNSIGNED && carry);
     }
   else if (overflow)
     {
@@ -1552,7 +1552,7 @@ wi::sub_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *op0,
       val[len] = mask0 - mask1 - borrow;
       len++;
       if (overflow)
-       *overflow = false;
+       *overflow = (sgn == UNSIGNED && borrow);
     }
   else if (overflow)
     {
@@ -2345,14 +2345,54 @@ static void run_all_wide_int_tests ()
   test_comparisons <VALUE_TYPE> ();
 }
 
+/* Test overflow conditions.  */
+
+static void
+test_overflow ()
+{
+  static int precs[] = { 31, 32, 33, 63, 64, 65, 127, 128 };
+  static int offsets[] = { 16, 1, 0 };
+  for (unsigned int i = 0; i < ARRAY_SIZE (precs); ++i)
+    for (unsigned int j = 0; j < ARRAY_SIZE (offsets); ++j)
+      {
+       int prec = precs[i];
+       int offset = offsets[j];
+       bool overflow;
+       wide_int sum, diff;
+
+       sum = wi::add (wi::max_value (prec, UNSIGNED) - offset, 1,
+                      UNSIGNED, &overflow);
+       ASSERT_EQ (sum, -offset);
+       ASSERT_EQ (overflow, offset == 0);
+
+       sum = wi::add (1, wi::max_value (prec, UNSIGNED) - offset,
+                      UNSIGNED, &overflow);
+       ASSERT_EQ (sum, -offset);
+       ASSERT_EQ (overflow, offset == 0);
+
+       diff = wi::sub (wi::max_value (prec, UNSIGNED) - offset,
+                       wi::max_value (prec, UNSIGNED),
+                       UNSIGNED, &overflow);
+       ASSERT_EQ (diff, -offset);
+       ASSERT_EQ (overflow, offset != 0);
+
+       diff = wi::sub (wi::max_value (prec, UNSIGNED) - offset,
+                       wi::max_value (prec, UNSIGNED) - 1,
+                       UNSIGNED, &overflow);
+       ASSERT_EQ (diff, 1 - offset);
+       ASSERT_EQ (overflow, offset > 1);
+    }
+}
+
 /* Run all of the selftests within this file, for all value types.  */
 
 void
 wide_int_cc_tests ()
 {
- run_all_wide_int_tests <wide_int> ();
- run_all_wide_int_tests <offset_int> ();
- run_all_wide_int_tests <widest_int> ();
+  run_all_wide_int_tests <wide_int> ();
+  run_all_wide_int_tests <offset_int> ();
+  run_all_wide_int_tests <widest_int> ();
+  test_overflow ();
 }
 
 } // namespace selftest