This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFA] Fix sparc64 argument passing
- From: Michael Snyder <msnyder at redhat dot com>
- To: "David S. Miller" <davem at redhat dot com>
- Cc: gdb-patches at sources dot redhat dot com
- Date: Tue, 23 Apr 2002 12:43:11 -0700
- Subject: Re: [RFA] Fix sparc64 argument passing
- Organization: Red Hat, Inc.
- References: <20020420.024122.73287574.davem@redhat.com>
"David S. Miller" wrote:
>
> Instead of trying to fixup the code there, I reimplemented it using
> the Sparc GCC backend code for argument passing as a template.
>
> Advantages:
>
> 1) It works
>
> 2) Sparc32 support can be folded into it
>
> 3) Matching code means fixes in one can propagate (hopefully)
> to the other. :-)
>
> Regression update:
>
> sparc32 sparc64
> failures before 83 110
> failures after 83 105
If these test results apply on Solaris as well as Linux,
then you can check this in. Thanks.
>
> 2002-04-20 David S. Miller <davem@redhat.com>
>
> Fix sparc64 call dummy argument passing.
> * sparc-tdep.c: Include gdb_assert.h
> (sparc32_push_arguments): Allocate minimum of 6 arg slots so
> that varargs doesn't write all over the stack.
> (sparc_fix_call_dummy): Note that V9/ARCH64 do not have the
> unimp after call convention.
> (SPARC_INT_ARG_MAX, SPARC_FP_ARG_MAX, INTEGER_P): Define.
> (sp64_compute_arg_slotno, sp64_arg_advance,
> sp64_compute_arg_stack_space, sp64_struct_regs_analyze,
> sp64_do_struct_regs_3, sp64_do_struct_regs_2,
> sp64_push_one_struct_regs, sp64_push_one_arg): New functions.
> (sparc64_push_arguments): Reimplement from scratch.
> (sp64_extract_return_value): Handle TYPE_CODE_COMPLEX.
>
> --- sparc-tdep.c.~1~ Sat Apr 20 02:13:23 2002
> +++ sparc-tdep.c Sat Apr 20 02:22:28 2002
> @@ -32,6 +32,7 @@
> #include "value.h"
> #include "bfd.h"
> #include "gdb_string.h"
> +#include "gdb_assert.h"
> #include "regcache.h"
>
> #ifdef USE_PROC_FS
> @@ -2070,6 +2071,12 @@ sparc32_push_arguments (int nargs, struc
> m_arg->contents = VALUE_CONTENTS (arg);
> }
>
> + /* Make room for at least 6 integer arguments for the sake of
> + varargs. Otherwise a varargs function, once called via
> + a CALL_DUMMY, can write over other parts of the stack. */
> + if (accumulate_size < (6 * 4))
> + accumulate_size = (6 * 4);
> +
> /* Make room for the arguments on the stack. */
> accumulate_size += CALL_DUMMY_STACK_ADJUST;
> sp = ((sp - accumulate_size) & ~7) + CALL_DUMMY_STACK_ADJUST;
> @@ -2186,6 +2193,9 @@ sparc_fix_call_dummy (char *dummy, CORE_
> which follows the call instruction.
> For details see the SPARC Architecture Manual Version 8, Appendix D.3.
>
> + This does not happen on V9/ARCH64, such structure returns are passed
> + by reference.
> +
> Adjust the call_dummy_breakpoint_offset for the bp_call_dummy breakpoint
> to the proper address in the call dummy, so that `finish' after a stop
> in a call dummy works.
> @@ -2303,131 +2313,578 @@ sparc64_write_sp (CORE_ADDR val)
> write_register (SP_REGNUM, val);
> }
>
> -/* The SPARC 64 ABI passes floating-point arguments in FP0 to FP31,
> - and all other arguments in O0 to O5. They are also copied onto
> - the stack in the correct places. Apparently (empirically),
> - structs of less than 16 bytes are passed member-by-member in
> - separate registers, but I am unable to figure out the algorithm.
> - Some members go in floating point regs, but I don't know which.
> -
> - FIXME: Handle small structs (less than 16 bytes containing floats).
> -
> - The counting regimen for using both integer and FP registers
> - for argument passing is rather odd -- a single counter is used
> - for both; this means that if the arguments alternate between
> - int and float, we will waste every other register of both types. */
> +/* This is basically extracted from the Sparc backend of GCC.
> + All errors introduced along the way are mine. -DaveM */
> +
> +#define SPARC_INT_ARG_MAX 6
> +#define SPARC_FP_ARG_MAX 16
> +
> +#define INTEGER_P(TYPE) \
> + ((TYPE) == TYPE_CODE_INT || (TYPE) == TYPE_CODE_BOOL \
> + || (TYPE) == TYPE_CODE_CHAR || (TYPE) == TYPE_CODE_RANGE \
> + || (TYPE) == TYPE_CODE_ENUM || (TYPE) == TYPE_CODE_PTR \
> + || (TYPE) == TYPE_CODE_REF)
> +
> +static int
> +sp64_compute_arg_slotno (int words, int *ppadding, int *pregno,
> + struct value *val, enum type_code type, int len)
> + {
> + int regbase = O0_REGNUM;
> + int slotno = words;
> + int regno;
> +
> + *ppadding = 0;
> +
> + switch (type)
> + {
> + case TYPE_CODE_UNDEF:
> + case TYPE_CODE_ARRAY:
> + case TYPE_CODE_FUNC:
> + case TYPE_CODE_VOID:
> + case TYPE_CODE_ERROR:
> + case TYPE_CODE_MEMBER:
> + case TYPE_CODE_METHOD:
> + case TYPE_CODE_SET:
> + case TYPE_CODE_STRING:
> + case TYPE_CODE_BITSTRING:
> + case TYPE_CODE_TYPEDEF:
> + case TYPE_CODE_TEMPLATE:
> + case TYPE_CODE_TEMPLATE_ARG:
> + /* If we see any of these, just bail... */
> + error ("Type cannot be pushed into argument slot by GDB target code.\n");
> +
> + default:
> + break;
> + };
> +
> + if (INTEGER_P (type))
> + {
> + if (slotno >= SPARC_INT_ARG_MAX)
> + {
> + return -1;
> + }
> + regno = regbase + slotno;
> + }
> + else if (type == TYPE_CODE_FLT
> + || type == TYPE_CODE_COMPLEX)
> + {
> + if (len == 16)
> + {
> + /* TFmode value. */
> + gdb_assert(SPARC_TARGET_LONG_DOUBLE_BYTES == 16
> + || type == TYPE_CODE_COMPLEX);
> + if ((slotno & 1) != 0)
> + {
> + slotno++;
> + *ppadding = 1;
> + }
> + }
> + if (SPARC_HAS_FPU)
> + {
> + if (slotno >= SPARC_FP_ARG_MAX)
> + {
> + return -1;
> + }
> + regno = FP0_REGNUM + slotno * 2;
> + if (len == 4)
> + {
> + /* SFmode value. */
> + regno++;
> + }
> + }
> + else
> + {
> + /* Passed in integer registers, if possible. */
> + if (slotno >= SPARC_INT_ARG_MAX)
> + {
> + return -1;
> + }
> + regno = regbase + slotno;
> + }
> + }
> + else
> + {
> + /* A structure or a union. */
> +
> + /* ??? No way to get at required alignment of types.
> + ??? We are supposed to give 16byte alignment to types
> + ??? that require it (via attribute((align)) or similar)
> + ??? but GDB appears to have no way to get at that information
> + ??? currently. */
> +#if 0
> + if (TYPE_ALIGN (VALUE_TYPE (val)) == 128
> + && (slotno & 1) != 0)
> + {
> + slotno++;
> + *ppadding = 1;
> + }
> +#endif
> +
> + if (type == TYPE_CODE_UNION
> + || len > 16)
> + {
> + if (slotno >= SPARC_INT_ARG_MAX)
> + {
> + return -1;
> + }
> + regno = regbase + slotno;
> + }
> + else
> + {
> + struct type *tp = VALUE_TYPE (val);
> + int intregs_p = 0, fpregs_p = 0;
> + int packed_p = 0;
> + int field;
> +
> + gdb_assert (type == TYPE_CODE_STRUCT);
> +
> + for (field = 0; field < tp->nfields; field++)
> + {
> + struct field *fp = &tp->fields[field];
> +
> + if ((TYPE_CODE (fp->type) == TYPE_CODE_FLT
> + || TYPE_CODE (fp->type) == TYPE_CODE_COMPLEX)
> + && SPARC_HAS_FPU)
> + fpregs_p = 1;
> + else
> + intregs_p = 1;
> +
> + /* ??? No way to get at this currently... */
> +#if 0
> + if (TYPE_PACKED (fp->type))
> + packed_p = 1;
> +#endif
> + }
> +
> + if (packed_p)
> + {
> + fpregs_p = 0;
> + intregs_p = 1;
> + }
> +
> + if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
> + {
> + return -1;
> + }
> +
> + if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
> + {
> + return -1;
> + }
> +
> + return slotno;
> + }
> + }
> +
> + *pregno = regno;
> + return slotno;
> +}
> +
> +static void
> +sp64_arg_advance (int *p_arg_words, struct value *val)
> +{
> + enum type_code type = TYPE_CODE (VALUE_TYPE (val));
> + int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (val)));
> + int slotno, regno, padding;
> +
> + slotno = sp64_compute_arg_slotno (*p_arg_words, &padding, ®no,
> + val, type, len);
> +
> + if (slotno != -1)
> + *p_arg_words += padding;
> +
> + if (type == TYPE_CODE_UNION
> + || type == TYPE_CODE_STRUCT)
> + {
> + gdb_assert (len <= 16);
> +
> + if (len <= 8)
> + *p_arg_words += 1;
> + else if (len <= 16)
> + *p_arg_words += 2;
> + }
> +#if 0 /* ??? How to do this */
> + else if (type == TYPE_CODE_COMPLEX_INT)
> + {
> + *p_arg_words += 2;
> + }
> + else if (type == TYPE_CODE_COMPLEX_FLOAT)
> + {
> + *p_arg_words += len / SPARC_INTREG_SIZE;
> + }
> +#endif
> + else
> + {
> + *p_arg_words += ((len + (SPARC_INTREG_SIZE - 1))
> + / SPARC_INTREG_SIZE);
> + }
> +}
> +
> +static void
> +sp64_compute_arg_stack_space (int *p_arg_words,
> + int nargs, struct value **args, int struct_return)
> +{
> + int i;
> +
> + *p_arg_words = 0;
> +
> + /* This is true if USING_STRUCT_CONVENTION, in which case the function
> + is returning a structure larger than 32 bytes and causes the first
> + argument slot to be a pointer to the allocated space for it. */
> + if (struct_return)
> + *p_arg_words += 1;
> +
> + for (i = 0; i < nargs; i++)
> + {
> + struct value *val = args[i];
> +
> + sp64_arg_advance (p_arg_words, val);
> + }
> +}
> +
> +struct sp64_struct_regs_state
> +{
> + int slotno;
> + unsigned int nregs;
> + int intoffset;
> +};
> +
> +static void
> +sp64_struct_regs_analyze (struct type *tp,
> + struct sp64_struct_regs_state *statep)
> +{
> + int field;
> +
> + for (field = 0; field < tp->nfields; field++)
> + {
> + struct field *fp = &tp->fields[field];
> + int bitpos = fp->loc.bitpos;
> + int this_len = TYPE_LENGTH (check_typedef (fp->type));
> +
> + if (this_len == 0)
> + bitpos = 0;
> +
> + if (TYPE_CODE (fp->type) == TYPE_CODE_STRUCT)
> + sp64_struct_regs_analyze (fp->type, statep);
> + else if ((TYPE_CODE (fp->type) == TYPE_CODE_FLT
> + || TYPE_CODE (fp->type) == TYPE_CODE_COMPLEX)
> + && SPARC_HAS_FPU)
> + {
> + if (statep->intoffset != -1)
> + {
> + int intslots, this_slotno;
> + int bits_per_word = SPARC_INTREG_SIZE * 8;
> +
> + intslots = (bitpos - statep->intoffset + (bits_per_word - 1))
> + / bits_per_word;
> + this_slotno = statep->slotno
> + + (statep->intoffset / bits_per_word);
> +
> + if (SPARC_INT_ARG_MAX - this_slotno < intslots)
> + intslots = SPARC_INT_ARG_MAX - this_slotno;
> + if (intslots < 0)
> + intslots = 0;
> + statep->nregs += intslots;
> + statep->intoffset = -1;
> + }
> +
> + statep->nregs += 1;
> + if (TYPE_CODE (fp->type) == TYPE_CODE_COMPLEX)
> + statep->nregs += 1;
> + }
> + else
> + {
> + if (statep->intoffset == -1)
> + statep->intoffset = bitpos;
> + }
> + }
> +}
> +
> +static void
> +sp64_do_struct_regs_3 (struct value *val, int bitpos,
> + struct sp64_struct_regs_state *statep)
> +{
> + int regno, startbit, endbit, this_slotno, intslots, intoffset;
> + int bits_per_word = (SPARC_INTREG_SIZE * 8);
> + char *zero_buf;
> +
> + if (statep->intoffset == -1)
> + return;
> +
> + intoffset = statep->intoffset;
> + statep->intoffset = -1;
> +
> + startbit = intoffset & -bits_per_word;
> + endbit = (bitpos + (bits_per_word - 1)) & -bits_per_word;
> + intslots = (endbit - startbit) / bits_per_word;
> + this_slotno = statep->slotno + (intoffset / bits_per_word);
> +
> + if (SPARC_INT_ARG_MAX - this_slotno < intslots)
> + intslots = SPARC_INT_ARG_MAX - this_slotno;
> + if (intslots <= 0)
> + return;
> +
> + zero_buf = alloca(SPARC_INTREG_SIZE);
> + memset (zero_buf, 0, sizeof (zero_buf));
> +
> + intoffset /= 8;
> + do
> + {
> + regno = O0_REGNUM + this_slotno;
> +
> + if (intoffset % SPARC_INTREG_SIZE)
> + {
> + write_register_gen (regno, zero_buf);
> + write_register_bytes (REGISTER_BYTE (regno)
> + + (intoffset % SPARC_INTREG_SIZE),
> + VALUE_CONTENTS (val) + intoffset,
> + SPARC_INTREG_SIZE
> + - (intoffset % SPARC_INTREG_SIZE));
> + }
> + else
> + {
> + write_register_gen (regno, VALUE_CONTENTS (val) + intoffset);
> + }
> +
> + this_slotno += 1;
> + intoffset = (intoffset | (SPARC_INTREG_SIZE - 1)) + 1;
> + statep->nregs += 1;
> + intslots -= 1;
> + }
> + while (intslots > 0);
> +}
> +
> +static void
> +sp64_do_struct_regs_2 (struct value *val, struct type *tp,
> + struct sp64_struct_regs_state *statep)
> +{
> + int field;
> +
> + for (field = 0; field < tp->nfields; field++)
> + {
> + struct field *fp = &tp->fields[field];
> + int bitpos = fp->loc.bitpos;
> + int this_len = TYPE_LENGTH (check_typedef (fp->type));
> +
> + if (this_len == 0)
> + bitpos = 0;
> +
> + if (TYPE_CODE (fp->type) == TYPE_CODE_STRUCT)
> + sp64_do_struct_regs_2 (val, fp->type, statep);
> + else if ((TYPE_CODE (fp->type) == TYPE_CODE_FLT
> + || TYPE_CODE (fp->type) == TYPE_CODE_COMPLEX)
> + && SPARC_HAS_FPU)
> + {
> + int bits_per_word = SPARC_INTREG_SIZE * 8;
> + int this_slotno = statep->slotno + (bitpos / bits_per_word);
> + int this_typelen = TYPE_LENGTH (check_typedef (fp->type));
> + int regno;
> +
> + sp64_do_struct_regs_3 (val, bitpos, statep);
> + regno = FP0_REGNUM + this_slotno * 2
> + + (this_typelen == 4 && (bitpos & 32) != 0);
> +
> + write_register_bytes (REGISTER_BYTE (regno),
> + VALUE_CONTENTS (val) + (bitpos / 8),
> + this_typelen);
> + statep->nregs += 1;
> + if (TYPE_CODE (fp->type) == TYPE_CODE_COMPLEX)
> + statep->nregs += 1;
> + }
> + else
> + {
> + if (statep->intoffset == -1)
> + statep->intoffset = bitpos;
> + }
> + }
> +}
> +
> +static void
> +sp64_push_one_struct_regs (int slotno,
> + struct value *val, enum type_code type, int len)
> +{
> + struct sp64_struct_regs_state state;
> + int nregs;
> +
> + state.slotno = slotno;
> +
> + state.nregs = 0;
> + state.intoffset = 0;
> + sp64_struct_regs_analyze (VALUE_TYPE (val), &state);
> +
> + if (state.intoffset != -1)
> + {
> + unsigned int startbit, endbit;
> + int intslots, this_slotno;
> + int bits_per_word;
> +
> + bits_per_word = SPARC_INTREG_SIZE * 8;
> +
> + startbit = state.intoffset & -bits_per_word;
> + endbit = (len * 8 + (bits_per_word - 1)) & -bits_per_word;
> + intslots = (endbit - startbit) / bits_per_word;
> + this_slotno = slotno + state.intoffset / bits_per_word;
> +
> + if (SPARC_INT_ARG_MAX - this_slotno < intslots)
> + intslots = SPARC_INT_ARG_MAX - this_slotno;
> + if (intslots < 0)
> + intslots = 0;
> +
> + state.nregs += intslots;
> + }
> + nregs = state.nregs;
> +
> + if (nregs == 0)
> + {
> + /* Nothing can actually go in the registers, oh well... */
> + return;
> + }
> +
> + state.nregs = 0;
> + state.intoffset = 0;
> + sp64_do_struct_regs_2 (val, VALUE_TYPE (val), &state);
> + sp64_do_struct_regs_3 (val, len * 8, &state);
> + gdb_assert (state.nregs == nregs);
> +}
> +
> +static void
> +sp64_push_one_arg (CORE_ADDR *sp, CORE_ADDR args_base,
> + struct value *val, enum type_code type, int len)
> +{
> + int cur_word = (*sp - args_base) / SPARC_INTREG_SIZE;
> + int slotno, padding, regno, dummy;
> + int orig_cur_word;
> +
> + slotno = sp64_compute_arg_slotno (cur_word, &padding, ®no,
> + val, type, len);
> +
> + /* If integral, it may need promotion. */
> + if (INTEGER_P (type)
> + && len < SPARC_INTREG_SIZE)
> + {
> + struct type *sparc_intreg_type =
> + TYPE_LENGTH (builtin_type_long) == SPARC_INTREG_SIZE ?
> + builtin_type_long : builtin_type_long_long;
> +
> + val = value_cast (sparc_intreg_type, val);
> + len = SPARC_INTREG_SIZE;
> + }
> +
> + if (slotno == -1)
> + {
> + /* Purely in memory on the stack */
> + write_memory (*sp, VALUE_CONTENTS (val), len);
> + goto advance;
> + }
> +
> + if ((type == TYPE_CODE_FLT
> + || type == TYPE_CODE_COMPLEX)
> + && (regno >= FP0_REGNUM && regno < FP_MAX_REGNUM))
> + {
> + /* We copy the value onto the stack always even though
> + in some cases the v9 ABI allows that to be optimized
> + away. */
> + write_memory (*sp, VALUE_CONTENTS (val), len);
> + write_register_bytes (REGISTER_BYTE (regno),
> + VALUE_CONTENTS (val),
> + len);
> +
> + /* If this is one of the first 6 argument slots, we also copy
> + to the integer register of the same slot to handle varargs
> + properly. */
> + if ((regno - FP0_REGNUM) < SPARC_INT_ARG_MAX * 2)
> + {
> + int intreg = O0_REGNUM + (regno - FP0_REGNUM) / 2;
> +
> + write_register_bytes (REGISTER_BYTE (intreg),
> + VALUE_CONTENTS (val),
> + len);
> + }
> + }
> + else if (type == TYPE_CODE_STRUCT
> + || type == TYPE_CODE_UNION)
> + {
> + /* Pass by reference of large structs is handled entirely in
> + valops.c via REG_STRUCT_HAS_ADDR. */
> + gdb_assert (len <= 16);
> +
> + /* On the stack, but partially in registers too. */
> + write_memory (*sp, VALUE_CONTENTS (val), len);
> + if (type == TYPE_CODE_UNION)
> + {
> + /* Simplest case. */
> + write_register_bytes (REGISTER_BYTE (regno),
> + VALUE_CONTENTS (val),
> + len);
> + }
> + else
> + {
> + /* Complex case :( */
> + sp64_push_one_struct_regs (slotno, val, type, len);
> + }
> + }
> + else
> + {
> + struct value *copyval = val;
> + int copylen = len;
> +
> + write_memory (*sp, VALUE_CONTENTS (val), len);
> + write_register_bytes (REGISTER_BYTE (regno),
> + VALUE_CONTENTS (val),
> + len);
> + }
> +
> + advance:
> + orig_cur_word = cur_word;
> + sp64_arg_advance (&cur_word, val);
> + *sp += ((cur_word - orig_cur_word) * SPARC_INTREG_SIZE);
> +}
>
> CORE_ADDR
> sparc64_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
> int struct_return, CORE_ADDR struct_retaddr)
> {
> - int i, j, register_counter = 0;
> - CORE_ADDR tempsp;
> + int i, j;
> + CORE_ADDR tempsp, struct_buf_sp;
> struct type *sparc_intreg_type =
> TYPE_LENGTH (builtin_type_long) == SPARC_INTREG_SIZE ?
> builtin_type_long : builtin_type_long_long;
> + int arg_words;
>
> sp = (sp & ~(((unsigned long) SPARC_INTREG_SIZE) - 1UL));
>
> /* Figure out how much space we'll need. */
> - for (i = nargs - 1; i >= 0; i--)
> - {
> - int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (args[i])));
> - struct value *copyarg = args[i];
> - int copylen = len;
> + sp64_compute_arg_stack_space(&arg_words, nargs, args, struct_return);
>
> - if (copylen < SPARC_INTREG_SIZE)
> - {
> - copyarg = value_cast (sparc_intreg_type, copyarg);
> - copylen = SPARC_INTREG_SIZE;
> - }
> - sp -= copylen;
> - }
> + /* Make room for at least 6 integer arguments for the sake of
> + varargs. Otherwise a varargs function, once called via
> + a CALL_DUMMY, can write over other parts of the stack. */
> + if (arg_words < 6)
> + arg_words = 6;
>
> - /* Round down. */
> - sp = sp & ~7;
> + sp -= arg_words * SPARC_INTREG_SIZE;
> tempsp = sp;
>
> /* if STRUCT_RETURN, then first argument is the struct return location. */
> if (struct_return)
> - write_register (O0_REGNUM + register_counter++, struct_retaddr);
> + {
> + write_register (O0_REGNUM, struct_retaddr);
> + write_memory (tempsp, (char *) &struct_retaddr, SPARC_INTREG_SIZE);
>
> - /* Now write the arguments onto the stack, while writing FP
> - arguments into the FP registers, and other arguments into the
> - first six 'O' registers. */
> + tempsp += SPARC_INTREG_SIZE;
> + }
>
> + /* now actually push the arguments */
> for (i = 0; i < nargs; i++)
> {
> - int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (args[i])));
> - struct value *copyarg = args[i];
> - enum type_code typecode = TYPE_CODE (VALUE_TYPE (args[i]));
> - int copylen = len;
> -
> - if (typecode == TYPE_CODE_INT ||
> - typecode == TYPE_CODE_BOOL ||
> - typecode == TYPE_CODE_CHAR ||
> - typecode == TYPE_CODE_RANGE ||
> - typecode == TYPE_CODE_ENUM)
> - if (len < SPARC_INTREG_SIZE)
> - {
> - /* Small ints will all take up the size of one intreg on
> - the stack. */
> - copyarg = value_cast (sparc_intreg_type, copyarg);
> - copylen = SPARC_INTREG_SIZE;
> - }
> -
> - write_memory (tempsp, VALUE_CONTENTS (copyarg), copylen);
> - tempsp += copylen;
> -
> - /* Corner case: Structs consisting of a single float member are floats.
> - * FIXME! I don't know about structs containing multiple floats!
> - * Structs containing mixed floats and ints are even more weird.
> - */
> -
> + struct value *val = args[i];
> + enum type_code type = TYPE_CODE (VALUE_TYPE (val));
> + int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (val)));
>
> -
> - /* Separate float args from all other args. */
> - if (typecode == TYPE_CODE_FLT && SPARC_HAS_FPU)
> - {
> - if (register_counter < 16)
> - {
> - /* This arg gets copied into a FP register. */
> - int fpreg;
> -
> - switch (len) {
> - case 4: /* Single-precision (float) */
> - fpreg = FP0_REGNUM + 2 * register_counter + 1;
> - register_counter += 1;
> - break;
> - case 8: /* Double-precision (double) */
> - fpreg = FP0_REGNUM + 2 * register_counter;
> - register_counter += 1;
> - break;
> - case 16: /* Quad-precision (long double) */
> - fpreg = FP0_REGNUM + 2 * register_counter;
> - register_counter += 2;
> - break;
> - default:
> - internal_error (__FILE__, __LINE__, "bad switch");
> - }
> - write_register_bytes (REGISTER_BYTE (fpreg),
> - VALUE_CONTENTS (args[i]),
> - len);
> - }
> - }
> - else /* all other args go into the first six 'o' registers */
> - {
> - for (j = 0;
> - j < len && register_counter < 6;
> - j += SPARC_INTREG_SIZE)
> - {
> - int oreg = O0_REGNUM + register_counter;
> -
> - write_register_gen (oreg, VALUE_CONTENTS (copyarg) + j);
> - register_counter += 1;
> - }
> - }
> + sp64_push_one_arg (&tempsp, sp,
> + val, type, len);
> }
> +
> return sp;
> }
>
> @@ -2441,7 +2898,9 @@ sp64_extract_return_value (struct type *
> int typelen = TYPE_LENGTH (type);
> int regsize = REGISTER_RAW_SIZE (O0_REGNUM);
>
> - if (TYPE_CODE (type) == TYPE_CODE_FLT && SPARC_HAS_FPU)
> + if ((TYPE_CODE (type) == TYPE_CODE_FLT
> + || TYPE_CODE (type) == TYPE_CODE_COMPLEX)
> + && SPARC_HAS_FPU)
> {
> memcpy (valbuf, ®buf[REGISTER_BYTE (FP0_REGNUM)], typelen);
> return;