diff mbox series

[Fortran] -- Check for overflow integer exponentation

Message ID 20190614225644.GA28622@troutmask.apl.washington.edu
State New
Headers show
Series [Fortran] -- Check for overflow integer exponentation | expand

Commit Message

Steve Kargl June 14, 2019, 10:56 p.m. UTC
I have had this patch in my tree since the beginning of May.  
During constant folding, gfortran would not issue an error
for overflow for integer exponentation.  Bootstrapped 
and regression tested multiple times on x86_64-*-freebsd?
OK to commit?

2019-06-15  Steven G. Kargl  <kargl@gcc.gnu.org>

	* arith.c (arith_power): Rework overflow of an integer to an integer
	exponent.

2019-06-15  Steven G. Kargl  <kargl@gcc.gnu.org>

	* gfortran.dg/integer_exponentiation_4.f90: Update test.
	* gfortran.dg/integer_exponentiation_5.F90: Ditto.
	* gfortran.dg/no_range_check_1.f90: Ditto.

Comments

Jerry DeLisle June 14, 2019, 11:43 p.m. UTC | #1
On 6/14/19 3:56 PM, Steve Kargl wrote:
> I have had this patch in my tree since the beginning of May.
> During constant folding, gfortran would not issue an error
> for overflow for integer exponentation.  Bootstrapped
> and regression tested multiple times on x86_64-*-freebsd?
> OK to commit?
> 
> 2019-06-15  Steven G. Kargl  <kargl@gcc.gnu.org>
> 
> 	* arith.c (arith_power): Rework overflow of an integer to an integer
> 	exponent.
> 
> 2019-06-15  Steven G. Kargl  <kargl@gcc.gnu.org>
> 
> 	* gfortran.dg/integer_exponentiation_4.f90: Update test.
> 	* gfortran.dg/integer_exponentiation_5.F90: Ditto.
> 	* gfortran.dg/no_range_check_1.f90: Ditto.
> 

OK, thanks Steve
diff mbox series

Patch

Index: gcc/fortran/arith.c
===================================================================
--- gcc/fortran/arith.c	(revision 269260)
+++ gcc/fortran/arith.c	(working copy)
@@ -848,8 +848,6 @@  arith_power (gfc_expr *op1, gfc_expr *op2, gfc_expr **
 	    {
 	    case BT_INTEGER:
 	      {
-		int power;
-
 		/* First, we simplify the cases of op1 == 1, 0 or -1.  */
 		if (mpz_cmp_si (op1->value.integer, 1) == 0)
 		  {
@@ -884,29 +882,36 @@  arith_power (gfc_expr *op1, gfc_expr *op2, gfc_expr **
 				       "exponent of integer has zero "
 				       "result at %L", &result->where);
 		  }
-		else if (gfc_extract_int (op2, &power))
+		else
 		  {
-		    /* If op2 doesn't fit in an int, the exponentiation will
-		       overflow, because op2 > 0 and abs(op1) > 1.  */
-		    mpz_t max;
-		    int i;
-		    i = gfc_validate_kind (BT_INTEGER, result->ts.kind, false);
+		    /* We have abs(op1) > 1 and op2 > 1.
+		       If op2 > bit_size(op1), we'll have an out-of-range
+		       result.  */
+		    int k, power;
 
-		    if (flag_range_check)
-		      rc = ARITH_OVERFLOW;
-
-		    /* Still, we want to give the same value as the
-		       processor.  */
-		    mpz_init (max);
-		    mpz_add_ui (max, gfc_integer_kinds[i].huge, 1);
-		    mpz_mul_ui (max, max, 2);
-		    mpz_powm (result->value.integer, op1->value.integer,
-			      op2->value.integer, max);
-		    mpz_clear (max);
+		    k = gfc_validate_kind (BT_INTEGER, op1->ts.kind, false);
+		    power = gfc_integer_kinds[k].bit_size;
+		    if (mpz_cmp_si (op2->value.integer, power) < 0)
+		      {
+			gfc_extract_int (op2, &power);
+			mpz_pow_ui (result->value.integer, op1->value.integer,
+				    power);
+			rc = gfc_range_check (result);
+			if (rc == ARITH_OVERFLOW)
+			  gfc_error_now ("Result of exponentiation at %L "
+					 "exceeds the range of %s", &op1->where,
+					 gfc_typename (&(op1->ts)));
+		      }
+		    else
+		      {
+			/* Provide a nonsense value to propagate up. */
+			mpz_set (result->value.integer,
+				 gfc_integer_kinds[k].huge);
+			mpz_add_ui (result->value.integer,
+				    result->value.integer, 1);
+			rc = ARITH_OVERFLOW;
+		      }
 		  }
-		else
-		  mpz_pow_ui (result->value.integer, op1->value.integer,
-			      power);
 	      }
 	      break;
 
Index: gcc/testsuite/gfortran.dg/integer_exponentiation_4.f90
===================================================================
--- gcc/testsuite/gfortran.dg/integer_exponentiation_4.f90	(revision 269260)
+++ gcc/testsuite/gfortran.dg/integer_exponentiation_4.f90	(working copy)
@@ -21,10 +21,10 @@  program test
   print *, (-1)**huge(0_8)
   print *, (-1)**(-huge(0_8)-1_8)
 
-  print *, 2**huge(0) ! { dg-error "Arithmetic overflow" }
-  print *, 2**huge(0_8) ! { dg-error "Arithmetic overflow" }
-  print *, (-2)**huge(0) ! { dg-error "Arithmetic overflow" }
-  print *, (-2)**huge(0_8) ! { dg-error "Arithmetic overflow" }
+  print *, 2**huge(0) ! { dg-error "Arithmetic overflow|exceeds the range" }
+  print *, 2**huge(0_8) ! { dg-error "Arithmetic overflow|exceeds the range" }
+  print *, (-2)**huge(0) ! { dg-error "Arithmetic overflow|exceeds the range" }
+  print *, (-2)**huge(0_8) ! { dg-error "Arithmetic overflow|exceeds the range" }
 
   print *, 2**(-huge(0)-1)
   print *, 2**(-huge(0_8)-1_8)
Index: gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90
===================================================================
--- gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90	(revision 269260)
+++ gcc/testsuite/gfortran.dg/integer_exponentiation_5.F90	(working copy)
@@ -67,8 +67,6 @@  program test
   TEST(3_8,43_8,i8)
   TEST(-3_8,43_8,i8)
 
-  TEST(17_8,int(huge(0_4),kind=8)+1,i8)
-
 !!!!! REAL BASE !!!!!
   TEST(0.0,-1,r4)
   TEST(0.0,-huge(0)-1,r4)
Index: gcc/testsuite/gfortran.dg/no_range_check_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/no_range_check_1.f90	(revision 269260)
+++ gcc/testsuite/gfortran.dg/no_range_check_1.f90	(working copy)
@@ -4,11 +4,8 @@ 
 ! This testcase arose from PR 31262
   integer :: a
   integer(kind=8) :: b
-  a = -3
   b = -huge(b) / 7
-  a = a ** 73
   b = 7894_8 * b - 78941_8
-  if ((-3)**73 /= a) STOP 1
   if (7894_8 * (-huge(b) / 7) - 78941_8 /= b) STOP 2
 
   a = 1234789786453123