On Wed, Nov 22, 2017 at 10:33 AM, Richard Sandiford
<richard.sandif...@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.sandif...@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

Reply via email to