diff options
author | Richard Henderson <rth@redhat.com> | 2004-08-23 21:32:10 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2004-08-23 21:32:10 -0700 |
commit | 5f0ae953a99f831c39c741ec1233f030eb6d6d90 (patch) | |
tree | dae142b4607285da7d9578aa436fa1dad223be30 /gcc/fortran/trans-const.c | |
parent | 663790f8b8f07e56cd63d6863b5718a3cad2e25d (diff) | |
download | gcc-5f0ae953a99f831c39c741ec1233f030eb6d6d90.zip gcc-5f0ae953a99f831c39c741ec1233f030eb6d6d90.tar.gz gcc-5f0ae953a99f831c39c741ec1233f030eb6d6d90.tar.bz2 |
trans-const.c (gfc_conv_mpz_to_tree): Use mpz_getlimbn instead of going through an intermediate string.
* trans-const.c (gfc_conv_mpz_to_tree): Use mpz_getlimbn instead
of going through an intermediate string. Fix 32/64 int/long bug.
From-SVN: r86464
Diffstat (limited to 'gcc/fortran/trans-const.c')
-rw-r--r-- | gcc/fortran/trans-const.c | 90 |
1 files changed, 41 insertions, 49 deletions
diff --git a/gcc/fortran/trans-const.c b/gcc/fortran/trans-const.c index 9f03f2e..c2a68b7 100644 --- a/gcc/fortran/trans-const.c +++ b/gcc/fortran/trans-const.c @@ -161,71 +161,63 @@ gfc_init_constants (void) gfc_option.source); } -#define BITS_PER_HOST_WIDE_INT (8 * sizeof (HOST_WIDE_INT)) /* Converts a GMP integer into a backend tree node. */ tree gfc_conv_mpz_to_tree (mpz_t i, int kind) { - int val; - tree res; HOST_WIDE_INT high; unsigned HOST_WIDE_INT low; - int negate; - char buff[10]; - char *p; - char *q; - int n; - /* TODO: could be wrong if sizeof(HOST_WIDE_INT) != SIZEOF (int). */ if (mpz_fits_slong_p (i)) { - val = mpz_get_si (i); - res = build_int_cst (gfc_get_int_type (kind), - val, (val < 0) ? (HOST_WIDE_INT)-1 : 0); - return (res); + /* Note that HOST_WIDE_INT is never smaller than long. */ + low = mpz_get_si (i); + high = mpz_sgn (i) < 0 ? -1 : 0; } - - n = mpz_sizeinbase (i, 16); - if (n > 8) - q = gfc_getmem (n + 2); else - q = buff; - - low = 0; - high = 0; - p = mpz_get_str (q, 16, i); - if (p[0] == '-') { - negate = 1; - p++; - } - else - negate = 0; + /* Note that mp_limb_t can be anywhere from short to long long, + which gives us a nice variety of cases to choose from. */ - while (*p) - { - n = *(p++); - if (n >= '0' && n <= '9') - n = n - '0'; - else if (n >= 'a' && n <= 'z') - n = n + 10 - 'a'; - else if (n >= 'A' && n <= 'Z') - n = n + 10 - 'A'; - else - abort (); + if (sizeof (mp_limb_t) == sizeof (HOST_WIDE_INT)) + { + low = mpz_getlimbn (i, 0); + high = mpz_getlimbn (i, 1); + } + else if (sizeof (mp_limb_t) == 2 * sizeof (HOST_WIDE_INT)) + { + mp_limb_t limb0 = mpz_getlimbn (i, 0); + int count = (sizeof (mp_limb_t) - sizeof (HOST_WIDE_INT)) * CHAR_BIT; + low = limb0; + high = limb0 >> count; + } + else if (sizeof (mp_limb_t) < sizeof (HOST_WIDE_INT)) + { + int n, count = sizeof (HOST_WIDE_INT) / sizeof (mp_limb_t); + for (low = n = 0; n < count; ++n) + { + low <<= sizeof (mp_limb_t) * CHAR_BIT; + low |= mpz_getlimbn (i, n); + } + for (high = 0; n < 2*count; ++n) + { + high <<= sizeof (mp_limb_t) * CHAR_BIT; + high |= mpz_getlimbn (i, n); + } + } - assert (n >= 0 && n < 16); - high = (high << 4) + (low >> (BITS_PER_HOST_WIDE_INT - 4)); - low = (low << 4) + n; + /* By extracting limbs we constructed the absolute value of the + desired number. Negate if necessary. */ + if (mpz_sgn (i) < 0) + { + if (low == 0) + high = -high; + else + low = -low, high = ~high; + } } - res = build_int_cst (gfc_get_int_type (kind), low, high); - if (negate) - res = fold (build1 (NEGATE_EXPR, TREE_TYPE (res), res)); - if (q != buff) - gfc_free (q); - - return res; + return build_int_cst (gfc_get_int_type (kind), low, high); } /* Converts a real constant into backend form. Uses an intermediate string |