Commit 22345357 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/50444 (-ftree-sra ignores alignment)

2012-01-27  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/50444
	* expr.c (mem_ref_refers_to_non_mem_p): New function.
	(expand_assignment): Use it.  Properly handle misaligned
	bases when expanding stores to component references.
	(expand_expr_real_1): Use mem_ref_refers_to_non_mem_p and
	refactor that case.

From-SVN: r183629
parent e08120b1
2012-01-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/50444
* expr.c (mem_ref_refers_to_non_mem_p): New function.
(expand_assignment): Use it. Properly handle misaligned
bases when expanding stores to component references.
(expand_expr_real_1): Use mem_ref_refers_to_non_mem_p and
refactor that case.
2012-01-27 Andrey Belevantsev <abel@ispras.ru> 2012-01-27 Andrey Belevantsev <abel@ispras.ru>
PR middle-end/51389 PR middle-end/51389
......
...@@ -4548,6 +4548,23 @@ get_bit_range (unsigned HOST_WIDE_INT *bitstart, ...@@ -4548,6 +4548,23 @@ get_bit_range (unsigned HOST_WIDE_INT *bitstart,
} }
} }
/* Returns true if the MEM_REF REF refers to an object that does not
reside in memory and has non-BLKmode. */
static bool
mem_ref_refers_to_non_mem_p (tree ref)
{
tree base = TREE_OPERAND (ref, 0);
if (TREE_CODE (base) != ADDR_EXPR)
return false;
base = TREE_OPERAND (base, 0);
return (DECL_P (base)
&& !TREE_ADDRESSABLE (base)
&& DECL_MODE (base) != BLKmode
&& DECL_RTL_SET_P (base)
&& !MEM_P (DECL_RTL (base)));
}
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL /* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
is true, try generating a nontemporal store. */ is true, try generating a nontemporal store. */
...@@ -4571,6 +4588,7 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4571,6 +4588,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
if (operand_equal_p (to, from, 0)) if (operand_equal_p (to, from, 0))
return; return;
/* Handle misaligned stores. */
mode = TYPE_MODE (TREE_TYPE (to)); mode = TYPE_MODE (TREE_TYPE (to));
if ((TREE_CODE (to) == MEM_REF if ((TREE_CODE (to) == MEM_REF
|| TREE_CODE (to) == TARGET_MEM_REF) || TREE_CODE (to) == TARGET_MEM_REF)
...@@ -4580,6 +4598,8 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4580,6 +4598,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
&& ((icode = optab_handler (movmisalign_optab, mode)) && ((icode = optab_handler (movmisalign_optab, mode))
!= CODE_FOR_nothing)) != CODE_FOR_nothing))
{ {
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
struct expand_operand ops[2]; struct expand_operand ops[2];
enum machine_mode address_mode; enum machine_mode address_mode;
rtx reg, op0, mem; rtx reg, op0, mem;
...@@ -4589,8 +4609,6 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4589,8 +4609,6 @@ expand_assignment (tree to, tree from, bool nontemporal)
if (TREE_CODE (to) == MEM_REF) if (TREE_CODE (to) == MEM_REF)
{ {
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
tree base = TREE_OPERAND (to, 0); tree base = TREE_OPERAND (to, 0);
address_mode = targetm.addr_space.address_mode (as); address_mode = targetm.addr_space.address_mode (as);
op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
...@@ -4598,7 +4616,7 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4598,7 +4616,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
if (!integer_zerop (TREE_OPERAND (to, 1))) if (!integer_zerop (TREE_OPERAND (to, 1)))
{ {
rtx off rtx off
= immed_double_int_const (mem_ref_offset (to), address_mode); = immed_double_int_const (mem_ref_offset (to), address_mode);
op0 = simplify_gen_binary (PLUS, address_mode, op0, off); op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
} }
op0 = memory_address_addr_space (mode, op0, as); op0 = memory_address_addr_space (mode, op0, as);
...@@ -4608,10 +4626,7 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4608,10 +4626,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
} }
else if (TREE_CODE (to) == TARGET_MEM_REF) else if (TREE_CODE (to) == TARGET_MEM_REF)
{ {
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
struct mem_address addr; struct mem_address addr;
get_address_description (to, &addr); get_address_description (to, &addr);
op0 = addr_for_mem_ref (&addr, as, true); op0 = addr_for_mem_ref (&addr, as, true);
op0 = memory_address_addr_space (mode, op0, as); op0 = memory_address_addr_space (mode, op0, as);
...@@ -4627,7 +4642,7 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4627,7 +4642,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
create_fixed_operand (&ops[0], mem); create_fixed_operand (&ops[0], mem);
create_input_operand (&ops[1], reg, mode); create_input_operand (&ops[1], reg, mode);
/* The movmisalign<mode> pattern cannot fail, else the assignment would /* The movmisalign<mode> pattern cannot fail, else the assignment would
silently be omitted. */ silently be omitted. */
expand_insn (icode, 2, ops); expand_insn (icode, 2, ops);
return; return;
} }
...@@ -4636,12 +4651,10 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4636,12 +4651,10 @@ expand_assignment (tree to, tree from, bool nontemporal)
if the structure component's rtx is not simply a MEM. if the structure component's rtx is not simply a MEM.
Assignment of an array element at a constant index, and assignment of Assignment of an array element at a constant index, and assignment of
an array element in an unaligned packed structure field, has the same an array element in an unaligned packed structure field, has the same
problem. */ problem. Same for (partially) storing into a non-memory object. */
if (handled_component_p (to) 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 (to) == MEM_REF
&& TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR) && mem_ref_refers_to_non_mem_p (to))
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE) || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{ {
enum machine_mode mode1; enum machine_mode mode1;
...@@ -4652,6 +4665,7 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4652,6 +4665,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
int unsignedp; int unsignedp;
int volatilep = 0; int volatilep = 0;
tree tem; tree tem;
bool misalignp;
push_temp_slots (); push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
...@@ -4664,8 +4678,22 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4664,8 +4678,22 @@ expand_assignment (tree to, tree from, bool nontemporal)
/* If we are going to use store_bit_field and extract_bit_field, /* If we are going to use store_bit_field and extract_bit_field,
make sure to_rtx will be safe for multiple use. */ make sure to_rtx will be safe for multiple use. */
mode = TYPE_MODE (TREE_TYPE (tem));
to_rtx = expand_normal (tem); if (TREE_CODE (tem) == MEM_REF
&& mode != BLKmode
&& ((align = get_object_or_type_alignment (tem))
< GET_MODE_ALIGNMENT (mode))
&& ((icode = optab_handler (movmisalign_optab, mode))
!= CODE_FOR_nothing))
{
misalignp = true;
to_rtx = gen_reg_rtx (mode);
}
else
{
misalignp = false;
to_rtx = expand_normal (tem);
}
/* If the bitfield is volatile, we want to access it in the /* If the bitfield is volatile, we want to access it in the
field's mode, not the computed mode. field's mode, not the computed mode.
...@@ -4811,6 +4839,37 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4811,6 +4839,37 @@ expand_assignment (tree to, tree from, bool nontemporal)
nontemporal); nontemporal);
} }
if (misalignp)
{
struct expand_operand ops[2];
enum machine_mode address_mode;
rtx op0, mem;
addr_space_t as = TYPE_ADDR_SPACE
(TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
tree base = TREE_OPERAND (tem, 0);
address_mode = targetm.addr_space.address_mode (as);
op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
op0 = convert_memory_address_addr_space (address_mode, op0, as);
if (!integer_zerop (TREE_OPERAND (tem, 1)))
{
rtx off = immed_double_int_const (mem_ref_offset (tem),
address_mode);
op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
}
op0 = memory_address_addr_space (mode, op0, as);
mem = gen_rtx_MEM (mode, op0);
set_mem_attributes (mem, tem, 0);
set_mem_addr_space (mem, as);
if (TREE_THIS_VOLATILE (tem))
MEM_VOLATILE_P (mem) = 1;
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) if (result)
preserve_temp_slots (result); preserve_temp_slots (result);
free_temp_slots (); free_temp_slots ();
...@@ -4866,11 +4925,8 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4866,11 +4925,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
return; return;
} }
/* Ordinary treatment. Expand TO to get a REG or MEM rtx. /* Ordinary treatment. Expand TO to get a REG or MEM rtx. */
Don't re-expand if it was expanded already (in COMPONENT_REF case). */ to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
if (to_rtx == 0)
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
/* Don't move directly into a return register. */ /* Don't move directly into a return register. */
if (TREE_CODE (to) == RESULT_DECL if (TREE_CODE (to) == RESULT_DECL
...@@ -9295,54 +9351,38 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, ...@@ -9295,54 +9351,38 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
unsigned align; unsigned align;
/* Handle expansion of non-aliased memory with non-BLKmode. That /* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */ might end up in a register. */
if (TREE_CODE (base) == ADDR_EXPR) if (mem_ref_refers_to_non_mem_p (exp))
{ {
HOST_WIDE_INT offset = mem_ref_offset (exp).low; HOST_WIDE_INT offset = mem_ref_offset (exp).low;
tree bit_offset; tree bit_offset;
tree bftype;
base = TREE_OPERAND (base, 0); base = TREE_OPERAND (base, 0);
if (!DECL_P (base)) if (offset == 0
{ && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
HOST_WIDE_INT off; && (GET_MODE_BITSIZE (DECL_MODE (base))
base = get_addr_base_and_unit_offset (base, &off); == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
gcc_assert (base); return expand_expr (build1 (VIEW_CONVERT_EXPR,
offset += off; TREE_TYPE (exp), base),
} target, tmode, modifier);
/* If we are expanding a MEM_REF of a non-BLKmode non-addressable bit_offset = bitsize_int (offset * BITS_PER_UNIT);
decl we must use bitfield operations. */ bftype = TREE_TYPE (base);
if (DECL_P (base) if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
&& !TREE_ADDRESSABLE (base) bftype = TREE_TYPE (exp);
&& DECL_MODE (base) != BLKmode else
&& DECL_RTL_SET_P (base)
&& !MEM_P (DECL_RTL (base)))
{ {
tree bftype; temp = assign_stack_temp (DECL_MODE (base),
if (offset == 0 GET_MODE_SIZE (DECL_MODE (base)),
&& host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1) 0);
&& (GET_MODE_BITSIZE (DECL_MODE (base)) store_expr (base, temp, 0, false);
== TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))) temp = adjust_address (temp, BLKmode, offset);
return expand_expr (build1 (VIEW_CONVERT_EXPR, set_mem_size (temp, int_size_in_bytes (TREE_TYPE (exp)));
TREE_TYPE (exp), base), return temp;
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);
else
{
temp = assign_stack_temp (DECL_MODE (base),
GET_MODE_SIZE (DECL_MODE (base)),
0);
store_expr (base, temp, 0, false);
temp = adjust_address (temp, BLKmode, offset);
set_mem_size (temp, int_size_in_bytes (TREE_TYPE (exp)));
return temp;
}
return expand_expr (build3 (BIT_FIELD_REF, bftype,
base,
TYPE_SIZE (TREE_TYPE (exp)),
bit_offset),
target, tmode, modifier);
} }
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); address_mode = targetm.addr_space.address_mode (as);
base = TREE_OPERAND (exp, 0); base = TREE_OPERAND (exp, 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment