This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB 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]

[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, &regno,
+				    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, &regno,
+				    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, &regbuf[REGISTER_BYTE (FP0_REGNUM)], typelen);
       return;


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