* expr.c (store_constructor): Add support for SET_TYPE.

From-SVN: r8604
This commit is contained in:
Per Bothner 1994-12-02 20:17:51 -08:00
parent 0be3720296
commit 071a659510

View File

@ -188,6 +188,7 @@ static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int));
static tree defer_cleanups_to PROTO((tree));
extern void (*interim_eh_hook) PROTO((tree));
extern tree get_set_constructor_words PROTO((tree, HOST_WIDE_INT*, int));
/* Record for each mode whether we can move a register directly to or
from an object of that mode in memory. If we can't, we won't try
@ -3099,6 +3100,172 @@ store_constructor (exp, target)
}
}
}
/* set constructor assignments */
else if (TREE_CODE (type) == SET_TYPE)
{
tree elt;
rtx xtarget = XEXP (target, 0);
int set_word_size = TYPE_ALIGN (type);
int nbytes = int_size_in_bytes (type);
int nwords;
tree non_const_elements;
int need_to_clear_first;
tree domain = TYPE_DOMAIN (type);
tree domain_min, domain_max, bitlength;
/* The default implementation stategy is to extract the constant
parts of the constructor, use that to initialize the target,
and then "or" in whatever non-constant ranges we need in addition.
If a large set is all zero or all ones, it is
probably better to set it using memset (if available) or bzero.
Also, if a large set has just a single range, it may also be
better to first clear all the first clear the set (using
bzero/memset), and set the bits we want. */
/* Check for all zeros. */
if (CONSTRUCTOR_ELTS (exp) == NULL_TREE)
{
clear_storage (target, nbytes);
return;
}
if (nbytes < 0)
abort();
nwords = (nbytes * BITS_PER_UNIT) / set_word_size;
if (nwords == 0)
nwords = 1;
domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
bitlength = size_binop (PLUS_EXPR,
size_binop (MINUS_EXPR, domain_max, domain_min),
size_one_node);
/* Check for range all ones, or at most a single range.
(This optimization is only a win for big sets.) */
if (GET_MODE (target) == BLKmode && nbytes > 16
&& TREE_CHAIN (CONSTRUCTOR_ELTS (exp)) == NULL_TREE)
{
need_to_clear_first = 1;
non_const_elements = CONSTRUCTOR_ELTS (exp);
}
else
{
HOST_WIDE_INT *buffer
= (HOST_WIDE_INT*) alloca (sizeof (HOST_WIDE_INT) * nwords);
non_const_elements = get_set_constructor_words (exp, buffer, nwords);
if (nbytes * BITS_PER_UNIT <= set_word_size)
{
if (BITS_BIG_ENDIAN)
buffer[0] >>= set_word_size - nbytes * BITS_PER_UNIT;
emit_move_insn (target, GEN_INT (buffer[0]));
}
else
{
rtx addr = XEXP (target, 0);
rtx to_rtx;
register int i;
enum machine_mode mode
= mode_for_size (set_word_size, MODE_INT, 1);
for (i = 0; i < nwords; i++)
{
int offset = i * set_word_size / BITS_PER_UNIT;
rtx datum = GEN_INT (buffer[i]);
rtx to_rtx = change_address (target, mode,
plus_constant (addr, offset));
MEM_IN_STRUCT_P (to_rtx) = 1;
emit_move_insn (to_rtx, datum);
}
}
need_to_clear_first = 0;
}
for (elt = non_const_elements; elt != NULL_TREE; elt = TREE_CHAIN (elt))
{
/* start of range of element or NULL */
tree startbit = TREE_PURPOSE (elt);
/* end of range of element, or element value */
tree endbit = TREE_VALUE (elt);
HOST_WIDE_INT startb, endb;
rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
bitlength_rtx = expand_expr (bitlength,
NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
/* handle non-range tuple element like [ expr ] */
if (startbit == NULL_TREE)
{
startbit = save_expr (endbit);
endbit = startbit;
}
startbit = convert (sizetype, startbit);
endbit = convert (sizetype, endbit);
if (! integer_zerop (domain_min))
{
startbit = size_binop (MINUS_EXPR, startbit, domain_min);
endbit = size_binop (MINUS_EXPR, endbit, domain_min);
}
startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
EXPAND_CONST_ADDRESS);
endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
EXPAND_CONST_ADDRESS);
if (REG_P (target))
{
targetx = assign_stack_temp (GET_MODE (target),
GET_MODE_SIZE (GET_MODE (target)),
0);
emit_move_insn (targetx, target);
}
else if (GET_CODE (target) == MEM)
targetx = target;
else
abort ();
#ifdef TARGET_MEM_FUNCTIONS
/* Optimization: If startbit and endbit are
constants divisble by BITS_PER_UNIT,
call memset instead. */
if (TREE_CODE (startbit) == INTEGER_CST
&& TREE_CODE (endbit) == INTEGER_CST
&& (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
&& (endb = TREE_INT_CST_LOW (endbit)) % BITS_PER_UNIT == 0)
{
if (need_to_clear_first
&& endb - startb != nbytes * BITS_PER_UNIT)
clear_storage (target, nbytes);
need_to_clear_first = 0;
emit_library_call (memset_libfunc, 0,
VOIDmode, 3,
plus_constant (XEXP (targetx, 0), startb),
Pmode,
constm1_rtx, Pmode,
GEN_INT ((endb - startb) / BITS_PER_UNIT),
Pmode);
}
else
#endif
{
if (need_to_clear_first)
{
clear_storage (target, nbytes);
need_to_clear_first = 0;
}
emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__setbits"),
0, VOIDmode, 4, XEXP (targetx, 0), Pmode,
bitlength_rtx, TYPE_MODE (sizetype),
startbit_rtx, TYPE_MODE (sizetype),
endbit_rtx, TYPE_MODE (sizetype));
}
if (REG_P (target))
emit_move_insn (target, targetx);
}
}
else
abort ();