This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[RFA] Fix sparc64 argument passing
- From: "David S. Miller" <davem at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Sat, 20 Apr 2002 02:41:22 -0700 (PDT)
- Subject: [RFA] Fix sparc64 argument passing
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
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;