diff mbox series

PR82547: Undetected overflow for UNSIGNED wide_ints

Message ID 871skq1wuc.fsf@linaro.org
State Accepted
Commit 2131f7f5b7fafad66c0ae3fcf91d531fc6f9ceb1
Headers show
Series PR82547: Undetected overflow for UNSIGNED wide_ints | expand

Commit Message

Richard Sandiford Nov. 22, 2017, 9:33 a.m. UTC
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?

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.

Comments

Richard Biener Nov. 22, 2017, 1:51 p.m. UTC | #1
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
diff mbox series

Patch

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