aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c225
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);