This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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 = &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;
}
*************** 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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]