static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
enum machine_mode, tree);
static void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
- HOST_WIDE_INT);
+ HOST_WIDE_INT, int);
static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
tree, HOST_WIDE_INT);
static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
static void
rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
- HOST_WIDE_INT bitpos)
+ HOST_WIDE_INT bitpos, int final)
{
unsigned int startbit, endbit;
int intregs, intoffset;
enum machine_mode mode;
+ /* Handle the situations where a float is taking up the first half
+ of the GPR, and the other half is empty (typically due to
+ alignment restrictions). We can detect this by a 8-byte-aligned
+ int field, or by seeing that this is the final flush for this
+ argument. Count the word and continue on. */
+ if (cum->floats_in_gpr == 1
+ && (cum->intoffset % 64 == 0
+ || (cum->intoffset == -1 && final)))
+ {
+ cum->words++;
+ cum->floats_in_gpr = 0;
+ }
+
if (cum->intoffset == -1)
return;
intoffset = cum->intoffset;
cum->intoffset = -1;
+ cum->floats_in_gpr = 0;
if (intoffset % BITS_PER_WORD != 0)
{
endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
intregs = (endbit - startbit) / BITS_PER_WORD;
cum->words += intregs;
+ /* words should be unsigned. */
+ if ((unsigned)cum->words < (endbit/BITS_PER_WORD))
+ {
+ int pad = (endbit/BITS_PER_WORD) - cum->words;
+ cum->words += pad;
+ }
}
/* The darwin64 ABI calls for us to recurse down through structs,
rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
{
- rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
+ rs6000_darwin64_record_arg_advance_flush (cum, bitpos, 0);
cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
- cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
+ /* Single-precision floats present a special problem for
+ us, because they are smaller than an 8-byte GPR, and so
+ the structure-packing rules combined with the standard
+ varargs behavior mean that we want to pack float/float
+ and float/int combinations into a single register's
+ space. This is complicated by the arg advance flushing,
+ which works on arbitrarily large groups of int-type
+ fields. */
+ if (mode == SFmode)
+ {
+ if (cum->floats_in_gpr == 1)
+ {
+ /* Two floats in a word; count the word and reset
+ the float count. */
+ cum->words++;
+ cum->floats_in_gpr = 0;
+ }
+ else if (bitpos % 64 == 0)
+ {
+ /* A float at the beginning of an 8-byte word;
+ count it and put off adjusting cum->words until
+ we see if a arg advance flush is going to do it
+ for us. */
+ cum->floats_in_gpr++;
+ }
+ else
+ {
+ /* The float is at the end of a word, preceded
+ by integer fields, so the arg advance flush
+ just above has already set cum->words and
+ everything is taken care of. */
+ }
+ }
+ else
+ cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
}
else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
{
- rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
+ rs6000_darwin64_record_arg_advance_flush (cum, bitpos, 0);
cum->vregno++;
cum->words += 2;
}
{ int; double; int; } [powerpc alignment]. We have to
grovel through the fields for these too. */
cum->intoffset = 0;
+ cum->floats_in_gpr = 0;
rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
rs6000_darwin64_record_arg_advance_flush (cum,
- size * BITS_PER_UNIT);
+ size * BITS_PER_UNIT, 1);
}
+ if (TARGET_DEBUG_ARG)
+ {
+ fprintf (stderr, "function_adv: words = %2d, align=%d, size=%d",
+ cum->words, TYPE_ALIGN (type), size);
+ fprintf (stderr,
+ "nargs = %4d, proto = %d, mode = %4s (darwin64 abi BLK)\n",
+ cum->nargs_prototype, cum->prototype,
+ GET_MODE_NAME (mode));
+ }
}
else if (DEFAULT_ABI == ABI_V4)
{