diff mbox

[Darwin,1/2] fix PPC64 ABI

Message ID C28F5DDC-8496-4077-B8A3-30C40BAEE6C0@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe July 24, 2010, 8:31 a.m. UTC
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;

Comments

Mike Stump July 24, 2010, 9:36 a.m. UTC | #1
On Jul 24, 2010, at 1:31 AM, IainS wrote:
> 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) ?

I'm fine with this, David, any objections?
diff mbox

Patch

Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 162457)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -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;

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 162457)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -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 *,