Commit 929634d8 by Eric Botcazou Committed by Eric Botcazou

re PR middle-end/54315 (unnecessary copy of return value for union)

	PR rtl-optimization/54315
	* calls.c (expand_call): Don't deal specifically with BLKmode values
	returned in naked registers.
	* expr.h (copy_blkmode_from_reg): Adjust prototype.
	* expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and
	make it required.  Assert that SRCREG hasn't BLKmode.  Add a couple of 
	short-circuits for common cases and be prepared for sub-word registers.
	(expand_assignment): Call copy_blkmode_from_reg for BLKmode values
	returned in naked registers.
	(store_expr): Likewise.
	(store_field): Likewise.

From-SVN: r192641
parent e598c332
2012-10-20 Eric Botcazou <ebotcazou@adacore.com>
PR rtl-optimization/54315
* calls.c (expand_call): Don't deal specifically with BLKmode values
returned in naked registers.
* expr.h (copy_blkmode_from_reg): Adjust prototype.
* expr.c (copy_blkmode_from_reg): Rename first parameter into TARGET and
make it required. Assert that SRCREG hasn't BLKmode. Add a couple of
short-circuits for common cases and be prepared for sub-word registers.
(expand_assignment): Call copy_blkmode_from_reg for BLKmode values
returned in naked registers.
(store_expr): Likewise.
(store_field): Likewise.
2012-10-20 Jan Hubicka <jh@suse.cz>
* loop-unroll.c (decide_unroll_constant_iterations): Don't
......@@ -3327,16 +3327,6 @@ expand_call (tree exp, rtx target, int ignore)
sibcall_failure = 1;
}
}
else if (TYPE_MODE (rettype) == BLKmode)
{
rtx val = valreg;
if (GET_MODE (val) != BLKmode)
val = avoid_likely_spilled_reg (val);
target = copy_blkmode_from_reg (target, val, rettype);
/* We can not support sibling calls for this case. */
sibcall_failure = 1;
}
else
target = copy_to_reg (avoid_likely_spilled_reg (valreg));
......
......@@ -2086,39 +2086,23 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
emit_move_insn (orig_dst, dst);
}
/* Generate code to copy a BLKmode object of TYPE out of a
set of registers starting with SRCREG into TGTBLK. If TGTBLK
is null, a stack temporary is created. TGTBLK is returned.
/* Copy a BLKmode object of TYPE out of a register SRCREG into TARGET.
The purpose of this routine is to handle functions that return
BLKmode structures in registers. Some machines (the PA for example)
want to return all small structures in registers regardless of the
structure's alignment. */
This is used on targets that return BLKmode values in registers. */
rtx
copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
void
copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
{
unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
rtx src = NULL, dst = NULL;
unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
enum machine_mode mode = GET_MODE (srcreg);
enum machine_mode tmode = GET_MODE (target);
enum machine_mode copy_mode;
if (tgtblk == 0)
{
tgtblk = assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST)),
1, 1);
preserve_temp_slots (tgtblk);
}
/* This code assumes srcreg is at least a full word. If it isn't, copy it
into a new pseudo which is a full word. */
if (GET_MODE (srcreg) != BLKmode
&& GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
/* BLKmode registers created in the back-end shouldn't have survived. */
gcc_assert (mode != BLKmode);
/* If the structure doesn't take up a whole number of words, see whether
SRCREG is padded on the left or on the right. If it's on the left,
......@@ -2136,22 +2120,54 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
padding_correction
= (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
/* We can use a single move if we have an exact mode for the size. */
else if (MEM_P (target)
&& (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
|| MEM_ALIGN (target) >= GET_MODE_ALIGNMENT (mode))
&& bytes == GET_MODE_SIZE (mode))
{
emit_move_insn (adjust_address (target, mode, 0), srcreg);
return;
}
/* And if we additionally have the same mode for a register. */
else if (REG_P (target)
&& GET_MODE (target) == mode
&& bytes == GET_MODE_SIZE (mode))
{
emit_move_insn (target, srcreg);
return;
}
/* This code assumes srcreg is at least a full word. If it isn't, copy it
into a new pseudo which is a full word. */
if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
{
srcreg = convert_to_mode (word_mode, srcreg, TYPE_UNSIGNED (type));
mode = word_mode;
}
/* Copy the structure BITSIZE bits at a time. If the target lives in
memory, take care of not reading/writing past its end by selecting
a copy mode suited to BITSIZE. This should always be possible given
how it is computed.
If the target lives in register, make sure not to select a copy mode
larger than the mode of the register.
We could probably emit more efficient code for machines which do not use
strict alignment, but it doesn't seem worth the effort at the current
time. */
copy_mode = word_mode;
if (MEM_P (tgtblk))
if (MEM_P (target))
{
enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
if (mem_mode != BLKmode)
copy_mode = mem_mode;
}
else if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
copy_mode = tmode;
for (bitpos = 0, xbitpos = padding_correction;
bitpos < bytes * BITS_PER_UNIT;
......@@ -2160,15 +2176,15 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
/* We need a new source operand each time xbitpos is on a
word boundary and when xbitpos == padding_correction
(the first time through). */
if (xbitpos % BITS_PER_WORD == 0
|| xbitpos == padding_correction)
src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
GET_MODE (srcreg));
if (xbitpos % BITS_PER_WORD == 0 || xbitpos == padding_correction)
src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD, mode);
/* We need a new destination operand each time bitpos is on
a word boundary. */
if (bitpos % BITS_PER_WORD == 0)
dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
if (REG_P (target) && GET_MODE_BITSIZE (tmode) < BITS_PER_WORD)
dst = target;
else if (bitpos % BITS_PER_WORD == 0)
dst = operand_subword (target, bitpos / BITS_PER_WORD, 1, tmode);
/* Use xbitpos for the source extraction (right justified) and
bitpos for the destination store (left justified). */
......@@ -2177,8 +2193,6 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
xbitpos % BITS_PER_WORD, 1, false,
NULL_RTX, copy_mode, copy_mode));
}
return tgtblk;
}
/* Copy BLKmode value SRC into a register of mode MODE. Return the
......@@ -4883,7 +4897,12 @@ expand_assignment (tree to, tree from, bool nontemporal)
emit_group_store (to_rtx, value, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
else if (GET_MODE (to_rtx) == BLKmode)
{
if (REG_P (value))
copy_blkmode_from_reg (to_rtx, value, TREE_TYPE (from));
else
emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
}
else
{
if (POINTER_TYPE_P (TREE_TYPE (to)))
......@@ -5225,21 +5244,26 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
supposed to be bit-copied or bit-initialized. */
&& expr_size (exp) != const0_rtx)
{
if (GET_MODE (temp) != GET_MODE (target)
&& GET_MODE (temp) != VOIDmode)
if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode)
{
if (GET_MODE (target) == BLKmode)
{
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
if (GET_MODE (target) == BLKmode
&& GET_MODE (temp) == BLKmode)
if (REG_P (temp))
{
if (TREE_CODE (exp) == CALL_EXPR)
copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
else
store_bit_field (target,
INTVAL (expr_size (exp)) * BITS_PER_UNIT,
0, 0, 0, GET_MODE (temp), temp);
}
else
emit_block_move (target, temp, expr_size (exp),
(call_param_p
? BLOCK_OP_CALL_PARM
: BLOCK_OP_NORMAL));
else if (GET_MODE (target) == BLKmode)
store_bit_field (target, INTVAL (expr_size (exp)) * BITS_PER_UNIT,
0, 0, 0, GET_MODE (temp), temp);
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
}
else
convert_move (target, temp, unsignedp);
convert_move (target, temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
}
else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
......@@ -6328,7 +6352,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
twice, once with emit_move_insn and once via store_field. */
if (mode == BLKmode
&& (REG_P (target) || GET_CODE (target) == SUBREG))
&& (REG_P (target) || GET_CODE (target) == SUBREG)
&& TREE_CODE (exp) != CALL_EXPR)
{
rtx object = assign_temp (type, 1, 1);
rtx blk_object = adjust_address (object, BLKmode, 0);
......@@ -6477,6 +6502,16 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
temp = temp_target;
}
/* Handle calls that return BLKmode values in registers. */
else if (mode == BLKmode
&& REG_P (temp)
&& TREE_CODE (exp) == CALL_EXPR)
{
rtx temp_target = gen_reg_rtx (GET_MODE (temp));
copy_blkmode_from_reg (temp_target, temp, TREE_TYPE (exp));
temp = temp_target;
}
/* Store the value in the bitfield. */
store_bit_field (target, bitsize, bitpos,
bitregion_start, bitregion_end,
......
......@@ -335,7 +335,7 @@ extern rtx emit_group_move_into_temps (rtx);
extern void emit_group_store (rtx, rtx, tree, int);
/* Copy BLKmode object from a set of registers. */
extern rtx copy_blkmode_from_reg (rtx, rtx, tree);
extern void copy_blkmode_from_reg (rtx, rtx, tree);
/* Mark REG as holding a parameter for the next CALL_INSN.
Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode. */
......
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