From 5f0ae953a99f831c39c741ec1233f030eb6d6d90 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 23 Aug 2004 21:32:10 -0700 Subject: [PATCH] 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 --- gcc/fortran/ChangeLog | 5 +++ gcc/fortran/trans-const.c | 90 ++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 49 deletions(-) diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 7501e613462..9d9992687e2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2004-08-23 Richard Henderson + + * trans-const.c (gfc_conv_mpz_to_tree): Use mpz_getlimbn instead + of going through an intermediate string. Fix 32/64 int/long bug. + 2004-08-23 Eric Christopher * trans-types.c (gfc_type_for_mode): Remove VECTOR_TYPE_SUPPORTED_P diff --git a/gcc/fortran/trans-const.c b/gcc/fortran/trans-const.c index 9f03f2ed2e3..c2a68b7732a 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 -- 2.30.2