Commit 3234b52d by Richard Henderson Committed by Richard Henderson

varasm.c (struct rtx_const, [...]): Remove.

        * varasm.c (struct rtx_const, struct pool_constant): Remove.
        (MAX_RTX_HASH_TABLE): Remove.
        (const_rtx_hash_table, const_rtx_sym_hash_table): Remove.
        (first_pool, last_pool, pool_offset): Remove.
        (struct rtx_constant_pool): Split out from ...
        (struct varasm_status): ... here.  Reference one via pointer.
        (struct constant_descriptor_rtx): Merge struct pool_constant.
        (SYMHASH): Remove.
        (decode_rtx_const): Remove.
        (const_hash_rtx, compare_constant_rtx): Remove.
        (record_constant_rtx): Remove.
        (const_desc_rtx_hash, const_desc_rtx_eq): New.
        (const_desc_rtx_sym_hash, const_desc_rtx_sym_eq): New.
        (const_rtx_hash_1, const_rtx_hash): New.
        (init_varasm_status): Allocate a rtx_constant_pool, and its hashes.
        (simplify_subtraction): Use simplify_rtx.
        (force_const_mem): Rewrite to use new data structures.
        (find_pool_constant): Likewise.
        (get_pool_constant, get_pool_constant_mark,
        get_pool_constant_for_function, get_pool_mode,
        get_pool_mode_for_function, get_pool_offset, get_pool_size): Likewise.
        (output_constant_pool_2): Split out from output_constant_pool.
        (output_constant_pool_1): Likewise.  Use new pool datastructures.
        (output_constant_pool): Zap entire pool datastructure.
        (mark_constant): Use new pool datastructures.
        (mark_constants): Use for_each_rtx.
        (mark_constant_pool): Use new pool datastructures.

From-SVN: r76985
parent be77d9e7
2004-01-30 Richard Henderson <rth@redhat.com>
* varasm.c (struct rtx_const, struct pool_constant): Remove.
(MAX_RTX_HASH_TABLE): Remove.
(const_rtx_hash_table, const_rtx_sym_hash_table): Remove.
(first_pool, last_pool, pool_offset): Remove.
(struct rtx_constant_pool): Split out from ...
(struct varasm_status): ... here. Reference one via pointer.
(struct constant_descriptor_rtx): Merge struct pool_constant.
(SYMHASH): Remove.
(decode_rtx_const): Remove.
(const_hash_rtx, compare_constant_rtx): Remove.
(record_constant_rtx): Remove.
(const_desc_rtx_hash, const_desc_rtx_eq): New.
(const_desc_rtx_sym_hash, const_desc_rtx_sym_eq): New.
(const_rtx_hash_1, const_rtx_hash): New.
(init_varasm_status): Allocate a rtx_constant_pool, and its hashes.
(simplify_subtraction): Use simplify_rtx.
(force_const_mem): Rewrite to use new data structures.
(find_pool_constant): Likewise.
(get_pool_constant, get_pool_constant_mark,
get_pool_constant_for_function, get_pool_mode,
get_pool_mode_for_function, get_pool_offset, get_pool_size): Likewise.
(output_constant_pool_2): Split out from output_constant_pool.
(output_constant_pool_1): Likewise. Use new pool datastructures.
(output_constant_pool): Zap entire pool datastructure.
(mark_constant): Use new pool datastructures.
(mark_constants): Use for_each_rtx.
(mark_constant_pool): Use new pool datastructures.
2004-01-30 Fariborz Jahanian <fjahanian@apple.com> 2004-01-30 Fariborz Jahanian <fjahanian@apple.com>
* config/rs6000/rs6000.c (rs6000_emit_move): Remove #if 0. * config/rs6000/rs6000.c (rs6000_emit_move): Remove #if 0.
......
...@@ -69,44 +69,18 @@ const char *weak_global_object_name; ...@@ -69,44 +69,18 @@ const char *weak_global_object_name;
struct addr_const; struct addr_const;
struct constant_descriptor_rtx; struct constant_descriptor_rtx;
struct rtx_const; struct rtx_constant_pool;
struct pool_constant;
#define MAX_RTX_HASH_TABLE 61
struct varasm_status GTY(()) struct varasm_status GTY(())
{ {
/* Hash facility for making memory-constants /* If we're using a per-function constant pool, this is it. */
from constant rtl-expressions. It is used on RISC machines struct rtx_constant_pool *pool;
where immediate integer arguments and constant addresses are restricted
so that such constants must be stored in memory.
This pool of constants is reinitialized for each function
so each function gets its own constants-pool that comes right before
it. */
struct constant_descriptor_rtx ** GTY ((length ("MAX_RTX_HASH_TABLE")))
x_const_rtx_hash_table;
struct pool_constant ** GTY ((length ("MAX_RTX_HASH_TABLE")))
x_const_rtx_sym_hash_table;
/* Pointers to first and last constant in pool. */
struct pool_constant *x_first_pool;
struct pool_constant *x_last_pool;
/* Current offset in constant pool (does not include any machine-specific
header). */
HOST_WIDE_INT x_pool_offset;
/* Number of tree-constants deferred during the expansion of this /* Number of tree-constants deferred during the expansion of this
function. */ function. */
unsigned int deferred_constants; unsigned int deferred_constants;
}; };
#define const_rtx_hash_table (cfun->varasm->x_const_rtx_hash_table)
#define const_rtx_sym_hash_table (cfun->varasm->x_const_rtx_sym_hash_table)
#define first_pool (cfun->varasm->x_first_pool)
#define last_pool (cfun->varasm->x_last_pool)
#define pool_offset (cfun->varasm->x_pool_offset)
#define n_deferred_constants (cfun->varasm->deferred_constants) #define n_deferred_constants (cfun->varasm->deferred_constants)
/* Number for making the label on the next /* Number for making the label on the next
...@@ -147,16 +121,6 @@ static hashval_t const_hash_1 (const tree); ...@@ -147,16 +121,6 @@ static hashval_t const_hash_1 (const tree);
static int compare_constant (const tree, const tree); static int compare_constant (const tree, const tree);
static tree copy_constant (tree); static tree copy_constant (tree);
static void output_constant_def_contents (rtx); static void output_constant_def_contents (rtx);
static void decode_rtx_const (enum machine_mode, rtx, struct rtx_const *);
static unsigned int const_hash_rtx (enum machine_mode, rtx);
static int compare_constant_rtx (enum machine_mode, rtx,
struct constant_descriptor_rtx *);
static struct constant_descriptor_rtx * record_constant_rtx
(enum machine_mode, rtx);
static struct pool_constant *find_pool_constant (struct function *, rtx);
static void mark_constant_pool (void);
static void mark_constants (rtx);
static int mark_constant (rtx *current_rtx, void *data);
static void output_addressed_constants (tree); static void output_addressed_constants (tree);
static unsigned HOST_WIDE_INT array_size_for_constructor (tree); static unsigned HOST_WIDE_INT array_size_for_constructor (tree);
static unsigned min_align (unsigned, unsigned); static unsigned min_align (unsigned, unsigned);
...@@ -2025,36 +1989,6 @@ decode_addr_const (tree exp, struct addr_const *value) ...@@ -2025,36 +1989,6 @@ decode_addr_const (tree exp, struct addr_const *value)
value->offset = offset; value->offset = offset;
} }
/* We do RTX_UNSPEC + XINT (blah), so nothing can go after RTX_UNSPEC. */
enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_VECTOR, RTX_INT, RTX_UNSPEC };
struct rtx_const GTY(())
{
ENUM_BITFIELD(kind) kind : 16;
ENUM_BITFIELD(machine_mode) mode : 16;
union rtx_const_un {
REAL_VALUE_TYPE GTY ((tag ("4"))) du;
struct rtx_const_u_addr {
rtx base;
const char *symbol;
HOST_WIDE_INT offset;
} GTY ((tag ("1"))) addr;
struct rtx_const_u_di {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
} GTY ((tag ("0"))) di;
/* The max vector size we have is 16 wide; two variants for
integral and floating point vectors. */
struct rtx_const_int_vec {
HOST_WIDE_INT high;
HOST_WIDE_INT low;
} GTY ((tag ("2"))) int_vec[16];
REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
} GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
};
/* Uniquize all constants that appear in memory. /* Uniquize all constants that appear in memory.
Each constant in memory thus far output is recorded Each constant in memory thus far output is recorded
in `const_desc_table'. */ in `const_desc_table'. */
...@@ -2612,314 +2546,189 @@ lookup_constant_def (tree exp) ...@@ -2612,314 +2546,189 @@ lookup_constant_def (tree exp)
/* Used in the hash tables to avoid outputting the same constant /* Used in the hash tables to avoid outputting the same constant
twice. Unlike 'struct constant_descriptor_tree', RTX constants twice. Unlike 'struct constant_descriptor_tree', RTX constants
are output once per function, not once per file; there seems are output once per function, not once per file. */
to be no reason for the difference. */ /* ??? Only a few targets need per-function constant pools. Most
can use one per-file pool. Should add a targetm bit to tell the
struct constant_descriptor_rtx GTY(()) difference. */
{
/* More constant_descriptors with the same hash code. */ struct rtx_constant_pool GTY(())
struct constant_descriptor_rtx *next; {
/* Pointers to first and last constant in pool, as ordered by offset. */
/* A MEM for the constant. */ struct constant_descriptor_rtx *first;
rtx rtl; struct constant_descriptor_rtx *last;
/* The value of the constant. */ /* Hash facility for making memory-constants from constant rtl-expressions.
struct rtx_const value; It is used on RISC machines where immediate integer arguments and
constant addresses are restricted so that such constants must be stored
in memory. */
htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_sym_htab;
/* Current offset in constant pool (does not include any
machine-specific header). */
HOST_WIDE_INT offset;
}; };
/* Structure to represent sufficient information about a constant so that struct constant_descriptor_rtx GTY((chain_next ("%h.next")))
it can be output when the constant pool is output, so that function
integration can be done, and to simplify handling on machines that reference
constant pool as base+displacement. */
struct pool_constant GTY(())
{ {
struct constant_descriptor_rtx *desc; struct constant_descriptor_rtx *next;
struct pool_constant *next; rtx mem;
struct pool_constant *next_sym; rtx sym;
rtx constant; rtx constant;
HOST_WIDE_INT offset;
hashval_t hash;
enum machine_mode mode; enum machine_mode mode;
int labelno;
unsigned int align; unsigned int align;
HOST_WIDE_INT offset; int labelno;
int mark; int mark;
}; };
/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true. /* Hash and compare functions for const_rtx_htab. */
The argument is XSTR (... , 0) */
#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE) static hashval_t
const_desc_rtx_hash (const void *ptr)
/* Initialize constant pool hashing for a new function. */ {
const struct constant_descriptor_rtx *desc = ptr;
return desc->hash;
}
void static int
init_varasm_status (struct function *f) const_desc_rtx_eq (const void *a, const void *b)
{ {
struct varasm_status *p; const struct constant_descriptor_rtx *x = a;
p = ggc_alloc (sizeof (struct varasm_status)); const struct constant_descriptor_rtx *y = b;
f->varasm = p;
p->x_const_rtx_hash_table if (x->mode != y->mode)
= ggc_alloc_cleared (MAX_RTX_HASH_TABLE return 0;
* sizeof (struct constant_descriptor_rtx *)); return rtx_equal_p (x->constant, y->constant);
p->x_const_rtx_sym_hash_table
= ggc_alloc_cleared (MAX_RTX_HASH_TABLE
* sizeof (struct pool_constant *));
p->x_first_pool = p->x_last_pool = 0;
p->x_pool_offset = 0;
p->deferred_constants = 0;
} }
/* Express an rtx for a constant integer (perhaps symbolic) /* Hash and compare functions for const_rtx_sym_htab. */
as the sum of a symbol or label plus an explicit integer.
They are stored into VALUE. */
static void static hashval_t
decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value) const_desc_rtx_sym_hash (const void *ptr)
{ {
/* Clear the whole structure, including any gaps. */ const struct constant_descriptor_rtx *desc = ptr;
memset (value, 0, sizeof (struct rtx_const)); return htab_hash_string (XSTR (desc->sym, 0));
}
value->kind = RTX_INT; /* Most usual kind. */ static int
value->mode = mode; const_desc_rtx_sym_eq (const void *a, const void *b)
{
const struct constant_descriptor_rtx *x = a;
const struct constant_descriptor_rtx *y = b;
return x->sym == y->sym;
}
switch (GET_CODE (x)) /* This is the worker function for const_rtx_hash, called via for_each_rtx. */
{
case CONST_DOUBLE:
value->kind = RTX_DOUBLE;
if (GET_MODE (x) != VOIDmode)
{
const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
value->mode = GET_MODE (x); static int
const_rtx_hash_1 (rtx *xp, void *data)
{
unsigned HOST_WIDE_INT hwi;
enum machine_mode mode;
enum rtx_code code;
hashval_t h, *hp;
rtx x;
/* Copy the REAL_VALUE_TYPE by members so that we don't x = *xp;
copy garbage from the original structure into our code = GET_CODE (x);
carefully cleaned hashing structure. */ mode = GET_MODE (x);
value->un.du.class = r->class; h = (hashval_t) code * 1048573 + mode;
value->un.du.sign = r->sign;
switch (r->class)
{
case rvc_zero:
case rvc_inf:
break;
case rvc_normal:
value->un.du.exp = r->exp;
/* Fall through. */
case rvc_nan:
memcpy (value->un.du.sig, r->sig, sizeof (r->sig));
break;
default:
abort ();
}
}
else
{
value->un.di.low = CONST_DOUBLE_LOW (x);
value->un.di.high = CONST_DOUBLE_HIGH (x);
}
break;
case CONST_VECTOR: switch (code)
{
case CONST_INT:
hwi = INTVAL (x);
fold_hwi:
{ {
int units, i; const int shift = sizeof (hashval_t) * CHAR_BIT;
const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
int i;
units = CONST_VECTOR_NUNITS (x); h ^= (hashval_t) hwi;
value->kind = RTX_VECTOR; for (i = 1; i < n; ++i)
value->mode = mode;
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
{
for (i = 0; i < units; ++i)
{
rtx elt = CONST_VECTOR_ELT (x, i);
if (GET_CODE (elt) == CONST_INT)
{
value->un.int_vec[i].low = INTVAL (elt);
value->un.int_vec[i].high = 0;
}
else
{
value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
}
}
}
else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
{ {
for (i = 0; i < units; ++i) hwi >>= shift;
{ h ^= (hashval_t) hwi;
const REAL_VALUE_TYPE *r
= CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
/* Copy the REAL_VALUE_TYPE by members so that we don't
copy garbage from the original structure into our
carefully cleaned hashing structure. */
d->class = r->class;
d->sign = r->sign;
switch (r->class)
{
case rvc_zero:
case rvc_inf:
break;
case rvc_normal:
d->exp = r->exp;
/* Fall through. */
case rvc_nan:
memcpy (d->sig, r->sig, sizeof (r->sig));
break;
default:
abort ();
}
}
} }
else
abort ();
} }
break; break;
case CONST_INT: case CONST_DOUBLE:
value->un.addr.offset = INTVAL (x); if (mode == VOIDmode)
{
hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
goto fold_hwi;
}
else
h ^= real_hash (CONST_DOUBLE_REAL_VALUE (x));
break; break;
case SYMBOL_REF: case SYMBOL_REF:
h ^= htab_hash_string (XSTR (x, 0));
break;
case LABEL_REF: case LABEL_REF:
case PC: h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
value->un.addr.base = x;
break; break;
case CONST: case UNSPEC:
x = XEXP (x, 0); case UNSPEC_VOLATILE:
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) h = h * 251 + XINT (x, 1);
{
value->un.addr.base = XEXP (x, 0);
value->un.addr.offset = INTVAL (XEXP (x, 1));
}
else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
value->un.addr.base = XEXP (x, 0);
value->un.addr.offset = - INTVAL (XEXP (x, 1));
}
else
{
value->un.addr.base = x;
value->un.addr.offset = 0;
}
break; break;
default: default:
value->kind = RTX_UNKNOWN;
break; break;
} }
if (value->kind == RTX_INT && value->un.addr.base != 0 hp = data;
&& GET_CODE (value->un.addr.base) == UNSPEC) *hp = *hp * 509 + h;
{ return 0;
/* For a simple UNSPEC, the base is set to the
operand, the kind field is set to the index of
the unspec expression.
Together with the code below, in case that
the operand is a SYMBOL_REF or LABEL_REF,
the address of the string or the code_label
is taken as base. */
if (XVECLEN (value->un.addr.base, 0) == 1)
{
value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
}
}
if (value->kind >= RTX_INT && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
case SYMBOL_REF:
/* Use the string's address, not the SYMBOL_REF's address,
for the sake of addresses of library routines. */
value->un.addr.symbol = XSTR (value->un.addr.base, 0);
value->un.addr.base = NULL_RTX;
break;
case LABEL_REF:
/* For a LABEL_REF, compare labels. */
value->un.addr.base = XEXP (value->un.addr.base, 0);
default:
break;
}
} }
/* Given a MINUS expression, simplify it if both sides /* Compute a hash value for X, which should be a constant. */
include the same symbol. */
rtx static hashval_t
simplify_subtraction (rtx x) const_rtx_hash (rtx x)
{ {
struct rtx_const val0, val1; hashval_t h = 0;
for_each_rtx (&x, const_rtx_hash_1, &h);
decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0); return h;
decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
if (val0.kind >= RTX_INT
&& val0.kind == val1.kind
&& val0.un.addr.base == val1.un.addr.base
&& val0.un.addr.symbol == val1.un.addr.symbol)
return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
return x;
} }
/* Compute a hash code for a constant RTL expression. */
/* Initialize constant pool hashing for a new function. */
static unsigned int void
const_hash_rtx (enum machine_mode mode, rtx x) init_varasm_status (struct function *f)
{ {
union { struct varasm_status *p;
struct rtx_const value; struct rtx_constant_pool *pool;
unsigned int data[sizeof(struct rtx_const) / sizeof (unsigned int)];
} u;
unsigned int hi;
size_t i;
decode_rtx_const (mode, x, &u.value);
/* Compute hashing function. */
hi = 0;
for (i = 0; i < ARRAY_SIZE (u.data); i++)
hi = hi * 613 + u.data[i];
return hi % MAX_RTX_HASH_TABLE;
}
/* Compare a constant rtl object X with a constant-descriptor DESC.
Return 1 if DESC describes a constant with the same value as X. */
static int p = ggc_alloc (sizeof (struct varasm_status));
compare_constant_rtx (enum machine_mode mode, rtx x, f->varasm = p;
struct constant_descriptor_rtx *desc)
{
struct rtx_const value;
decode_rtx_const (mode, x, &value); pool = ggc_alloc (sizeof (struct rtx_constant_pool));
p->pool = pool;
p->deferred_constants = 0;
/* Compare constant contents. */ pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0; const_desc_rtx_eq, NULL);
pool->const_rtx_sym_htab = htab_create_ggc (31, const_desc_rtx_sym_hash,
const_desc_rtx_sym_eq, NULL);
pool->first = pool->last = NULL;
pool->offset = 0;
} }
/* Given a MINUS expression, simplify it if both sides
include the same symbol. */
/* Construct a constant descriptor for the rtl-expression X. rtx
It is up to the caller to enter the descriptor in the hash table. */ simplify_subtraction (rtx x)
static struct constant_descriptor_rtx *
record_constant_rtx (enum machine_mode mode, rtx x)
{ {
struct constant_descriptor_rtx *ptr; rtx r = simplify_rtx (x);
return r ? r : x;
ptr = ggc_alloc (sizeof (*ptr));
decode_rtx_const (mode, x, &ptr->value);
return ptr;
} }
/* Given a constant rtx X, make (or find) a memory constant for its value /* Given a constant rtx X, make (or find) a memory constant for its value
...@@ -2928,30 +2737,32 @@ record_constant_rtx (enum machine_mode mode, rtx x) ...@@ -2928,30 +2737,32 @@ record_constant_rtx (enum machine_mode mode, rtx x)
rtx rtx
force_const_mem (enum machine_mode mode, rtx x) force_const_mem (enum machine_mode mode, rtx x)
{ {
int hash; struct constant_descriptor_rtx *desc, tmp;
struct constant_descriptor_rtx *desc; struct rtx_constant_pool *pool = cfun->varasm->pool;
char label[256]; char label[256];
rtx def, symbol; rtx def, symbol;
struct pool_constant *pool; hashval_t hash;
unsigned int align; unsigned int align;
void **slot;
/* If we're not allowed to drop X into the constant pool, don't. */ /* If we're not allowed to drop X into the constant pool, don't. */
if ((*targetm.cannot_force_const_mem) (x)) if ((*targetm.cannot_force_const_mem) (x))
return NULL_RTX; return NULL_RTX;
/* Compute hash code of X. Search the descriptors for that hash code /* Lookup the value in the hashtable. */
to see if any of them describes X. If yes, we have an rtx to use. */ tmp.constant = x;
hash = const_hash_rtx (mode, x); tmp.mode = mode;
for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next) hash = const_rtx_hash (x);
if (compare_constant_rtx (mode, x, desc)) slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
return copy_rtx (desc->rtl); desc = *slot;
/* No constant equal to X is known to have been output. /* If the constant was already present, return its memory. */
Make a constant descriptor to enter X in the hash table if (desc)
and make a MEM for it. */ return copy_rtx (desc->mem);
desc = record_constant_rtx (mode, x);
desc->next = const_rtx_hash_table[hash]; /* Otherwise, create a new descriptor. */
const_rtx_hash_table[hash] = desc; desc = ggc_alloc (sizeof (*desc));
*slot = desc;
/* Align the location counter as required by EXP's data type. */ /* Align the location counter as required by EXP's data type. */
align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode); align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
...@@ -2963,73 +2774,64 @@ force_const_mem (enum machine_mode mode, rtx x) ...@@ -2963,73 +2774,64 @@ force_const_mem (enum machine_mode mode, rtx x)
} }
#endif #endif
pool_offset += (align / BITS_PER_UNIT) - 1; pool->offset += (align / BITS_PER_UNIT) - 1;
pool_offset &= ~ ((align / BITS_PER_UNIT) - 1); pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
if (GET_CODE (x) == LABEL_REF) desc->next = NULL;
LABEL_PRESERVE_P (XEXP (x, 0)) = 1; desc->constant = tmp.constant;
desc->offset = pool->offset;
/* Allocate a pool constant descriptor, fill it in, and chain it in. */ desc->hash = hash;
pool = ggc_alloc (sizeof (struct pool_constant)); desc->mode = mode;
pool->desc = desc; desc->align = align;
pool->constant = x; desc->labelno = const_labelno;
pool->mode = mode; desc->mark = 0;
pool->labelno = const_labelno;
pool->align = align; pool->offset += GET_MODE_SIZE (mode);
pool->offset = pool_offset; if (pool->last)
pool->mark = 1; pool->last->next = desc;
pool->next = 0;
if (last_pool == 0)
first_pool = pool;
else else
last_pool->next = pool; pool->first = pool->last = desc;
pool->last = desc;
last_pool = pool;
pool_offset += GET_MODE_SIZE (mode);
/* Create a string containing the label name, in LABEL. */ /* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
++const_labelno; ++const_labelno;
/* Construct the SYMBOL_REF and the MEM. */ /* Construct the SYMBOL_REF. Make sure to mark it as belonging to
the constants pool. */
symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL; SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
CONSTANT_POOL_ADDRESS_P (symbol) = 1;
current_function_uses_const_pool = 1;
/* Insert the descriptor into the symbol cross-reference table too. */
slot = htab_find_slot (pool->const_rtx_sym_htab, desc, INSERT);
if (*slot)
abort ();
*slot = desc;
pool->desc->rtl = def = gen_rtx_MEM (mode, symbol); /* Construct the MEM. */
desc->mem = def = gen_rtx_MEM (mode, symbol);
set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1); set_mem_attributes (def, (*lang_hooks.types.type_for_mode) (mode, 0), 1);
RTX_UNCHANGING_P (def) = 1; RTX_UNCHANGING_P (def) = 1;
/* Add label to symbol hash table. */ /* If we're dropping a label to the constant pool, make sure we
hash = SYMHASH (XSTR (symbol, 0)); don't delete it. */
pool->next_sym = const_rtx_sym_hash_table[hash]; if (GET_CODE (x) == LABEL_REF)
const_rtx_sym_hash_table[hash] = pool; LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
/* Mark the symbol_ref as belonging to this constants pool. */
CONSTANT_POOL_ADDRESS_P (symbol) = 1;
SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL;
current_function_uses_const_pool = 1;
return copy_rtx (def); return copy_rtx (def);
} }
/* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to /* Given a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true, return a pointer to
the corresponding pool_constant structure. */ the corresponding constant_descriptor_rtx structure. */
static struct pool_constant * static struct constant_descriptor_rtx *
find_pool_constant (struct function *f, rtx addr) find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
{ {
struct pool_constant *pool; struct constant_descriptor_rtx tmp;
const char *label = XSTR (addr, 0); tmp.sym = sym;
return htab_find (pool->const_rtx_sym_htab, &tmp);
for (pool = f->varasm->x_const_rtx_sym_hash_table[SYMHASH (label)]; pool;
pool = pool->next_sym)
if (XSTR (XEXP (pool->desc->rtl, 0), 0) == label)
return pool;
abort ();
} }
/* Given a constant pool SYMBOL_REF, return the corresponding constant. */ /* Given a constant pool SYMBOL_REF, return the corresponding constant. */
...@@ -3037,7 +2839,7 @@ find_pool_constant (struct function *f, rtx addr) ...@@ -3037,7 +2839,7 @@ find_pool_constant (struct function *f, rtx addr)
rtx rtx
get_pool_constant (rtx addr) get_pool_constant (rtx addr)
{ {
return (find_pool_constant (cfun, addr))->constant; return find_pool_constant (cfun->varasm->pool, addr)->constant;
} }
/* Given a constant pool SYMBOL_REF, return the corresponding constant /* Given a constant pool SYMBOL_REF, return the corresponding constant
...@@ -3046,9 +2848,11 @@ get_pool_constant (rtx addr) ...@@ -3046,9 +2848,11 @@ get_pool_constant (rtx addr)
rtx rtx
get_pool_constant_mark (rtx addr, bool *pmarked) get_pool_constant_mark (rtx addr, bool *pmarked)
{ {
struct pool_constant *pool = find_pool_constant (cfun, addr); struct constant_descriptor_rtx *desc;
*pmarked = (pool->mark != 0);
return pool->constant; desc = find_pool_constant (cfun->varasm->pool, addr);
*pmarked = (desc->mark != 0);
return desc->constant;
} }
/* Likewise, but for the constant pool of a specific function. */ /* Likewise, but for the constant pool of a specific function. */
...@@ -3056,7 +2860,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked) ...@@ -3056,7 +2860,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
rtx rtx
get_pool_constant_for_function (struct function *f, rtx addr) get_pool_constant_for_function (struct function *f, rtx addr)
{ {
return (find_pool_constant (f, addr))->constant; return find_pool_constant (f->varasm->pool, addr)->constant;
} }
/* Similar, return the mode. */ /* Similar, return the mode. */
...@@ -3064,13 +2868,13 @@ get_pool_constant_for_function (struct function *f, rtx addr) ...@@ -3064,13 +2868,13 @@ get_pool_constant_for_function (struct function *f, rtx addr)
enum machine_mode enum machine_mode
get_pool_mode (rtx addr) get_pool_mode (rtx addr)
{ {
return (find_pool_constant (cfun, addr))->mode; return find_pool_constant (cfun->varasm->pool, addr)->mode;
} }
enum machine_mode enum machine_mode
get_pool_mode_for_function (struct function *f, rtx addr) get_pool_mode_for_function (struct function *f, rtx addr)
{ {
return (find_pool_constant (f, addr))->mode; return find_pool_constant (f->varasm->pool, addr)->mode;
} }
/* Similar, return the offset in the constant pool. */ /* Similar, return the offset in the constant pool. */
...@@ -3078,7 +2882,7 @@ get_pool_mode_for_function (struct function *f, rtx addr) ...@@ -3078,7 +2882,7 @@ get_pool_mode_for_function (struct function *f, rtx addr)
int int
get_pool_offset (rtx addr) get_pool_offset (rtx addr)
{ {
return (find_pool_constant (cfun, addr))->offset; return find_pool_constant (cfun->varasm->pool, addr)->offset;
} }
/* Return the size of the constant pool. */ /* Return the size of the constant pool. */
...@@ -3086,295 +2890,243 @@ get_pool_offset (rtx addr) ...@@ -3086,295 +2890,243 @@ get_pool_offset (rtx addr)
int int
get_pool_size (void) get_pool_size (void)
{ {
return pool_offset; return cfun->varasm->pool->offset;
} }
/* Write all the constants in the constant pool. */ /* Worker function for output_constant_pool_1. Emit assembly for X
in MODE with known alignment ALIGN. */
void static void
output_constant_pool (const char *fnname ATTRIBUTE_UNUSED, output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
tree fndecl ATTRIBUTE_UNUSED)
{ {
struct pool_constant *pool; switch (GET_MODE_CLASS (mode))
rtx x;
REAL_VALUE_TYPE r;
/* It is possible for gcc to call force_const_mem and then to later
discard the instructions which refer to the constant. In such a
case we do not need to output the constant. */
mark_constant_pool ();
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
for (pool = first_pool; pool; pool = pool->next)
{ {
rtx tmp; case MODE_FLOAT:
if (GET_CODE (x) != CONST_DOUBLE)
x = pool->constant; abort ();
else
if (! pool->mark)
continue;
/* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
whose CODE_LABEL has been deleted. This can occur if a jump table
is eliminated by optimization. If so, write a constant of zero
instead. Note that this can also happen by turning the
CODE_LABEL into a NOTE. */
/* ??? This seems completely and utterly wrong. Certainly it's
not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
functioning even with INSN_DELETED_P and friends. */
tmp = x;
switch (GET_CODE (x))
{ {
case CONST: REAL_VALUE_TYPE r;
if (GET_CODE (XEXP (x, 0)) != PLUS REAL_VALUE_FROM_CONST_DOUBLE (r, x);
|| GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF) assemble_real (r, mode, align);
break;
tmp = XEXP (XEXP (x, 0), 0);
/* Fall through. */
case LABEL_REF:
tmp = XEXP (x, 0);
if (INSN_DELETED_P (tmp)
|| (GET_CODE (tmp) == NOTE
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
{
abort ();
x = const0_rtx;
}
break;
default:
break;
} }
break;
/* First switch to correct section. */ case MODE_INT:
(*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align); case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY break;
ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, pool->mode,
pool->align, pool->labelno, done);
#endif
assemble_align (pool->align);
/* Output the label. */
(*targetm.asm_out.internal_label) (asm_out_file, "LC", pool->labelno);
/* Output the value of the constant itself. */
switch (GET_MODE_CLASS (pool->mode))
{
case MODE_FLOAT:
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
REAL_VALUE_FROM_CONST_DOUBLE (r, x); case MODE_VECTOR_FLOAT:
assemble_real (r, pool->mode, pool->align); case MODE_VECTOR_INT:
break; {
int i, units;
enum machine_mode submode = GET_MODE_INNER (mode);
unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
case MODE_INT: if (GET_CODE (x) != CONST_VECTOR)
case MODE_PARTIAL_INT: abort ();
assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1); units = CONST_VECTOR_NUNITS (x);
break;
case MODE_VECTOR_FLOAT: for (i = 0; i < units; i++)
{ {
int i, units; rtx elt = CONST_VECTOR_ELT (x, i);
rtx elt; output_constant_pool_2 (submode, elt, i ? subalign : align);
if (GET_CODE (x) != CONST_VECTOR)
abort ();
units = CONST_VECTOR_NUNITS (x);
for (i = 0; i < units; i++)
{
elt = CONST_VECTOR_ELT (x, i);
REAL_VALUE_FROM_CONST_DOUBLE (r, elt);
assemble_real (r, GET_MODE_INNER (pool->mode), pool->align);
}
} }
break; }
break;
case MODE_VECTOR_INT: default:
{ abort ();
int i, units; }
rtx elt; }
if (GET_CODE (x) != CONST_VECTOR) /* Worker function for output_constant_pool. Emit POOL. */
abort ();
units = CONST_VECTOR_NUNITS (x); static void
output_constant_pool_1 (struct constant_descriptor_rtx *desc)
{
rtx x, tmp;
for (i = 0; i < units; i++) if (!desc->mark)
{ return;
elt = CONST_VECTOR_ELT (x, i); x = desc->constant;
assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
pool->align, 1); /* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
} whose CODE_LABEL has been deleted. This can occur if a jump table
} is eliminated by optimization. If so, write a constant of zero
break; instead. Note that this can also happen by turning the
CODE_LABEL into a NOTE. */
/* ??? This seems completely and utterly wrong. Certainly it's
not true for NOTE_INSN_DELETED_LABEL, but I disbelieve proper
functioning even with INSN_DELETED_P and friends. */
tmp = x;
switch (GET_CODE (x))
{
case CONST:
if (GET_CODE (XEXP (x, 0)) != PLUS
|| GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
break;
tmp = XEXP (XEXP (x, 0), 0);
/* FALLTHRU */
default: case LABEL_REF:
tmp = XEXP (x, 0);
if (INSN_DELETED_P (tmp)
|| (GET_CODE (tmp) == NOTE
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_DELETED))
{
abort (); abort ();
x = const0_rtx;
} }
break;
default:
break;
}
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS /* First switch to correct section. */
sections have proper size. */ (*targetm.asm_out.select_rtx_section) (desc->mode, x, desc->align);
if (pool->align > GET_MODE_BITSIZE (pool->mode)
&& in_section == in_named
&& get_named_section_flags (in_named_name) & SECTION_MERGE)
assemble_align (pool->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ; ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
desc->align, desc->labelno, done);
#endif #endif
}
#ifdef ASM_OUTPUT_POOL_EPILOGUE assemble_align (desc->align);
ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
/* Done with this pool. */ /* Output the label. */
first_pool = last_pool = 0; (*targetm.asm_out.internal_label) (asm_out_file, "LC", desc->labelno);
}
/* Look through the instructions for this function, and mark all the /* Output the data. */
entries in the constant pool which are actually being used. Emit output_constant_pool_2 (desc->mode, x, desc->align);
deferred constants which have indeed been used. */
static void /* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
mark_constant_pool (void) sections have proper size. */
{ if (desc->align > GET_MODE_BITSIZE (desc->mode)
rtx insn; && in_section == in_named
rtx link; && get_named_section_flags (in_named_name) & SECTION_MERGE)
struct pool_constant *pool; assemble_align (desc->align);
if (first_pool == 0 && n_deferred_constants == 0) #ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
return; done:
#endif
return;
}
for (pool = first_pool; pool; pool = pool->next) /* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
pool->mark = 0; to as used. Emit referenced deferred strings. This function can
be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) static int
if (INSN_P (insn)) mark_constant (rtx *current_rtx, void *data)
mark_constants (PATTERN (insn)); {
struct rtx_constant_pool *pool = data;
rtx x = *current_rtx;
for (link = current_function_epilogue_delay_list; if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
link; return 0;
link = XEXP (link, 1))
{
insn = XEXP (link, 0);
if (INSN_P (insn)) if (CONSTANT_POOL_ADDRESS_P (x))
mark_constants (PATTERN (insn)); {
struct constant_descriptor_rtx *desc = find_pool_constant (pool, x);
if (desc->mark == 0)
{
desc->mark = 1;
for_each_rtx (&desc->constant, mark_constant, pool);
}
} }
} else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
{
tree exp = SYMBOL_REF_DECL (x);
if (!TREE_ASM_WRITTEN (exp))
{
n_deferred_constants--;
output_constant_def_contents (x);
}
}
return -1;
}
/* Look through appropriate parts of X, marking all entries in the /* Look through appropriate parts of INSN, marking all entries in the
constant pool which are actually being used. Entries that are only constant pool which are actually being used. Entries that are only
referenced by other constants are also marked as used. Emit referenced by other constants are also marked as used. Emit
deferred strings that are used. */ deferred strings that are used. */
static void static void
mark_constants (rtx x) mark_constants (struct rtx_constant_pool *pool, rtx insn)
{ {
int i; if (!INSN_P (insn))
const char *format_ptr;
if (x == 0)
return; return;
if (GET_CODE (x) == SYMBOL_REF)
{
mark_constant (&x, NULL);
return;
}
/* Insns may appear inside a SEQUENCE. Only check the patterns of /* Insns may appear inside a SEQUENCE. Only check the patterns of
insns, not any notes that may be attached. We don't want to mark insns, not any notes that may be attached. We don't want to mark
a constant just because it happens to appear in a REG_EQUIV note. */ a constant just because it happens to appear in a REG_EQUIV note. */
if (INSN_P (x)) if (GET_CODE (PATTERN (insn)) == SEQUENCE)
{ {
mark_constants (PATTERN (x)); rtx seq = PATTERN (insn);
return; int i, n = XVECLEN (seq, 0);
for (i = 0; i < n; ++i)
{
rtx subinsn = XVECEXP (seq, 0, i);
if (INSN_P (subinsn))
for_each_rtx (&PATTERN (subinsn), mark_constant, pool);
}
} }
else
for_each_rtx (&PATTERN (insn), mark_constant, pool);
}
format_ptr = GET_RTX_FORMAT (GET_CODE (x)); /* Look through the instructions for this function, and mark all the
entries in POOL which are actually being used. Emit deferred constants
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++) which have indeed been used. */
{
switch (*format_ptr++)
{
case 'e':
mark_constants (XEXP (x, i));
break;
case 'E': static void
if (XVEC (x, i) != 0) mark_constant_pool (struct rtx_constant_pool *pool)
{ {
int j; rtx insn, link;
for (j = 0; j < XVECLEN (x, i); j++) if (pool->first == 0 && n_deferred_constants == 0)
mark_constants (XVECEXP (x, i, j)); return;
}
break;
case 'S': for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
case 's': mark_constants (pool, insn);
case '0':
case 'i':
case 'w':
case 'n':
case 'u':
case 'B':
break;
default: for (link = current_function_epilogue_delay_list;
abort (); link;
} link = XEXP (link, 1))
} mark_constants (pool, XEXP (link, 0));
} }
/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers /* Write all the constants in the constant pool. */
to as used. Emit referenced deferred strings. This function can
be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */
static int void
mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED) output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
tree fndecl ATTRIBUTE_UNUSED)
{ {
rtx x = *current_rtx; struct rtx_constant_pool *pool = cfun->varasm->pool;
struct constant_descriptor_rtx *desc;
if (x == NULL_RTX) /* It is possible for gcc to call force_const_mem and then to later
return 0; discard the instructions which refer to the constant. In such a
case we do not need to output the constant. */
mark_constant_pool (pool);
else if (GET_CODE (x) == SYMBOL_REF) #ifdef ASM_OUTPUT_POOL_PROLOGUE
{ ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
if (CONSTANT_POOL_ADDRESS_P (x)) #endif
{
struct pool_constant *pool = find_pool_constant (cfun, x); for (desc = pool->first; desc ; desc = desc->next)
if (pool->mark == 0) output_constant_pool_1 (desc);
{
pool->mark = 1; #ifdef ASM_OUTPUT_POOL_EPILOGUE
for_each_rtx (&(pool->constant), &mark_constant, NULL); ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
} #endif
else
return -1; /* Done with this pool. */
} cfun->varasm->pool = NULL;
else if (TREE_CONSTANT_POOL_ADDRESS_P (x))
{
tree exp = SYMBOL_REF_DECL (x);
if (!TREE_ASM_WRITTEN (exp))
{
n_deferred_constants--;
output_constant_def_contents (x);
}
}
}
return 0;
} }
/* Determine what kind of relocations EXP may need. */ /* Determine what kind of relocations EXP may need. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment