aboutsummaryrefslogtreecommitdiff
path: root/gcc/emit-rtl.c
diff options
context:
space:
mode:
authorZack Weinberg <zack@gcc.gnu.org>2002-05-13 04:50:20 +0000
committerZack Weinberg <zack@gcc.gnu.org>2002-05-13 04:50:20 +0000
commit5692c7bc60a884946e782bb9c1fe72e919301557 (patch)
treee4ab53634b284c98ed87220fcf4d28bcf380dd5b /gcc/emit-rtl.c
parent31397a7b647de5fd81965c36a86ac04b1de7da57 (diff)
downloadgcc-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.c206
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);