Comments
Patch
===================================================================
@@ -1673,6 +1673,8 @@ typedef struct rs6000_args
int sysv_gregno; /* next available GP register */
int intoffset; /* running offset in struct (darwin64) */
int use_stack; /* any part of struct on stack (darwin64) */
+ int floats_in_gpr; /* count of SFmode floats taking up
+ GPR space (darwin64) */
int named; /* false for varargs params */
} CUMULATIVE_ARGS;
===================================================================
@@ -1154,7 +1154,7 @@ static rtx rs6000_complex_function_value (enum mac
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 *,
Hi, Part 1, a long-overdue merge from the apple-local 4.2 branch. It doesn't touch anything outside darwin-specific code, other than adding a darwin-specific field to the CUMULATIVE_ARGS structure. OK for trunk (and 4.5 when it re-opens) ? Iain gcc/ PR target/35491 PR target/29090 Merge from Apple local 4.2.1. 2005-05-11 Stan Shebs <shebs@apple.com> Fix 64-bit varargs for Darwin (Radar 4028089). * config/rs6000/rs6000.h (rs6000_args): New field floats_in_gpr. * config/rs6000/rs6000.c (rs6000_darwin64_record_arg_advance_flush): Add argument, add case for 8-byte register half-filled with a float. (rs6000_darwin64_record_arg_advance_recurse): Detect and handle single-precision floats specially. tree, HOST_WIDE_INT); static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *, @@ -7542,17 +7542,31 @@ rs6000_arg_size (enum machine_mode mode, tree type 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) { @@ -7572,6 +7586,12 @@ rs6000_darwin64_record_arg_advance_flush (CUMULATI 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, @@ -7606,13 +7626,47 @@ rs6000_darwin64_record_arg_advance_recurse (CUMULA 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; } @@ -7718,10 +7772,20 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum m { 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) { @@ -8920,8 +8984,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, gi tree gpr, fpr, ovf, sav, reg, t, u; int size, rsize, n_reg, sav_ofs, sav_scale; tree lab_false, lab_over, addr; + tree ptrtype = build_pointer_type_for_mode (type, ptr_mode, true); int align; - tree ptrtype = build_pointer_type_for_mode (type, ptr_mode, true); int regalign = 0; gimple stmt;