diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 225 |
1 files changed, 100 insertions, 125 deletions
diff --git a/gcc/expr.c b/gcc/expr.c index f83a7d0d448..8ec37336989 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -4708,8 +4708,6 @@ expand_assignment (tree to, tree from, bool nontemporal) int unsignedp; int volatilep = 0; tree tem; - bool misalignp; - rtx mem = NULL_RTX; push_temp_slots (); tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, @@ -4728,40 +4726,7 @@ expand_assignment (tree to, tree from, bool nontemporal) && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1))) get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset); - /* If we are going to use store_bit_field and extract_bit_field, - make sure to_rtx will be safe for multiple use. */ - mode = TYPE_MODE (TREE_TYPE (tem)); - if (TREE_CODE (tem) == MEM_REF - && mode != BLKmode - && ((align = get_object_alignment (tem)) - < GET_MODE_ALIGNMENT (mode)) - && ((icode = optab_handler (movmisalign_optab, mode)) - != CODE_FOR_nothing)) - { - struct expand_operand ops[2]; - - misalignp = true; - to_rtx = gen_reg_rtx (mode); - mem = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); - - /* If the misaligned store doesn't overwrite all bits, perform - rmw cycle on MEM. */ - if (bitsize != GET_MODE_BITSIZE (mode)) - { - create_input_operand (&ops[0], to_rtx, mode); - create_fixed_operand (&ops[1], mem); - /* The movmisalign<mode> pattern cannot fail, else the assignment - would silently be omitted. */ - expand_insn (icode, 2, ops); - - mem = copy_rtx (mem); - } - } - else - { - misalignp = false; - to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); - } + to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE); /* If the bitfield is volatile, we want to access it in the field's mode, not the computed mode. @@ -4900,17 +4865,6 @@ expand_assignment (tree to, tree from, bool nontemporal) get_alias_set (to), nontemporal); } - if (misalignp) - { - struct expand_operand ops[2]; - - create_fixed_operand (&ops[0], mem); - create_input_operand (&ops[1], to_rtx, mode); - /* The movmisalign<mode> pattern cannot fail, else the assignment - would silently be omitted. */ - expand_insn (icode, 2, ops); - } - if (result) preserve_temp_slots (result); pop_temp_slots (); @@ -5262,7 +5216,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) temp = expand_expr_real (exp, tmp_target, GET_MODE (target), (call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL), - &alt_rtl); + &alt_rtl, false); } /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not @@ -7590,11 +7544,13 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, break; case COMPOUND_LITERAL_EXPR: - /* Allow COMPOUND_LITERAL_EXPR in initializers, if e.g. - rtl_for_decl_init is called on DECL_INITIAL with - COMPOUNT_LITERAL_EXPRs in it, they aren't gimplified. */ - if (modifier == EXPAND_INITIALIZER - && COMPOUND_LITERAL_EXPR_DECL (exp)) + /* Allow COMPOUND_LITERAL_EXPR in initializers or coming from + initializers, if e.g. rtl_for_decl_init is called on DECL_INITIAL + with COMPOUND_LITERAL_EXPRs in it, or ARRAY_REF on a const static + array with address of COMPOUND_LITERAL_EXPR in DECL_INITIAL; + the initializers aren't gimplified. */ + if (COMPOUND_LITERAL_EXPR_DECL (exp) + && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp))) return expand_expr_addr_expr_1 (COMPOUND_LITERAL_EXPR_DECL (exp), target, tmode, modifier, as); /* FALLTHRU */ @@ -7879,11 +7835,21 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier, address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the DECL_RTL of the VAR_DECL. *ALT_RTL is also set if EXP is a COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on - recursively. */ + recursively. + + If INNER_REFERENCE_P is true, we are expanding an inner reference. + In this case, we don't adjust a returned MEM rtx that wouldn't be + sufficiently aligned for its mode; instead, it's up to the caller + to deal with it afterwards. This is used to make sure that unaligned + base objects for which out-of-bounds accesses are supported, for + example record types with trailing arrays, aren't realigned behind + the back of the caller. + The normal operating mode is to pass FALSE for this parameter. */ rtx expand_expr_real (tree exp, rtx target, enum machine_mode tmode, - enum expand_modifier modifier, rtx *alt_rtl) + enum expand_modifier modifier, rtx *alt_rtl, + bool inner_reference_p) { rtx ret; @@ -7895,7 +7861,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, return ret ? ret : const0_rtx; } - ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl); + ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl, + inner_reference_p); return ret; } @@ -9188,7 +9155,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, rtx expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, - enum expand_modifier modifier, rtx *alt_rtl) + enum expand_modifier modifier, rtx *alt_rtl, + bool inner_reference_p) { rtx op0, op1, temp, decl_rtl; tree type; @@ -9334,7 +9302,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, set_curr_insn_location (gimple_location (g)); r = expand_expr_real (gimple_assign_rhs_to_tree (g), target, - tmode, modifier, NULL); + tmode, modifier, NULL, inner_reference_p); set_curr_insn_location (saved_loc); if (REG_P (r) && !REG_EXPR (r)) set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r); @@ -9555,7 +9523,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case SAVE_EXPR: { tree val = treeop0; - rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl); + rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl, + inner_reference_p); if (!SAVE_EXPR_RESOLVED_P (exp)) { @@ -9704,6 +9673,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, MEM_VOLATILE_P (temp) = 1; if (modifier != EXPAND_WRITE && modifier != EXPAND_MEMORY + && !inner_reference_p && mode != BLKmode && align < GET_MODE_ALIGNMENT (mode)) { @@ -9938,18 +9908,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, computation, since it will need a temporary and TARGET is known to have to do. This occurs in unchecked conversion in Ada. */ orig_op0 = op0 - = expand_expr (tem, - (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE - && COMPLETE_TYPE_P (TREE_TYPE (tem)) - && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) - != INTEGER_CST) - && modifier != EXPAND_STACK_PARM - ? target : NULL_RTX), - VOIDmode, - (modifier == EXPAND_INITIALIZER - || modifier == EXPAND_CONST_ADDRESS - || modifier == EXPAND_STACK_PARM) - ? modifier : EXPAND_NORMAL); + = expand_expr_real (tem, + (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE + && COMPLETE_TYPE_P (TREE_TYPE (tem)) + && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) + != INTEGER_CST) + && modifier != EXPAND_STACK_PARM + ? target : NULL_RTX), + VOIDmode, + (modifier == EXPAND_INITIALIZER + || modifier == EXPAND_CONST_ADDRESS + || modifier == EXPAND_STACK_PARM) + ? modifier : EXPAND_NORMAL, + NULL, true); /* If the bitfield is volatile, we want to access it in the @@ -10300,17 +10271,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, { /* See the normal_inner_ref case for the rationale. */ orig_op0 - = expand_expr (tem, - (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE - && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) - != INTEGER_CST) - && modifier != EXPAND_STACK_PARM - ? target : NULL_RTX), - VOIDmode, - (modifier == EXPAND_INITIALIZER - || modifier == EXPAND_CONST_ADDRESS - || modifier == EXPAND_STACK_PARM) - ? modifier : EXPAND_NORMAL); + = expand_expr_real (tem, + (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE + && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) + != INTEGER_CST) + && modifier != EXPAND_STACK_PARM + ? target : NULL_RTX), + VOIDmode, + (modifier == EXPAND_INITIALIZER + || modifier == EXPAND_CONST_ADDRESS + || modifier == EXPAND_STACK_PARM) + ? modifier : EXPAND_NORMAL, + NULL, true); if (MEM_P (orig_op0)) { @@ -10337,8 +10309,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, } if (!op0) - op0 = expand_expr (treeop0, - NULL_RTX, VOIDmode, modifier); + op0 = expand_expr_real (treeop0, NULL_RTX, VOIDmode, modifier, + NULL, inner_reference_p); /* If the input and output modes are both the same, we are done. */ if (mode == GET_MODE (op0)) @@ -10405,50 +10377,53 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, op0 = copy_rtx (op0); set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type))); } - else if (mode != BLKmode - && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode) - /* If the target does have special handling for unaligned - loads of mode then use them. */ - && ((icode = optab_handler (movmisalign_optab, mode)) - != CODE_FOR_nothing)) - { - rtx reg, insn; - - op0 = adjust_address (op0, mode, 0); - /* We've already validated the memory, and we're creating a - new pseudo destination. The predicates really can't - fail. */ - reg = gen_reg_rtx (mode); - - /* Nor can the insn generator. */ - insn = GEN_FCN (icode) (reg, op0); - emit_insn (insn); - return reg; - } - else if (STRICT_ALIGNMENT + else if (modifier != EXPAND_WRITE + && modifier != EXPAND_MEMORY + && !inner_reference_p && mode != BLKmode && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)) { - tree inner_type = TREE_TYPE (treeop0); - HOST_WIDE_INT temp_size - = MAX (int_size_in_bytes (inner_type), - (HOST_WIDE_INT) GET_MODE_SIZE (mode)); - rtx new_rtx - = assign_stack_temp_for_type (mode, temp_size, type); - rtx new_with_op0_mode - = adjust_address (new_rtx, GET_MODE (op0), 0); - - gcc_assert (!TREE_ADDRESSABLE (exp)); - - if (GET_MODE (op0) == BLKmode) - emit_block_move (new_with_op0_mode, op0, - GEN_INT (GET_MODE_SIZE (mode)), - (modifier == EXPAND_STACK_PARM - ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); - else - emit_move_insn (new_with_op0_mode, op0); + /* If the target does have special handling for unaligned + loads of mode then use them. */ + if ((icode = optab_handler (movmisalign_optab, mode)) + != CODE_FOR_nothing) + { + rtx reg, insn; + + op0 = adjust_address (op0, mode, 0); + /* We've already validated the memory, and we're creating a + new pseudo destination. The predicates really can't + fail. */ + reg = gen_reg_rtx (mode); + + /* Nor can the insn generator. */ + insn = GEN_FCN (icode) (reg, op0); + emit_insn (insn); + return reg; + } + else if (STRICT_ALIGNMENT) + { + tree inner_type = TREE_TYPE (treeop0); + HOST_WIDE_INT temp_size + = MAX (int_size_in_bytes (inner_type), + (HOST_WIDE_INT) GET_MODE_SIZE (mode)); + rtx new_rtx + = assign_stack_temp_for_type (mode, temp_size, type); + rtx new_with_op0_mode + = adjust_address (new_rtx, GET_MODE (op0), 0); + + gcc_assert (!TREE_ADDRESSABLE (exp)); + + if (GET_MODE (op0) == BLKmode) + emit_block_move (new_with_op0_mode, op0, + GEN_INT (GET_MODE_SIZE (mode)), + (modifier == EXPAND_STACK_PARM + ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); + else + emit_move_insn (new_with_op0_mode, op0); - op0 = new_rtx; + op0 = new_rtx; + } } op0 = adjust_address (op0, mode, 0); @@ -10548,7 +10523,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, /* WITH_SIZE_EXPR expands to its first argument. The caller should have pulled out the size to use in whatever context it needed. */ return expand_expr_real (treeop0, original_target, tmode, - modifier, alt_rtl); + modifier, alt_rtl, inner_reference_p); default: return expand_expr_real_2 (&ops, target, tmode, modifier); |