diff options
author | hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-07-23 19:37:40 +0000 |
---|---|---|
committer | hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-07-23 19:37:40 +0000 |
commit | 10ada81fea4490f94ba2eb5923bf5baa367a38bd (patch) | |
tree | 437dca120093cc7b1f6debf6f6b31779526c7192 /gcc/expr.c | |
parent | 95a236de8aa10bf009e9368dfd28f95a980e5570 (diff) | |
parent | 3bd7a983695352a99f7dd597725eb5b839d4b4cf (diff) | |
download | gcc-ifunc.tar.gz |
Merged with trunk at revision 162480.ifunc
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/ifunc@162483 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 324 |
1 files changed, 193 insertions, 131 deletions
diff --git a/gcc/expr.c b/gcc/expr.c index 2763dc91991..3e5d18bdebc 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "df.h" #include "diagnostic.h" #include "ssaexpand.h" +#include "target-globals.h" /* Decide whether a function's arguments should be processed from first to last or from last to first. @@ -158,17 +159,6 @@ static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx); static rtx const_vector_from_tree (tree); static void write_complex_part (rtx, rtx, bool); -/* 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 - to use that mode directly when accessing a field of that mode. */ - -static char direct_load[NUM_MACHINE_MODES]; -static char direct_store[NUM_MACHINE_MODES]; - -/* Record for each mode whether we can float-extend from memory. */ - -static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES]; - /* This macro is used to determine whether move_by_pieces should be called to perform a structure copy. */ #ifndef MOVE_BY_PIECES_P @@ -201,41 +191,6 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES]; < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ())) #endif -/* This array records the insn_code of insns to perform block moves. */ -enum insn_code movmem_optab[NUM_MACHINE_MODES]; - -/* This array records the insn_code of insns to perform block sets. */ -enum insn_code setmem_optab[NUM_MACHINE_MODES]; - -/* These arrays record the insn_code of three different kinds of insns - to perform block compares. */ -enum insn_code cmpstr_optab[NUM_MACHINE_MODES]; -enum insn_code cmpstrn_optab[NUM_MACHINE_MODES]; -enum insn_code cmpmem_optab[NUM_MACHINE_MODES]; - -/* Synchronization primitives. */ -enum insn_code sync_add_optab[NUM_MACHINE_MODES]; -enum insn_code sync_sub_optab[NUM_MACHINE_MODES]; -enum insn_code sync_ior_optab[NUM_MACHINE_MODES]; -enum insn_code sync_and_optab[NUM_MACHINE_MODES]; -enum insn_code sync_xor_optab[NUM_MACHINE_MODES]; -enum insn_code sync_nand_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_add_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_sub_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_ior_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_and_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_xor_optab[NUM_MACHINE_MODES]; -enum insn_code sync_old_nand_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_add_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_sub_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_ior_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_and_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES]; -enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES]; -enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES]; -enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES]; -enum insn_code sync_lock_release[NUM_MACHINE_MODES]; - /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */ #ifndef SLOW_UNALIGNED_ACCESS @@ -434,7 +389,7 @@ convert_move (rtx to, rtx from, int unsignedp) /* Try converting directly if the insn is supported. */ - code = convert_optab_handler (tab, to_mode, from_mode)->insn_code; + code = convert_optab_handler (tab, to_mode, from_mode); if (code != CODE_FOR_nothing) { emit_unop_insn (code, to, from, @@ -468,12 +423,12 @@ convert_move (rtx to, rtx from, int unsignedp) enum machine_mode full_mode = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT); - gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code + gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode) != CODE_FOR_nothing); if (full_mode != from_mode) from = convert_to_mode (full_mode, from, unsignedp); - emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code, + emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode), to, from, UNKNOWN); return; } @@ -483,18 +438,19 @@ convert_move (rtx to, rtx from, int unsignedp) enum machine_mode full_mode = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT); - gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code + gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode) != CODE_FOR_nothing); if (to_mode == full_mode) { - emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code, + emit_unop_insn (convert_optab_handler (sext_optab, full_mode, + from_mode), to, from, UNKNOWN); return; } new_from = gen_reg_rtx (full_mode); - emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code, + emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode), new_from, from, UNKNOWN); /* else proceed to integer conversions below. */ @@ -695,9 +651,10 @@ convert_move (rtx to, rtx from, int unsignedp) } /* Support special truncate insns for certain modes. */ - if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing) + if (convert_optab_handler (trunc_optab, to_mode, + from_mode) != CODE_FOR_nothing) { - emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code, + emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode), to, from, UNKNOWN); return; } @@ -990,7 +947,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, if (mode == VOIDmode) break; - icode = optab_handler (mov_optab, mode)->insn_code; + icode = optab_handler (mov_optab, mode); if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) move_by_pieces_1 (GEN_FCN (icode), mode, &data); @@ -1071,7 +1028,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align, if (mode == VOIDmode) break; - icode = optab_handler (mov_optab, mode)->insn_code; + icode = optab_handler (mov_optab, mode); if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode); @@ -1163,6 +1120,11 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, rtx retval = 0; unsigned int align; + gcc_assert (size); + if (CONST_INT_P (size) + && INTVAL (size) == 0) + return 0; + switch (method) { case BLOCK_OP_NORMAL: @@ -1186,13 +1148,10 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, gcc_unreachable (); } + gcc_assert (MEM_P (x) && MEM_P (y)); align = MIN (MEM_ALIGN (x), MEM_ALIGN (y)); gcc_assert (align >= BITS_PER_UNIT); - gcc_assert (MEM_P (x)); - gcc_assert (MEM_P (y)); - gcc_assert (size); - /* Make sure we've got BLKmode addresses; store_one_arg can decide that block copy is more efficient for other large modes, e.g. DCmode. */ x = adjust_address (x, BLKmode, 0); @@ -1202,9 +1161,6 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, can be incorrect is coming from __builtin_memcpy. */ if (CONST_INT_P (size)) { - if (INTVAL (size) == 0) - return 0; - x = shallow_copy_rtx (x); y = shallow_copy_rtx (y); set_mem_size (x, size); @@ -1313,7 +1269,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align, for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { - enum insn_code code = movmem_optab[(int) mode]; + enum insn_code code = direct_optab_handler (movmem_optab, mode); insn_operand_predicate_fn pred; if (code != CODE_FOR_nothing @@ -2352,7 +2308,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len, if (mode == VOIDmode) break; - icode = optab_handler (mov_optab, mode)->insn_code; + icode = optab_handler (mov_optab, mode); if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) { @@ -2565,7 +2521,7 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, if (mode == VOIDmode) break; - icode = optab_handler (mov_optab, mode)->insn_code; + icode = optab_handler (mov_optab, mode); if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) store_by_pieces_2 (GEN_FCN (icode), mode, data); @@ -2789,7 +2745,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align, for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode)) { - enum insn_code code = setmem_optab[(int) mode]; + enum insn_code code = direct_optab_handler (setmem_optab, mode); insn_operand_predicate_fn pred; if (code != CODE_FOR_nothing @@ -3034,7 +2990,7 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force) return NULL_RTX; /* The target must support moves in this mode. */ - code = optab_handler (mov_optab, imode)->insn_code; + code = optab_handler (mov_optab, imode); if (code == CODE_FOR_nothing) return NULL_RTX; @@ -3184,7 +3140,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y) /* Move floating point as parts. */ if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT - && optab_handler (mov_optab, GET_MODE_INNER (mode))->insn_code != CODE_FOR_nothing) + && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing) try_int = false; /* Not possible if the values are inherently not adjacent. */ else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT) @@ -3235,7 +3191,7 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y) /* Assume all MODE_CC modes are equivalent; if we have movcc, use it. */ if (mode != CCmode) { - enum insn_code code = optab_handler (mov_optab, CCmode)->insn_code; + enum insn_code code = optab_handler (mov_optab, CCmode); if (code != CODE_FOR_nothing) { x = emit_move_change_mode (CCmode, mode, x, true); @@ -3375,7 +3331,7 @@ emit_move_insn_1 (rtx x, rtx y) gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE); - code = optab_handler (mov_optab, mode)->insn_code; + code = optab_handler (mov_optab, mode); if (code != CODE_FOR_nothing) return emit_insn (GEN_FCN (code) (x, y)); @@ -3627,7 +3583,7 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type) stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode)); /* If there is push pattern, use it. Otherwise try old way of throwing MEM representing push operation to move expander. */ - icode = optab_handler (push_optab, mode)->insn_code; + icode = optab_handler (push_optab, mode); if (icode != CODE_FOR_nothing) { if (((pred = insn_data[(int) icode].operand[0].predicate) @@ -4213,6 +4169,10 @@ expand_assignment (tree to, tree from, bool nontemporal) an array element in an unaligned packed structure field, has the same problem. */ if (handled_component_p (to) + /* ??? We only need to handle MEM_REF here if the access is not + a full access of the base object. */ + || (TREE_CODE (to) == MEM_REF + && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR) || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE) { enum machine_mode mode1; @@ -4359,7 +4319,7 @@ expand_assignment (tree to, tree from, bool nontemporal) set_mem_attributes (mem, to, 0); set_mem_addr_space (mem, as); - icode = movmisalign_optab->handlers[mode].insn_code; + icode = optab_handler (movmisalign_optab, mode); gcc_assert (icode != CODE_FOR_nothing); op_mode1 = insn_data[icode].operand[1].mode; @@ -4492,7 +4452,7 @@ bool emit_storent_insn (rtx to, rtx from) { enum machine_mode mode = GET_MODE (to), imode; - enum insn_code code = optab_handler (storent_optab, mode)->insn_code; + enum insn_code code = optab_handler (storent_optab, mode); rtx pattern; if (code == CODE_FOR_nothing) @@ -4686,6 +4646,51 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) BLOCK_OP_NORMAL); return NULL_RTX; } + else if (TREE_CODE (exp) == MEM_REF + && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == STRING_CST + && integer_zerop (TREE_OPERAND (exp, 1)) + && !nontemporal && !call_param_p + && TYPE_MODE (TREE_TYPE (exp)) == BLKmode) + { + /* Optimize initialization of an array with a STRING_CST. */ + HOST_WIDE_INT exp_len, str_copy_len; + rtx dest_mem; + tree str = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + + exp_len = int_expr_size (exp); + if (exp_len <= 0) + goto normal_expr; + + str_copy_len = strlen (TREE_STRING_POINTER (str)); + if (str_copy_len < TREE_STRING_LENGTH (str) - 1) + goto normal_expr; + + str_copy_len = TREE_STRING_LENGTH (str); + if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0) + { + str_copy_len += STORE_MAX_PIECES - 1; + str_copy_len &= ~(STORE_MAX_PIECES - 1); + } + str_copy_len = MIN (str_copy_len, exp_len); + if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str, + CONST_CAST(char *, TREE_STRING_POINTER (str)), + MEM_ALIGN (target), false)) + goto normal_expr; + + dest_mem = target; + + dest_mem = store_by_pieces (dest_mem, + str_copy_len, builtin_strncpy_read_str, + CONST_CAST(char *, TREE_STRING_POINTER (str)), + MEM_ALIGN (target), false, + exp_len > str_copy_len ? 1 : 0); + if (exp_len > str_copy_len) + clear_storage (adjust_address (dest_mem, BLKmode, 0), + GEN_INT (exp_len - str_copy_len), + BLOCK_OP_NORMAL); + return NULL_RTX; + } else { rtx tmp_target; @@ -5048,7 +5053,7 @@ count_type_elements (const_tree type, bool allow_flexarr) HOST_WIDE_INT n = 0, t; tree f; - for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) + for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f)) if (TREE_CODE (f) == FIELD_DECL) { t = count_type_elements (TREE_TYPE (f), false); @@ -5057,7 +5062,7 @@ count_type_elements (const_tree type, bool allow_flexarr) /* Check for structures with flexible array member. */ tree tf = TREE_TYPE (f); if (allow_flexarr - && TREE_CHAIN (f) == NULL + && DECL_CHAIN (f) == NULL && TREE_CODE (tf) == ARRAY_TYPE && TYPE_DOMAIN (tf) && TYPE_MIN_VALUE (TYPE_DOMAIN (tf)) @@ -5654,7 +5659,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) { enum machine_mode mode = GET_MODE (target); - icode = (int) optab_handler (vec_init_optab, mode)->insn_code; + icode = (int) optab_handler (vec_init_optab, mode); if (icode != CODE_FOR_nothing) { unsigned int i; @@ -5852,7 +5857,15 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, operations. */ || (bitsize >= 0 && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST - && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)) + && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0) + /* If we are expanding a MEM_REF of a non-BLKmode non-addressable + decl we must use bitfield operations. */ + || (bitsize >= 0 + && TREE_CODE (exp) == MEM_REF + && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 )) + && DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode)) { rtx temp; gimple nop_def; @@ -6113,6 +6126,24 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, goto done; break; + case MEM_REF: + /* Hand back the decl for MEM[&decl, off]. */ + if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR) + { + tree off = TREE_OPERAND (exp, 1); + if (!integer_zerop (off)) + { + double_int boff, coff = mem_ref_offset (exp); + boff = double_int_lshift (coff, + BITS_PER_UNIT == 8 + ? 3 : exact_log2 (BITS_PER_UNIT), + HOST_BITS_PER_DOUBLE_INT, true); + bit_offset = double_int_add (bit_offset, boff); + } + exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + } + goto done; + default: goto done; } @@ -6628,7 +6659,6 @@ safe_from_p (const_rtx x, tree exp, int top_p) break; case MISALIGNED_INDIRECT_REF: - case ALIGN_INDIRECT_REF: case INDIRECT_REF: if (MEM_P (x) && alias_sets_conflict_p (MEM_ALIAS_SET (x), @@ -6796,8 +6826,7 @@ emutls_var_address (tree var) tree emuvar = emutls_decl (var); tree fn = built_in_decls [BUILT_IN_EMUTLS_GET_ADDRESS]; tree arg = build_fold_addr_expr_with_type (emuvar, ptr_type_node); - tree arglist = build_tree_list (NULL_TREE, arg); - tree call = build_function_call_expr (UNKNOWN_LOCATION, fn, arglist); + tree call = build_call_expr (fn, 1, arg); return fold_convert (build_pointer_type (TREE_TYPE (var)), call); } @@ -6873,6 +6902,16 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, /* This case will happen via recursion for &a->b. */ return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier); + case MEM_REF: + { + tree tem = TREE_OPERAND (exp, 0); + if (!integer_zerop (TREE_OPERAND (exp, 1))) + tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)), + tem, + double_int_to_tree (sizetype, mem_ref_offset (exp))); + return expand_expr (tem, target, tmode, modifier); + } + case CONST_DECL: /* Expand the initializer like constants above. */ return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0); @@ -7619,7 +7658,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, this_optab = usmul_widen_optab; if (mode == GET_MODE_2XWIDER_MODE (innermode)) { - if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing) + if (optab_handler (this_optab, mode) != CODE_FOR_nothing) { if (TYPE_UNSIGNED (TREE_TYPE (treeop0))) expand_operands (treeop0, treeop1, subtarget, &op0, &op1, @@ -7645,7 +7684,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, if (mode == GET_MODE_2XWIDER_MODE (innermode)) { - if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing) + if (optab_handler (this_optab, mode) != CODE_FOR_nothing) { expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); @@ -7653,7 +7692,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, unsignedp, this_optab); return REDUCE_BIT_FIELD (temp); } - if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing + if (optab_handler (other_optab, mode) != CODE_FOR_nothing && innermode == word_mode) { rtx htem, hipart; @@ -8594,12 +8633,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return expand_constructor (exp, target, modifier, false); case MISALIGNED_INDIRECT_REF: - case ALIGN_INDIRECT_REF: case INDIRECT_REF: { tree exp1 = treeop0; addr_space_t as = ADDR_SPACE_GENERIC; - enum machine_mode address_mode = Pmode; if (modifier != EXPAND_WRITE) { @@ -8611,21 +8648,11 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, } if (POINTER_TYPE_P (TREE_TYPE (exp1))) - { - as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1))); - address_mode = targetm.addr_space.address_mode (as); - } + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1))); op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address_addr_space (mode, op0, as); - if (code == ALIGN_INDIRECT_REF) - { - int align = TYPE_ALIGN_UNIT (type); - op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align)); - op0 = memory_address_addr_space (mode, op0, as); - } - temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); @@ -8642,7 +8669,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, || modifier == EXPAND_STACK_PARM); /* The vectorizer should have already checked the mode. */ - icode = optab_handler (movmisalign_optab, mode)->insn_code; + icode = optab_handler (movmisalign_optab, mode); gcc_assert (icode != CODE_FOR_nothing); /* We've already validated the memory, and we're creating a @@ -8684,6 +8711,74 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, } return temp; + case MEM_REF: + { + addr_space_t as + = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1)))); + enum machine_mode address_mode; + tree base = TREE_OPERAND (exp, 0); + gimple def_stmt; + /* Handle expansion of non-aliased memory with non-BLKmode. That + might end up in a register. */ + if (TREE_CODE (base) == ADDR_EXPR) + { + HOST_WIDE_INT offset = mem_ref_offset (exp).low; + tree bit_offset; + base = TREE_OPERAND (base, 0); + if (!DECL_P (base)) + { + HOST_WIDE_INT off; + base = get_addr_base_and_unit_offset (base, &off); + gcc_assert (base); + offset += off; + } + /* If we are expanding a MEM_REF of a non-BLKmode non-addressable + decl we must use bitfield operations. */ + if (DECL_P (base) + && !TREE_ADDRESSABLE (base) + && DECL_MODE (base) != BLKmode + && DECL_RTL_SET_P (base) + && !MEM_P (DECL_RTL (base))) + { + tree bftype; + if (offset == 0 + && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1) + && (GET_MODE_BITSIZE (DECL_MODE (base)) + == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))) + return expand_expr (build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (exp), base), + target, tmode, modifier); + bit_offset = bitsize_int (offset * BITS_PER_UNIT); + bftype = TREE_TYPE (base); + if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode) + bftype = TREE_TYPE (exp); + return expand_expr (build3 (BIT_FIELD_REF, bftype, + base, + TYPE_SIZE (TREE_TYPE (exp)), + bit_offset), + target, tmode, modifier); + } + } + address_mode = targetm.addr_space.address_mode (as); + base = TREE_OPERAND (exp, 0); + if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR))) + base = build2 (BIT_AND_EXPR, TREE_TYPE (base), + gimple_assign_rhs1 (def_stmt), + gimple_assign_rhs2 (def_stmt)); + if (!integer_zerop (TREE_OPERAND (exp, 1))) + base = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base), + base, double_int_to_tree (sizetype, + mem_ref_offset (exp))); + op0 = expand_expr (base, NULL_RTX, address_mode, EXPAND_SUM); + op0 = memory_address_addr_space (mode, op0, as); + temp = gen_rtx_MEM (mode, op0); + set_mem_attributes (temp, exp, 0); + set_mem_addr_space (temp, as); + if (TREE_THIS_VOLATILE (exp)) + MEM_VOLATILE_P (temp) = 1; + return temp; + } + case ARRAY_REF: { @@ -10145,39 +10240,6 @@ try_tablejump (tree index_type, tree index_expr, tree minval, tree range, return 1; } -/* Nonzero if the mode is a valid vector mode for this architecture. - This returns nonzero even if there is no hardware support for the - vector mode, but we can emulate with narrower modes. */ - -int -vector_mode_valid_p (enum machine_mode mode) -{ - enum mode_class mclass = GET_MODE_CLASS (mode); - enum machine_mode innermode; - - /* Doh! What's going on? */ - if (mclass != MODE_VECTOR_INT - && mclass != MODE_VECTOR_FLOAT - && mclass != MODE_VECTOR_FRACT - && mclass != MODE_VECTOR_UFRACT - && mclass != MODE_VECTOR_ACCUM - && mclass != MODE_VECTOR_UACCUM) - return 0; - - /* Hardware support. Woo hoo! */ - if (targetm.vector_mode_supported_p (mode)) - return 1; - - innermode = GET_MODE_INNER (mode); - - /* We should probably return 1 if requesting V4DI and we have no DI, - but we have V2DI, but this is probably very unlikely. */ - - /* If we have support for the inner mode, we can safely emulate it. - We may not have V2DI, but me can emulate with a pair of DIs. */ - return targetm.scalar_mode_supported_p (innermode); -} - /* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */ static rtx const_vector_from_tree (tree exp) |