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:
parent
cd04883188
commit
4ab561180c
89
gcc/calls.c
89
gcc/calls.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue