diff options
Diffstat (limited to 'gcc/emit-rtl.c')
-rw-r--r-- | gcc/emit-rtl.c | 208 |
1 files changed, 185 insertions, 23 deletions
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index f33df263382..eeb5128fec9 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -144,6 +144,9 @@ rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1]; static htab_t const_int_htab; +/* A hash table storing memory attribute structures. */ +static htab_t mem_attrs_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: @@ -182,13 +185,16 @@ 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 int rtx_htab_mark_1 PARAMS ((void **, void *)); -static void rtx_htab_mark PARAMS ((void *)); +static hashval_t mem_attrs_htab_hash PARAMS ((const void *)); +static int mem_attrs_htab_eq PARAMS ((const void *, + const void *)); +static void mem_attrs_mark PARAMS ((const void *)); +static mem_attrs *get_mem_attrs PARAMS ((HOST_WIDE_INT, tree, rtx, + rtx, unsigned int)); /* Probability of the conditional branch currently proceeded by try_split. Set to -1 otherwise. */ int split_branch_probability = -1; - /* Returns a hash code for X (which is a really a CONST_INT). */ @@ -211,26 +217,83 @@ const_int_htab_eq (x, y) return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y)); } -/* Mark the hash-table element X (which is really a pointer to an - rtx). */ +/* Returns a hash code for X (which is a really a mem_attrs *). */ + +static hashval_t +mem_attrs_htab_hash (x) + const void *x; +{ + mem_attrs *p = (mem_attrs *) x; + + return (p->alias ^ (p->align * 1000) + ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) + ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) + ^ (long) p->decl); +} + +/* Returns non-zero if the value represented by X (which is really a + mem_attrs *) is the same as that given by Y (which is also really a + mem_attrs *). */ static int -rtx_htab_mark_1 (x, data) - void **x; - void *data ATTRIBUTE_UNUSED; +mem_attrs_htab_eq (x, y) + const void *x; + const void *y; { - ggc_mark_rtx (*x); - return 1; + mem_attrs *p = (mem_attrs *) x; + mem_attrs *q = (mem_attrs *) y; + + return (p->alias == q->alias && p->decl == q->decl && p->offset == q->offset + && p->size == q->size && p->align == q->align); } -/* Mark all the elements of HTAB (which is really an htab_t full of - rtxs). */ +/* This routine is called when we determine that we need a mem_attrs entry. + It marks the associated decl and RTL as being used, if present. */ static void -rtx_htab_mark (htab) - void *htab; +mem_attrs_mark (x) + const void *x; { - htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL); + mem_attrs *p = (mem_attrs *) x; + + if (p->decl) + ggc_mark_tree (p->decl); + + if (p->offset) + ggc_mark_rtx (p->offset); + + if (p->size) + ggc_mark_rtx (p->size); +} + +/* Allocate a new mem_attrs structure and insert it into the hash table if + one identical to it is not already in the table. */ + +static mem_attrs * +get_mem_attrs (alias, decl, offset, size, align) + HOST_WIDE_INT alias; + tree decl; + rtx offset; + rtx size; + unsigned int align; +{ + mem_attrs attrs; + void **slot; + + attrs.alias = alias; + attrs.decl = decl; + attrs.offset = offset; + attrs.size = size; + attrs.align = align; + + slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT); + if (*slot == 0) + { + *slot = ggc_alloc (sizeof (mem_attrs)); + memcpy (*slot, &attrs, sizeof (mem_attrs)); + } + + return *slot; } /* Generate a new REG rtx. Make sure ORIGINAL_REGNO is set properly, and @@ -350,7 +413,7 @@ gen_rtx_MEM (mode, addr) /* This field is not cleared by the mere allocation of the rtx, so we clear it here. */ - MEM_ALIAS_SET (rt) = 0; + MEM_ATTRS (rt) = 0; return rt; } @@ -377,9 +440,9 @@ gen_rtx_SUBREG (mode, reg, offset) return gen_rtx_fmt_ei (SUBREG, mode, reg, offset); } -/* Generate a SUBREG representing the least-significant part - * of REG if MODE is smaller than mode of REG, otherwise - * paradoxical SUBREG. */ +/* Generate a SUBREG representing the least-significant part of REG if MODE + is smaller than mode of REG, otherwise paradoxical SUBREG. */ + rtx gen_lowpart_SUBREG (mode, reg) enum machine_mode mode; @@ -556,7 +619,6 @@ gen_rtvec_v (n, argp) return rt_val; } - /* Generate a REG rtx for a new pseudo register of mode MODE. This pseudo is assigned the next sequential register number. */ @@ -1569,6 +1631,103 @@ reverse_comparison (insn) } } + +/* Given REF, a MEM, and T, either the type of X or the expression + corresponding to REF, set the memory attributes. OBJECTP is nonzero + if we are making a new object of this type. */ + +void +set_mem_attributes (ref, t, objectp) + rtx ref; + tree t; + int objectp; +{ + tree type; + + /* It can happen that type_for_mode was given a mode for which there + is no language-level type. In which case it returns NULL, which + we can see here. */ + if (t == NULL_TREE) + return; + + type = TYPE_P (t) ? t : TREE_TYPE (t); + + /* Get the alias set from the expression or type (perhaps using a + front-end routine) and then copy bits from the type. */ + + /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type) + here, because, in C and C++, the fact that a location is accessed + through a const expression does not mean that the value there can + never change. */ + + /* If we have already set DECL_RTL = ref, get_alias_set will get the + wrong answer, as it assumes that DECL_RTL already has the right alias + info. Callers should not set DECL_RTL until after the call to + set_mem_attributes. */ + if (DECL_P (t) && ref == DECL_RTL_IF_SET (t)) + abort (); + + set_mem_alias_set (ref, get_alias_set (t)); + + MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type); + MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); + + /* If we are making an object of this type, we know that it is a scalar if + the type is not an aggregate. */ + if (objectp && ! AGGREGATE_TYPE_P (type)) + MEM_SCALAR_P (ref) = 1; + + /* If T is a type, this is all we can do. Otherwise, we may be able + to deduce some more information about the expression. */ + if (TYPE_P (t)) + return; + + maybe_set_unchanging (ref, t); + if (TREE_THIS_VOLATILE (t)) + MEM_VOLATILE_P (ref) = 1; + + /* Now see if we can say more about whether it's an aggregate or + scalar. If we already know it's an aggregate, don't bother. */ + if (MEM_IN_STRUCT_P (ref)) + return; + + /* Now remove any NOPs: they don't change what the underlying object is. + Likewise for SAVE_EXPR. */ + while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR + || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR) + t = TREE_OPERAND (t, 0); + + /* Since we already know the type isn't an aggregate, if this is a decl, + it must be a scalar. Or if it is a reference into an aggregate, + this is part of an aggregate. Otherwise we don't know. */ + if (DECL_P (t)) + MEM_SCALAR_P (ref) = 1; + else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == ARRAY_RANGE_REF + || TREE_CODE (t) == BIT_FIELD_REF) + MEM_IN_STRUCT_P (ref) = 1; +} + +/* Set the alias set of MEM to SET. */ + +void +set_mem_alias_set (mem, set) + rtx mem; + HOST_WIDE_INT set; +{ + /* It would be nice to enable this check, but we can't quite yet. */ +#if 0 +#ifdef ENABLE_CHECKING + /* If the new and old alias sets don't conflict, something is wrong. */ + if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))) + abort (); +#endif +#endif + + MEM_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem), + MEM_SIZE (mem), MEM_ALIGN (mem)); +} + /* Return a memory reference like MEMREF, but with its mode changed to MODE and its address changed to ADDR. (VOIDmode means don't change the mode. @@ -4281,11 +4440,14 @@ init_emit_once (line_numbers) enum machine_mode mode; enum machine_mode double_mode; - /* Initialize the CONST_INT hash table. */ + /* Initialize the CONST_INT and memory attribute hash tables. */ const_int_htab = htab_create (37, const_int_htab_hash, const_int_htab_eq, NULL); - ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), - rtx_htab_mark); + ggc_add_deletable_htab (const_int_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); no_line_numbers = ! line_numbers; |