diff options
author | Per Bothner <bothner@gcc.gnu.org> | 1994-12-02 20:17:51 -0800 |
---|---|---|
committer | Per Bothner <bothner@gcc.gnu.org> | 1994-12-02 20:17:51 -0800 |
commit | 071a6595101473e436302942d2ec631c7799c583 (patch) | |
tree | f6a49673490ec9cb77e4cf8ff66c13c01d254018 | |
parent | 0be37202964cb589ce07001406a9dca99ec21b0d (diff) | |
download | gcc-071a6595101473e436302942d2ec631c7799c583.zip gcc-071a6595101473e436302942d2ec631c7799c583.tar.gz gcc-071a6595101473e436302942d2ec631c7799c583.tar.bz2 |
* expr.c (store_constructor): Add support for SET_TYPE.
From-SVN: r8604
-rw-r--r-- | gcc/expr.c | 167 |
1 files changed, 167 insertions, 0 deletions
@@ -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 (); |