aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@linaro.org>2017-11-22 13:58:57 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2017-11-22 13:58:57 +0000
commit2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1 (patch)
treedde1145642e089c705eba8a6de288f81437c2a6a
parenta76ef9c5a8447bf3e90ed832ef1286cda205e115 (diff)
downloadgcc-2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1.zip
gcc-2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1.tar.gz
gcc-2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1.tar.bz2
PR82547: Undetected overflow for UNSIGNED wide_ints
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
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/wide-int.cc50
2 files changed, 53 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ed0dc47..e4efc76 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,13 @@
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
has the same mode class as Pmode.
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index ba0fd25..ec4d1f3 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -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