This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

64-bit Darwin ABI changes, for real


No one having flamed me about all the obvious bugs :-), here is the
version of 64-bit Darwin ABI change that I expect to commit when the
bootstrap and testsuite run finishes (not that the code will be
really exercised until the 64-bit multilib is enabled). I'm omitting
the expr.c changes until I've finished the generic dual register/stack
handling for PARALLELs; better to get an ICE for the affected cases
than silently scrambled stacks which were pretty hard to debug...

2004-11-13 Stan Shebs <shebs@apple.com>

   Basic ABI changes for passing structs by value in 64-bit Darwin.
   * config/rs6000/rs6000.c (rs6000_darwin64_abi): New flag.
   (rs6000_override_options): Set it for 64-bit Darwin.
   (rs6000_parse_abi_options): Add testing options to change it.
   (rs6000_return_in_memory): Test whether the type is one
   that can be passed in registers.
   (darwin64_function_arg_advance): New.
   (function_arg_advance): Call it, plus add recursion depth
   argument and test when counting off arguments.
   (rs6000_darwin64_function_arg): New.
   (function_arg): Call it.
   (setup_incoming_varargs): Add argument to function_arg_advance.
   (rs6000_darwin64_function_value): New.
   (rs6000_function_value): Call it.
   * config/rs6000/rs6000.h (FUNCTION_ARG_ADVANCE): Pass depth arg.
   * config/rs6000/rs6000-protos.h: Update decl of
   function_arg_advance.

Index: rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.90
diff -p -r1.90 rs6000-protos.h
*** rs6000-protos.h    7 Oct 2004 16:05:35 -0000    1.90
--- rs6000-protos.h    14 Nov 2004 02:41:35 -0000
*************** extern rtx rs6000_machopic_legitimize_pi
*** 156,162 ****
 #ifdef TREE_CODE
 extern unsigned int rs6000_special_round_type_align (tree, int, int);
 extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
!                   tree, int);
 extern int function_arg_boundary (enum machine_mode, tree);
 extern struct rtx_def *function_arg (CUMULATIVE_ARGS *,
                      enum machine_mode, tree, int);
--- 156,162 ----
 #ifdef TREE_CODE
 extern unsigned int rs6000_special_round_type_align (tree, int, int);
 extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
!                   tree, int, int);
 extern int function_arg_boundary (enum machine_mode, tree);
 extern struct rtx_def *function_arg (CUMULATIVE_ARGS *,
                      enum machine_mode, tree, int);
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.741
diff -p -r1.741 rs6000.c
*** rs6000.c    11 Nov 2004 17:03:33 -0000    1.741
--- rs6000.c    14 Nov 2004 02:41:50 -0000
*************** int rs6000_spe;
*** 175,180 ****
--- 175,183 ----
 /* Nonzero if floating point operations are done in the GPRs.  */
 int rs6000_float_gprs = 0;

+ /* Nonzero if we want Darwin's struct-by-value-in-regs ABI.  */
+ int rs6000_darwin64_abi;
+
 /* String from -mfloat-gprs=.  */
 const char *rs6000_float_gprs_string;

*************** static int rs6000_get_some_local_dynamic
*** 746,751 ****
--- 749,756 ----
 static rtx rs6000_complex_function_value (enum machine_mode);
 static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
                     enum machine_mode, tree);
+ static rtx rs6000_darwin64_function_arg (CUMULATIVE_ARGS *,
+                      enum machine_mode, tree, int);
 static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
 static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
 static void setup_incoming_varargs (CUMULATIVE_ARGS *,
*************** rs6000_override_options (const char *def
*** 1292,1297 ****
--- 1297,1308 ----
       rs6000_altivec_vrsave = 1;
     }

+   /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
+   if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
+     {
+       rs6000_darwin64_abi = 1;
+     }
+
   /* Handle -mabi= options.  */
   rs6000_parse_abi_options ();

*************** rs6000_parse_abi_options (void)
*** 1625,1630 ****
--- 1636,1654 ----
     error ("not configured for ABI: '%s'", rs6000_abi_string);
     }

+ /* These are here for testing during development only, do not
+ document in the manual please. */
+ else if (! strcmp (rs6000_abi_string, "d64"))
+ {
+ rs6000_darwin64_abi = 1;
+ warning ("Using darwin64 ABI");
+ }
+ else if (! strcmp (rs6000_abi_string, "d32"))
+ {
+ rs6000_darwin64_abi = 0;
+ warning ("Using old darwin ABI");
+ }
+
else if (! strcmp (rs6000_abi_string, "no-spe"))
rs6000_spe_abi = 0;
else
*************** rs6000_emit_move (rtx dest, rtx source,
*** 4603,4608 ****
--- 4627,4641 ----
static bool
rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
+ /* In the darwin64 abi, try to use registers for larger structs
+ if possible. */
+ if (AGGREGATE_TYPE_P (type)
+ && rs6000_darwin64_abi
+ && TREE_CODE (type) == RECORD_TYPE
+ && ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) <= 32)
+ && ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 0))
+ return false;
+
if (AGGREGATE_TYPE_P (type)
&& (TARGET_AIX_STRUCT_RET
|| (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
*************** rs6000_arg_size (enum machine_mode mode,
*** 4783,4788 ****
--- 4816,4863 ----
return (size + 7) >> 3;
}

+ /* The darwin64 ABI calls for us to recurse down through structs,
+ applying the same rules to struct elements as if a reference to
+ each were being passed directly. */
+
+ static void
+ darwin64_function_arg_advance (CUMULATIVE_ARGS *cum, tree type,
+ int named, int depth)
+ {
+ tree f, ftype;
+ int i, tot;
+
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ ftype = TREE_TYPE (f);
+ function_arg_advance (cum, TYPE_MODE (ftype), ftype,
+ named, depth + 1);
+ }
+ break;
+
+ case ARRAY_TYPE:
+ tot = int_size_in_bytes (type);
+ if (tot <= 0)
+ return;
+ ftype = TREE_TYPE (type);
+ tot /= int_size_in_bytes (ftype);
+ + for (i = 0; i < tot; ++i)
+ {
+ function_arg_advance (cum, TYPE_MODE (ftype), ftype,
+ named, depth + 1);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.)
*************** rs6000_arg_size (enum machine_mode mode,
*** 4793,4801 ****


 void
 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
!               tree type, int named)
 {
!   cum->nargs_prototype--;

   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
--- 4868,4878 ----

 void
 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
!               tree type, int named, int depth)
 {
!   /* Only tick off an argument if we're not recursing.  */
!   if (depth == 0)
!     cum->nargs_prototype--;

   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 4850,4855 ****
--- 4927,4939 ----
        && !cum->stdarg
        && cum->sysv_gregno <= GP_ARG_MAX_REG)
     cum->sysv_gregno++;
+
+   else if (rs6000_darwin64_abi
+        && mode == BLKmode
+        && (TREE_CODE (type) == RECORD_TYPE
+            || TREE_CODE (type) == ARRAY_TYPE))
+     darwin64_function_arg_advance (cum, type, named, depth);
+
   else if (DEFAULT_ABI == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 4925,4931 ****
            cum->words, cum->fregno);
       fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
            cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
!       fprintf (stderr, "named = %d, align = %d\n", named, align);
     }
     }
 }
--- 5009,5016 ----
            cum->words, cum->fregno);
       fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
            cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
!       fprintf (stderr, "named = %d, align = %d, depth = %d\n",
!            named, align, depth);
     }
     }
 }
*************** rs6000_spe_function_arg (CUMULATIVE_ARGS
*** 5003,5008 ****
--- 5088,5210 ----
     }
 }

+ /* For the darwin64 ABI, we want to construct a PARALLEL consisting of
+ the register(s) to be used for each field and subfield of a struct
+ being passed by value, along with the offset of where the
+ register's value may be found in the block. */
+
+ static rtx
+ rs6000_darwin64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named)
+ {
+ tree f, ftype, offset;
+ rtx rvec[FIRST_PSEUDO_REGISTER], sub, suboff, roffset;
+ int k = 0, i, j, bytepos, subbytepos, tot;
+ CUMULATIVE_ARGS saved_cum = *cum;
+ enum machine_mode submode;
+
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ ftype = TREE_TYPE (f);
+ offset = DECL_FIELD_OFFSET (f);
+ bytepos = int_bit_position (f) / BITS_PER_UNIT;
+ /* Force substructs to be handled as BLKmode even if
+ they're small enough to be recorded as DImode, so we
+ drill through to non-record fields. */
+ submode = TYPE_MODE (ftype);
+ if (TREE_CODE (ftype) == RECORD_TYPE)
+ submode = BLKmode;
+ sub = function_arg (cum, submode, ftype, named);
+ if (sub == NULL_RTX)
+ return NULL_RTX;
+ if (GET_CODE (sub) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (sub, 0); i++)
+ {
+ rtx subsub = XVECEXP (sub, 0, i);
+ suboff = XEXP (subsub, 1);
+ subbytepos = INTVAL (suboff);
+ subbytepos += bytepos;
+ roffset = gen_rtx_CONST_INT (SImode, subbytepos);
+ subsub = XEXP (subsub, 0);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset);
+ }
+ }
+ else
+ {
+ roffset = gen_rtx_CONST_INT (SImode, bytepos);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
+ }
+ /* Now do an arg advance to get all the cumulative arg
+ stuff set correctly for the next subfield. Note that it
+ has no lasting effect, because it is being done on a
+ temporary copy of the cumulative arg data. */
+ function_arg_advance (cum, submode, ftype, named, 1);
+ }
+ break;
+
+ case ARRAY_TYPE:
+ tot = int_size_in_bytes (type);
+ if (tot <= 0)
+ return NULL_RTX;
+ ftype = TREE_TYPE (type);
+ tot /= int_size_in_bytes (ftype);
+ bytepos = 0;
+
+ for (j = 0; j < tot; ++j)
+ {
+ /* Force substructs to be handled as BLKmode even if
+ they're small enough to be recorded as DImode, so we
+ drill through to non-record fields. */
+ submode = TYPE_MODE (ftype);
+ if (TREE_CODE (ftype) == RECORD_TYPE)
+ submode = BLKmode;
+ sub = function_arg (cum, submode, ftype, named);
+ if (sub == NULL_RTX)
+ return NULL_RTX;
+ if (GET_CODE (sub) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (sub, 0); i++)
+ {
+ rtx subsub = XVECEXP (sub, 0, i);
+
+ suboff = XEXP (subsub, 1);
+ subbytepos = INTVAL (suboff);
+ subbytepos += bytepos;
+ roffset = gen_rtx_CONST_INT (SImode, subbytepos);
+ subsub = XEXP (subsub, 0);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset);
+ }
+ }
+ else
+ {
+ roffset = gen_rtx_CONST_INT (SImode, bytepos);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
+ }
+ /* Now do an arg advance to get all the cumulative arg
+ stuff set correctly for the next subfield. Note that it
+ has no lasting effect, because it is being done on a
+ temporary copy of the cumulative arg data. */
+ function_arg_advance (cum, submode, ftype, named, 1);
+ bytepos += int_size_in_bytes (ftype);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ *cum = saved_cum;
+ if (k > 0)
+ return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
+ else
+ return NULL_RTX;
+ }
+
/* Determine where to place an argument in 64-bit mode with 32-bit ABI. */


 static rtx
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 5180,5185 ****
--- 5382,5394 ----
        && (SPE_VECTOR_MODE (mode)
            || (TARGET_E500_DOUBLE && mode == DFmode)))
     return rs6000_spe_function_arg (cum, mode, type);
+
+   else if (rs6000_darwin64_abi
+        && mode == BLKmode
+        && (TREE_CODE (type) == RECORD_TYPE
+            || TREE_CODE (type) == ARRAY_TYPE))
+     return rs6000_darwin64_function_arg (cum, mode, type, named);
+
   else if (abi == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
*************** setup_incoming_varargs (CUMULATIVE_ARGS
*** 5454,5460 ****

   /* Skip the last named argument.  */
   next_cum = *cum;
!   function_arg_advance (&next_cum, mode, type, 1);

   if (DEFAULT_ABI == ABI_V4)
     {
--- 5663,5669 ----

   /* Skip the last named argument.  */
   next_cum = *cum;
!   function_arg_advance (&next_cum, mode, type, 1, 0);

   if (DEFAULT_ABI == ABI_V4)
     {
*************** rs6000_complex_function_value (enum mach
*** 18127,18132 ****
--- 18338,18465 ----
   return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
 }

+ /* Compose a PARALLEL for a darwin64 struct being returned by
+ value. */
+
+ static rtx
+ rs6000_darwin64_function_value (CUMULATIVE_ARGS *cum, tree valtype)
+ {
+ tree f, ftype;
+ rtx rvec[FIRST_PSEUDO_REGISTER], sub, roffset, suboff;
+ int k = 0, bytepos, tot, elt, i, subbytepos;
+ enum machine_mode fmode;
+
+ switch (TREE_CODE (valtype))
+ {
+ case RECORD_TYPE:
+ for (f = TYPE_FIELDS (valtype); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ ftype = TREE_TYPE (f);
+ fmode = TYPE_MODE (ftype);
+ bytepos = int_bit_position (f) / BITS_PER_UNIT;
+ if (USE_FP_FOR_ARG_P (cum, fmode, ftype))
+ {
+ sub = gen_rtx_REG (fmode, cum->fregno++);
+ cum->sysv_gregno++;
+ }
+ else if (USE_ALTIVEC_FOR_ARG_P (cum, fmode, ftype, 1))
+ {
+ sub = gen_rtx_REG (fmode, cum->vregno++);
+ cum->sysv_gregno++;
+ }
+ else if (fmode == BLKmode
+ && (TREE_CODE (ftype) == RECORD_TYPE
+ || TREE_CODE (ftype) == ARRAY_TYPE))
+ sub = rs6000_darwin64_function_value (cum, ftype);
+ else
+ sub = gen_rtx_REG (fmode, cum->sysv_gregno++);
+ if (sub == NULL_RTX)
+ return sub;
+ else if (GET_CODE (sub) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (sub, 0); i++)
+ {
+ rtx subsub = XVECEXP (sub, 0, i);
+
+ suboff = XEXP (subsub, 1);
+ subbytepos = INTVAL (suboff);
+ subbytepos += bytepos;
+ roffset = gen_rtx_CONST_INT (SImode, subbytepos);
+ subsub = XEXP (subsub, 0);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset);
+ }
+ }
+ else
+ {
+ roffset = gen_rtx_CONST_INT (SImode, bytepos);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
+ }
+ }
+ if (k > 0)
+ return gen_rtx_PARALLEL (TYPE_MODE (valtype), gen_rtvec_v (k, rvec));
+ else
+ return NULL_RTX;
+
+ case ARRAY_TYPE:
+ /* If passing by value won't work, give up. */
+ if (int_size_in_bytes (valtype) <= 0)
+ return NULL_RTX;
+ ftype = TREE_TYPE (valtype);
+ fmode = TYPE_MODE (ftype);
+ tot = int_size_in_bytes (valtype) / int_size_in_bytes (ftype);
+ bytepos = 0;
+ for (elt = 0; elt < tot; ++elt)
+ {
+ if (USE_FP_FOR_ARG_P (cum, fmode, ftype))
+ {
+ sub = gen_rtx_REG (fmode, cum->fregno++);
+ cum->sysv_gregno++;
+ }
+ else if (USE_ALTIVEC_FOR_ARG_P (cum, fmode, ftype, 1))
+ {
+ sub = gen_rtx_REG (fmode, cum->vregno++);
+ cum->sysv_gregno++;
+ }
+ else if (fmode == BLKmode
+ && (TREE_CODE (ftype) == RECORD_TYPE
+ || TREE_CODE (ftype) == ARRAY_TYPE))
+ sub = rs6000_darwin64_function_value (cum, ftype);
+ else
+ sub = gen_rtx_REG (fmode, cum->sysv_gregno++);
+ if (sub == NULL_RTX)
+ return sub;
+ else if (GET_CODE (sub) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (sub, 0); i++)
+ {
+ rtx subsub = XVECEXP (sub, 0, i);
+
+ suboff = XEXP (subsub, 1);
+ subbytepos = INTVAL (suboff);
+ subbytepos += bytepos;
+ roffset = gen_rtx_CONST_INT (SImode, subbytepos);
+ subsub = XEXP (subsub, 0);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset);
+ }
+ }
+ else
+ {
+ roffset = gen_rtx_CONST_INT (SImode, bytepos);
+ rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
+ }
+ bytepos += int_size_in_bytes (ftype);
+ }
+ if (k > 0)
+ return gen_rtx_PARALLEL (TYPE_MODE (valtype), gen_rtvec_v (k, rvec));
+ else
+ return NULL_RTX;
+
+ default:
+ abort ();
+ }
+ }
+
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
*************** rs6000_function_value (tree valtype, tre
*** 18143,18148 ****
--- 18476,18499 ----
enum machine_mode mode;
unsigned int regno;


+ /* Special handling for structs in darwin64. */
+ if (rs6000_darwin64_abi
+ && TYPE_MODE (valtype) == BLKmode
+ && (TREE_CODE (valtype) == RECORD_TYPE
+ || TREE_CODE (valtype) == ARRAY_TYPE))
+ {
+ CUMULATIVE_ARGS valcum;
+ rtx valret;
+
+ valcum.sysv_gregno = GP_ARG_RETURN;
+ valcum.fregno = FP_ARG_MIN_REG;
+ valcum.vregno = ALTIVEC_ARG_MIN_REG;
+ valret = rs6000_darwin64_function_value (&valcum, valtype);
+ if (valret)
+ return valret;
+ /* Otherwise fall through to standard ABI rules. */
+ }
+
if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
{
/* Long long return value need be split in -mpowerpc64, 32bit ABI. */
Index: rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.345
diff -p -r1.345 rs6000.h
*** rs6000.h 26 Oct 2004 17:36:22 -0000 1.345
--- rs6000.h 14 Nov 2004 02:41:52 -0000
*************** typedef struct rs6000_args
*** 1713,1719 ****
(TYPE is null for libcalls where that information may not be available.) */


 #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)    \
!   function_arg_advance (&CUM, MODE, TYPE, NAMED)

/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
--- 1713,1719 ----
(TYPE is null for libcalls where that information may not be available.) */


 #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)    \
!   function_arg_advance (&CUM, MODE, TYPE, NAMED, 0)

 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]