Message ID | 871skq1wuc.fsf@linaro.org |
---|---|
State | Accepted |
Commit | 2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1 |
Headers | show |
Series | PR82547: Undetected overflow for UNSIGNED wide_ints | expand |
On Wed, Nov 22, 2017 at 10:33 AM, Richard Sandiford <richard.sandiford@linaro.org> wrote: > 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. > > Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64le-linux-gnu. > OK to install? Ok. Richard. > Richard > > > 2017-11-21 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. > > Index: gcc/wide-int.cc > =================================================================== > --- gcc/wide-int.cc 2017-11-22 09:21:12.516930172 +0000 > +++ gcc/wide-int.cc 2017-11-22 09:33:00.427739376 +0000 > @@ -1158,7 +1158,7 @@ wi::add_large (HOST_WIDE_INT *val, const > 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 > 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
Index: gcc/wide-int.cc =================================================================== --- gcc/wide-int.cc 2017-11-22 09:21:12.516930172 +0000 +++ gcc/wide-int.cc 2017-11-22 09:33:00.427739376 +0000 @@ -1158,7 +1158,7 @@ wi::add_large (HOST_WIDE_INT *val, const 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 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