From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3433 invoked by alias); 23 Apr 2002 19:55:14 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 3363 invoked from network); 23 Apr 2002 19:55:11 -0000 Received: from unknown (HELO cygnus.com) (205.180.83.203) by sources.redhat.com with SMTP; 23 Apr 2002 19:55:11 -0000 Received: from redhat.com (reddwarf.sfbay.redhat.com [172.16.24.50]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id MAA21465; Tue, 23 Apr 2002 12:55:10 -0700 (PDT) Message-ID: <3CC5B94F.CBE1ACCF@redhat.com> Date: Tue, 23 Apr 2002 12:55:00 -0000 From: Michael Snyder Organization: Red Hat, Inc. X-Accept-Language: en MIME-Version: 1.0 To: "David S. Miller" CC: gdb-patches@sources.redhat.com Subject: Re: [RFA] Fix sparc64 argument passing References: <20020420.024122.73287574.davem@redhat.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-04/txt/msg00875.txt.bz2 "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 > > 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;