aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-02-23 23:02:50 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-02-23 23:02:50 +0000
commit025e5647099ed6387bd4d5f4a856c7cca77ca244 (patch)
treed45ea001d353538ed0b73bde01cbc59ecde404cd
parent8628d6e6502c436e94fecbcbe6770ea56757c18e (diff)
downloadgcc-025e5647099ed6387bd4d5f4a856c7cca77ca244.zip
gcc-025e5647099ed6387bd4d5f4a856c7cca77ca244.tar.gz
gcc-025e5647099ed6387bd4d5f4a856c7cca77ca244.tar.bz2
re PR fortran/63427 (hwint.h:250:29: runtime error: shift exponent 64 is too large for 64-bit type 'long int')
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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gfortran.dg/integer_exponentiation_6.F904
-rw-r--r--gcc/wide-int.cc20
4 files changed, 31 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5a652bc..0bc898e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e695467..ff48d0a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..55c2543
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90
@@ -0,0 +1,4 @@
+! { dg-options "-fno-range-check" }
+program test
+ write (*), (2_8 ** 64009999_8) / 2
+end program test
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index fd7cbb4..7662648 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -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;