Commit 5ef0b50d by Eric Botcazou Committed by Eric Botcazou

re PR rtl-optimization/44194 (struct returned by value generates useless stores)

	PR rtl-optimization/44194
	* calls.c (expand_call): In the PARALLEL case, copy the return value
	into pseudos instead of spilling it onto the stack.
	* emit-rtl.c (adjust_address_1): Rename ADJUST into ADJUST_ADDRESS and
	add new ADJUST_OBJECT parameter.
	If ADJUST_OBJECT is set, drop the underlying object if it cannot be
	proved that the adjusted memory access is still within its bounds.
	(adjust_automodify_address_1): Adjust call to adjust_address_1.
	(widen_memory_access): Likewise.
	* expmed.c (store_bit_field_1): Call adjust_bitfield_address instead
	of adjust_address.  Do not drop the underlying object of a MEM.
	(store_fixed_bit_field): Likewise.
	(extract_bit_field_1): Likewise.  Fix oversight in recursion.
	(extract_fixed_bit_field): Likewise.
	* expr.h (adjust_address_1): Adjust prototype.
	(adjust_address): Adjust call to adjust_address_1.
	(adjust_address_nv): Likewise.
	(adjust_bitfield_address): New macro.
	(adjust_bitfield_address_nv): Likewise.
	* expr.c (expand_assignment): Handle a PARALLEL in more cases.
	(store_expr): Likewise.
	(store_field): Likewise.

	* dse.c: Fix typos in the head comment.

From-SVN: r191302
parent fcf8632e
2012-09-14 Eric Botcazou <ebotcazou@adacore.com>
PR rtl-optimization/44194
* calls.c (expand_call): In the PARALLEL case, copy the return value
into pseudos instead of spilling it onto the stack.
* emit-rtl.c (adjust_address_1): Rename ADJUST into ADJUST_ADDRESS and
add new ADJUST_OBJECT parameter.
If ADJUST_OBJECT is set, drop the underlying object if it cannot be
proved that the adjusted memory access is still within its bounds.
(adjust_automodify_address_1): Adjust call to adjust_address_1.
(widen_memory_access): Likewise.
* expmed.c (store_bit_field_1): Call adjust_bitfield_address instead
of adjust_address. Do not drop the underlying object of a MEM.
(store_fixed_bit_field): Likewise.
(extract_bit_field_1): Likewise. Fix oversight in recursion.
(extract_fixed_bit_field): Likewise.
* expr.h (adjust_address_1): Adjust prototype.
(adjust_address): Adjust call to adjust_address_1.
(adjust_address_nv): Likewise.
(adjust_bitfield_address): New macro.
(adjust_bitfield_address_nv): Likewise.
* expr.c (expand_assignment): Handle a PARALLEL in more cases.
(store_expr): Likewise.
(store_field): Likewise.
* dse.c: Fix typos in the head comment.
2012-09-14 Christian Bruel <christian.bruel@st.com> 2012-09-14 Christian Bruel <christian.bruel@st.com>
PR target/54546 PR target/54546
......
...@@ -3272,16 +3272,8 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -3272,16 +3272,8 @@ expand_call (tree exp, rtx target, int ignore)
else if (GET_CODE (valreg) == PARALLEL) else if (GET_CODE (valreg) == PARALLEL)
{ {
if (target == 0) if (target == 0)
{ target = emit_group_move_into_temps (valreg);
/* This will only be assigned once, so it can be readonly. */ else if (!rtx_equal_p (target, valreg))
tree nt = build_qualified_type (rettype,
(TYPE_QUALS (rettype)
| TYPE_QUAL_CONST));
target = assign_temp (nt, 1, 1);
}
if (! rtx_equal_p (target, valreg))
emit_group_store (target, valreg, rettype, emit_group_store (target, valreg, rettype,
int_size_in_bytes (rettype)); int_size_in_bytes (rettype));
......
...@@ -105,7 +105,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -105,7 +105,7 @@ along with GCC; see the file COPYING3. If not see
the first pass could examine a block in either direction. The the first pass could examine a block in either direction. The
forwards ordering is to accommodate cselib. forwards ordering is to accommodate cselib.
We a simplifying assumption: addresses fall into four broad We make a simplifying assumption: addresses fall into four broad
categories: categories:
1) base has rtx_varies_p == false, offset is constant. 1) base has rtx_varies_p == false, offset is constant.
...@@ -114,18 +114,18 @@ along with GCC; see the file COPYING3. If not see ...@@ -114,18 +114,18 @@ along with GCC; see the file COPYING3. If not see
4) base has rtx_varies_p == true, offset variable. 4) base has rtx_varies_p == true, offset variable.
The local passes are able to process all 4 kinds of addresses. The The local passes are able to process all 4 kinds of addresses. The
global pass only handles (1). global pass only handles 1).
The global problem is formulated as follows: The global problem is formulated as follows:
A store, S1, to address A, where A is not relative to the stack A store, S1, to address A, where A is not relative to the stack
frame, can be eliminated if all paths from S1 to the end of the frame, can be eliminated if all paths from S1 to the end of the
of the function contain another store to A before a read to A. function contain another store to A before a read to A.
If the address A is relative to the stack frame, a store S2 to A If the address A is relative to the stack frame, a store S2 to A
can be eliminated if there are no paths from S1 that reach the can be eliminated if there are no paths from S2 that reach the
end of the function that read A before another store to A. In end of the function that read A before another store to A. In
this case S2 can be deleted if there are paths to from S2 to the this case S2 can be deleted if there are paths from S2 to the
end of the function that have no reads or writes to A. This end of the function that have no reads or writes to A. This
second case allows stores to the stack frame to be deleted that second case allows stores to the stack frame to be deleted that
would otherwise die when the function returns. This cannot be would otherwise die when the function returns. This cannot be
...@@ -136,7 +136,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -136,7 +136,7 @@ along with GCC; see the file COPYING3. If not see
dataflow problem where the stores are the gens and reads are the dataflow problem where the stores are the gens and reads are the
kills. Set union problems are rare and require some special kills. Set union problems are rare and require some special
handling given our representation of bitmaps. A straightforward handling given our representation of bitmaps. A straightforward
implementation of requires a lot of bitmaps filled with 1s. implementation requires a lot of bitmaps filled with 1s.
These are expensive and cumbersome in our bitmap formulation so These are expensive and cumbersome in our bitmap formulation so
care has been taken to avoid large vectors filled with 1s. See care has been taken to avoid large vectors filled with 1s. See
the comments in bb_info and in the dataflow confluence functions the comments in bb_info and in the dataflow confluence functions
......
...@@ -2051,12 +2051,16 @@ change_address (rtx memref, enum machine_mode mode, rtx addr) ...@@ -2051,12 +2051,16 @@ change_address (rtx memref, enum machine_mode mode, rtx addr)
/* Return a memory reference like MEMREF, but with its mode changed /* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address offset by OFFSET bytes. If VALIDATE is to MODE and its address offset by OFFSET bytes. If VALIDATE is
nonzero, the memory address is forced to be valid. nonzero, the memory address is forced to be valid.
If ADJUST is zero, OFFSET is only used to update MEM_ATTRS If ADJUST_ADDRESS is zero, OFFSET is only used to update MEM_ATTRS
and caller is responsible for adjusting MEMREF base register. */ and the caller is responsible for adjusting MEMREF base register.
If ADJUST_OBJECT is zero, the underlying object associated with the
memory reference is left unchanged and the caller is responsible for
dealing with it. Otherwise, if the new memory reference is outside
the underlying object, even partially, then the object is dropped. */
rtx rtx
adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
int validate, int adjust) int validate, int adjust_address, int adjust_object)
{ {
rtx addr = XEXP (memref, 0); rtx addr = XEXP (memref, 0);
rtx new_rtx; rtx new_rtx;
...@@ -2089,7 +2093,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, ...@@ -2089,7 +2093,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
>> shift); >> shift);
} }
if (adjust) if (adjust_address)
{ {
/* If MEMREF is a LO_SUM and the offset is within the alignment of the /* If MEMREF is a LO_SUM and the offset is within the alignment of the
object, we can merge it into the LO_SUM. */ object, we can merge it into the LO_SUM. */
...@@ -2111,10 +2115,26 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, ...@@ -2111,10 +2115,26 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
if (new_rtx == memref && offset != 0) if (new_rtx == memref && offset != 0)
new_rtx = copy_rtx (new_rtx); new_rtx = copy_rtx (new_rtx);
/* Conservatively drop the object if we don't know where we start from. */
if (adjust_object && (!attrs.offset_known_p || !attrs.size_known_p))
{
attrs.expr = NULL_TREE;
attrs.alias = 0;
}
/* Compute the new values of the memory attributes due to this adjustment. /* Compute the new values of the memory attributes due to this adjustment.
We add the offsets and update the alignment. */ We add the offsets and update the alignment. */
if (attrs.offset_known_p) if (attrs.offset_known_p)
attrs.offset += offset; {
attrs.offset += offset;
/* Drop the object if the new left end is not within its bounds. */
if (adjust_object && attrs.offset < 0)
{
attrs.expr = NULL_TREE;
attrs.alias = 0;
}
}
/* Compute the new alignment by taking the MIN of the alignment and the /* Compute the new alignment by taking the MIN of the alignment and the
lowest-order set bit in OFFSET, but don't change the alignment if OFFSET lowest-order set bit in OFFSET, but don't change the alignment if OFFSET
...@@ -2129,16 +2149,24 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, ...@@ -2129,16 +2149,24 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)]; defattrs = mode_mem_attrs[(int) GET_MODE (new_rtx)];
if (defattrs->size_known_p) if (defattrs->size_known_p)
{ {
/* Drop the object if the new right end is not within its bounds. */
if (adjust_object && (offset + defattrs->size) > attrs.size)
{
attrs.expr = NULL_TREE;
attrs.alias = 0;
}
attrs.size_known_p = true; attrs.size_known_p = true;
attrs.size = defattrs->size; attrs.size = defattrs->size;
} }
else if (attrs.size_known_p) else if (attrs.size_known_p)
attrs.size -= offset; {
attrs.size -= offset;
/* ??? The store_by_pieces machinery generates negative sizes. */
gcc_assert (!(adjust_object && attrs.size < 0));
}
set_mem_attrs (new_rtx, &attrs); set_mem_attrs (new_rtx, &attrs);
/* At some point, we should validate that this offset is within the object,
if all the appropriate values are known. */
return new_rtx; return new_rtx;
} }
...@@ -2152,7 +2180,7 @@ adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr, ...@@ -2152,7 +2180,7 @@ adjust_automodify_address_1 (rtx memref, enum machine_mode mode, rtx addr,
HOST_WIDE_INT offset, int validate) HOST_WIDE_INT offset, int validate)
{ {
memref = change_address_1 (memref, VOIDmode, addr, validate); memref = change_address_1 (memref, VOIDmode, addr, validate);
return adjust_address_1 (memref, mode, offset, validate, 0); return adjust_address_1 (memref, mode, offset, validate, 0, 0);
} }
/* Return a memory reference like MEMREF, but whose address is changed by /* Return a memory reference like MEMREF, but whose address is changed by
...@@ -2234,7 +2262,7 @@ replace_equiv_address_nv (rtx memref, rtx addr) ...@@ -2234,7 +2262,7 @@ replace_equiv_address_nv (rtx memref, rtx addr)
rtx rtx
widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
{ {
rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1); rtx new_rtx = adjust_address_1 (memref, mode, offset, 1, 1, 0);
struct mem_attrs attrs; struct mem_attrs attrs;
unsigned int size = GET_MODE_SIZE (mode); unsigned int size = GET_MODE_SIZE (mode);
......
...@@ -500,7 +500,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -500,7 +500,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0)))) && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
{ {
if (MEM_P (op0)) if (MEM_P (op0))
op0 = adjust_address (op0, fieldmode, offset); op0 = adjust_bitfield_address (op0, fieldmode, offset);
else if (GET_MODE (op0) != fieldmode) else if (GET_MODE (op0) != fieldmode)
op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0), op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
byte_offset); byte_offset);
...@@ -517,7 +517,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -517,7 +517,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if (imode != GET_MODE (op0)) if (imode != GET_MODE (op0))
{ {
if (MEM_P (op0)) if (MEM_P (op0))
op0 = adjust_address (op0, imode, 0); op0 = adjust_bitfield_address (op0, imode, 0);
else else
{ {
gcc_assert (imode != BLKmode); gcc_assert (imode != BLKmode);
...@@ -526,16 +526,6 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -526,16 +526,6 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
} }
} }
/* We may be accessing data outside the field, which means
we can alias adjacent data. */
/* ?? not always for C++0x memory model ?? */
if (MEM_P (op0))
{
op0 = shallow_copy_rtx (op0);
set_mem_alias_set (op0, 0);
set_mem_expr (op0, 0);
}
/* If OP0 is a register, BITPOS must count within a word. /* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has. But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */ On a bigendian machine, these are not the same, so convert. */
...@@ -718,7 +708,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -718,7 +708,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
/* Add OFFSET into OP0's address. */ /* Add OFFSET into OP0's address. */
if (MEM_P (xop0)) if (MEM_P (xop0))
xop0 = adjust_address (xop0, byte_mode, offset); xop0 = adjust_bitfield_address (xop0, byte_mode, offset);
/* If xop0 is a register, we need it in OP_MODE /* If xop0 is a register, we need it in OP_MODE
to make it acceptable to the format of insv. */ to make it acceptable to the format of insv. */
...@@ -852,7 +842,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -852,7 +842,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unit = GET_MODE_BITSIZE (bestmode); unit = GET_MODE_BITSIZE (bestmode);
xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode); xoffset = (bitnum / unit) * GET_MODE_SIZE (bestmode);
xbitpos = bitnum % unit; xbitpos = bitnum % unit;
xop0 = adjust_address (op0, bestmode, xoffset); xop0 = adjust_bitfield_address (op0, bestmode, xoffset);
/* Fetch that unit, store the bitfield in it, then store /* Fetch that unit, store the bitfield in it, then store
the unit. */ the unit. */
...@@ -1024,7 +1014,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset, ...@@ -1024,7 +1014,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
Then alter OP0 to refer to that word. */ Then alter OP0 to refer to that word. */
bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
offset -= (offset % (total_bits / BITS_PER_UNIT)); offset -= (offset % (total_bits / BITS_PER_UNIT));
op0 = adjust_address (op0, mode, offset); op0 = adjust_bitfield_address (op0, mode, offset);
} }
mode = GET_MODE (op0); mode = GET_MODE (op0);
...@@ -1388,7 +1378,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1388,7 +1378,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
if (imode != GET_MODE (op0)) if (imode != GET_MODE (op0))
{ {
if (MEM_P (op0)) if (MEM_P (op0))
op0 = adjust_address (op0, imode, 0); op0 = adjust_bitfield_address (op0, imode, 0);
else if (imode != BLKmode) else if (imode != BLKmode)
{ {
op0 = gen_lowpart (imode, op0); op0 = gen_lowpart (imode, op0);
...@@ -1414,20 +1404,11 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1414,20 +1404,11 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
rtx mem = assign_stack_temp (GET_MODE (op0), rtx mem = assign_stack_temp (GET_MODE (op0),
GET_MODE_SIZE (GET_MODE (op0))); GET_MODE_SIZE (GET_MODE (op0)));
emit_move_insn (mem, op0); emit_move_insn (mem, op0);
op0 = adjust_address (mem, BLKmode, 0); op0 = adjust_bitfield_address (mem, BLKmode, 0);
} }
} }
} }
/* We may be accessing data outside the field, which means
we can alias adjacent data. */
if (MEM_P (op0))
{
op0 = shallow_copy_rtx (op0);
set_mem_alias_set (op0, 0);
set_mem_expr (op0, 0);
}
/* Extraction of a full-word or multi-word value from a structure /* Extraction of a full-word or multi-word value from a structure
in a register or aligned memory can be done with just a SUBREG. in a register or aligned memory can be done with just a SUBREG.
A subword value in the least significant part of a register A subword value in the least significant part of a register
...@@ -1487,7 +1468,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1487,7 +1468,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
&& MEM_ALIGN (op0) % bitsize == 0))))) && MEM_ALIGN (op0) % bitsize == 0)))))
{ {
if (MEM_P (op0)) if (MEM_P (op0))
op0 = adjust_address (op0, mode1, offset); op0 = adjust_bitfield_address (op0, mode1, offset);
else if (mode1 != GET_MODE (op0)) else if (mode1 != GET_MODE (op0))
{ {
rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0), rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
...@@ -1513,6 +1494,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1513,6 +1494,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD; unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i; unsigned int i;
rtx last;
if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target)) if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target))
target = gen_reg_rtx (mode); target = gen_reg_rtx (mode);
...@@ -1520,6 +1502,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1520,6 +1502,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
/* Indicate for flow that the entire target reg is being set. */ /* Indicate for flow that the entire target reg is being set. */
emit_clobber (target); emit_clobber (target);
last = get_last_insn ();
for (i = 0; i < nwords; i++) for (i = 0; i < nwords; i++)
{ {
/* If I is 0, use the low-order word in both field and target; /* If I is 0, use the low-order word in both field and target;
...@@ -1536,12 +1519,17 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1536,12 +1519,17 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
: (int) i * BITS_PER_WORD); : (int) i * BITS_PER_WORD);
rtx target_part = operand_subword (target, wordnum, 1, VOIDmode); rtx target_part = operand_subword (target, wordnum, 1, VOIDmode);
rtx result_part rtx result_part
= extract_bit_field (op0, MIN (BITS_PER_WORD, = extract_bit_field_1 (op0, MIN (BITS_PER_WORD,
bitsize - i * BITS_PER_WORD), bitsize - i * BITS_PER_WORD),
bitnum + bit_offset, 1, false, target_part, mode, bitnum + bit_offset, 1, false, target_part,
word_mode); mode, word_mode, fallback_p);
gcc_assert (target_part); gcc_assert (target_part);
if (!result_part)
{
delete_insns_since (last);
return NULL;
}
if (result_part != target_part) if (result_part != target_part)
emit_move_insn (target_part, result_part); emit_move_insn (target_part, result_part);
...@@ -1629,7 +1617,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1629,7 +1617,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
xop0 = gen_lowpart_SUBREG (ext_mode, xop0); xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
if (MEM_P (xop0)) if (MEM_P (xop0))
/* Get ref to first byte containing part of the field. */ /* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset); xop0 = adjust_bitfield_address (xop0, byte_mode, xoffset);
/* Now convert from counting within UNIT to counting in EXT_MODE. */ /* Now convert from counting within UNIT to counting in EXT_MODE. */
if (BYTES_BIG_ENDIAN && !MEM_P (xop0)) if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
...@@ -1725,7 +1713,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, ...@@ -1725,7 +1713,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
last = get_last_insn (); last = get_last_insn ();
/* Fetch it to a register in that size. */ /* Fetch it to a register in that size. */
xop0 = adjust_address (op0, bestmode, xoffset); xop0 = adjust_bitfield_address (op0, bestmode, xoffset);
xop0 = force_reg (bestmode, xop0); xop0 = force_reg (bestmode, xop0);
result = extract_bit_field_1 (xop0, bitsize, xbitpos, result = extract_bit_field_1 (xop0, bitsize, xbitpos,
unsignedp, packedp, target, unsignedp, packedp, target,
...@@ -1906,7 +1894,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, ...@@ -1906,7 +1894,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
offset -= (offset % (total_bits / BITS_PER_UNIT)); offset -= (offset % (total_bits / BITS_PER_UNIT));
} }
op0 = adjust_address (op0, mode, offset); op0 = adjust_bitfield_address (op0, mode, offset);
} }
mode = GET_MODE (op0); mode = GET_MODE (op0);
......
...@@ -4870,8 +4870,16 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4870,8 +4870,16 @@ expand_assignment (tree to, tree from, bool nontemporal)
/* Handle calls that return values in multiple non-contiguous locations. /* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
if (GET_CODE (to_rtx) == PARALLEL) if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, value, TREE_TYPE (from), {
int_size_in_bytes (TREE_TYPE (from))); if (GET_CODE (value) == PARALLEL)
emit_group_move (to_rtx, value);
else
emit_group_load (to_rtx, value, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
}
else if (GET_CODE (value) == PARALLEL)
emit_group_store (to_rtx, value, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
else if (GET_MODE (to_rtx) == BLKmode) else if (GET_MODE (to_rtx) == BLKmode)
emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL); emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
else else
...@@ -4903,9 +4911,16 @@ expand_assignment (tree to, tree from, bool nontemporal) ...@@ -4903,9 +4911,16 @@ expand_assignment (tree to, tree from, bool nontemporal)
else else
temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
/* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */
if (GET_CODE (to_rtx) == PARALLEL) if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, temp, TREE_TYPE (from), {
int_size_in_bytes (TREE_TYPE (from))); if (GET_CODE (temp) == PARALLEL)
emit_group_move (to_rtx, temp);
else
emit_group_load (to_rtx, temp, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
}
else if (temp) else if (temp)
emit_move_insn (to_rtx, temp); emit_move_insn (to_rtx, temp);
...@@ -5299,16 +5314,22 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ...@@ -5299,16 +5314,22 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
/* Handle calls that return values in multiple non-contiguous locations. /* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */ The Irix 6 ABI has examples of this. */
else if (GET_CODE (target) == PARALLEL) else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp, TREE_TYPE (exp), {
int_size_in_bytes (TREE_TYPE (exp))); if (GET_CODE (temp) == PARALLEL)
emit_group_move (target, temp);
else
emit_group_load (target, temp, TREE_TYPE (exp),
int_size_in_bytes (TREE_TYPE (exp)));
}
else if (GET_CODE (temp) == PARALLEL)
emit_group_store (target, temp, TREE_TYPE (exp),
int_size_in_bytes (TREE_TYPE (exp)));
else if (GET_MODE (temp) == BLKmode) else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp), emit_block_move (target, temp, expr_size (exp),
(call_param_p (call_param_p
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else if (nontemporal /* If we emit a nontemporal store, there is nothing else to do. */
&& emit_storent_insn (target, temp)) else if (nontemporal && emit_storent_insn (target, temp))
/* If we managed to emit a nontemporal store, there is nothing else to
do. */
; ;
else else
{ {
...@@ -6429,10 +6450,18 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, ...@@ -6429,10 +6450,18 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
return const0_rtx; return const0_rtx;
} }
/* Store the value in the bitfield. */ /* Handle calls that return values in multiple non-contiguous locations.
store_bit_field (target, bitsize, bitpos, The Irix 6 ABI has examples of this. */
bitregion_start, bitregion_end, if (bitpos == 0
mode, temp); && bitsize == GET_MODE_BITSIZE (mode)
&& GET_CODE (temp) == PARALLEL)
emit_group_store (target, temp, TREE_TYPE (exp),
int_size_in_bytes (TREE_TYPE (exp)));
else
/* Store the value in the bitfield. */
store_bit_field (target, bitsize, bitpos,
bitregion_start, bitregion_end,
mode, temp);
return const0_rtx; return const0_rtx;
} }
......
...@@ -557,11 +557,22 @@ extern rtx change_address (rtx, enum machine_mode, rtx); ...@@ -557,11 +557,22 @@ extern rtx change_address (rtx, enum machine_mode, rtx);
/* Return a memory reference like MEMREF, but with its mode changed /* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address offset by OFFSET bytes. */ to MODE and its address offset by OFFSET bytes. */
#define adjust_address(MEMREF, MODE, OFFSET) \ #define adjust_address(MEMREF, MODE, OFFSET) \
adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1) adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1, 0)
/* Likewise, but the reference is not required to be valid. */ /* Likewise, but the reference is not required to be valid. */
#define adjust_address_nv(MEMREF, MODE, OFFSET) \ #define adjust_address_nv(MEMREF, MODE, OFFSET) \
adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1) adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1, 0)
/* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address offset by OFFSET bytes. Assume that it's
for a bitfield and conservatively drop the underlying object if we
cannot be sure to stay within its bounds. */
#define adjust_bitfield_address(MEMREF, MODE, OFFSET) \
adjust_address_1 (MEMREF, MODE, OFFSET, 1, 1, 1)
/* Likewise, but the reference is not required to be valid. */
#define adjust_bitfield_address_nv(MEMREF, MODE, OFFSET) \
adjust_address_1 (MEMREF, MODE, OFFSET, 0, 1, 1)
/* Return a memory reference like MEMREF, but with its mode changed /* Return a memory reference like MEMREF, but with its mode changed
to MODE and its address changed to ADDR, which is assumed to be to MODE and its address changed to ADDR, which is assumed to be
...@@ -573,7 +584,8 @@ extern rtx change_address (rtx, enum machine_mode, rtx); ...@@ -573,7 +584,8 @@ extern rtx change_address (rtx, enum machine_mode, rtx);
#define adjust_automodify_address_nv(MEMREF, MODE, ADDR, OFFSET) \ #define adjust_automodify_address_nv(MEMREF, MODE, ADDR, OFFSET) \
adjust_automodify_address_1 (MEMREF, MODE, ADDR, OFFSET, 0) adjust_automodify_address_1 (MEMREF, MODE, ADDR, OFFSET, 0)
extern rtx adjust_address_1 (rtx, enum machine_mode, HOST_WIDE_INT, int, int); extern rtx adjust_address_1 (rtx, enum machine_mode, HOST_WIDE_INT, int, int,
int);
extern rtx adjust_automodify_address_1 (rtx, enum machine_mode, rtx, extern rtx adjust_automodify_address_1 (rtx, enum machine_mode, rtx,
HOST_WIDE_INT, int); HOST_WIDE_INT, int);
......
2012-09-14 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/pr44194-1.c: Check that there are no memory accesses left.
2012-09-14 Jakub Jelinek <jakub@redhat.com> 2012-09-14 Jakub Jelinek <jakub@redhat.com>
PR target/54564 PR target/54564
......
/* { dg-do compile { target { { { { { i?86-*-* x86_64-*-* } && x32 } || lp64 } && { ! s390*-*-* } } && { ! alpha*-*-* } } } } */ /* { dg-do compile { target { { { { { i?86-*-* x86_64-*-* } && x32 } || lp64 } && { ! s390*-*-* } } && { ! alpha*-*-* } } } } */
/* { dg-options "-O2 -fdump-rtl-dse1" } */ /* { dg-options "-O2 -fdump-rtl-dse1 -fdump-rtl-final" } */
/* Restricting to 64-bit targets since 32-bit targets return
/* Restrict to 64-bit targets since 32-bit targets usually return small
structures in memory. */ structures in memory. */
struct ints { int a, b, c; } foo(); struct ints { int a, b, c; } foo();
...@@ -10,5 +11,9 @@ void func() { ...@@ -10,5 +11,9 @@ void func() {
struct ints s = foo(); struct ints s = foo();
bar(s.a, s.b); bar(s.a, s.b);
} }
/* { dg-final { scan-rtl-dump "global deletions = (2|3)" "dse1" } } */
/* { dg-final { scan-rtl-dump "global deletions = (2|3)" "dse1" } } */
/* { dg-final { cleanup-rtl-dump "dse1" } } */ /* { dg-final { cleanup-rtl-dump "dse1" } } */
/* { dg-final { scan-rtl-dump-not "set \\(mem" "final" } } */
/* { dg-final { cleanup-rtl-dump "final" } } */
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