This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/3] Move MEM_REF expansion to a new function
- From: Martin Jambor <mjambor at suse dot cz>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Guenther <rguenther at suse dot de>
- Date: Mon, 12 Mar 2012 15:09:03 +0100
- Subject: [PATCH 2/3] Move MEM_REF expansion to a new function
- References: <20120312140901.004541946@virgil.suse.cz>
Hi,
when we expand a misaligned MEM_REF on the LHS, we must not call the
code in expand_expr_real_1 if the subsequent patch is applied, because
the code generates code extracting the contents of the memory to a
register, which is of course bad if the intent is to write into that
memory. Therefore expand_assignment should expand MEM_REFs itself,
just as it do when it encounters naked misaligned ones.
In order not to have nearly identical code twice in expand_assignment
and once more in expand_expr_real_1, I put it into a separate function
expand_mem_ref_to_mem_rtx (I'll be happy to change the name to
anything more correct or fitting). Nevertheless, the existing code
pieces in expand_assignment and expand_expr_real_1 sre not exactly
identical, the differences are:
- expand_expr_real_1 handles a special case when the defining
statement of the MEM_REF base is a BIT_AND_EXPR, expand_assignment
does not. The changelog introducing the change says "TER
BIT_AND_EXPRs into MEM_REFs" which I suspect is a good thing for
LHSs as well, so I kept the code.
- When expanding the base, the two functions differ in the
expand_modifier they pass down to expand_expr. expand_assignment
uses EXPAND_NORMAL while expand_expr_real_1 passes EXPAND_SUM.
According to the comment in expr.h the latter seemed more permissive
and so I used that, even though I admit I do not really know what
the implications of this modifier are. Is it OK to use EXPAND_SUM
also on a LHS?
- expand_expr_real_1 calls memory_address_addr_space twice, whereas
expand_assignment replaces the first call with
convert_memory_address_addr_space. Looking at the two functions I
thought it might be OK to call memory_address_addr_space (which
itself calls convert_memory_address_addr_space) only once.
But again, my expertise in this area is limited, I'll be happy to be
shown I'm wrong here.
So far I have bootstrapped and tested this patch separately on
x86_64-linx and i686-linux. Additionally, it has also passed
bootstrap and testing on usparc64-linux and ia64-linux.
Thanks in advance for any comments,
Martin
2012-03-09 Martin Jambor <mjambor@suse.cz>
* expr.c (expand_mem_ref_to_mem_rtx): New function.
(expand_assignment): Call it when expanding a MEM_REF on the LHS.
(expand_expr_real_1): Likewise.
Index: src/gcc/expr.c
===================================================================
--- src.orig/gcc/expr.c
+++ src/gcc/expr.c
@@ -4565,6 +4565,47 @@ mem_ref_refers_to_non_mem_p (tree ref)
&& !MEM_P (DECL_RTL (base)));
}
+/* Expand a MEM_REF referring an object in memory to a MEM RTX. Any spacial
+ treatment of misalignment must be handled on top of the returned result. */
+
+static rtx
+expand_mem_ref_to_mem_rtx (tree ref)
+{
+ enum machine_mode address_mode, mode = TYPE_MODE (TREE_TYPE (ref));
+ tree base = TREE_OPERAND (ref, 0);
+ addr_space_t as
+ = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref, 0))));
+ gimple def_stmt;
+ rtx mem, op0;
+
+ gcc_checking_assert (!mem_ref_refers_to_non_mem_p (ref));
+
+ address_mode = targetm.addr_space.address_mode (as);
+
+ if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
+ {
+ tree mask = gimple_assign_rhs2 (def_stmt);
+ base = build2 (BIT_AND_EXPR, TREE_TYPE (base),
+ gimple_assign_rhs1 (def_stmt), mask);
+ TREE_OPERAND (ref, 0) = base;
+ }
+ op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM);
+ op0 = convert_memory_address_addr_space (address_mode, op0, as);
+ if (!integer_zerop (TREE_OPERAND (ref, 1)))
+ {
+ rtx off
+ = immed_double_int_const (mem_ref_offset (ref), 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, ref, 0);
+ set_mem_addr_space (mem, as);
+ if (TREE_THIS_VOLATILE (ref))
+ MEM_VOLATILE_P (mem) = 1;
+ return mem;
+}
+
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
is true, try generating a nontemporal store. */
@@ -4600,46 +4641,31 @@ expand_assignment (tree to, tree from, b
!= CODE_FOR_nothing)
|| SLOW_UNALIGNED_ACCESS (mode, align)))
{
- addr_space_t as
- = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
struct expand_operand ops[2];
- enum machine_mode address_mode;
- rtx reg, op0, mem;
+ rtx reg, mem;
reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
reg = force_not_mem (reg);
if (TREE_CODE (to) == MEM_REF)
- {
- tree base = TREE_OPERAND (to, 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 (to, 1)))
- {
- rtx off
- = immed_double_int_const (mem_ref_offset (to), 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, to, 0);
- set_mem_addr_space (mem, as);
- }
+ mem = expand_mem_ref_to_mem_rtx (to);
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;
+ rtx op0;
get_address_description (to, &addr);
op0 = addr_for_mem_ref (&addr, as, true);
op0 = memory_address_addr_space (mode, op0, as);
mem = gen_rtx_MEM (mode, op0);
set_mem_attributes (mem, to, 0);
set_mem_addr_space (mem, as);
+ if (TREE_THIS_VOLATILE (to))
+ MEM_VOLATILE_P (mem) = 1;
}
else
gcc_unreachable ();
- if (TREE_THIS_VOLATILE (to))
- MEM_VOLATILE_P (mem) = 1;
if (icode != CODE_FOR_nothing)
{
@@ -4737,7 +4763,11 @@ expand_assignment (tree to, tree from, b
else
{
misalignp = false;
- to_rtx = expand_normal (tem);
+ if (TREE_CODE (tem) == MEM_REF
+ && !mem_ref_refers_to_non_mem_p (tem))
+ to_rtx = expand_mem_ref_to_mem_rtx (tem);
+ else
+ to_rtx = expand_normal (tem);
}
/* If the bitfield is volatile, we want to access it in the
@@ -9395,17 +9425,12 @@ expand_expr_real_1 (tree exp, rtx target
case MEM_REF:
{
- addr_space_t as
- = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
- enum machine_mode address_mode;
- tree base = TREE_OPERAND (exp, 0);
- gimple def_stmt;
enum insn_code icode;
- unsigned align;
/* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */
if (mem_ref_refers_to_non_mem_p (exp))
{
+ tree base = TREE_OPERAND (exp, 0);
HOST_WIDE_INT offset = mem_ref_offset (exp).low;
tree bit_offset;
tree bftype;
@@ -9437,32 +9462,9 @@ expand_expr_real_1 (tree exp, rtx target
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)))
- {
- tree mask = gimple_assign_rhs2 (def_stmt);
- base = build2 (BIT_AND_EXPR, TREE_TYPE (base),
- gimple_assign_rhs1 (def_stmt), mask);
- TREE_OPERAND (exp, 0) = base;
- }
- align = get_object_or_type_alignment (exp);
- op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM);
- op0 = memory_address_addr_space (address_mode, op0, as);
- if (!integer_zerop (TREE_OPERAND (exp, 1)))
- {
- rtx off
- = immed_double_int_const (mem_ref_offset (exp), address_mode);
- op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
- }
- 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;
+ temp = expand_mem_ref_to_mem_rtx (exp);
if (mode != BLKmode
- && align < GET_MODE_ALIGNMENT (mode)
+ && get_object_or_type_alignment (exp) < GET_MODE_ALIGNMENT (mode)
/* If the target does not have special handling for unaligned
loads of mode then it can use regular moves for them. */
&& ((icode = optab_handler (movmisalign_optab, mode))