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]

PATCH: 64-bit Darwin ABI change for structs passed by value


The 64-bit version of Darwin specifies some ABI changes with the
goal of improving performance, most notably to use registers when
passing and returning medium-sized structs by value. To quote from
the draft spec:

 "If a parameter is a struct passed-by-value (but not unions),
 recursively examine each field in the struct. Examine the type
 of each parameter (or struct field), if it is of type float or
 double, assign it to next FP register. If it is a vector type,
 assign it to next V register."

and

 "To determine if a function result is returned in registers, you
 must look at the declared return type. If that type could be
 passed purely in registers as the first parameter to another
 function, then those same registers is how that result is
 returned."

A simple way to look at it is equivalent to a source-to-source
transformation where a struct passed by value is replaced with
a long list of foo.a.b.c arguments, one for each field including
those in substructs. Fields that are arrays also get this
treatment - equivalent to passing foo.a[0], foo.a[1], etc
as individual arguments.

The changes to make this work are (so far) almost entirely
restricted to rs6000.c; the trick I used is to call things like
rs6000_function_arg and rs6000_function_value recursively,
and assembly the results into PARALLELs. This generally seems
to work, and in some small cases of using functions that multiply
and add "points" represented as three-element structs (in 32-bit
code), I've seen as much as a 10% speedup over the usual ABI.

The bad news is that the testsuite shows some problems with
handling structs by value in varargs cases still, and it seems
that it will need some generic changes. In particular, rs6000
code returns null rtxes as parallels to indicate the need to
push as well as pass in registers, but the generic code is not
prepared to deal with, say, an eight-way parallel that includes
four nulls within the parallel. No doubt more will turn up,
since it seems no other ABI does quite the same thing.

So the purpose of this posting is to solicit comments on the
strategy (despite the s-to-s analogy, backend seems less
disruptive than doing this with gimple hacking, for instance),
and to give people a heads-up - I'm sure this patch has a
hundred things wrong with it. :-) The patch as-is can be
used with vanilla FSF GCC, and defaults to the changed ABI
for testing purposes, plus includes a -mabi=d32 and -mabi=d64
to control, although I don't expect to keep those in the
final version - this ABI change is only supposed to affect
powerpc-darwin when passed the -m64 option.

Stan

Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.738
diff -p -r1.738 expr.c
*** expr.c 4 Nov 2004 23:22:26 -0000 1.738
--- expr.c 6 Nov 2004 01:06:10 -0000
*************** void
*** 1566,1572 ****
emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
{
rtx *tmps, src;
! int start, i;
enum machine_mode m = GET_MODE (orig_src);


gcc_assert (GET_CODE (dst) == PARALLEL);
--- 1566,1572 ----
emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
{
rtx *tmps, src;
! int start = 0, i;
enum machine_mode m = GET_MODE (orig_src);


   gcc_assert (GET_CODE (dst) == PARALLEL);
*************** emit_group_load (rtx dst, rtx orig_src,
*** 1589,1611 ****
       return;
     }

   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
   if (XEXP (XVECEXP (dst, 0, 0), 0))
     start = 0;
   else
     start = 1;

tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));

   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
!       enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
!       HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
!       unsigned int bytelen = GET_MODE_SIZE (mode);
       int shift = 0;

/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
--- 1589,1620 ----
return;
}


+ #if 0
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
   if (XEXP (XVECEXP (dst, 0, 0), 0))
     start = 0;
   else
     start = 1;
+ #endif

tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));

   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
!       enum machine_mode mode;
!       HOST_WIDE_INT bytepos;
!       unsigned int bytelen;
       int shift = 0;

+ if (XEXP (XVECEXP (dst, 0, i), 0) == NULL_RTX)
+ continue;
+
+ mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
+ bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
+ bytelen = GET_MODE_SIZE (mode);
+
/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
*************** emit_group_load (rtx dst, rtx orig_src,
*** 1711,1717 ****


   /* Copy the extracted pieces into the proper (probable) hard regs.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
!     emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }

 /* Emit code to move a block SRC to block DST, where SRC and DST are
--- 1720,1727 ----

   /* Copy the extracted pieces into the proper (probable) hard regs.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
!     if (XEXP (XVECEXP (dst, 0, i), 0))
!       emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
 }

 /* Emit code to move a block SRC to block DST, where SRC and DST are
Index: config/rs6000/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
*** config/rs6000/rs6000-protos.h    7 Oct 2004 16:05:35 -0000    1.90
--- config/rs6000/rs6000-protos.h    6 Nov 2004 01:06:15 -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: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.735
diff -p -r1.735 rs6000.c
*** config/rs6000/rs6000.c    6 Nov 2004 00:53:20 -0000    1.735
--- config/rs6000/rs6000.c    6 Nov 2004 01:06: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_yes_no_option (const char *
*** 1608,1613 ****
--- 1619,1626 ----
 static void
 rs6000_parse_abi_options (void)
 {
+   rs6000_darwin64_abi = 1; /* for testing */
+
   if (rs6000_abi_string == 0)
     return;
   else if (! strcmp (rs6000_abi_string, "altivec"))
*************** rs6000_parse_abi_options (void)
*** 1624,1629 ****
--- 1637,1652 ----
       if (!TARGET_SPE_ABI)
     error ("not configured for ABI: '%s'", rs6000_abi_string);
     }
+   else if (! strcmp (rs6000_abi_string, "d64"))
+     {
+       rs6000_darwin64_abi = 1;
+       warning ("new darwin abi");
+     }
+   else if (! strcmp (rs6000_abi_string, "d32"))
+     {
+       rs6000_darwin64_abi = 0;
+       warning ("old darwin abi");
+     }

else if (! strcmp (rs6000_abi_string, "no-spe"))
rs6000_spe_abi = 0;
*************** rs6000_emit_move (rtx dest, rtx source,
*** 4596,4601 ****
--- 4619,4633 ----
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,
*** 4776,4781 ****
--- 4808,4855 ----
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,
*** 4786,4794 ****


 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))
     {
--- 4860,4870 ----

 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
*** 4843,4848 ****
--- 4919,4929 ----
&& !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))
+ return 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
*** 4918,4924 ****
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);
}
}
}
--- 4999,5005 ----
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
*** 4996,5001 ****
--- 5077,5200 ----
}
}


+ /* 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
*** 5173,5178 ****
--- 5372,5382 ----
        && (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
*** 5447,5453 ****

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

   if (DEFAULT_ABI == ABI_V4)
     {
--- 5651,5657 ----

   /* 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
*** 18075,18080 ****
--- 18281,18408 ----
   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[101], 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
*** 18091,18096 ****
--- 18419,18442 ----
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: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.345
diff -p -r1.345 rs6000.h
*** config/rs6000/rs6000.h 26 Oct 2004 17:36:22 -0000 1.345
--- config/rs6000/rs6000.h 6 Nov 2004 01:06:57 -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]