Allow passing nonaligned BLKmode structs in regs.

(struct arg_data): New fields aligned_regs and n_aligned_regs.
(expand_call): Set and use these fields when required.
(store_one_arg): Don't pass reg to emit_push_insn if we have previously
formed aligned registers.

From-SVN: r3440
This commit is contained in:
Richard Kenner 1993-02-08 05:51:58 -05:00
parent cd04883188
commit 4ab561180c
1 changed files with 85 additions and 4 deletions

View File

@ -84,6 +84,14 @@ struct arg_data
/* Place that this stack area has been saved, if needed. */
rtx save_area;
#endif
#ifdef STRICT_ALIGNMENT
/* If an argument's alignment does not permit direct copying into registers,
copy in smaller-sized pieces into pseudos. These are stored in a
block pointed to by this field. The next field says how many
word-sized pseudos we made. */
rtx *aligned_regs;
int n_aligned_regs;
#endif
};
#ifdef ACCUMULATE_OUTGOING_ARGS
@ -514,7 +522,7 @@ expand_call (exp, target, ignore)
rtx use_insns = 0;
register tree p;
register int i;
register int i, j;
/* See if we can find a DECL-node for the actual function.
As a result, decide whether this is a call to an integrable function. */
@ -625,8 +633,6 @@ expand_call (exp, target, ignore)
/* If inlining succeeded, return. */
if ((HOST_WIDE_INT) temp != -1)
{
int i;
/* Perform all cleanups needed for the arguments of this call
(i.e. destructors in C++). It is ok if these destructors
clobber RETURN_VALUE_REG, because the only time we care about
@ -1529,6 +1535,63 @@ expand_call (exp, target, ignore)
store_one_arg (&args[i], argblock, may_be_alloca,
args_size.var != 0, fndecl, reg_parm_stack_space);
#ifdef STRICT_ALIGNMENT
/* If we have a parm that is passed in registers but not in memory
and whose alignment does not permit a direct copy into registers,
make a group of pseudos that correspond to each register that we
will later fill. */
for (i = 0; i < num_actuals; i++)
if (args[i].reg != 0 && ! args[i].pass_on_stack
&& args[i].mode == BLKmode
&& (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
< MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))
{
int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
args[i].n_aligned_regs
= args[i].partial ? args[i].partial
: (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
args[i].aligned_regs = (rtx *) alloca (sizeof (rtx)
* args[i].n_aligned_regs);
for (j = 0; j < args[i].n_aligned_regs; j++)
{
rtx reg = gen_reg_rtx (word_mode);
rtx word = operand_subword_force (args[i].value, j, BLKmode);
int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value));
int bitpos;
args[i].aligned_regs[j] = reg;
/* Clobber REG and move each partword into it. Ensure we don't
go past the end of the structure. Note that the loop below
works because we've already verified that padding
and endianness are compatible. */
emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
for (bitpos = 0;
bitpos < BITS_PER_WORD && bytes >= 0;
bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
{
int xbitpos = (BYTES_BIG_ENDIAN
? bitpos = BITS_PER_WORD - bitpos - bitsize
: bitpos);
store_bit_field (reg, bitsize, xbitpos, word_mode,
extract_bit_field (word, bitsize, xbitpos, 1,
NULL_RTX, word_mode,
word_mode,
bitsize / BITS_PER_UNIT,
BITS_PER_WORD),
bitsize / BITS_PER_UNIT, BITS_PER_WORD);
}
}
}
#endif
/* Now store any partially-in-registers parm.
This is the last place a block-move can happen. */
if (reg_parm_seen)
@ -1609,6 +1672,17 @@ expand_call (exp, target, ignore)
if (nregs == 0)
emit_move_insn (reg, args[i].value);
#ifdef STRICT_ALIGNMENT
/* If we have pre-computed the values to put in the registers in
the case of non-aligned structures, copy them in now. */
else if (args[i].n_aligned_regs != 0)
for (j = 0; j < args[i].n_aligned_regs; j++)
emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j),
args[i].aligned_regs[j]);
#endif
else if (args[i].partial == 0 || args[i].pass_on_stack)
move_block_to_reg (REGNO (reg),
validize_mem (args[i].value), nregs,
@ -1989,13 +2063,20 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
this case. */
abort ();
#ifdef STRICT_ALIGNMENT
/* If this arg needs special alignment, don't load the registers
here. */
if (arg->n_aligned_regs != 0)
reg = 0;
#endif
/* If this is being partially passed in a register, but multiple locations
are specified, we assume that the one partially used is the one that is
listed first. */
if (reg && GET_CODE (reg) == EXPR_LIST)
reg = XEXP (reg, 0);
/* If this is being passes partially in a register, we can't evaluate
/* If this is being passed partially in a register, we can't evaluate
it directly into its stack slot. Otherwise, we can. */
if (arg->value == 0)
{