aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Shebs <shebs@apple.com>2004-11-14 20:28:58 +0000
committerStan Shebs <shebs@gcc.gnu.org>2004-11-14 20:28:58 +0000
commit594a51febe0e6419db7bf30ca233da8a563301fa (patch)
treec5f0272bf5c341b9e9b100e210c59c9a41ee1a0e
parent1e1b864906576c1e8ccd53595a727fc393fc0074 (diff)
downloadgcc-594a51febe0e6419db7bf30ca233da8a563301fa.zip
gcc-594a51febe0e6419db7bf30ca233da8a563301fa.tar.gz
gcc-594a51febe0e6419db7bf30ca233da8a563301fa.tar.bz2
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. From-SVN: r90629
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/config/rs6000/rs6000-protos.h2
-rw-r--r--gcc/config/rs6000/rs6000.c357
-rw-r--r--gcc/config/rs6000/rs6000.h2
4 files changed, 375 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d6adbcb..4eea1ed 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2004-11-14 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.
+
2004-11-14 Andrew Pinski <pinskia@physics.uc.edu>
PR c/17279
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index d3a3122..b756693 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -156,7 +156,7 @@ extern rtx rs6000_machopic_legitimize_pic_address (rtx orig,
#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);
+ 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);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index ada49ce..a0c607f 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -175,6 +175,9 @@ int rs6000_spe;
/* 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;
@@ -746,6 +749,8 @@ static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
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 *,
@@ -1292,6 +1297,12 @@ rs6000_override_options (const char *default_cpu)
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 ();
@@ -1625,6 +1636,19 @@ rs6000_parse_abi_options (void)
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
@@ -4603,6 +4627,15 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
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))
@@ -4783,6 +4816,48 @@ rs6000_arg_size (enum machine_mode mode, tree type)
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.)
@@ -4793,9 +4868,11 @@ rs6000_arg_size (enum machine_mode mode, tree type)
void
function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type, int named)
+ tree type, int named, int depth)
{
- cum->nargs_prototype--;
+ /* Only tick off an argument if we're not recursing. */
+ if (depth == 0)
+ cum->nargs_prototype--;
if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
{
@@ -4850,6 +4927,13 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
&& !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
@@ -4925,7 +5009,8 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
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);
+ fprintf (stderr, "named = %d, align = %d, depth = %d\n",
+ named, align, depth);
}
}
}
@@ -5003,6 +5088,123 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
}
+/* 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
@@ -5180,6 +5382,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
&& (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
@@ -5454,7 +5663,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
/* Skip the last named argument. */
next_cum = *cum;
- function_arg_advance (&next_cum, mode, type, 1);
+ function_arg_advance (&next_cum, mode, type, 1, 0);
if (DEFAULT_ABI == ABI_V4)
{
@@ -18127,6 +18336,128 @@ rs6000_complex_function_value (enum machine_mode mode)
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;
@@ -18143,6 +18474,24 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
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. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 50b6ac1..1b74db8 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1713,7 +1713,7 @@ typedef struct rs6000_args
(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)
+ 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,