diff options
author | Richard Sandiford <richard.sandiford@linaro.org> | 2017-11-22 13:58:57 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2017-11-22 13:58:57 +0000 |
commit | 2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1 (patch) | |
tree | dde1145642e089c705eba8a6de288f81437c2a6a | |
parent | a76ef9c5a8447bf3e90ed832ef1286cda205e115 (diff) | |
download | gcc-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/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/wide-int.cc | 50 |
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 |