From: Iain Sandoe Date: Tue, 27 Jul 2010 13:24:08 +0000 (+0000) Subject: re PR target/35491 (wrong ABI for some struct passing with vector code) X-Git-Tag: releases/gcc-4.6.0~5405 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a9ab25e2b426a24273f121ea8d29239cc526ce72;p=thirdparty%2Fgcc.git re PR target/35491 (wrong ABI for some struct passing with vector code) PR target/35491 PR target/29090 Merge from Apple local 4.2.1. 2005-05-11 Stan Shebs 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. From-SVN: r162567 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7dc1e0dfa937..3fcf579c87bd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2010-07-27 Iain Sandoe + + PR target/35491 + PR target/29090 + + Merge from Apple local 4.2.1. + 2005-05-11 Stan Shebs + 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. + 2010-07-27 Ira Rosen PR tree-optimization/44152 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 130d1ac9be2f..e8fad12caada 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1154,7 +1154,7 @@ static rtx rs6000_complex_function_value (enum machine_mode); 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 *, @@ -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 (CUMULATIVE_ARGS *cum, 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 (CUMULATIVE_ARGS *cum, 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 machine_mode mode, { 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) { diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index ab0784572d56..6065463691b1 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -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;