Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [rfa:ppc] Cleanup SVR4 push dummy call
@ 2003-09-12 14:47 Andrew Cagney
  2003-09-12 15:02 ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2003-09-12 14:47 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 474 bytes --]

Hello,

This patch rewrites ppc_svr4_push_dummy_call so that it implements the 
two-pass push-arguments algorithm using a "for" loop.

The simplification identified and fixed the bugs:

- Altivec registers on the stack weren't being 16 byte aligned
- Floats weren't being converted to doubles before being stored in 
register/memory ("gdb.base/callfuncs.exp: p t_float_values2" now passes).

Ok?

Andrew

PS: I intend moving align_{up,down} to utils.c but that is separate.

[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 17363 bytes --]

2003-09-12  Andrew Cagney  <cagney@redhat.com>

	* ppc-sysv-tdep.c (round_up): Replace "round2" macro.
	(ppc_sysv_abi_push_dummy_call): Rewrite, use a two pass loop.

Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.9
diff -u -r1.9 ppc-sysv-tdep.c
--- ppc-sysv-tdep.c	11 Sep 2003 19:27:25 -0000	1.9
+++ ppc-sysv-tdep.c	12 Sep 2003 14:28:44 -0000
@@ -29,11 +29,20 @@
 
 #include "ppc-tdep.h"
 
-/* round2 rounds x up to the nearest multiple of s assuming that s is a
-   power of 2 */
+/* Ensure that X is aligned to an S byte boundary (assuming that S is
+   a power of 2) rounding up/down where necessary.  */
 
-#undef round2
-#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
+static ULONGEST
+align_up (ULONGEST x, int s)
+{
+  return (x + s - 1) & -s;
+}
+
+static ULONGEST
+align_down (ULONGEST x, int s)
+{
+  return (x & -s);
+}
 
 /* Pass the arguments in either registers, or in the stack. Using the
    ppc sysv ABI, the first eight words of the argument list (that might
@@ -52,298 +61,270 @@
 			      int nargs, struct value **args, CORE_ADDR sp,
 			      int struct_return, CORE_ADDR struct_addr)
 {
-  int argno;
-  /* Next available general register for non-float, non-vector arguments. */
-  int greg;
-  /* Next available floating point register for float arguments. */
-  int freg;
-  /* Next available vector register for vector arguments. */
-  int vreg;
-  int argstkspace;
-  int structstkspace;
-  int argoffset;
-  int structoffset;
-  struct type *type;
-  int len;
-  char old_sp_buf[4];
-  CORE_ADDR saved_sp;
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  const CORE_ADDR saved_sp = read_sp ();
+  int argspace = 0;		/* 0 is an initial wrong guess.  */
+  int write_pass;
+
+  /* Go through the argument list twice.
+
+     Pass 1: Figure out how much new stack space is required for
+     arguments and pushed values.  Unlike the PowerOpen ABI, the SysV
+     ABI doesn't reserve any extra space for parameters which are put
+     in registers, but does always push structures and then pass their
+     address.
 
-  greg = 3;
-  freg = 1;
-  vreg = 2;
-  argstkspace = 0;
-  structstkspace = 0;
-
-  /* If the function is returning a `struct', then the first word
-     (which will be passed in r3) is used for struct return address.
-     In that case we should advance one word and start from r4
-     register to copy parameters.  */
-  if (struct_return)
-    {
-      regcache_raw_write_signed (regcache, tdep->ppc_gp0_regnum + greg,
-				 struct_addr);
-      greg++;
-    }
+     Pass 2: Replay the same computation but this time also write the
+     values out to the target.  */
 
-  /* Figure out how much new stack space is required for arguments
-     which don't fit in registers.  Unlike the PowerOpen ABI, the
-     SysV ABI doesn't reserve any extra space for parameters which
-     are put in registers. */
-  for (argno = 0; argno < nargs; argno++)
+  for (write_pass = 0; write_pass < 2; write_pass++)
     {
-      struct value *arg = args[argno];
-      type = check_typedef (VALUE_TYPE (arg));
-      len = TYPE_LENGTH (type);
-
-      if (TYPE_CODE (type) == TYPE_CODE_FLT
-          && ppc_floating_point_unit_p (current_gdbarch))
+      int argno;
+      /* Next available floating point register for float and double
+         arguments.  */
+      int freg = 1;
+      /* Next available general register for non-float, non-vector
+         arguments.  */
+      int greg = 3;
+      /* Next available vector register for vector arguments.  */
+      int vreg = 2;
+      /* Arguments start above the "LR save word" and "Back chain".  */
+      int argoffset = 2 * tdep->wordsize;
+      /* Structures start after the arguments.  */
+      int structoffset = argoffset + argspace;
+
+      /* If the function is returning a `struct', then the first word
+	 (which will be passed in r3) is used for struct return
+	 address.  In that case we should advance one word and start
+	 from r4 register to copy parameters.  */
+      if (struct_return)
 	{
-	  if (freg <= 8)
-	    freg++;
-	  else
-	    {
-	      /* SysV ABI converts floats to doubles when placed in
-	         memory and requires 8 byte alignment */
-	      if (argstkspace & 0x4)
-		argstkspace += 4;
-	      argstkspace += 8;
-	    }
+	  if (write_pass)
+	    regcache_cooked_write_signed (regcache,
+					  tdep->ppc_gp0_regnum + greg,
+					  struct_addr);
+	  greg++;
 	}
-      else if (len == 8 
-               && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
-                   || (!ppc_floating_point_unit_p (current_gdbarch)
-                       && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
+
+      for (argno = 0; argno < nargs; argno++)
 	{
-	  if (greg > 9)
-	    {
-	      greg = 11;
-	      if (argstkspace & 0x4)
-		argstkspace += 4;
-	      argstkspace += 8;
-	    }
-	  else
-	    {
-	      if ((greg & 1) == 0)
-		greg++;
-	      greg += 2;
-	    }
-	}
-      else if (!TYPE_VECTOR (type))
-        {
-	  if (len > 4
-	      || TYPE_CODE (type) == TYPE_CODE_STRUCT
-	      || TYPE_CODE (type) == TYPE_CODE_UNION)
-	    {
-	      /* Rounding to the nearest multiple of 8 may not be necessary,
-		 but it is safe.  Particularly since we don't know the
-		 field types of the structure */
-	      structstkspace += round2 (len, 8);
-	    }
-	  if (greg <= 10)
-	    greg++;
-	  else
-	    argstkspace += 4;
-    	}
-      else
-        {
-          if (len == 16
-	      && TYPE_CODE (type) == TYPE_CODE_ARRAY
-	      && TYPE_VECTOR (type))
-	    {
-	      if (vreg <= 13)
-		vreg++;
+	  struct value *arg = args[argno];
+	  struct type *type = check_typedef (VALUE_TYPE (arg));
+	  int len = TYPE_LENGTH (type);
+	  char *val = VALUE_CONTENTS (arg);
+
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT
+	      && ppc_floating_point_unit_p (current_gdbarch)
+	      && len <= 8)
+	    {
+	      /* Floating point value converted to "double" then
+                 passed in an FP register, when the registers run out,
+                 8 byte aligned stack is used.  */
+	      if (freg <= 8)
+		{
+		  if (write_pass)
+		    {
+		      /* Always store the floating point value using
+                         the register's floating-point format.  */
+		      char regval[MAX_REGISTER_SIZE];
+		      struct type *regtype
+			= register_type (gdbarch, FP0_REGNUM + freg);
+		      convert_typed_floating (val, type, regval, regtype);
+		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
+					     regval);
+		    }
+		  freg++;
+		}
 	      else
 		{
-		  /* Vector arguments must be aligned to 16 bytes on
-                     the stack. */
-		  argstkspace += round2 (argstkspace, 16);
-		  argstkspace += 16;
+		  /* SysV ABI converts floats to doubles before
+                     writing them to an 8 byte aligned stack location.  */
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    {
+		      char memval[8];
+		      struct type *memtype;
+		      switch (TARGET_BYTE_ORDER)
+			{
+			case BFD_ENDIAN_BIG:
+			  memtype = builtin_type_ieee_double_big;
+			  break;
+			case BFD_ENDIAN_LITTLE:
+			  memtype = builtin_type_ieee_double_little;
+			  break;
+			default:
+			  internal_error (__FILE__, __LINE__, "bad switch");
+			}
+		      convert_typed_floating (val, type, memval, memtype);
+		      write_memory (sp + argoffset, val, len);
+		    }
+		  argoffset += 8;
 		}
 	    }
-          else if (len == 8 
-                   && TYPE_CODE (type) == TYPE_CODE_ARRAY
-                   && TYPE_VECTOR (type))
-            {
-              if (greg <= 10)
-                greg++;
-              else
-                {
-                  /* Vector arguments must be aligned to 8 bytes on
-                     the stack. */
-                  argstkspace += round2 (argstkspace, 8);
-                  argstkspace += 8;
-                }
-            }
-	}
-    }
-
-  /* Get current SP location */
-  saved_sp = read_sp ();
-
-  sp -= argstkspace + structstkspace;
-
-  /* Allocate space for backchain and callee's saved lr */
-  sp -= 8;
-
-  /* Make sure that we maintain 16 byte alignment */
-  sp &= ~0x0f;
-
-  /* Update %sp before proceeding any further.   */
-  regcache_raw_write_signed (regcache, SP_REGNUM, sp);
-
-  /* write the backchain */
-  store_unsigned_integer (old_sp_buf, 4, saved_sp);
-  write_memory (sp, old_sp_buf, 4);
-
-  argoffset = 8;
-  structoffset = argoffset + argstkspace;
-  freg = 1;
-  greg = 3;
-  vreg = 2;
-
-  /* Fill in r3 with the return structure, if any */
-  if (struct_return)
-    {
-      write_register (tdep->ppc_gp0_regnum + greg, struct_addr);
-      greg++;
-    }
-
-  /* Now fill in the registers and stack... */
-  for (argno = 0; argno < nargs; argno++)
-    {
-      struct value *arg = args[argno];
-      char *val = VALUE_CONTENTS (arg);
-      type = check_typedef (VALUE_TYPE (arg));
-      len = TYPE_LENGTH (type);
-
-      if (TYPE_CODE (type) == TYPE_CODE_FLT
-          && ppc_floating_point_unit_p (current_gdbarch))
-	{
-	  if (freg <= 8)
-	    {
-	      ULONGEST regval;
-	      if (len > 8)
-		printf_unfiltered (
-				   "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
-              regval = extract_unsigned_integer (val, len);
-              write_register (FP0_REGNUM + freg, regval);
-	      freg++;
-	    }
-	  else
-	    {
-	      /* SysV ABI converts floats to doubles when placed in
-	         memory and requires 8 byte alignment */
-	      /* FIXME: Convert floats to doubles */
-	      if (argoffset & 0x4)
-		argoffset += 4;
-	      write_memory (sp + argoffset, val, len);
-	      argoffset += 8;
-	    }
-	}
-      else if (len == 8 
-               && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
-                   || (!ppc_floating_point_unit_p (current_gdbarch)
-                        && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
-	{
-	  if (greg > 9)
-	    {
-	      greg = 11;
-	      if (argoffset & 0x4)
-		argoffset += 4;
-	      write_memory (sp + argoffset, val, len);
-	      argoffset += 8;
-	    }
-	  else
-	    {
-	      ULONGEST regval;
-	      if ((greg & 1) == 0)
-		greg++;
-              regval = extract_unsigned_integer (val, 4);
-              write_register (tdep->ppc_gp0_regnum + greg, regval);
-              regval = extract_unsigned_integer (val + 4, 4);
-              write_register (tdep->ppc_gp0_regnum + greg + 1, regval);
-	      greg += 2;
-	    }
-	}
-      else if (!TYPE_VECTOR (type))
-	{
-	  char val_buf[4];
-	  if (len > 4
-	      || TYPE_CODE (type) == TYPE_CODE_STRUCT
-	      || TYPE_CODE (type) == TYPE_CODE_UNION)
-	    {
-	      write_memory (sp + structoffset, val, len);
-	      store_unsigned_integer (val_buf, 4, sp + structoffset);
-	      structoffset += round2 (len, 8);
-	    }
-	  else
-	    {
-	      memset (val_buf, 0, 4);
-	      memcpy (val_buf, val, len);
-	    }
-	  if (greg <= 10)
-	    {
-              ULONGEST regval = extract_unsigned_integer (val_buf, 4);
-              write_register (tdep->ppc_gp0_regnum + greg, regval);
-	      greg++;
-	    }
-	  else
-	    {
-	      write_memory (sp + argoffset, val_buf, 4);
-	      argoffset += 4;
+	  else if (len == 8 
+		   && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
+		       || (!ppc_floating_point_unit_p (current_gdbarch)
+			   && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
+	    {
+	      /* "long long" or "double" passed in an odd/even
+                 register pair with the low addressed word in the odd
+                 register and the high addressed word in the even
+                 register, or when the registers run out an 8 byte
+                 aligned stack location.  */
+	      if (greg > 9)
+		{
+		  /* Just in case GREG was 10.  */
+		  greg = 11;
+		  argoffset = align_up (argoffset, 8);
+		  write_memory (sp + argoffset, val, len);
+		  argoffset += 8;
+		}
+	      else if (tdep->wordsize == 8)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_gp0_regnum + greg,
+					   val);
+		  greg += 1;
+		}
+	      else
+		{
+		  /* Must start on an odd register - r3/r4 etc.  */
+		  if ((greg & 1) == 0)
+		    greg++;
+		  if (write_pass)
+		    {
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 0,
+					     val + 0);
+		      regcache_cooked_write (regcache,
+					     tdep->ppc_gp0_regnum + greg + 1,
+					     val + 4);
+		    }
+		  greg += 2;
+		}
 	    }
-	}
-      else
-	{
-	  if (len == 16
-	      && TYPE_CODE (type) == TYPE_CODE_ARRAY
-	      && TYPE_VECTOR (type))
+	  else if (len == 16
+		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
+		   && TYPE_VECTOR (type)
+		   && tdep->ppc_vr0_regnum >= 0)
 	    {
-	      char *v_val_buf = alloca (16);
-	      memset (v_val_buf, 0, 16);
-	      memcpy (v_val_buf, val, len);
+	      /* Vector parameter passed in an Altivec register, or
+                 when that runs out, 16 byte aligned stack location.  */
 	      if (vreg <= 13)
 		{
-		  regcache_cooked_write (current_regcache,
-					 tdep->ppc_vr0_regnum + vreg,
-					 v_val_buf);
+		  if (write_pass)
+		    regcache_cooked_write (current_regcache,
+					   tdep->ppc_vr0_regnum + vreg,
+					   val);
 		  vreg++;
 		}
 	      else
 		{
-		  write_memory (sp + argoffset, v_val_buf, 16);
+		  argoffset = align_up (argoffset, 16);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, 16);
 		  argoffset += 16;
 		}
 	    }
           else if (len == 8 
 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
-		   && TYPE_VECTOR (type))
+		   && TYPE_VECTOR (type)
+		   && tdep->ppc_ev0_regnum >= 0)
             {
-              char *v_val_buf = alloca (8);
-              memset (v_val_buf, 0, 8);
-              memcpy (v_val_buf, val, len);
+	      /* Vector parameter passed in an e500 register, or when
+                 that runs out, 8 byte aligned stack location.  Note
+                 that since e500 vector and general purpose registers
+                 both map onto the same underlying register set, a
+                 "greg" and not a "vreg" is consumed here.  A cooked
+                 write stores the value in the correct locations
+                 within the raw register cache.  */
               if (greg <= 10)
                 {
-		  regcache_cooked_write (current_regcache,
-					 tdep->ppc_ev0_regnum + greg,
-					 v_val_buf);
+		  if (write_pass)
+		    regcache_cooked_write (current_regcache,
+					   tdep->ppc_ev0_regnum + greg,
+					   val);
                   greg++;
                 }
               else
                 {
-                  write_memory (sp + argoffset, v_val_buf, 8);
+		  argoffset = align_up (argoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + argoffset, val, 8);
                   argoffset += 8;
                 }
             }
-        }
+	  else
+	    {
+	      /* Reduce the parameter down to something that fits in a
+                 "word".  */
+	      char word[MAX_REGISTER_SIZE];
+	      memset (word, 0, MAX_REGISTER_SIZE);
+	      if (len > tdep->wordsize
+		  || TYPE_CODE (type) == TYPE_CODE_STRUCT
+		  || TYPE_CODE (type) == TYPE_CODE_UNION)
+		{
+		  /* Structs and large values are put on an 8 byte
+                     aligned stack ... */
+		  structoffset = align_up (structoffset, 8);
+		  if (write_pass)
+		    write_memory (sp + structoffset, val, len);
+		  /* ... and then a "word" pointing to that address is
+                     passed as the parameter.  */
+		  store_unsigned_integer (word, tdep->wordsize,
+					  sp + structoffset);
+		  structoffset += len;
+		}
+	      else if (TYPE_CODE (type) == TYPE_CODE_INT)
+		/* Sign or zero extend the "int" into a "word".  */
+		store_unsigned_integer (word, tdep->wordsize,
+					unpack_long (type, val));
+	      else
+		/* Always goes in the low address.  */
+		memcpy (word, val, len);
+	      /* Store that "word" in a register, or on the stack.
+                 The words have "4" byte alignment.  */
+	      if (greg <= 10)
+		{
+		  if (write_pass)
+		    regcache_cooked_write (regcache,
+					   tdep->ppc_gp0_regnum + greg,
+					   word);
+		  greg++;
+		}
+	      else
+		{
+		  argoffset = align_up (argoffset, tdep->wordsize);
+		  if (write_pass)
+		    write_memory (sp + argoffset, word, tdep->wordsize);
+		  argoffset += tdep->wordsize;
+		}
+	    }
+	}
+
+      /* Compute the actual stack space requirements.  */
+      if (!write_pass)
+	{
+	  /* Remember the amount of space needed by the arguments.  */
+	  argspace = argoffset;
+	  /* Allocate space for both the arguments and the structures.  */
+	  sp -= (argoffset + structoffset);
+	  /* Ensure that the stack is still 16 byte aligned.  */
+	  sp = align_down (sp, 16);
+	}
     }
 
+  /* Update %sp.   */
+  regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+
+  /* Write the backchain (it occupies WORDSIZED bytes).  */
+  write_memory_signed_integer (sp, tdep->wordsize, saved_sp);
+
   /* Point the inferior function call's return address at the dummy's
      breakpoint.  */
-  regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+  regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
 
-  target_store_registers (-1);
   return sp;
 }
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [rfa:ppc] Cleanup SVR4 push dummy call
  2003-09-12 14:47 [rfa:ppc] Cleanup SVR4 push dummy call Andrew Cagney
@ 2003-09-12 15:02 ` Andrew Cagney
  2003-09-12 17:56   ` Kevin Buettner
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2003-09-12 15:02 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 601 bytes --]

> Hello,
> 
> This patch rewrites ppc_svr4_push_dummy_call so that it implements the two-pass push-arguments algorithm using a "for" loop.
> 
> The simplification identified and fixed the bugs:
> 
> - Altivec registers on the stack weren't being 16 byte aligned
> - Floats weren't being converted to doubles before being stored in register/memory ("gdb.base/callfuncs.exp: p t_float_values2" now passes).
> 
> Ok?
> 
> Andrew
> 
> PS: I intend moving align_{up,down} to utils.c but that is separate.

Oops, try this.  It's got the up-to-date changelog and uses a more 
readable context diff.

Andrew


[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 18966 bytes --]

2003-09-12  Andrew Cagney  <cagney@redhat.com>
 
 	* ppc-sysv-tdep.c (align_up, align_down): Replace "round2" macro.
 	(ppc_sysv_abi_push_dummy_call): Rewrite, use a two pass loop.
 
Index: ppc-sysv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-sysv-tdep.c,v
retrieving revision 1.9
diff -c -r1.9 ppc-sysv-tdep.c
*** ppc-sysv-tdep.c	11 Sep 2003 19:27:25 -0000	1.9
--- ppc-sysv-tdep.c	12 Sep 2003 14:57:41 -0000
***************
*** 29,39 ****
  
  #include "ppc-tdep.h"
  
! /* round2 rounds x up to the nearest multiple of s assuming that s is a
!    power of 2 */
  
! #undef round2
! #define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
  
  /* Pass the arguments in either registers, or in the stack. Using the
     ppc sysv ABI, the first eight words of the argument list (that might
--- 29,48 ----
  
  #include "ppc-tdep.h"
  
! /* Ensure that X is aligned to an S byte boundary (assuming that S is
!    a power of 2) rounding up/down where necessary.  */
  
! static ULONGEST
! align_up (ULONGEST x, int s)
! {
!   return (x + s - 1) & -s;
! }
! 
! static ULONGEST
! align_down (ULONGEST x, int s)
! {
!   return (x & -s);
! }
  
  /* Pass the arguments in either registers, or in the stack. Using the
     ppc sysv ABI, the first eight words of the argument list (that might
***************
*** 52,349 ****
  			      int nargs, struct value **args, CORE_ADDR sp,
  			      int struct_return, CORE_ADDR struct_addr)
  {
-   int argno;
-   /* Next available general register for non-float, non-vector arguments. */
-   int greg;
-   /* Next available floating point register for float arguments. */
-   int freg;
-   /* Next available vector register for vector arguments. */
-   int vreg;
-   int argstkspace;
-   int structstkspace;
-   int argoffset;
-   int structoffset;
-   struct type *type;
-   int len;
-   char old_sp_buf[4];
-   CORE_ADDR saved_sp;
    struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  
!   greg = 3;
!   freg = 1;
!   vreg = 2;
!   argstkspace = 0;
!   structstkspace = 0;
! 
!   /* If the function is returning a `struct', then the first word
!      (which will be passed in r3) is used for struct return address.
!      In that case we should advance one word and start from r4
!      register to copy parameters.  */
!   if (struct_return)
!     {
!       regcache_raw_write_signed (regcache, tdep->ppc_gp0_regnum + greg,
! 				 struct_addr);
!       greg++;
!     }
  
!   /* Figure out how much new stack space is required for arguments
!      which don't fit in registers.  Unlike the PowerOpen ABI, the
!      SysV ABI doesn't reserve any extra space for parameters which
!      are put in registers. */
!   for (argno = 0; argno < nargs; argno++)
      {
!       struct value *arg = args[argno];
!       type = check_typedef (VALUE_TYPE (arg));
!       len = TYPE_LENGTH (type);
! 
!       if (TYPE_CODE (type) == TYPE_CODE_FLT
!           && ppc_floating_point_unit_p (current_gdbarch))
  	{
! 	  if (freg <= 8)
! 	    freg++;
! 	  else
! 	    {
! 	      /* SysV ABI converts floats to doubles when placed in
! 	         memory and requires 8 byte alignment */
! 	      if (argstkspace & 0x4)
! 		argstkspace += 4;
! 	      argstkspace += 8;
! 	    }
  	}
!       else if (len == 8 
!                && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
!                    || (!ppc_floating_point_unit_p (current_gdbarch)
!                        && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
  	{
! 	  if (greg > 9)
! 	    {
! 	      greg = 11;
! 	      if (argstkspace & 0x4)
! 		argstkspace += 4;
! 	      argstkspace += 8;
! 	    }
! 	  else
! 	    {
! 	      if ((greg & 1) == 0)
! 		greg++;
! 	      greg += 2;
! 	    }
! 	}
!       else if (!TYPE_VECTOR (type))
!         {
! 	  if (len > 4
! 	      || TYPE_CODE (type) == TYPE_CODE_STRUCT
! 	      || TYPE_CODE (type) == TYPE_CODE_UNION)
! 	    {
! 	      /* Rounding to the nearest multiple of 8 may not be necessary,
! 		 but it is safe.  Particularly since we don't know the
! 		 field types of the structure */
! 	      structstkspace += round2 (len, 8);
! 	    }
! 	  if (greg <= 10)
! 	    greg++;
! 	  else
! 	    argstkspace += 4;
!     	}
!       else
!         {
!           if (len == 16
! 	      && TYPE_CODE (type) == TYPE_CODE_ARRAY
! 	      && TYPE_VECTOR (type))
! 	    {
! 	      if (vreg <= 13)
! 		vreg++;
  	      else
  		{
! 		  /* Vector arguments must be aligned to 16 bytes on
!                      the stack. */
! 		  argstkspace += round2 (argstkspace, 16);
! 		  argstkspace += 16;
  		}
  	    }
!           else if (len == 8 
!                    && TYPE_CODE (type) == TYPE_CODE_ARRAY
!                    && TYPE_VECTOR (type))
!             {
!               if (greg <= 10)
!                 greg++;
!               else
!                 {
!                   /* Vector arguments must be aligned to 8 bytes on
!                      the stack. */
!                   argstkspace += round2 (argstkspace, 8);
!                   argstkspace += 8;
!                 }
!             }
! 	}
!     }
! 
!   /* Get current SP location */
!   saved_sp = read_sp ();
! 
!   sp -= argstkspace + structstkspace;
! 
!   /* Allocate space for backchain and callee's saved lr */
!   sp -= 8;
! 
!   /* Make sure that we maintain 16 byte alignment */
!   sp &= ~0x0f;
! 
!   /* Update %sp before proceeding any further.   */
!   regcache_raw_write_signed (regcache, SP_REGNUM, sp);
! 
!   /* write the backchain */
!   store_unsigned_integer (old_sp_buf, 4, saved_sp);
!   write_memory (sp, old_sp_buf, 4);
! 
!   argoffset = 8;
!   structoffset = argoffset + argstkspace;
!   freg = 1;
!   greg = 3;
!   vreg = 2;
! 
!   /* Fill in r3 with the return structure, if any */
!   if (struct_return)
!     {
!       write_register (tdep->ppc_gp0_regnum + greg, struct_addr);
!       greg++;
!     }
! 
!   /* Now fill in the registers and stack... */
!   for (argno = 0; argno < nargs; argno++)
!     {
!       struct value *arg = args[argno];
!       char *val = VALUE_CONTENTS (arg);
!       type = check_typedef (VALUE_TYPE (arg));
!       len = TYPE_LENGTH (type);
! 
!       if (TYPE_CODE (type) == TYPE_CODE_FLT
!           && ppc_floating_point_unit_p (current_gdbarch))
! 	{
! 	  if (freg <= 8)
! 	    {
! 	      ULONGEST regval;
! 	      if (len > 8)
! 		printf_unfiltered (
! 				   "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
!               regval = extract_unsigned_integer (val, len);
!               write_register (FP0_REGNUM + freg, regval);
! 	      freg++;
! 	    }
! 	  else
! 	    {
! 	      /* SysV ABI converts floats to doubles when placed in
! 	         memory and requires 8 byte alignment */
! 	      /* FIXME: Convert floats to doubles */
! 	      if (argoffset & 0x4)
! 		argoffset += 4;
! 	      write_memory (sp + argoffset, val, len);
! 	      argoffset += 8;
! 	    }
! 	}
!       else if (len == 8 
!                && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
!                    || (!ppc_floating_point_unit_p (current_gdbarch)
!                         && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
! 	{
! 	  if (greg > 9)
! 	    {
! 	      greg = 11;
! 	      if (argoffset & 0x4)
! 		argoffset += 4;
! 	      write_memory (sp + argoffset, val, len);
! 	      argoffset += 8;
! 	    }
! 	  else
! 	    {
! 	      ULONGEST regval;
! 	      if ((greg & 1) == 0)
! 		greg++;
!               regval = extract_unsigned_integer (val, 4);
!               write_register (tdep->ppc_gp0_regnum + greg, regval);
!               regval = extract_unsigned_integer (val + 4, 4);
!               write_register (tdep->ppc_gp0_regnum + greg + 1, regval);
! 	      greg += 2;
! 	    }
! 	}
!       else if (!TYPE_VECTOR (type))
! 	{
! 	  char val_buf[4];
! 	  if (len > 4
! 	      || TYPE_CODE (type) == TYPE_CODE_STRUCT
! 	      || TYPE_CODE (type) == TYPE_CODE_UNION)
! 	    {
! 	      write_memory (sp + structoffset, val, len);
! 	      store_unsigned_integer (val_buf, 4, sp + structoffset);
! 	      structoffset += round2 (len, 8);
! 	    }
! 	  else
! 	    {
! 	      memset (val_buf, 0, 4);
! 	      memcpy (val_buf, val, len);
! 	    }
! 	  if (greg <= 10)
! 	    {
!               ULONGEST regval = extract_unsigned_integer (val_buf, 4);
!               write_register (tdep->ppc_gp0_regnum + greg, regval);
! 	      greg++;
! 	    }
! 	  else
! 	    {
! 	      write_memory (sp + argoffset, val_buf, 4);
! 	      argoffset += 4;
  	    }
! 	}
!       else
! 	{
! 	  if (len == 16
! 	      && TYPE_CODE (type) == TYPE_CODE_ARRAY
! 	      && TYPE_VECTOR (type))
  	    {
! 	      char *v_val_buf = alloca (16);
! 	      memset (v_val_buf, 0, 16);
! 	      memcpy (v_val_buf, val, len);
  	      if (vreg <= 13)
  		{
! 		  regcache_cooked_write (current_regcache,
! 					 tdep->ppc_vr0_regnum + vreg,
! 					 v_val_buf);
  		  vreg++;
  		}
  	      else
  		{
! 		  write_memory (sp + argoffset, v_val_buf, 16);
  		  argoffset += 16;
  		}
  	    }
            else if (len == 8 
  		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
! 		   && TYPE_VECTOR (type))
              {
!               char *v_val_buf = alloca (8);
!               memset (v_val_buf, 0, 8);
!               memcpy (v_val_buf, val, len);
                if (greg <= 10)
                  {
! 		  regcache_cooked_write (current_regcache,
! 					 tdep->ppc_ev0_regnum + greg,
! 					 v_val_buf);
                    greg++;
                  }
                else
                  {
!                   write_memory (sp + argoffset, v_val_buf, 8);
                    argoffset += 8;
                  }
              }
!         }
      }
  
    /* Point the inferior function call's return address at the dummy's
       breakpoint.  */
!   regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
  
-   target_store_registers (-1);
    return sp;
  }
  
--- 61,330 ----
  			      int nargs, struct value **args, CORE_ADDR sp,
  			      int struct_return, CORE_ADDR struct_addr)
  {
    struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+   const CORE_ADDR saved_sp = read_sp ();
+   int argspace = 0;		/* 0 is an initial wrong guess.  */
+   int write_pass;
+ 
+   /* Go through the argument list twice.
+ 
+      Pass 1: Figure out how much new stack space is required for
+      arguments and pushed values.  Unlike the PowerOpen ABI, the SysV
+      ABI doesn't reserve any extra space for parameters which are put
+      in registers, but does always push structures and then pass their
+      address.
  
!      Pass 2: Replay the same computation but this time also write the
!      values out to the target.  */
  
!   for (write_pass = 0; write_pass < 2; write_pass++)
      {
!       int argno;
!       /* Next available floating point register for float and double
!          arguments.  */
!       int freg = 1;
!       /* Next available general register for non-float, non-vector
!          arguments.  */
!       int greg = 3;
!       /* Next available vector register for vector arguments.  */
!       int vreg = 2;
!       /* Arguments start above the "LR save word" and "Back chain".  */
!       int argoffset = 2 * tdep->wordsize;
!       /* Structures start after the arguments.  */
!       int structoffset = argoffset + argspace;
! 
!       /* If the function is returning a `struct', then the first word
! 	 (which will be passed in r3) is used for struct return
! 	 address.  In that case we should advance one word and start
! 	 from r4 register to copy parameters.  */
!       if (struct_return)
  	{
! 	  if (write_pass)
! 	    regcache_cooked_write_signed (regcache,
! 					  tdep->ppc_gp0_regnum + greg,
! 					  struct_addr);
! 	  greg++;
  	}
! 
!       for (argno = 0; argno < nargs; argno++)
  	{
! 	  struct value *arg = args[argno];
! 	  struct type *type = check_typedef (VALUE_TYPE (arg));
! 	  int len = TYPE_LENGTH (type);
! 	  char *val = VALUE_CONTENTS (arg);
! 
! 	  if (TYPE_CODE (type) == TYPE_CODE_FLT
! 	      && ppc_floating_point_unit_p (current_gdbarch)
! 	      && len <= 8)
! 	    {
! 	      /* Floating point value converted to "double" then
!                  passed in an FP register, when the registers run out,
!                  8 byte aligned stack is used.  */
! 	      if (freg <= 8)
! 		{
! 		  if (write_pass)
! 		    {
! 		      /* Always store the floating point value using
!                          the register's floating-point format.  */
! 		      char regval[MAX_REGISTER_SIZE];
! 		      struct type *regtype
! 			= register_type (gdbarch, FP0_REGNUM + freg);
! 		      convert_typed_floating (val, type, regval, regtype);
! 		      regcache_cooked_write (regcache, FP0_REGNUM + freg,
! 					     regval);
! 		    }
! 		  freg++;
! 		}
  	      else
  		{
! 		  /* SysV ABI converts floats to doubles before
!                      writing them to an 8 byte aligned stack location.  */
! 		  argoffset = align_up (argoffset, 8);
! 		  if (write_pass)
! 		    {
! 		      char memval[8];
! 		      struct type *memtype;
! 		      switch (TARGET_BYTE_ORDER)
! 			{
! 			case BFD_ENDIAN_BIG:
! 			  memtype = builtin_type_ieee_double_big;
! 			  break;
! 			case BFD_ENDIAN_LITTLE:
! 			  memtype = builtin_type_ieee_double_little;
! 			  break;
! 			default:
! 			  internal_error (__FILE__, __LINE__, "bad switch");
! 			}
! 		      convert_typed_floating (val, type, memval, memtype);
! 		      write_memory (sp + argoffset, val, len);
! 		    }
! 		  argoffset += 8;
  		}
  	    }
! 	  else if (len == 8 
! 		   && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
! 		       || (!ppc_floating_point_unit_p (current_gdbarch)
! 			   && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
! 	    {
! 	      /* "long long" or "double" passed in an odd/even
!                  register pair with the low addressed word in the odd
!                  register and the high addressed word in the even
!                  register, or when the registers run out an 8 byte
!                  aligned stack location.  */
! 	      if (greg > 9)
! 		{
! 		  /* Just in case GREG was 10.  */
! 		  greg = 11;
! 		  argoffset = align_up (argoffset, 8);
! 		  write_memory (sp + argoffset, val, len);
! 		  argoffset += 8;
! 		}
! 	      else if (tdep->wordsize == 8)
! 		{
! 		  if (write_pass)
! 		    regcache_cooked_write (regcache,
! 					   tdep->ppc_gp0_regnum + greg,
! 					   val);
! 		  greg += 1;
! 		}
! 	      else
! 		{
! 		  /* Must start on an odd register - r3/r4 etc.  */
! 		  if ((greg & 1) == 0)
! 		    greg++;
! 		  if (write_pass)
! 		    {
! 		      regcache_cooked_write (regcache,
! 					     tdep->ppc_gp0_regnum + greg + 0,
! 					     val + 0);
! 		      regcache_cooked_write (regcache,
! 					     tdep->ppc_gp0_regnum + greg + 1,
! 					     val + 4);
! 		    }
! 		  greg += 2;
! 		}
  	    }
! 	  else if (len == 16
! 		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
! 		   && TYPE_VECTOR (type)
! 		   && tdep->ppc_vr0_regnum >= 0)
  	    {
! 	      /* Vector parameter passed in an Altivec register, or
!                  when that runs out, 16 byte aligned stack location.  */
  	      if (vreg <= 13)
  		{
! 		  if (write_pass)
! 		    regcache_cooked_write (current_regcache,
! 					   tdep->ppc_vr0_regnum + vreg,
! 					   val);
  		  vreg++;
  		}
  	      else
  		{
! 		  argoffset = align_up (argoffset, 16);
! 		  if (write_pass)
! 		    write_memory (sp + argoffset, val, 16);
  		  argoffset += 16;
  		}
  	    }
            else if (len == 8 
  		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
! 		   && TYPE_VECTOR (type)
! 		   && tdep->ppc_ev0_regnum >= 0)
              {
! 	      /* Vector parameter passed in an e500 register, or when
!                  that runs out, 8 byte aligned stack location.  Note
!                  that since e500 vector and general purpose registers
!                  both map onto the same underlying register set, a
!                  "greg" and not a "vreg" is consumed here.  A cooked
!                  write stores the value in the correct locations
!                  within the raw register cache.  */
                if (greg <= 10)
                  {
! 		  if (write_pass)
! 		    regcache_cooked_write (current_regcache,
! 					   tdep->ppc_ev0_regnum + greg,
! 					   val);
                    greg++;
                  }
                else
                  {
! 		  argoffset = align_up (argoffset, 8);
! 		  if (write_pass)
! 		    write_memory (sp + argoffset, val, 8);
                    argoffset += 8;
                  }
              }
! 	  else
! 	    {
! 	      /* Reduce the parameter down to something that fits in a
!                  "word".  */
! 	      char word[MAX_REGISTER_SIZE];
! 	      memset (word, 0, MAX_REGISTER_SIZE);
! 	      if (len > tdep->wordsize
! 		  || TYPE_CODE (type) == TYPE_CODE_STRUCT
! 		  || TYPE_CODE (type) == TYPE_CODE_UNION)
! 		{
! 		  /* Structs and large values are put on an 8 byte
!                      aligned stack ... */
! 		  structoffset = align_up (structoffset, 8);
! 		  if (write_pass)
! 		    write_memory (sp + structoffset, val, len);
! 		  /* ... and then a "word" pointing to that address is
!                      passed as the parameter.  */
! 		  store_unsigned_integer (word, tdep->wordsize,
! 					  sp + structoffset);
! 		  structoffset += len;
! 		}
! 	      else if (TYPE_CODE (type) == TYPE_CODE_INT)
! 		/* Sign or zero extend the "int" into a "word".  */
! 		store_unsigned_integer (word, tdep->wordsize,
! 					unpack_long (type, val));
! 	      else
! 		/* Always goes in the low address.  */
! 		memcpy (word, val, len);
! 	      /* Store that "word" in a register, or on the stack.
!                  The words have "4" byte alignment.  */
! 	      if (greg <= 10)
! 		{
! 		  if (write_pass)
! 		    regcache_cooked_write (regcache,
! 					   tdep->ppc_gp0_regnum + greg,
! 					   word);
! 		  greg++;
! 		}
! 	      else
! 		{
! 		  argoffset = align_up (argoffset, tdep->wordsize);
! 		  if (write_pass)
! 		    write_memory (sp + argoffset, word, tdep->wordsize);
! 		  argoffset += tdep->wordsize;
! 		}
! 	    }
! 	}
! 
!       /* Compute the actual stack space requirements.  */
!       if (!write_pass)
! 	{
! 	  /* Remember the amount of space needed by the arguments.  */
! 	  argspace = argoffset;
! 	  /* Allocate space for both the arguments and the structures.  */
! 	  sp -= (argoffset + structoffset);
! 	  /* Ensure that the stack is still 16 byte aligned.  */
! 	  sp = align_down (sp, 16);
! 	}
      }
  
+   /* Update %sp.   */
+   regcache_cooked_write_signed (regcache, SP_REGNUM, sp);
+ 
+   /* Write the backchain (it occupies WORDSIZED bytes).  */
+   write_memory_signed_integer (sp, tdep->wordsize, saved_sp);
+ 
    /* Point the inferior function call's return address at the dummy's
       breakpoint.  */
!   regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
  
    return sp;
  }
  

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [rfa:ppc] Cleanup SVR4 push dummy call
  2003-09-12 15:02 ` Andrew Cagney
@ 2003-09-12 17:56   ` Kevin Buettner
  2003-09-12 18:33     ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Kevin Buettner @ 2003-09-12 17:56 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: gdb-patches

On Sep 12, 11:01am, Andrew Cagney wrote:

> 	* ppc-sysv-tdep.c (align_up, align_down): Replace "round2" macro.
> 	(ppc_sysv_abi_push_dummy_call): Rewrite, use a two pass loop.

Okay, except...

> ! 	  else if (len == 8 
> ! 		   && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
> ! 		       || (!ppc_floating_point_unit_p (current_gdbarch)
> ! 			   && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
> ! 	    {
> ! 	      /* "long long" or "double" passed in an odd/even
> !                  register pair with the low addressed word in the odd
> !                  register and the high addressed word in the even
> !                  register, or when the registers run out an 8 byte
> !                  aligned stack location.  */
> ! 	      if (greg > 9)
> ! 		{
> ! 		  /* Just in case GREG was 10.  */
> ! 		  greg = 11;
> ! 		  argoffset = align_up (argoffset, 8);
> ! 		  write_memory (sp + argoffset, val, len);

...I believe you forgot the ``if (write_pass)'' check on the above
call to write_memory().

Kevin


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [rfa:ppc] Cleanup SVR4 push dummy call
  2003-09-12 17:56   ` Kevin Buettner
@ 2003-09-12 18:33     ` Andrew Cagney
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Cagney @ 2003-09-12 18:33 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

> On Sep 12, 11:01am, Andrew Cagney wrote:
> 
> 
>> 	* ppc-sysv-tdep.c (align_up, align_down): Replace "round2" macro.
>> 	(ppc_sysv_abi_push_dummy_call): Rewrite, use a two pass loop.
> 
> 
> Okay, except...
> 
> 
>> ! 	  else if (len == 8 
>> ! 		   && (TYPE_CODE (type) == TYPE_CODE_INT /* long long */
>> ! 		       || (!ppc_floating_point_unit_p (current_gdbarch)
>> ! 			   && TYPE_CODE (type) == TYPE_CODE_FLT))) /* double */
>> ! 	    {
>> ! 	      /* "long long" or "double" passed in an odd/even
>> !                  register pair with the low addressed word in the odd
>> !                  register and the high addressed word in the even
>> !                  register, or when the registers run out an 8 byte
>> !                  aligned stack location.  */
>> ! 	      if (greg > 9)
>> ! 		{
>> ! 		  /* Just in case GREG was 10.  */
>> ! 		  greg = 11;
>> ! 		  argoffset = align_up (argoffset, 8);
>> ! 		  write_memory (sp + argoffset, val, len);
> 
> 
> ...I believe you forgot the ``if (write_pass)'' check on the above
> call to write_memory().

Outch, yes.  Good catch.  Committed with fix.

Andrew



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-09-12 18:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-12 14:47 [rfa:ppc] Cleanup SVR4 push dummy call Andrew Cagney
2003-09-12 15:02 ` Andrew Cagney
2003-09-12 17:56   ` Kevin Buettner
2003-09-12 18:33     ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox