This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Better structure handling for 64-bit Darwin
- From: Stan Shebs <shebs at apple dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 28 Feb 2005 19:34:05 -0800
- Subject: Better structure handling for 64-bit Darwin
This is Dale Johannesen's rewrite of my original feeble attempt at
passing and returning structures by value in 64-bit Darwin, plus
a bit of my own cosmetic tinkering. It cuts the number of testsuite
failures with -m64 from 200 down to 100. Testsuite shows no additional
failures with 32-bit, and a cross-build for powerpc-eabi went OK too.
The patch should be a no-op for non-Darwin targets, and I'm going to
add it to the 4.0 branch as well, once that testing finishes.
Stan
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.
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.789
diff -p -r1.789 rs6000.c
*** config/rs6000/rs6000.c 28 Feb 2005 19:07:29 -0000 1.789
--- config/rs6000/rs6000.c 1 Mar 2005 01:34:52 -0000
*************** static int rs6000_get_some_local_dynamic
*** 737,744 ****
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 *,
--- 737,753 ----
static rtx rs6000_complex_function_value (enum machine_mode);
static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
enum machine_mode, tree);
! 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 *,
*************** rs6000_return_in_memory (tree type, tree
*** 3833,3844 ****
{
/* 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
--- 3842,3864 ----
{
/* In the darwin64 abi, try to use registers for larger structs
if possible. */
! if (rs6000_darwin64_abi
&& TREE_CODE (type) == RECORD_TYPE
! && 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
*************** function_arg_boundary (enum machine_mode
*** 4029,4034 ****
--- 4049,4057 ----
|| (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;
}
*************** rs6000_arg_size (enum machine_mode mode,
*** 4051,4096 ****
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
--- 4074,4157 ----
return (size + 7) >> 3;
}
! /* Use this to flush pending int fields. */
static void
! rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
! HOST_WIDE_INT bitpos)
{
! unsigned int startbit, endbit;
! int intregs, intoffset;
! enum machine_mode mode;
! if (cum->intoffset == -1)
! return;
! 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)
{
! /* 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;
}
}
+
+ 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
*************** void
*** 4105,4110 ****
--- 4166,4173 ----
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--;
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 4168,4177 ****
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
--- 4231,4260 ----
else if (rs6000_darwin64_abi
&& mode == BLKmode
! && 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
*************** rs6000_spe_function_arg (CUMULATIVE_ARGS
*** 4330,4465 ****
}
}
! /* 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 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));
else
return NULL_RTX;
}
--- 4413,4596 ----
}
}
! /* 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. 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_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 = ©_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;
}
*************** rs6000_mixed_function_arg (enum machine_
*** 4523,4529 ****
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.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
--- 4654,4661 ----
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. 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).
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 4571,4583 ****
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))
{
! rtx rslt = rs6000_darwin64_function_arg (cum, mode, type, named);
if (rslt != NULL_RTX)
return rslt;
/* Else fall through to usual handling. */
--- 4703,4712 ----
return GEN_INT (cum->call_cookie);
}
! if (rs6000_darwin64_abi && mode == BLKmode
! && TREE_CODE (type) == RECORD_TYPE)
{
! rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
if (rslt != NULL_RTX)
return rslt;
/* Else fall through to usual handling. */
*************** rs6000_arg_partial_bytes (CUMULATIVE_ARG
*** 4818,4823 ****
--- 4947,4958 ----
&& 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);
*************** rs6000_complex_function_value (enum mach
*** 17147,17274 ****
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;
--- 17282,17287 ----
*************** rs6000_function_value (tree valtype, tre
*** 17288,17303 ****
/* 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. */
--- 17301,17318 ----
/* Special handling for structs in darwin64. */
if (rs6000_darwin64_abi
&& TYPE_MODE (valtype) == BLKmode
! && TREE_CODE (valtype) == RECORD_TYPE
! && int_size_in_bytes (valtype) > 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, valtype, 1, true);
if (valret)
return valret;
/* Otherwise fall through to standard ABI rules. */
Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.355
diff -p -r1.355 rs6000.h
*** config/rs6000/rs6000.h 28 Feb 2005 19:07:34 -0000 1.355
--- config/rs6000/rs6000.h 1 Mar 2005 01:34:54 -0000
*************** typedef struct rs6000_args
*** 1700,1705 ****
--- 1700,1708 ----
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