OSDN Git Service

PR target/35491
authoriains <iains@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 27 Jul 2010 13:24:08 +0000 (13:24 +0000)
committeriains <iains@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 27 Jul 2010 13:24:08 +0000 (13:24 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@162567 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h

index 7dc1e0d..3fcf579 100644 (file)
@@ -1,3 +1,17 @@
+2010-07-27  Iain Sandoe  <iains@gcc.gnu.org>
+
+       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.
+
 2010-07-27  Ira Rosen  <irar@il.ibm.com>
 
        PR tree-optimization/44152
index 130d1ac..e8fad12 100644 (file)
@@ -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)
     {
index ab07845..6065463 100644 (file)
@@ -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;