diff options
author | Zack Weinberg <zack@gcc.gnu.org> | 2002-05-13 04:50:20 +0000 |
---|---|---|
committer | Zack Weinberg <zack@gcc.gnu.org> | 2002-05-13 04:50:20 +0000 |
commit | 5692c7bc60a884946e782bb9c1fe72e919301557 (patch) | |
tree | e4ab53634b284c98ed87220fcf4d28bcf380dd5b /gcc/emit-rtl.c | |
parent | 31397a7b647de5fd81965c36a86ac04b1de7da57 (diff) | |
download | gcc-5692c7bc60a884946e782bb9c1fe72e919301557.zip gcc-5692c7bc60a884946e782bb9c1fe72e919301557.tar.gz gcc-5692c7bc60a884946e782bb9c1fe72e919301557.tar.bz2 |
emit-rtl.c (global_rtl): Update comment.
* emit-rtl.c (global_rtl): Update comment.
(const_double_htab, const_double_htab_hash,
const_double_htab_hash, lookup_const_double): New.
(const_int_htab_hash, const_int_htab_eq): Remove const
qualifiers, which cause tons of warnings with RTL checking on.
(gen_rtx_CONST_DOUBLE): Deleted.
(const_double_from_real_value): New function - bears some
resemblance to the former immed_real_const_1.
(immed_double_const): Moved here from varasm.c and
simplified.
(gen_rtx_REG): Make REGNO unsigned to squelch warnings.
(gen_rtx_SUBREG): Use gen_rtx_raw_SUBREG.
(gen_rtx): Use immed_double_const.
(init_emit_once): Initialize the const_double_htab. Use
REAL_VALUE_FROM_INT where possible. Can now use
CONST_DOUBLE_FROM_REAL_VALUE when setting up const_tiny_rtx.
* varasm.c (struct varasm_status): Remove x_const_double_chain.
(const_double_chain, immed_real_const, clear_const_double_mem): Delete.
(immed_double_const, immed_real_const_1): Moved to emit-rtl.c.
(init_varasm_status, mark_varasm_status): Don't touch
x_const_double_chain.
* output.h: Delete prototype for clear_const_double_mem.
* real.h: Make REAL_VALUE_TYPE a macro again. Remove leading
'0' slot from all CONST_DOUBLE_FORMAT definitions. Prototype
const_double_from_real_value, not immed_real_const_1, and use
it to define CONST_DOUBLE_FROM_REAL_VALUE. Define new macro
CONST_DOUBLE_ATOF.
* rtl.h (CONST_DOUBLE_CHAIN): Kill.
(CONST_DOUBLE_LOW, CONST_DOUBLE_HIGH): Adjust.
(gen_rtx_CONST_DOUBLE, immed_real_const): Delete prototypes.
(gen_rtx_REG): Second arg is unsigned.
* gengenrtl.c (special_rtx): Take out CONST_DOUBLE.
(excluded_rtx): New, return true for CONST_DOUBLE.
(genmacro): Write nothing for excluded codes.
* combine.c (combine_simplify_rtx): Use CONST_DOUBLE_FROM_REAL_VALUE.
* expr.c (expand_expr): Likewise.
* ggc-common.c (ggc_mark_rtx_children_1): Don't mark the
CONST_DOUBLE_CHAIN.
* toplev.c (rest_of_compilation): Don't call
clear_const_double_mem.
* config/rs6000/rs6000.c (rs6000_float_const): Delete.
(rs6000_hash_constant): Remove CONST_DOUBLE special case.
(toc_hash_eq): Remove CONST_DOUBLE and LABEL_REF special cases.
* config/rs6000/rs6000-protos.h: Don't prototype rs6000_float_const.
* config/c4x/c4x.md, config/rs6000/rs6000.md: Use CONST_DOUBLE_ATOF.
* config/dsp16xx/dsp16xx.md, config/mips/mips.md,
config/pa/pa.md: Use CONST_DOUBLE_FROM_REAL_VALUE.
* config/sparc/sparc.md, config/sparc/sparc.c: Use immed_double_const.
From-SVN: r53409
Diffstat (limited to 'gcc/emit-rtl.c')
-rw-r--r-- | gcc/emit-rtl.c | 206 |
1 files changed, 170 insertions, 36 deletions
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index adeabe9..2e86dff 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -87,8 +87,8 @@ static int no_line_numbers; /* Commonly used rtx's, so that we only need space for one copy. These are initialized once for the entire compilation. - All of these except perhaps the floating-point CONST_DOUBLEs - are unique; no other rtx-object will be equal to any of these. */ + All of these are unique; no other rtx-object will be equal to any + of these. */ rtx global_rtl[GR_MAX]; @@ -148,6 +148,9 @@ static htab_t const_int_htab; /* A hash table storing memory attribute structures. */ static htab_t mem_attrs_htab; +/* A hash table storing all CONST_DOUBLEs. */ +static htab_t const_double_htab; + /* start_sequence and gen_sequence can make a lot of rtx expressions which are shortly thrown away. We use two mechanisms to prevent this waste: @@ -188,6 +191,10 @@ static void mark_label_nuses PARAMS ((rtx)); static hashval_t const_int_htab_hash PARAMS ((const void *)); static int const_int_htab_eq PARAMS ((const void *, const void *)); +static hashval_t const_double_htab_hash PARAMS ((const void *)); +static int const_double_htab_eq PARAMS ((const void *, + const void *)); +static rtx lookup_const_double PARAMS ((rtx)); static hashval_t mem_attrs_htab_hash PARAMS ((const void *)); static int mem_attrs_htab_eq PARAMS ((const void *, const void *)); @@ -208,7 +215,7 @@ static hashval_t const_int_htab_hash (x) const void *x; { - return (hashval_t) INTVAL ((const struct rtx_def *) x); + return (hashval_t) INTVAL ((struct rtx_def *) x); } /* Returns non-zero if the value represented by X (which is really a @@ -220,7 +227,40 @@ const_int_htab_eq (x, y) const void *x; const void *y; { - return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y)); + return (INTVAL ((rtx) x) == *((const HOST_WIDE_INT *) y)); +} + +/* Returns a hash code for X (which is really a CONST_DOUBLE). */ +static hashval_t +const_double_htab_hash (x) + const void *x; +{ + hashval_t h = 0; + size_t i; + rtx value = (rtx) x; + + for (i = 0; i < sizeof(CONST_DOUBLE_FORMAT)-1; i++) + h ^= XWINT (value, i); + return h; +} + +/* Returns non-zero if the value represented by X (really a ...) + is the same as that represented by Y (really a ...) */ +static int +const_double_htab_eq (x, y) + const void *x; + const void *y; +{ + rtx a = (rtx)x, b = (rtx)y; + size_t i; + + if (GET_MODE (a) != GET_MODE (b)) + return 0; + for (i = 0; i < sizeof(CONST_DOUBLE_FORMAT)-1; i++) + if (XWINT (a, i) != XWINT (b, i)) + return 0; + + return 1; } /* Returns a hash code for X (which is a really a mem_attrs *). */ @@ -363,32 +403,130 @@ gen_int_mode (c, mode) return GEN_INT (trunc_int_for_mode (c, mode)); } -/* CONST_DOUBLEs needs special handling because their length is known - only at run-time. */ +/* CONST_DOUBLEs might be created from pairs of integers, or from + REAL_VALUE_TYPEs. Also, their length is known only at run time, + so we cannot use gen_rtx_raw_CONST_DOUBLE. */ + +/* Determine whether REAL, a CONST_DOUBLE, already exists in the + hash table. If so, return its counterpart; otherwise add it + to the hash table and return it. */ +static rtx +lookup_const_double (real) + rtx real; +{ + void **slot = htab_find_slot (const_double_htab, real, INSERT); + if (*slot == 0) + *slot = real; + + return (rtx) *slot; +} +/* Return a CONST_DOUBLE rtx for a floating-point value specified by + VALUE in mode MODE. */ rtx -gen_rtx_CONST_DOUBLE (mode, arg0, arg1) +const_double_from_real_value (value, mode) + REAL_VALUE_TYPE value; enum machine_mode mode; - HOST_WIDE_INT arg0, arg1; { - rtx r = rtx_alloc (CONST_DOUBLE); - int i; + rtx real = rtx_alloc (CONST_DOUBLE); + PUT_MODE (real, mode); + + memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE)); + + return lookup_const_double (real); +} + +/* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair + of ints: I0 is the low-order word and I1 is the high-order word. + Do not use this routine for non-integer modes; convert to + REAL_VALUE_TYPE and use CONST_DOUBLE_FROM_REAL_VALUE. */ + +rtx +immed_double_const (i0, i1, mode) + HOST_WIDE_INT i0, i1; + enum machine_mode mode; +{ + rtx value; + unsigned int i; + + if (mode != VOIDmode) + { + int width; + if (GET_MODE_CLASS (mode) != MODE_INT + && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) + abort (); + + /* We clear out all bits that don't belong in MODE, unless they and + our sign bit are all one. So we get either a reasonable negative + value or a reasonable unsigned value for this mode. */ + width = GET_MODE_BITSIZE (mode); + if (width < HOST_BITS_PER_WIDE_INT + && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1))) + != ((HOST_WIDE_INT) (-1) << (width - 1)))) + i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0; + else if (width == HOST_BITS_PER_WIDE_INT + && ! (i1 == ~0 && i0 < 0)) + i1 = 0; + else if (width > 2 * HOST_BITS_PER_WIDE_INT) + /* We cannot represent this value as a constant. */ + abort (); + + /* If this would be an entire word for the target, but is not for + the host, then sign-extend on the host so that the number will + look the same way on the host that it would on the target. + + For example, when building a 64 bit alpha hosted 32 bit sparc + targeted compiler, then we want the 32 bit unsigned value -1 to be + represented as a 64 bit value -1, and not as 0x00000000ffffffff. + The latter confuses the sparc backend. */ + + if (width < HOST_BITS_PER_WIDE_INT + && (i0 & ((HOST_WIDE_INT) 1 << (width - 1)))) + i0 |= ((HOST_WIDE_INT) (-1) << width); - PUT_MODE (r, mode); - X0EXP (r, 0) = NULL_RTX; - XWINT (r, 1) = arg0; - XWINT (r, 2) = arg1; + /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a + CONST_INT. - for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 2; --i) - XWINT (r, i) = 0; + ??? Strictly speaking, this is wrong if we create a CONST_INT for + a large unsigned constant with the size of MODE being + HOST_BITS_PER_WIDE_INT and later try to interpret that constant + in a wider mode. In that case we will mis-interpret it as a + negative number. - return r; + Unfortunately, the only alternative is to make a CONST_DOUBLE for + any constant in any mode if it is an unsigned constant larger + than the maximum signed integer in an int on the host. However, + doing this will break everyone that always expects to see a + CONST_INT for SImode and smaller. + + We have always been making CONST_INTs in this case, so nothing + new is being broken. */ + + if (width <= HOST_BITS_PER_WIDE_INT) + i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0; + } + + /* If this integer fits in one word, return a CONST_INT. */ + if ((i1 == 0 && i0 >= 0) || (i1 == ~0 && i0 < 0)) + return GEN_INT (i0); + + /* We use VOIDmode for integers. */ + value = rtx_alloc (CONST_DOUBLE); + PUT_MODE (value, VOIDmode); + + CONST_DOUBLE_LOW (value) = i0; + CONST_DOUBLE_HIGH (value) = i1; + + for (i = 2; i < (sizeof CONST_DOUBLE_FORMAT - 1); i++) + XWINT (value, i) = 0; + + return lookup_const_double (value); } rtx gen_rtx_REG (mode, regno) enum machine_mode mode; - int regno; + unsigned int regno; { /* In case the MD file explicitly references the frame pointer, have all such references point to the same frame pointer. This is @@ -463,7 +601,7 @@ gen_rtx_SUBREG (mode, reg, offset) if (offset >= GET_MODE_SIZE (GET_MODE (reg))) abort (); #endif - return gen_rtx_fmt_ei (SUBREG, mode, reg, offset); + return gen_rtx_raw_SUBREG (mode, reg, offset); } /* Generate a SUBREG representing the least-significant part of REG if MODE @@ -532,7 +670,7 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...)) HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT); HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT); - rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1); + rt_val = immed_double_const (arg0, arg1, mode); } break; @@ -4849,11 +4987,16 @@ init_emit_once (line_numbers) enum machine_mode mode; enum machine_mode double_mode; - /* Initialize the CONST_INT and memory attribute hash tables. */ + /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash + tables. */ const_int_htab = htab_create (37, const_int_htab_hash, const_int_htab_eq, NULL); ggc_add_deletable_htab (const_int_htab, 0, 0); + const_double_htab = htab_create (37, const_double_htab_hash, + const_double_htab_eq, NULL); + ggc_add_deletable_htab (const_double_htab, 0, 0); + mem_attrs_htab = htab_create (37, mem_attrs_htab_hash, mem_attrs_htab_eq, NULL); ggc_add_deletable_htab (mem_attrs_htab, 0, mem_attrs_mark); @@ -4937,10 +5080,10 @@ init_emit_once (line_numbers) else const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE); - dconst0 = REAL_VALUE_ATOF ("0", double_mode); - dconst1 = REAL_VALUE_ATOF ("1", double_mode); - dconst2 = REAL_VALUE_ATOF ("2", double_mode); - dconstm1 = REAL_VALUE_ATOF ("-1", double_mode); + REAL_VALUE_FROM_INT (dconst0, 0, 0, double_mode); + REAL_VALUE_FROM_INT (dconst1, 1, 0, double_mode); + REAL_VALUE_FROM_INT (dconst2, 2, 0, double_mode); + REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode); for (i = 0; i <= 2; i++) { @@ -4949,17 +5092,8 @@ init_emit_once (line_numbers) for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) - { - rtx tem = rtx_alloc (CONST_DOUBLE); - - /* Can't use CONST_DOUBLE_FROM_REAL_VALUE here; that uses the - tables we're setting up right now. */ - memcpy (&CONST_DOUBLE_LOW (tem), r, sizeof (REAL_VALUE_TYPE)); - CONST_DOUBLE_CHAIN (tem) = NULL_RTX; - PUT_MODE (tem, mode); - - const_tiny_rtx[i][(int) mode] = tem; - } + const_tiny_rtx[i][(int) mode] = + CONST_DOUBLE_FROM_REAL_VALUE (*r, mode); const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i); |