re PR fortran/63427 (hwint.h:250:29: runtime error: shift exponent 64 is too large...
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 23 Feb 2015 23:02:50 +0000 (23:02 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 23 Feb 2015 23:02:50 +0000 (23:02 +0000)
gcc/
PR fortran/63427
* wide-int.cc (wi::from_mpz): Cope with unwrapped values that are
too big for a wide_int.  Implement missing wrapping operation.

gcc/testsuite/
PR fortran/63427
* gfortran.dg/integer_exponentiation_6.F90: New test.

From-SVN: r220921

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90 [new file with mode: 0644]
gcc/wide-int.cc

index 5a652bce77ff1a8f714b24d42d196bf7c07ed714..0bc898e9e8f3aa4149b732208ae722b92170dfcd 100644 (file)
@@ -1,3 +1,9 @@
+2015-02-23  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR fortran/63427
+       * wide-int.cc (wi::from_mpz): Cope with unwrapped values that are
+       too big for a wide_int.  Implement missing wrapping operation.
+
 2015-02-23  Oleg Endo  <olegendo@gcc.gnu.org>
 
        PR target/65163
index e695467666a567a0ef916256d2ffa5bbb14cff46..ff48d0a8bf3097e8ad2452241ee8d3f6cffc6ad5 100644 (file)
@@ -1,3 +1,8 @@
+2015-02-23  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR fortran/63427
+       * gfortran.dg/integer_exponentiation_6.F90: New test.
+
 2015-02-23  Martin Sebor  <msebor@redhat.com>
 
        PR target/65109
diff --git a/gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90 b/gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90
new file mode 100644 (file)
index 0000000..55c2543
--- /dev/null
@@ -0,0 +1,4 @@
+! { dg-options "-fno-range-check" }
+program test
+  write (*), (2_8 ** 64009999_8) / 2
+end program test
index fd7cbb4c3843514d4b81ab2d8d15cf66b6e3c89e..7662648c20ed1a4ea9a5536a0abf04bc13e6edf2 100644 (file)
@@ -237,7 +237,7 @@ wide_int
 wi::from_mpz (const_tree type, mpz_t x, bool wrap)
 {
   size_t count, numb;
-  int prec = TYPE_PRECISION (type);
+  unsigned int prec = TYPE_PRECISION (type);
   wide_int res = wide_int::create (prec);
 
   if (!wrap)
@@ -261,16 +261,28 @@ wi::from_mpz (const_tree type, mpz_t x, bool wrap)
      for representing the value.  The code to calculate count is
      extracted from the GMP manual, section "Integer Import and Export":
      http://gmplib.org/manual/Integer-Import-and-Export.html  */
-  numb = 8 * sizeof(HOST_WIDE_INT);
+  numb = CHAR_BIT * sizeof (HOST_WIDE_INT);
   count = (mpz_sizeinbase (x, 2) + numb - 1) / numb;
   HOST_WIDE_INT *val = res.write_val ();
-  mpz_export (val, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, x);
+  /* Write directly to the wide_int storage if possible, otherwise leave
+     GMP to allocate the memory for us.  It might be slightly more efficient
+     to use mpz_tdiv_r_2exp for the latter case, but the situation is
+     pathological and it seems safer to operate on the original mpz value
+     in all cases.  */
+  void *valres = mpz_export (count <= WIDE_INT_MAX_ELTS ? val : 0,
+                            &count, -1, sizeof (HOST_WIDE_INT), 0, 0, x);
   if (count < 1)
     {
       val[0] = 0;
       count = 1;
     }
-  res.set_len (count);
+  count = MIN (count, BLOCKS_NEEDED (prec));
+  if (valres != val)
+    {
+      memcpy (val, valres, count * sizeof (HOST_WIDE_INT));
+      free (valres);
+    }
+  res.set_len (canonize (val, count, prec));
 
   if (mpz_sgn (x) < 0)
     res = -res;