aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorDale Johannesen <dalej@apple.com>2005-03-01 02:56:35 +0000
committerStan Shebs <shebs@gcc.gnu.org>2005-03-01 02:56:35 +0000
commit0b5383eba096fa2bec2d62242ea0f1bc5350ebc3 (patch)
tree46b25cc4e0cf6fdd8d58b935495c31cf0e99bfff /gcc
parent1a9dddada346b812bafc8918d082c993c7f0a82d (diff)
downloadgcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.zip
gcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.tar.gz
gcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.tar.bz2
Rewrite of 64-bit Darwin structure-by-value pass/return.
2005-02-28 Dale Johannesen <dalej@apple.com> Stan Shebs <shebs@apple.com> Rewrite of 64-bit Darwin structure-by-value pass/return. * config/rs6000/rs6000.h (CUMULATIVE_ARGS): New fields intoffset, use_stack, named. * config/rs6000/rs6000.c (rs6000_darwin64_function_arg): Remove. (rs6000_darwin64_record_arg_advance_flush): New. (rs6000_darwin64_record_arg_advance_recurse): New. (rs6000_darwin64_record_arg_flush): New. (rs6000_darwin64_record_arg_recurse): New. (rs6000_darwin64_record_arg): New. (rs6000_return_in_memory): Remove AGGREGATE_TYPE_P check. (function_arg_boundary): Handle 128-bit aligned structs. (function_arg_advance): Rewrite darwin64 struct handling. (function_arg): Call rs6000_darwin64_record_arg. (function_arg_partial_nregs): Handle darwin64 structs. (rs6000_darwin64_function_value): Remove. (rs6000_function_value): Call rs6000_darwin64_record_arg. Co-Authored-By: Stan Shebs <shebs@apple.com> From-SVN: r95723
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/config/rs6000/rs6000.c603
-rw-r--r--gcc/config/rs6000/rs6000.h3
3 files changed, 332 insertions, 294 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7eed832..18a3070 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2005-02-28 Dale Johannesen <dalej@apple.com>
+ Stan Shebs <shebs@apple.com>
+
+ Rewrite of 64-bit Darwin structure-by-value pass/return.
+ * config/rs6000/rs6000.h (CUMULATIVE_ARGS): New fields
+ intoffset, use_stack, named.
+ * config/rs6000/rs6000.c (rs6000_darwin64_function_arg): Remove.
+ (rs6000_darwin64_record_arg_advance_flush): New.
+ (rs6000_darwin64_record_arg_advance_recurse): New.
+ (rs6000_darwin64_record_arg_flush): New.
+ (rs6000_darwin64_record_arg_recurse): New.
+ (rs6000_darwin64_record_arg): New.
+ (rs6000_return_in_memory): Remove AGGREGATE_TYPE_P check.
+ (function_arg_boundary): Handle 128-bit aligned structs.
+ (function_arg_advance): Rewrite darwin64 struct handling.
+ (function_arg): Call rs6000_darwin64_record_arg.
+ (function_arg_partial_nregs): Handle darwin64 structs.
+ (rs6000_darwin64_function_value): Remove.
+ (rs6000_function_value): Call rs6000_darwin64_record_arg.
+
2005-02-28 Roger Sayle <roger@eyesopen.com>
PR tree-optimization/20216
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index f0b7c18..ff6d09d 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -737,8 +737,17 @@ 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 void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
+ HOST_WIDE_INT);
+static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
+ tree, HOST_WIDE_INT);
+static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
+ HOST_WIDE_INT,
+ rtx[], int *);
+static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
+ tree, HOST_WIDE_INT,
+ rtx[], int *);
+static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool);
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 *,
@@ -3833,12 +3842,23 @@ 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
+ if (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;
+ && int_size_in_bytes (type) > 0)
+ {
+ CUMULATIVE_ARGS valcum;
+ rtx valret;
+
+ valcum.words = 0;
+ valcum.fregno = FP_ARG_MIN_REG;
+ valcum.vregno = ALTIVEC_ARG_MIN_REG;
+ /* Do a trial code generation as if this were going to be passed
+ as an argument; if any part goes in memory, we return NULL. */
+ valret = rs6000_darwin64_record_arg (&valcum, type, 1, true);
+ if (valret)
+ return false;
+ /* Otherwise fall through to more conventional ABI rules. */
+ }
if (AGGREGATE_TYPE_P (type)
&& (TARGET_AIX_STRUCT_RET
@@ -4029,6 +4049,9 @@ function_arg_boundary (enum machine_mode mode, tree type)
|| (type && TREE_CODE (type) == VECTOR_TYPE
&& int_size_in_bytes (type) >= 16))
return 128;
+ else if (rs6000_darwin64_abi && mode == BLKmode
+ && type && TYPE_ALIGN (type) > 64)
+ return 128;
else
return PARM_BOUNDARY;
}
@@ -4051,46 +4074,84 @@ 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. */
+/* Use this to flush pending int fields. */
static void
-darwin64_function_arg_advance (CUMULATIVE_ARGS *cum, tree type,
- int named, int depth)
+rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
+ HOST_WIDE_INT bitpos)
{
- tree f, ftype;
- int i, tot;
+ unsigned int startbit, endbit;
+ int intregs, intoffset;
+ enum machine_mode mode;
- 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;
+ if (cum->intoffset == -1)
+ return;
- 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)
+ intoffset = cum->intoffset;
+ cum->intoffset = -1;
+
+ if (intoffset % BITS_PER_WORD != 0)
+ {
+ mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+ MODE_INT, 0);
+ if (mode == BLKmode)
{
- function_arg_advance (cum, TYPE_MODE (ftype), ftype,
- named, depth + 1);
+ /* We couldn't find an appropriate mode, which happens,
+ e.g., in packed structs when there are 3 bytes to load.
+ Back intoffset back to the beginning of the word in this
+ case. */
+ intoffset = intoffset & -BITS_PER_WORD;
}
- break;
-
- default:
- abort ();
}
+
+ startbit = intoffset & -BITS_PER_WORD;
+ endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+ intregs = (endbit - startbit) / BITS_PER_WORD;
+ cum->words += intregs;
+}
+
+/* The darwin64 ABI calls for us to recurse down through structs,
+ looking for elements passed in registers. Unfortunately, we have
+ to track int register count here also because of misalignments
+ in powerpc alignment mode. */
+
+static void
+rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
+ tree type,
+ HOST_WIDE_INT startbitpos)
+{
+ tree f;
+
+ for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ HOST_WIDE_INT bitpos = startbitpos;
+ tree ftype = TREE_TYPE (f);
+ enum machine_mode mode = TYPE_MODE (ftype);
+
+ if (DECL_SIZE (f) != 0
+ && host_integerp (bit_position (f), 1))
+ bitpos += int_bit_position (f);
+
+ /* ??? FIXME: else assume zero offset. */
+
+ if (TREE_CODE (ftype) == RECORD_TYPE)
+ 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);
+ cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+ 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);
+ cum->vregno++;
+ cum->words += 2;
+ }
+ else if (cum->intoffset == -1)
+ cum->intoffset = bitpos;
+ }
}
/* Update the data in CUM to advance over an argument
@@ -4105,6 +4166,8 @@ void
function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named, int depth)
{
+ int size;
+
/* Only tick off an argument if we're not recursing. */
if (depth == 0)
cum->nargs_prototype--;
@@ -4168,10 +4231,30 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
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);
-
+ && TREE_CODE (type) == RECORD_TYPE
+ && (size = int_size_in_bytes (type)) > 0)
+ {
+ /* Variable sized types have size == -1 and are
+ treated as if consisting entirely of ints.
+ Pad to 16 byte boundary if needed. */
+ if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
+ && (cum->words % 2) != 0)
+ cum->words++;
+ /* For varargs, we can just go up by the size of the struct. */
+ if (!named)
+ cum->words += (size + 7) / 8;
+ else
+ {
+ /* It is tempting to say int register count just goes up by
+ sizeof(type)/8, but this is wrong in a case such as
+ { int; double; int; } [powerpc alignment]. We have to
+ grovel through the fields for these too. */
+ cum->intoffset = 0;
+ rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
+ rs6000_darwin64_record_arg_advance_flush (cum,
+ size * BITS_PER_UNIT);
+ }
+ }
else if (DEFAULT_ABI == ABI_V4)
{
if (TARGET_HARD_FLOAT && TARGET_FPRS
@@ -4330,136 +4413,184 @@ 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. */
+/* A subroutine of rs6000_darwin64_record_arg. Assign the bits of the
+ structure between cum->intoffset and bitpos to integer registers. */
-static rtx
-rs6000_darwin64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type, int named)
+static void
+rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
+ HOST_WIDE_INT bitpos, rtx rvec[], int *k)
{
- 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;
+ enum machine_mode mode;
+ unsigned int regno;
+ unsigned int startbit, endbit;
+ int this_regno, intregs, intoffset;
+ rtx reg;
- switch (TREE_CODE (type))
+ if (cum->intoffset == -1)
+ return;
+
+ intoffset = cum->intoffset;
+ cum->intoffset = -1;
+
+ /* If this is the trailing part of a word, try to only load that
+ much into the register. Otherwise load the whole register. Note
+ that in the latter case we may pick up unwanted bits. It's not a
+ problem at the moment but may wish to revisit. */
+
+ if (intoffset % BITS_PER_WORD != 0)
{
- case RECORD_TYPE:
- for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
- if (TREE_CODE (f) == FIELD_DECL)
+ mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+ MODE_INT, 0);
+ if (mode == BLKmode)
+ {
+ /* We couldn't find an appropriate mode, which happens,
+ e.g., in packed structs when there are 3 bytes to load.
+ Back intoffset back to the beginning of the word in this
+ case. */
+ intoffset = intoffset & -BITS_PER_WORD;
+ mode = word_mode;
+ }
+ }
+ else
+ mode = word_mode;
+
+ startbit = intoffset & -BITS_PER_WORD;
+ endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+ intregs = (endbit - startbit) / BITS_PER_WORD;
+ this_regno = cum->words + intoffset / BITS_PER_WORD;
+
+ if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno)
+ cum->use_stack = 1;
+
+ intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno);
+ if (intregs <= 0)
+ return;
+
+ intoffset /= BITS_PER_UNIT;
+ do
+ {
+ regno = GP_ARG_MIN_REG + this_regno;
+ reg = gen_rtx_REG (mode, regno);
+ rvec[(*k)++] =
+ gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
+
+ this_regno += 1;
+ intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+ mode = word_mode;
+ intregs -= 1;
+ }
+ while (intregs > 0);
+}
+
+/* Recursive workhorse for the following. */
+
+static void
+rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
+ HOST_WIDE_INT startbitpos, rtx rvec[],
+ int *k)
+{
+ tree f;
+
+ for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ HOST_WIDE_INT bitpos = startbitpos;
+ tree ftype = TREE_TYPE (f);
+ enum machine_mode mode = TYPE_MODE (ftype);
+
+ if (DECL_SIZE (f) != 0
+ && host_integerp (bit_position (f), 1))
+ bitpos += int_bit_position (f);
+
+ /* ??? FIXME: else assume zero offset. */
+
+ if (TREE_CODE (ftype) == RECORD_TYPE)
+ rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
+ else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
{
- 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
+#if 0
+ switch (mode)
{
- roffset = gen_rtx_CONST_INT (SImode, bytepos);
- rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
+ case SCmode: mode = SFmode; break;
+ case DCmode: mode = DFmode; break;
+ case TCmode: mode = TFmode; break;
+ default: break;
}
- /* 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);
+#endif
+ rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
+ rvec[(*k)++]
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, cum->fregno++),
+ GEN_INT (bitpos / BITS_PER_UNIT));
+ if (mode == TFmode)
+ cum->fregno++;
}
- break;
+ else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
+ {
+ rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
+ rvec[(*k)++]
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, cum->vregno++),
+ GEN_INT (bitpos / BITS_PER_UNIT));
+ }
+ else if (cum->intoffset == -1)
+ cum->intoffset = bitpos;
+ }
+}
- case UNION_TYPE:
- tot = rs6000_arg_size (mode, type);
- if (tot <= 0)
- return NULL_RTX;
- bytepos = 0;
+/* 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. FP fields go in FP
+ register, vector fields go in vector registers, and everything
+ else goes in int registers, packed as in memory.
- for (j = 0; j < tot; ++j)
- {
- sub = gen_rtx_REG ((TARGET_64BIT ? DImode : SImode), GP_ARG_MIN_REG + cum->words++);
- roffset = gen_rtx_CONST_INT (SImode, bytepos);
- rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset);
- if (cum->words >= GP_ARG_NUM_REG)
- break;
- bytepos += (TARGET_64BIT ? 8 : 4);
- }
- break;
+ This code is also used for function return values. RETVAL indicates
+ whether this is the case.
- 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;
+ Much of this is taken from the Sparc V9 port, which has a similar
+ calling convention. */
- 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));
+static rtx
+rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
+ int named, bool retval)
+{
+ rtx rvec[FIRST_PSEUDO_REGISTER];
+ int k = 1, kbase = 1;
+ HOST_WIDE_INT typesize = int_size_in_bytes (type);
+ /* This is a copy; modifications are not visible to our caller. */
+ CUMULATIVE_ARGS copy_cum = *orig_cum;
+ CUMULATIVE_ARGS *cum = &copy_cum;
+
+ /* Pad to 16 byte boundary if needed. */
+ if (!retval && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
+ && (cum->words % 2) != 0)
+ cum->words++;
+
+ cum->intoffset = 0;
+ cum->use_stack = 0;
+ cum->named = named;
+
+ /* Put entries into rvec[] for individual FP and vector fields, and
+ for the chunks of memory that go in int regs. Note we start at
+ element 1; 0 is reserved for an indication of using memory, and
+ may or may not be filled in below. */
+ rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k);
+ rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k);
+
+ /* If any part of the struct went on the stack put all of it there.
+ This hack is because the generic code for
+ FUNCTION_ARG_PARTIAL_NREGS cannot handle cases where the register
+ parts of the struct are not at the beginning. */
+ if (cum->use_stack)
+ {
+ if (retval)
+ return NULL_RTX; /* doesn't go in registers at all */
+ kbase = 0;
+ rvec[0] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+ }
+ if (k > 1 || cum->use_stack)
+ return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k - kbase, &rvec[kbase]));
else
return NULL_RTX;
}
@@ -4523,7 +4654,8 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
This is null for libcalls where that information may
not be available.
CUM is a variable of type CUMULATIVE_ARGS which gives info about
- the preceding args and about the function being called.
+ the preceding args and about the function being called. It is
+ not modified in this routine.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
@@ -4571,13 +4703,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
return GEN_INT (cum->call_cookie);
}
- if (mode == BLKmode
- && rs6000_darwin64_abi
- && (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE
- || TREE_CODE (type) == ARRAY_TYPE))
+ if (rs6000_darwin64_abi && mode == BLKmode
+ && TREE_CODE (type) == RECORD_TYPE)
{
- rtx rslt = rs6000_darwin64_function_arg (cum, mode, type, named);
+ rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
if (rslt != NULL_RTX)
return rslt;
/* Else fall through to usual handling. */
@@ -4818,6 +4947,12 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
&& cum->nargs_prototype >= 0)
return 0;
+ /* In this complicated case we just disable the partial_nregs code. */
+ if (rs6000_darwin64_abi && mode == BLKmode
+ && TREE_CODE (type) == RECORD_TYPE
+ && int_size_in_bytes (type) > 0)
+ return 0;
+
align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
parm_offset = TARGET_32BIT ? 2 : 0;
align_words = cum->words + ((parm_offset - cum->words) & align);
@@ -17147,128 +17282,6 @@ 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;
@@ -17288,16 +17301,18 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
/* Special handling for structs in darwin64. */
if (rs6000_darwin64_abi
&& TYPE_MODE (valtype) == BLKmode
- && (TREE_CODE (valtype) == RECORD_TYPE
- || TREE_CODE (valtype) == ARRAY_TYPE))
+ && TREE_CODE (valtype) == RECORD_TYPE
+ && int_size_in_bytes (valtype) > 0)
{
CUMULATIVE_ARGS valcum;
rtx valret;
- valcum.sysv_gregno = GP_ARG_RETURN;
+ valcum.words = 0;
valcum.fregno = FP_ARG_MIN_REG;
valcum.vregno = ALTIVEC_ARG_MIN_REG;
- valret = rs6000_darwin64_function_value (&valcum, valtype);
+ /* Do a trial code generation as if this were going to be passed as
+ an argument; if any part goes in memory, we return NULL. */
+ valret = rs6000_darwin64_record_arg (&valcum, valtype, 1, true);
if (valret)
return valret;
/* Otherwise fall through to standard ABI rules. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 9b8f1fd..d9c2e8e 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1700,6 +1700,9 @@ typedef struct rs6000_args
int stdarg; /* Whether function is a stdarg function. */
int call_cookie; /* Do special things for this call */
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 named; /* false for varargs params */
} CUMULATIVE_ARGS;
/* Initialize a variable CUM of type CUMULATIVE_ARGS