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
This commit is contained in:
Dale Johannesen 2005-03-01 02:56:35 +00:00 committed by Stan Shebs
parent 1a9dddada3
commit 0b5383eba0
3 changed files with 336 additions and 298 deletions

View file

@ -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

View file

@ -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))
if (cum->intoffset == -1)
return;
intoffset = cum->intoffset;
cum->intoffset = -1;
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)
{
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)
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,
}
}
/* A subroutine of rs6000_darwin64_record_arg. Assign the bits of the
structure between cum->intoffset and bitpos to integer registers. */
static void
rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
HOST_WIDE_INT bitpos, rtx rvec[], int *k)
{
enum machine_mode mode;
unsigned int regno;
unsigned int startbit, endbit;
int this_regno, intregs, intoffset;
rtx reg;
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)
{
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))
{
#if 0
switch (mode)
{
case SCmode: mode = SFmode; break;
case DCmode: mode = DFmode; break;
case TCmode: mode = TFmode; break;
default: break;
}
#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++;
}
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;
}
}
/* 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. */
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.
This code is also used for function return values. RETVAL indicates
whether this is the case.
Much of this is taken from the Sparc V9 port, which has a similar
calling convention. */
static rtx
rs6000_darwin64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
tree type, int named)
rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
int named, bool retval)
{
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;
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;
switch (TREE_CODE (type))
/* 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)
{
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 UNION_TYPE:
tot = rs6000_arg_size (mode, type);
if (tot <= 0)
return NULL_RTX;
bytepos = 0;
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;
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));
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. */

View file

@ -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