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:
parent
1a9dddada3
commit
0b5383eba0
3 changed files with 336 additions and 298 deletions
|
@ -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
|
||||
|
|
|
@ -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 = ©_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. */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue