===================================================================
@@ -2854,6 +2854,21 @@ assign_parm_setup_block (struct assign_p
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_par
/* 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_par
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_par
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_par
}
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. */