re PR target/42235 (redundant memory move from parameter space to spill space)

PR target/42235
	* function.c (record_hard_reg_sets): New static function.
	(assign_parm_setup_reg): If an optab for extending exists and the
	generated code clobbbers no hard regs, emit the insn directly and
	create a REG_EQUIV note.

From-SVN: r162240
This commit is contained in:
Bernd Schmidt 2010-07-16 02:09:03 +00:00 committed by Bernd Schmidt
parent f7587ed0d8
commit 71008de4b3
2 changed files with 97 additions and 10 deletions

View File

@ -1,3 +1,11 @@
2010-07-16 Bernd Schmidt <bernds@codesourcery.com>
PR target/42235
* function.c (record_hard_reg_sets): New static function.
(assign_parm_setup_reg): If an optab for extending exists and the
generated code clobbbers no hard regs, emit the insn directly and
create a REG_EQUIV note.
2010-07-15 Nathan Froyd <froydnj@codesourcery.com>
* c-decl.c (detect_field_duplicates): Use DECL_CHAIN insted of

View File

@ -2854,6 +2854,21 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
SET_DECL_RTL (parm, stack_parm);
}
/* A subroutine of assign_parm_setup_reg, called through note_stores.
This collects sets and clobbers of hard registers in a HARD_REG_SET,
which is pointed to by DATA. */
static void
record_hard_reg_sets (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
{
HARD_REG_SET *pset = (HARD_REG_SET *)data;
if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
{
int nregs = hard_regno_nregs[REGNO (x)][GET_MODE (x)];
while (nregs-- > 0)
SET_HARD_REG_BIT (*pset, REGNO (x) + nregs);
}
}
/* A subroutine of assign_parms. Allocate a pseudo to hold the current
parameter. Get it there. Perform all ABI specified conversions. */
@ -2861,10 +2876,12 @@ static void
assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
struct assign_parm_data_one *data)
{
rtx parmreg;
rtx parmreg, validated_mem;
rtx equiv_stack_parm;
enum machine_mode promoted_nominal_mode;
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
bool did_conversion = false;
bool need_conversion, moved;
/* Store the parm in a pseudoregister during the function, but we may
need to do it in a wider mode. Using 2 here makes the result
@ -2893,11 +2910,16 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
/* Copy the value into the register, thus bridging between
assign_parm_find_data_types and expand_expr_real_1. */
if (data->nominal_mode != data->passed_mode
|| promoted_nominal_mode != data->promoted_mode)
{
int save_tree_used;
equiv_stack_parm = data->stack_parm;
validated_mem = validize_mem (data->entry_parm);
need_conversion = (data->nominal_mode != data->passed_mode
|| promoted_nominal_mode != data->promoted_mode);
moved = false;
if (need_conversion)
{
/* ENTRY_PARM has been converted to PROMOTED_MODE, its
mode, by the caller. We now have to convert it to
NOMINAL_MODE, if different. However, PARMREG may be in
@ -2913,13 +2935,70 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
In addition, the conversion may involve a call, which could
clobber parameters which haven't been copied to pseudo
registers yet. Therefore, we must first copy the parm to
a pseudo reg here, and save the conversion until after all
registers yet.
First, we try to emit an insn which performs the necessary
conversion. We verify that this insn does not clobber any
hard registers. */
enum insn_code icode;
rtx op0, op1;
icode = can_extend_p (promoted_nominal_mode, data->passed_mode,
unsignedp);
op0 = parmreg;
op1 = validated_mem;
if (icode != CODE_FOR_nothing
&& insn_data[icode].operand[0].predicate (op0, promoted_nominal_mode)
&& insn_data[icode].operand[1].predicate (op1, data->passed_mode))
{
enum rtx_code code = unsignedp ? ZERO_EXTEND : SIGN_EXTEND;
rtx insn, insns;
HARD_REG_SET hardregs;
start_sequence ();
insn = gen_extend_insn (op0, op1, promoted_nominal_mode,
data->passed_mode, unsignedp);
emit_insn (insn);
insns = get_insns ();
moved = true;
CLEAR_HARD_REG_SET (hardregs);
for (insn = insns; insn && moved; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
note_stores (PATTERN (insn), record_hard_reg_sets,
&hardregs);
if (!hard_reg_set_empty_p (hardregs))
moved = false;
}
end_sequence ();
if (moved)
{
emit_insn (insns);
equiv_stack_parm = gen_rtx_fmt_e (code, GET_MODE (parmreg),
equiv_stack_parm);
}
}
}
if (moved)
/* Nothing to do. */
;
else if (need_conversion)
{
/* We did not have an insn to convert directly, or the sequence
generated appeared unsafe. We must first copy the parm to a
pseudo reg, and save the conversion until after all
parameters have been moved. */
int save_tree_used;
rtx tempreg = gen_reg_rtx (GET_MODE (data->entry_parm));
emit_move_insn (tempreg, validize_mem (data->entry_parm));
emit_move_insn (tempreg, validated_mem);
push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
tempreg = convert_to_mode (data->nominal_mode, tempreg, unsignedp);
@ -2949,7 +3028,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
did_conversion = true;
}
else
emit_move_insn (parmreg, validize_mem (data->entry_parm));
emit_move_insn (parmreg, validated_mem);
/* If we were passed a pointer but the actual value can safely live
in a register, put it in one. */
@ -3034,7 +3113,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
}
else if ((set = single_set (linsn)) != 0
&& SET_DEST (set) == parmreg)
set_unique_reg_note (linsn, REG_EQUIV, data->stack_parm);
set_unique_reg_note (linsn, REG_EQUIV, equiv_stack_parm);
}
/* For pointer data type, suggest pointer register. */