From 025e5647099ed6387bd4d5f4a856c7cca77ca244 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 23 Feb 2015 23:02:50 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 6 ++++++ gcc/testsuite/ChangeLog | 5 +++++ .../gfortran.dg/integer_exponentiation_6.F90 | 4 ++++ gcc/wide-int.cc | 20 +++++++++++++++---- 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/integer_exponentiation_6.F90 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5a652bce77f..0bc898e9e8f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2015-02-23 Richard Sandiford + + 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 PR target/65163 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e695467666a..ff48d0a8bf3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-02-23 Richard Sandiford + + PR fortran/63427 + * gfortran.dg/integer_exponentiation_6.F90: New test. + 2015-02-23 Martin Sebor 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 00000000000..55c2543e705 --- /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 fd7cbb4c384..7662648c20e 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; -- 2.30.2