From efa591c57ef118d3e21c0a1550a31fb00d75407e Mon Sep 17 00:00:00 2001 From: Francois-Xavier Coudert Date: Thu, 22 Mar 2007 23:51:50 +0100 Subject: [PATCH] re PR fortran/31262 (-fno-range-check with large integer values triggers ICE) PR fortran/31262 * trans-const.c (gfc_conv_mpz_to_tree): Allow integer constants larger than twice the width of a HOST_WIDE_INT. * gfortran.dg/no_range_check_1.f90: New test. From-SVN: r123136 --- gcc/fortran/ChangeLog | 6 ++++ gcc/fortran/trans-const.c | 28 +++++++++++++------ gcc/testsuite/ChangeLog | 5 ++++ .../gfortran.dg/no_range_check_1.f90 | 16 +++++++++++ 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/no_range_check_1.f90 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 4e366aa0274..0cee9c8c1bd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2007-03-22 Francois-Xavier Coudert + + PR fortran/31262 + * trans-const.c (gfc_conv_mpz_to_tree): Allow integer constants + larger than twice the width of a HOST_WIDE_INT. + 2006-03-22 Paul Thomas PR fortran/31193 diff --git a/gcc/fortran/trans-const.c b/gcc/fortran/trans-const.c index c1c96619715..5e27134b006 100644 --- a/gcc/fortran/trans-const.c +++ b/gcc/fortran/trans-const.c @@ -165,23 +165,33 @@ gfc_conv_mpz_to_tree (mpz_t i, int kind) } else { - unsigned HOST_WIDE_INT words[2]; - size_t count; + unsigned HOST_WIDE_INT *words; + size_t count, numb; + + /* Determine the number of unsigned HOST_WIDE_INT that are required + for represent 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); + count = (mpz_sizeinbase (i, 2) + numb-1) / numb; + if (count < 2) + count = 2; + words = (unsigned HOST_WIDE_INT *) alloca (count * sizeof(HOST_WIDE_INT)); /* Since we know that the value is not zero (mpz_fits_slong_p), we know that at least one word will be written, but we don't know about the second. It's quicker to zero the second word before than conditionally clear it later. */ words[1] = 0; - + /* Extract the absolute value into words. */ - mpz_export (words, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, i); - - /* We assume that all numbers are in range for its type, and that - we never create a type larger than 2*HWI, which is the largest - that the middle-end can handle. */ - gcc_assert (count == 1 || count == 2); + mpz_export (words, &count, -1, sizeof(HOST_WIDE_INT), 0, 0, i); + /* We don't assume that all numbers are in range for its type. + However, we never create a type larger than 2*HWI, which is the + largest that the middle-end can handle. So, we only take the + first two elements of words, which is equivalent to wrapping the + value if it's larger than the type range. */ low = words[0]; high = words[1]; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 821fc016cf3..936cebc8237 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-03-22 Francois-Xavier Coudert + + PR fortran/31262 + * gfortran.dg/no_range_check_1.f90: New test. + 2007-03-22 Dirk Mueller * g++.old-deja/g++.brendan/warnings2.C: Don't use -pedantic. diff --git a/gcc/testsuite/gfortran.dg/no_range_check_1.f90 b/gcc/testsuite/gfortran.dg/no_range_check_1.f90 new file mode 100644 index 00000000000..36890866e3a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/no_range_check_1.f90 @@ -0,0 +1,16 @@ +! { dg-do run } +! { dg-options "-fno-range-check -O0" } +! +! 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) call abort + if (7894_8 * (-huge(b) / 7) - 78941_8 /= b) call abort + + a = 1234789786453123 + if (a - 1234789786453123 /= a - (-426244989)) call abort + end