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>
* config/rs6000/rs6000.c (rs6000_emit_move): Remove #if 0.
......
......@@ -69,44 +69,18 @@ const char *weak_global_object_name;
struct addr_const;
struct constant_descriptor_rtx;
struct rtx_const;
struct pool_constant;
#define MAX_RTX_HASH_TABLE 61
struct rtx_constant_pool;
struct varasm_status GTY(())
{
/* Hash facility for making memory-constants
from constant rtl-expressions. It is used on RISC machines
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;
/* If we're using a per-function constant pool, this is it. */
struct rtx_constant_pool *pool;
/* Number of tree-constants deferred during the expansion of this
function. */
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)
/* Number for making the label on the next
......@@ -147,16 +121,6 @@ static hashval_t const_hash_1 (const tree);
static int compare_constant (const tree, const tree);
static tree copy_constant (tree);
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 unsigned HOST_WIDE_INT array_size_for_constructor (tree);
static unsigned min_align (unsigned, unsigned);
......@@ -2025,36 +1989,6 @@ decode_addr_const (tree exp, struct addr_const *value)
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.
Each constant in memory thus far output is recorded
in `const_desc_table'. */
......@@ -2612,314 +2546,189 @@ lookup_constant_def (tree exp)
/* Used in the hash tables to avoid outputting the same constant
twice. Unlike 'struct constant_descriptor_tree', RTX constants
are output once per function, not once per file; there seems
to be no reason for the difference. */
struct constant_descriptor_rtx GTY(())
{
/* More constant_descriptors with the same hash code. */
struct constant_descriptor_rtx *next;
/* A MEM for the constant. */
rtx rtl;
/* The value of the constant. */
struct rtx_const value;
are output once per function, not once per file. */
/* ??? Only a few targets need per-function constant pools. Most
can use one per-file pool. Should add a targetm bit to tell the
difference. */
struct rtx_constant_pool GTY(())
{
/* Pointers to first and last constant in pool, as ordered by offset. */
struct constant_descriptor_rtx *first;
struct constant_descriptor_rtx *last;
/* Hash facility for making memory-constants from constant rtl-expressions.
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
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 GTY((chain_next ("%h.next")))
{
struct constant_descriptor_rtx *desc;
struct pool_constant *next;
struct pool_constant *next_sym;
struct constant_descriptor_rtx *next;
rtx mem;
rtx sym;
rtx constant;
HOST_WIDE_INT offset;
hashval_t hash;
enum machine_mode mode;
int labelno;
unsigned int align;
HOST_WIDE_INT offset;
int labelno;
int mark;
};
/* Hash code for a SYMBOL_REF with CONSTANT_POOL_ADDRESS_P true.
The argument is XSTR (... , 0) */
/* Hash and compare functions for const_rtx_htab. */
#define SYMHASH(LABEL) (((unsigned long) (LABEL)) % MAX_RTX_HASH_TABLE)
/* Initialize constant pool hashing for a new function. */
static hashval_t
const_desc_rtx_hash (const void *ptr)
{
const struct constant_descriptor_rtx *desc = ptr;
return desc->hash;
}
void
init_varasm_status (struct function *f)
static int
const_desc_rtx_eq (const void *a, const void *b)
{
struct varasm_status *p;
p = ggc_alloc (sizeof (struct varasm_status));
f->varasm = p;
p->x_const_rtx_hash_table
= ggc_alloc_cleared (MAX_RTX_HASH_TABLE
* sizeof (struct constant_descriptor_rtx *));
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;
const struct constant_descriptor_rtx *x = a;
const struct constant_descriptor_rtx *y = b;
if (x->mode != y->mode)
return 0;
return rtx_equal_p (x->constant, y->constant);
}
/* Express an rtx for a constant integer (perhaps symbolic)
as the sum of a symbol or label plus an explicit integer.
They are stored into VALUE. */
/* Hash and compare functions for const_rtx_sym_htab. */
static void
decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value)
static hashval_t
const_desc_rtx_sym_hash (const void *ptr)
{
/* Clear the whole structure, including any gaps. */
memset (value, 0, sizeof (struct rtx_const));
const struct constant_descriptor_rtx *desc = ptr;
return htab_hash_string (XSTR (desc->sym, 0));
}
value->kind = RTX_INT; /* Most usual kind. */
value->mode = mode;
static int
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))
{
case CONST_DOUBLE:
value->kind = RTX_DOUBLE;
if (GET_MODE (x) != VOIDmode)
{
const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
/* This is the worker function for const_rtx_hash, called via for_each_rtx. */
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
copy garbage from the original structure into our
carefully cleaned hashing structure. */
value->un.du.class = r->class;
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;
x = *xp;
code = GET_CODE (x);
mode = GET_MODE (x);
h = (hashval_t) code * 1048573 + mode;
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);
value->kind = RTX_VECTOR;
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)
h ^= (hashval_t) hwi;
for (i = 1; i < n; ++i)
{
for (i = 0; i < units; ++i)
{
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 ();
}
}
hwi >>= shift;
h ^= (hashval_t) hwi;
}
else
abort ();
}
break;
case CONST_INT:
value->un.addr.offset = INTVAL (x);
case CONST_DOUBLE:
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;
case SYMBOL_REF:
h ^= htab_hash_string (XSTR (x, 0));
break;
case LABEL_REF:
case PC:
value->un.addr.base = x;
h = h * 251 + CODE_LABEL_NUMBER (XEXP (x, 0));
break;
case CONST:
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
{
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;
}
case UNSPEC:
case UNSPEC_VOLATILE:
h = h * 251 + XINT (x, 1);
break;
default:
value->kind = RTX_UNKNOWN;
break;
}
if (value->kind == RTX_INT && value->un.addr.base != 0
&& GET_CODE (value->un.addr.base) == UNSPEC)
{
/* 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;
}
hp = data;
*hp = *hp * 509 + h;
return 0;
}
/* Given a MINUS expression, simplify it if both sides
include the same symbol. */
/* Compute a hash value for X, which should be a constant. */
rtx
simplify_subtraction (rtx x)
static hashval_t
const_rtx_hash (rtx x)
{
struct rtx_const val0, val1;
decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
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;
hashval_t h = 0;
for_each_rtx (&x, const_rtx_hash_1, &h);
return h;
}
/* Compute a hash code for a constant RTL expression. */
/* Initialize constant pool hashing for a new function. */
static unsigned int
const_hash_rtx (enum machine_mode mode, rtx x)
void
init_varasm_status (struct function *f)
{
union {
struct rtx_const value;
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. */
struct varasm_status *p;
struct rtx_constant_pool *pool;
static int
compare_constant_rtx (enum machine_mode mode, rtx x,
struct constant_descriptor_rtx *desc)
{
struct rtx_const value;
p = ggc_alloc (sizeof (struct varasm_status));
f->varasm = p;
decode_rtx_const (mode, x, &value);
pool = ggc_alloc (sizeof (struct rtx_constant_pool));
p->pool = pool;
p->deferred_constants = 0;
/* Compare constant contents. */
return memcmp (&value, &desc->value, sizeof (struct rtx_const)) == 0;
pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
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.
It is up to the caller to enter the descriptor in the hash table. */
static struct constant_descriptor_rtx *
record_constant_rtx (enum machine_mode mode, rtx x)
rtx
simplify_subtraction (rtx x)
{
struct constant_descriptor_rtx *ptr;
ptr = ggc_alloc (sizeof (*ptr));
decode_rtx_const (mode, x, &ptr->value);
return ptr;
rtx r = simplify_rtx (x);
return r ? r : x;
}
/* 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)
rtx
force_const_mem (enum machine_mode mode, rtx x)
{
int hash;
struct constant_descriptor_rtx *desc;
struct constant_descriptor_rtx *desc, tmp;
struct rtx_constant_pool *pool = cfun->varasm->pool;
char label[256];
rtx def, symbol;
struct pool_constant *pool;
hashval_t hash;
unsigned int align;
void **slot;
/* If we're not allowed to drop X into the constant pool, don't. */
if ((*targetm.cannot_force_const_mem) (x))
return NULL_RTX;
/* Compute hash code of X. Search the descriptors for that hash code
to see if any of them describes X. If yes, we have an rtx to use. */
hash = const_hash_rtx (mode, x);
for (desc = const_rtx_hash_table[hash]; desc; desc = desc->next)
if (compare_constant_rtx (mode, x, desc))
return copy_rtx (desc->rtl);
/* No constant equal to X is known to have been output.
Make a constant descriptor to enter X in the hash table
and make a MEM for it. */
desc = record_constant_rtx (mode, x);
desc->next = const_rtx_hash_table[hash];
const_rtx_hash_table[hash] = desc;
/* Lookup the value in the hashtable. */
tmp.constant = x;
tmp.mode = mode;
hash = const_rtx_hash (x);
slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
desc = *slot;
/* If the constant was already present, return its memory. */
if (desc)
return copy_rtx (desc->mem);
/* Otherwise, create a new descriptor. */
desc = ggc_alloc (sizeof (*desc));
*slot = desc;
/* Align the location counter as required by EXP's data type. */
align = GET_MODE_ALIGNMENT (mode == VOIDmode ? word_mode : mode);
......@@ -2963,73 +2774,64 @@ force_const_mem (enum machine_mode mode, rtx x)
}
#endif
pool_offset += (align / BITS_PER_UNIT) - 1;
pool_offset &= ~ ((align / BITS_PER_UNIT) - 1);
if (GET_CODE (x) == LABEL_REF)
LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
/* Allocate a pool constant descriptor, fill it in, and chain it in. */
pool = ggc_alloc (sizeof (struct pool_constant));
pool->desc = desc;
pool->constant = x;
pool->mode = mode;
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
first_pool = pool;
pool->offset += (align / BITS_PER_UNIT) - 1;
pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
desc->next = NULL;
desc->constant = tmp.constant;
desc->offset = pool->offset;
desc->hash = hash;
desc->mode = mode;
desc->align = align;
desc->labelno = const_labelno;
desc->mark = 0;
pool->offset += GET_MODE_SIZE (mode);
if (pool->last)
pool->last->next = desc;
else
last_pool->next = pool;
last_pool = pool;
pool_offset += GET_MODE_SIZE (mode);
pool->first = pool->last = desc;
pool->last = desc;
/* Create a string containing the label name, in LABEL. */
ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
++const_labelno;
/* Construct the SYMBOL_REF and the MEM. */
symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
/* Construct the SYMBOL_REF. Make sure to mark it as belonging to
the constants pool. */
desc->sym = symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label));
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);
RTX_UNCHANGING_P (def) = 1;
/* Add label to symbol hash table. */
hash = SYMHASH (XSTR (symbol, 0));
pool->next_sym = const_rtx_sym_hash_table[hash];
const_rtx_sym_hash_table[hash] = pool;
/* 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;
/* If we're dropping a label to the constant pool, make sure we
don't delete it. */
if (GET_CODE (x) == LABEL_REF)
LABEL_PRESERVE_P (XEXP (x, 0)) = 1;
return copy_rtx (def);
}
/* 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 *
find_pool_constant (struct function *f, rtx addr)
static struct constant_descriptor_rtx *
find_pool_constant (struct rtx_constant_pool *pool, rtx sym)
{
struct pool_constant *pool;
const char *label = XSTR (addr, 0);
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 ();
struct constant_descriptor_rtx tmp;
tmp.sym = sym;
return htab_find (pool->const_rtx_sym_htab, &tmp);
}
/* Given a constant pool SYMBOL_REF, return the corresponding constant. */
......@@ -3037,7 +2839,7 @@ find_pool_constant (struct function *f, rtx addr)
rtx
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
......@@ -3046,9 +2848,11 @@ get_pool_constant (rtx addr)
rtx
get_pool_constant_mark (rtx addr, bool *pmarked)
{
struct pool_constant *pool = find_pool_constant (cfun, addr);
*pmarked = (pool->mark != 0);
return pool->constant;
struct constant_descriptor_rtx *desc;
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. */
......@@ -3056,7 +2860,7 @@ get_pool_constant_mark (rtx addr, bool *pmarked)
rtx
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. */
......@@ -3064,13 +2868,13 @@ get_pool_constant_for_function (struct function *f, rtx addr)
enum machine_mode
get_pool_mode (rtx addr)
{
return (find_pool_constant (cfun, addr))->mode;
return find_pool_constant (cfun->varasm->pool, addr)->mode;
}
enum machine_mode
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. */
......@@ -3078,7 +2882,7 @@ get_pool_mode_for_function (struct function *f, rtx addr)
int
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. */
......@@ -3086,295 +2890,243 @@ get_pool_offset (rtx addr)
int
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
output_constant_pool (const char *fnname ATTRIBUTE_UNUSED,
tree fndecl ATTRIBUTE_UNUSED)
static void
output_constant_pool_2 (enum machine_mode mode, rtx x, unsigned int align)
{
struct pool_constant *pool;
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)
switch (GET_MODE_CLASS (mode))
{
rtx tmp;
x = pool->constant;
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 MODE_FLOAT:
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
else
{
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);
/* 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;
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
assemble_real (r, mode, align);
}
break;
/* First switch to correct section. */
(*targetm.asm_out.select_rtx_section) (pool->mode, x, pool->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
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 ();
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (mode), align, 1);
break;
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
assemble_real (r, pool->mode, pool->align);
break;
case MODE_VECTOR_FLOAT:
case MODE_VECTOR_INT:
{
int i, units;
enum machine_mode submode = GET_MODE_INNER (mode);
unsigned int subalign = MIN (align, GET_MODE_BITSIZE (submode));
case MODE_INT:
case MODE_PARTIAL_INT:
assemble_integer (x, GET_MODE_SIZE (pool->mode), pool->align, 1);
break;
if (GET_CODE (x) != CONST_VECTOR)
abort ();
units = CONST_VECTOR_NUNITS (x);
case MODE_VECTOR_FLOAT:
for (i = 0; i < units; i++)
{
int i, units;
rtx elt;
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);
}
rtx elt = CONST_VECTOR_ELT (x, i);
output_constant_pool_2 (submode, elt, i ? subalign : align);
}
break;
}
break;
case MODE_VECTOR_INT:
{
int i, units;
rtx elt;
default:
abort ();
}
}
if (GET_CODE (x) != CONST_VECTOR)
abort ();
/* Worker function for output_constant_pool. Emit POOL. */
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++)
{
elt = CONST_VECTOR_ELT (x, i);
assemble_integer (elt, GET_MODE_UNIT_SIZE (pool->mode),
pool->align, 1);
}
}
break;
if (!desc->mark)
return;
x = desc->constant;
/* 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:
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 ();
x = const0_rtx;
}
break;
default:
break;
}
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
sections have proper size. */
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);
/* First switch to correct section. */
(*targetm.asm_out.select_rtx_section) (desc->mode, x, desc->align);
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ;
ASM_OUTPUT_SPECIAL_POOL_ENTRY (asm_out_file, x, desc->mode,
desc->align, desc->labelno, done);
#endif
}
#ifdef ASM_OUTPUT_POOL_EPILOGUE
ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
assemble_align (desc->align);
/* Done with this pool. */
first_pool = last_pool = 0;
}
/* Output the label. */
(*targetm.asm_out.internal_label) (asm_out_file, "LC", desc->labelno);
/* Look through the instructions for this function, and mark all the
entries in the constant pool which are actually being used. Emit
deferred constants which have indeed been used. */
/* Output the data. */
output_constant_pool_2 (desc->mode, x, desc->align);
static void
mark_constant_pool (void)
{
rtx insn;
rtx link;
struct pool_constant *pool;
/* Make sure all constants in SECTION_MERGE and not SECTION_STRINGS
sections have proper size. */
if (desc->align > GET_MODE_BITSIZE (desc->mode)
&& in_section == in_named
&& get_named_section_flags (in_named_name) & SECTION_MERGE)
assemble_align (desc->align);
if (first_pool == 0 && n_deferred_constants == 0)
return;
#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done:
#endif
return;
}
for (pool = first_pool; pool; pool = pool->next)
pool->mark = 0;
/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
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))
if (INSN_P (insn))
mark_constants (PATTERN (insn));
static int
mark_constant (rtx *current_rtx, void *data)
{
struct rtx_constant_pool *pool = data;
rtx x = *current_rtx;
for (link = current_function_epilogue_delay_list;
link;
link = XEXP (link, 1))
{
insn = XEXP (link, 0);
if (x == NULL_RTX || GET_CODE (x) != SYMBOL_REF)
return 0;
if (INSN_P (insn))
mark_constants (PATTERN (insn));
if (CONSTANT_POOL_ADDRESS_P (x))
{
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
referenced by other constants are also marked as used. Emit
deferred strings that are used. */
static void
mark_constants (rtx x)
mark_constants (struct rtx_constant_pool *pool, rtx insn)
{
int i;
const char *format_ptr;
if (x == 0)
if (!INSN_P (insn))
return;
if (GET_CODE (x) == SYMBOL_REF)
{
mark_constant (&x, NULL);
return;
}
/* 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
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));
return;
rtx seq = PATTERN (insn);
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));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
{
switch (*format_ptr++)
{
case 'e':
mark_constants (XEXP (x, i));
break;
/* Look through the instructions for this function, and mark all the
entries in POOL which are actually being used. Emit deferred constants
which have indeed been used. */
case 'E':
if (XVEC (x, i) != 0)
{
int j;
static void
mark_constant_pool (struct rtx_constant_pool *pool)
{
rtx insn, link;
for (j = 0; j < XVECLEN (x, i); j++)
mark_constants (XVECEXP (x, i, j));
}
break;
if (pool->first == 0 && n_deferred_constants == 0)
return;
case 'S':
case 's':
case '0':
case 'i':
case 'w':
case 'n':
case 'u':
case 'B':
break;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
mark_constants (pool, insn);
default:
abort ();
}
}
for (link = current_function_epilogue_delay_list;
link;
link = XEXP (link, 1))
mark_constants (pool, XEXP (link, 0));
}
/* Given a SYMBOL_REF CURRENT_RTX, mark it and all constants it refers
to as used. Emit referenced deferred strings. This function can
be used with for_each_rtx to mark all SYMBOL_REFs in an rtx. */
/* Write all the constants in the constant pool. */
static int
mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED)
void
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)
return 0;
/* 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 (pool);
else if (GET_CODE (x) == SYMBOL_REF)
{
if (CONSTANT_POOL_ADDRESS_P (x))
{
struct pool_constant *pool = find_pool_constant (cfun, x);
if (pool->mark == 0)
{
pool->mark = 1;
for_each_rtx (&(pool->constant), &mark_constant, NULL);
}
else
return -1;
}
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;
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool->offset);
#endif
for (desc = pool->first; desc ; desc = desc->next)
output_constant_pool_1 (desc);
#ifdef ASM_OUTPUT_POOL_EPILOGUE
ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool->offset);
#endif
/* Done with this pool. */
cfun->varasm->pool = NULL;
}
/* 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