Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA] mips_push_arguments gdbarch-ified
@ 2002-08-08 17:29 Michael Snyder
  2002-08-08 20:51 ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Snyder @ 2002-08-08 17:29 UTC (permalink / raw)
  To: gdb-patches, cagney

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

These changes fix 16 testsuite failures, based in the Irix native 
compiler running with -n32 (and produce no regressions for -o32).

[-- Attachment #2: patch5.diff --]
[-- Type: text/plain, Size: 17178 bytes --]

2002-08-08  Michael Snyder  <msnyder@redhat.com>

	* mips-tdep.c (ROUND_UP, ROUND_DOWN): Move to global scope.
	(mips_n32n64_push_arguments): Cloned from mips_push_arguments.
	Tuned for n32 and n64 abi.
	(mips_gdbarch_init): Set push_arguments per individual ABI.	
	* config/mips/tm-mips.h (PUSH_ARGUMENTS): Undefine.

Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.92
diff -c -3 -p -r1.92 mips-tdep.c
*** mips-tdep.c	8 Aug 2002 00:26:51 -0000	1.92
--- mips-tdep.c	9 Aug 2002 00:13:00 -0000
*************** mips_type_needs_double_align (struct typ
*** 2412,2417 ****
--- 2412,2423 ----
    return 0;
  }
  
+ /* Macros to round N up or down to the next A boundary; 
+    A must be a power of two.  */
+ 
+ #define ROUND_DOWN(n,a) ((n) & ~((a)-1))
+ #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+ 
  CORE_ADDR
  mips_push_arguments (int nargs,
  		     struct value **args,
*************** mips_push_arguments (int nargs,
*** 2426,2436 ****
    int stack_offset = 0;
    struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  
-   /* Macros to round N up or down to the next A boundary; A must be
-      a power of two. */
- #define ROUND_DOWN(n,a) ((n) & ~((a)-1))
- #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
- 
    /* First ensure that the stack and structure return address (if any)
       are properly aligned. The stack has to be at least 64-bit aligned
       even on 32-bit machines, because doubles must be 64-bit aligned.
--- 2432,2437 ----
*************** mips_push_arguments (int nargs,
*** 2749,2754 ****
--- 2750,3052 ----
  }
  
  CORE_ADDR
+ mips_n32n64_push_arguments (int nargs,
+ 			    struct value **args,
+ 			    CORE_ADDR sp,
+ 			    int struct_return,
+ 			    CORE_ADDR struct_addr)
+ {
+   int argreg;
+   int float_argreg;
+   int argnum;
+   int len = 0;
+   int stack_offset = 0;
+ 
+   /* First ensure that the stack and structure return address (if any)
+      are properly aligned.  The stack has to be at least 64-bit
+      aligned even on 32-bit machines, because doubles must be 64-bit
+      aligned.  On at least one MIPS variant, stack frames need to be
+      128-bit aligned, so we round to this widest known alignment.  */
+ 
+   sp = ROUND_DOWN (sp, 16);
+   struct_addr = ROUND_DOWN (struct_addr, 16);
+ 
+   /* Now make space on the stack for the args.  We allocate more
+      than necessary for EABI, because the first few arguments are
+      passed in registers, but that's OK.  */
+   for (argnum = 0; argnum < nargs; argnum++)
+     len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
+ 		     MIPS_STACK_ARGSIZE);
+   sp -= ROUND_UP (len, 16);
+ 
+   if (mips_debug)
+     fprintf_unfiltered (gdb_stdlog, 
+ 			"mips_push_arguments: sp=0x%lx allocated %d\n",
+ 			(long) sp, ROUND_UP (len, 16));
+ 
+   /* Initialize the integer and float register pointers.  */
+   argreg = A0_REGNUM;
+   float_argreg = FPA0_REGNUM;
+ 
+   /* the struct_return pointer occupies the first parameter-passing reg */
+   if (struct_return)
+     {
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog,
+ 			    "mips_push_arguments: struct_return reg=%d 0x%lx\n",
+ 			    argreg, (long) struct_addr);
+       write_register (argreg++, struct_addr);
+       if (MIPS_REGS_HAVE_HOME_P)
+ 	stack_offset += MIPS_STACK_ARGSIZE;
+     }
+ 
+   /* Now load as many as possible of the first arguments into
+      registers, and push the rest onto the stack.  Loop thru args
+      from first to last.  */
+   for (argnum = 0; argnum < nargs; argnum++)
+     {
+       char *val;
+       char valbuf[MAX_REGISTER_RAW_SIZE];
+       struct value *arg = args[argnum];
+       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+       int len = TYPE_LENGTH (arg_type);
+       enum type_code typecode = TYPE_CODE (arg_type);
+ 
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog,
+ 			    "mips_push_arguments: %d len=%d type=%d",
+ 			    argnum + 1, len, (int) typecode);
+ 
+       val = (char *) VALUE_CONTENTS (arg);
+ 
+       /* 32-bit ABIs always start floating point arguments in an
+          even-numbered floating point register.  Round the FP register
+          up before the check to see if there are any FP registers
+          left.  Non MIPS_EABI targets also pass the FP in the integer
+          registers so also round up normal registers.  */
+       if (!FP_REGISTER_DOUBLE
+ 	  && fp_register_arg_p (typecode, arg_type))
+ 	{
+ 	  if ((float_argreg & 1))
+ 	    float_argreg++;
+ 	}
+ 
+       /* Floating point arguments passed in registers have to be
+          treated specially.  On 32-bit architectures, doubles
+          are passed in register pairs; the even register gets
+          the low word, and the odd register gets the high word.
+          On non-EABI processors, the first two floating point arguments are
+          also copied to general registers, because MIPS16 functions
+          don't use float registers for arguments.  This duplication of
+          arguments in general registers can't hurt non-MIPS16 functions
+          because those registers are normally skipped.  */
+ 
+       if (fp_register_arg_p (typecode, arg_type)
+ 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ 	{
+ 	  if (!FP_REGISTER_DOUBLE && len == 8)
+ 	    {
+ 	      int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ 	      unsigned long regval;
+ 
+ 	      /* Write the low word of the double to the even register(s).  */
+ 	      regval = extract_unsigned_integer (val + low_offset, 4);
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ 				    float_argreg, phex (regval, 4));
+ 	      write_register (float_argreg++, regval);
+ 
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ 				    argreg, phex (regval, 4));
+ 	      write_register (argreg++, regval);
+ 
+ 	      /* Write the high word of the double to the odd register(s).  */
+ 	      regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ 				    float_argreg, phex (regval, 4));
+ 	      write_register (float_argreg++, regval);
+ 
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ 				    argreg, phex (regval, 4));
+ 	      write_register (argreg++, regval);
+ 	    }
+ 	  else
+ 	    {
+ 	      /* This is a floating point value that fits entirely
+ 	         in a single register.  */
+ 	      /* On 32 bit ABI's the float_argreg is further adjusted
+                  above to ensure that it is even register aligned.  */
+ 	      LONGEST regval = extract_unsigned_integer (val, len);
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ 				    float_argreg, phex (regval, len));
+ 	      write_register (float_argreg++, regval);
+ 
+ 	      /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+ 		 registers for each argument.  The below is (my
+ 		 guess) to ensure that the corresponding integer
+ 		 register has reserved the same space.  */
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ 				    argreg, phex (regval, len));
+ 	      write_register (argreg, regval);
+ 	      argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+ 	    }
+ 	  /* Reserve space for the FP register.  */
+ 	  if (MIPS_REGS_HAVE_HOME_P)
+ 	    stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+ 	}
+       else
+ 	{
+ 	  /* Copy the argument to general registers or the stack in
+ 	     register-sized pieces.  Large arguments are split between
+ 	     registers and stack.  */
+ 	  /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ 	     are treated specially: Irix cc passes them in registers
+ 	     where gcc sometimes puts them on the stack.  For maximum
+ 	     compatibility, we will put them in both places.  */
+ 	  int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+ 				  (len % MIPS_SAVED_REGSIZE != 0));
+ 	  /* Note: Floating-point values that didn't fit into an FP
+              register are only written to memory.  */
+ 	  while (len > 0)
+ 	    {
+ 	      /* Rememer if the argument was written to the stack.  */
+ 	      int stack_used_p = 0;
+ 	      int partial_len = len < MIPS_SAVED_REGSIZE ? 
+ 		len : MIPS_SAVED_REGSIZE;
+ 
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ 				    partial_len);
+ 
+ 	      /* Write this portion of the argument to the stack.  */
+ 	      if (argreg > MIPS_LAST_ARG_REGNUM
+ 		  || odd_sized_struct
+ 		  || fp_register_arg_p (typecode, arg_type))
+ 		{
+ 		  /* Should shorter than int integer values be
+ 		     promoted to int before being stored? */
+ 		  int longword_offset = 0;
+ 		  CORE_ADDR addr;
+ 		  stack_used_p = 1;
+ 		  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ 		    {
+ 		      if (MIPS_STACK_ARGSIZE == 8 &&
+ 			  (typecode == TYPE_CODE_INT ||
+ 			   typecode == TYPE_CODE_PTR ||
+ 			   typecode == TYPE_CODE_FLT) && len <= 4)
+ 			longword_offset = MIPS_STACK_ARGSIZE - len;
+ 		      else if ((typecode == TYPE_CODE_STRUCT ||
+ 				typecode == TYPE_CODE_UNION) &&
+ 			       TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
+ 			longword_offset = MIPS_STACK_ARGSIZE - len;
+ 		    }
+ 
+ 		  if (mips_debug)
+ 		    {
+ 		      fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%lx",
+ 					  (long) stack_offset);
+ 		      fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%lx",
+ 					  (long) longword_offset);
+ 		    }
+ 
+ 		  addr = sp + stack_offset + longword_offset;
+ 
+ 		  if (mips_debug)
+ 		    {
+ 		      int i;
+ 		      fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
+ 		      for (i = 0; i < partial_len; i++)
+ 			{
+ 			  fprintf_unfiltered (gdb_stdlog, "%02x", 
+ 					      val[i] & 0xff);
+ 			}
+ 		    }
+ 		  write_memory (addr, val, partial_len);
+ 		}
+ 
+ 	      /* Note!!! This is NOT an else clause.  Odd sized
+ 	         structs may go thru BOTH paths.  Floating point
+ 	         arguments will not.  */
+ 	      /* Write this portion of the argument to a general
+                  purpose register.  */
+ 	      if (argreg <= MIPS_LAST_ARG_REGNUM
+ 		  && !fp_register_arg_p (typecode, arg_type))
+ 		{
+ 		  LONGEST regval = extract_unsigned_integer (val, partial_len);
+ 
+ 		  /* A non-floating-point argument being passed in a
+ 		     general register.  If a struct or union, and if
+ 		     the remaining length is smaller than the register
+ 		     size, we have to adjust the register value on
+ 		     big endian targets.
+ 
+ 		     It does not seem to be necessary to do the
+ 		     same for integral types.
+ 
+ 		     cagney/2001-07-23: gdb/179: Also, GCC, when
+ 		     outputting LE O32 with sizeof (struct) <
+ 		     MIPS_SAVED_REGSIZE, generates a left shift as
+ 		     part of storing the argument in a register a
+ 		     register (the left shift isn't generated when
+ 		     sizeof (struct) >= MIPS_SAVED_REGSIZE).  Since it
+ 		     is quite possible that this is GCC contradicting
+ 		     the LE/O32 ABI, GDB has not been adjusted to
+ 		     accommodate this.  Either someone needs to
+ 		     demonstrate that the LE/O32 ABI specifies such a
+ 		     left shift OR this new ABI gets identified as
+ 		     such and GDB gets tweaked accordingly.  */
+ 
+ 		  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ 		      && partial_len < MIPS_SAVED_REGSIZE
+ 		      && (typecode == TYPE_CODE_STRUCT ||
+ 			  typecode == TYPE_CODE_UNION))
+ 		    regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
+ 				TARGET_CHAR_BIT);
+ 
+ 		  if (mips_debug)
+ 		    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ 				      argreg,
+ 				      phex (regval, MIPS_SAVED_REGSIZE));
+ 		  write_register (argreg, regval);
+ 		  argreg++;
+ 
+ 		  /* Prevent subsequent floating point arguments from
+ 		     being passed in floating point registers.  */
+ 		  float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+ 		}
+ 
+ 	      len -= partial_len;
+ 	      val += partial_len;
+ 
+ 	      /* Compute the the offset into the stack at which we
+ 		 will copy the next parameter.
+ 
+ 		 In older ABIs, the caller reserved space for
+ 		 registers that contained arguments.  This was loosely
+ 		 refered to as their "home".  Consequently, space is
+ 		 always allocated.
+ 
+ 	         In N32, the stack_offset only needs to be adjusted
+ 	         when it has been used.  FIXME is this true?  */
+ 
+ 	      if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
+ 		stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ 	    }
+ 	}
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog, "\n");
+     }
+ 
+   /* Return adjusted stack pointer.  */
+   return sp;
+ }
+ 
+ CORE_ADDR
  mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
  {
    /* Set the return address register to point to the entry
*************** return_value_location (struct type *valt
*** 3612,3618 ****
  	  lo->reg_offset = MIPS_SAVED_REGSIZE - len;
  	  lo->len = len;
  	  hi->reg_offset = 0;
! 	  hi->len = 0;
  	}
        else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
  	       && len > MIPS_SAVED_REGSIZE	/* odd-size structs */
--- 3910,3916 ----
  	  lo->reg_offset = MIPS_SAVED_REGSIZE - len;
  	  lo->len = len;
  	  hi->reg_offset = 0;
!   	  hi->len = 0;
  	}
        else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
  	       && len > MIPS_SAVED_REGSIZE	/* odd-size structs */
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4516,4521 ****
--- 4814,4820 ----
    switch (mips_abi)
      {
      case MIPS_ABI_O32:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 4;
        tdep->mips_default_stack_argsize = 4;
        tdep->mips_fp_register_double = 0;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4533,4538 ****
--- 4832,4838 ----
  					 mips_o32_use_struct_convention);
        break;
      case MIPS_ABI_O64:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4550,4555 ****
--- 4850,4856 ----
  					 mips_o32_use_struct_convention);
        break;
      case MIPS_ABI_EABI32:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 4;
        tdep->mips_default_stack_argsize = 4;
        tdep->mips_fp_register_double = 0;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4567,4572 ****
--- 4868,4874 ----
  					 mips_eabi_use_struct_convention);
        break;
      case MIPS_ABI_EABI64:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4584,4589 ****
--- 4886,4892 ----
  					 mips_eabi_use_struct_convention);
        break;
      case MIPS_ABI_N32:
+       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4613,4618 ****
--- 4916,4922 ----
  				       mips_n32n64_reg_struct_has_addr);
        break;
      case MIPS_ABI_N64:
+       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4731,4737 ****
    set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words);
    set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words));
    set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
-   set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
    set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
    set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
  
--- 5035,5040 ----
Index: config/mips/tm-mips.h
===================================================================
RCS file: /cvs/src/src/gdb/config/mips/tm-mips.h,v
retrieving revision 1.29
diff -c -3 -p -r1.29 tm-mips.h
*** config/mips/tm-mips.h	8 Aug 2002 22:44:46 -0000	1.29
--- config/mips/tm-mips.h	9 Aug 2002 00:24:27 -0000
*************** extern void mips_find_saved_regs (struct
*** 325,335 ****
     function calls.  We don't need STACK_ALIGN, PUSH_ARGUMENTS will
     handle it. */
  
- extern CORE_ADDR mips_push_arguments (int, struct value **, CORE_ADDR, int,
- 				      CORE_ADDR);
- #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
-   (mips_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr)))
- 
  extern CORE_ADDR mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp);
  #define PUSH_RETURN_ADDRESS(PC, SP) (mips_push_return_address ((PC), (SP)))
  
--- 325,330 ----

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

* Re: [RFA] mips_push_arguments gdbarch-ified
  2002-08-08 17:29 [RFA] mips_push_arguments gdbarch-ified Michael Snyder
@ 2002-08-08 20:51 ` Andrew Cagney
  2002-08-09 18:10   ` Michael Snyder
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2002-08-08 20:51 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches

> These changes fix 16 testsuite failures, based in the Irix native 
> compiler running with -n32 (and produce no regressions for -o32).

Yes, with tweaks.

General comment.  You may want to consider restructuring the function to 
read:

for (argument in arguments)
   for (argument broken down in to 8 byte chunks)
     if (fp argument && fnpreg <= num fp arg regs)
       write argument chunk to fp register
     else if (!fp argument && reg <= num arg regs)
       write chunk (carefully aligned) to gp register
     else
       write chunk to (carefully aligned) memory



The comment below out of date.  Both n32 and n64 require quad word (4x32 
== 128 bit) alignment.

> +   /* First ensure that the stack and structure return address (if any)
> +      are properly aligned.  The stack has to be at least 64-bit
> +      aligned even on 32-bit machines, because doubles must be 64-bit
> +      aligned.  On at least one MIPS variant, stack frames need to be
> +      128-bit aligned, so we round to this widest known alignment.  */



No need to refer to EABI.

> +   /* Now make space on the stack for the args.  We allocate more
> +      than necessary for EABI, because the first few arguments are
> +      passed in registers, but that's OK.  */


> +   for (argnum = 0; argnum < nargs; argnum++)
> +     len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
> + 		     MIPS_STACK_ARGSIZE);
> +   sp -= ROUND_UP (len, 16);
> + 
> +   if (mips_debug)
> +     fprintf_unfiltered (gdb_stdlog, 
> + 			"mips_push_arguments: sp=0x%lx allocated %d\n",

mips_n32n64_... et.al.



> + 			(long) sp, ROUND_UP (len, 16));

Might as well use ``paddr_nz (s)''. et.al.



> + 
> +   /* Initialize the integer and float register pointers.  */
> +   argreg = A0_REGNUM;
> +   float_argreg = FPA0_REGNUM;
> + 
> +   /* the struct_return pointer occupies the first parameter-passing reg */
> +   if (struct_return)
> +     {
> +       if (mips_debug)
> + 	fprintf_unfiltered (gdb_stdlog,
> + 			    "mips_push_arguments: struct_return reg=%d 0x%lx\n",
> + 			    argreg, (long) struct_addr);
> +       write_register (argreg++, struct_addr);



This can go.  n32n64 registers do not have homes.

> +       if (MIPS_REGS_HAVE_HOME_P)
> + 	stack_offset += MIPS_STACK_ARGSIZE;


> +     }
> + 
> +   /* Now load as many as possible of the first arguments into
> +      registers, and push the rest onto the stack.  Loop thru args
> +      from first to last.  */
> +   for (argnum = 0; argnum < nargs; argnum++)
> +     {
> +       char *val;
> +       char valbuf[MAX_REGISTER_RAW_SIZE];

... = alloca (MAX_REGISTER_RAW_SIZE);



> +       struct value *arg = args[argnum];
> +       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
> +       int len = TYPE_LENGTH (arg_type);
> +       enum type_code typecode = TYPE_CODE (arg_type);
> + 
> +       if (mips_debug)
> + 	fprintf_unfiltered (gdb_stdlog,
> + 			    "mips_push_arguments: %d len=%d type=%d",
> + 			    argnum + 1, len, (int) typecode);
> + 
> +       val = (char *) VALUE_CONTENTS (arg);



The below can go.  It only applies to o32 ...

> +       /* 32-bit ABIs always start floating point arguments in an
> +          even-numbered floating point register.  Round the FP register
> +          up before the check to see if there are any FP registers
> +          left.  Non MIPS_EABI targets also pass the FP in the integer
> +          registers so also round up normal registers.  */
> +       if (!FP_REGISTER_DOUBLE
> + 	  && fp_register_arg_p (typecode, arg_type))
> + 	{
> + 	  if ((float_argreg & 1))
> + 	    float_argreg++;
> + 	}




The below can go, it doesn't apply to n32/n64.

> +       /* Floating point arguments passed in registers have to be
> +          treated specially.  On 32-bit architectures, doubles
> +          are passed in register pairs; the even register gets
> +          the low word, and the odd register gets the high word.
> +          On non-EABI processors, the first two floating point arguments are
> +          also copied to general registers, because MIPS16 functions
> +          don't use float registers for arguments.  This duplication of
> +          arguments in general registers can't hurt non-MIPS16 functions
> +          because those registers are normally skipped.  */


> +       if (fp_register_arg_p (typecode, arg_type)
> + 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
> + 	{



The entire if() below can be zapped.  FP_REGISTER_DOUBLE is true.
(if someone is stupid to try to use n32/n64 on a MIPS1 then they loose :-)

> + 	  if (!FP_REGISTER_DOUBLE && len == 8)
> + 	    {
> + 	      int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
> + 	      unsigned long regval;



That will leave just this else clause ...

> + 	  else
> + 	    {
> + 	      /* This is a floating point value that fits entirely
> + 	         in a single register.  */
> + 	      /* On 32 bit ABI's the float_argreg is further adjusted
> +                  above to ensure that it is even register aligned.  */
> + 	      LONGEST regval = extract_unsigned_integer (val, len);
> + 	      if (mips_debug)
> + 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
> + 				    float_argreg, phex (regval, len));
> + 	      write_register (float_argreg++, regval);



My comment is wrong and should be deleted.  n32 uses every register.

> + 	      /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
> + 		 registers for each argument.  The below is (my
> + 		 guess) to ensure that the corresponding integer
> + 		 register has reserved the same space.  */

> + 	      if (mips_debug)
> + 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
> + 				    argreg, phex (regval, len));
> + 	      write_register (argreg, regval);



Since FP_REGISTER_DOUBLE is true, this can be simplified.

> + 	      argreg += FP_REGISTER_DOUBLE ? 1 : 2;
> + 	    }



The below can go.  n32n64 do not have a home for the registers used as 
parameters.

> + 	  /* Reserve space for the FP register.  */
> + 	  if (MIPS_REGS_HAVE_HOME_P)
> + 	    stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
> + 	}



> +       else
> + 	{
> + 	  /* Copy the argument to general registers or the stack in
> + 	     register-sized pieces.  Large arguments are split between
> + 	     registers and stack.  */
> + 	  /* Note: structs whose size is not a multiple of MIPS_REGSIZE
> + 	     are treated specially: Irix cc passes them in registers
> + 	     where gcc sometimes puts them on the stack.  For maximum
> + 	     compatibility, we will put them in both places.  */
> + 	  int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
> + 				  (len % MIPS_SAVED_REGSIZE != 0));
> + 	  /* Note: Floating-point values that didn't fit into an FP
> +              register are only written to memory.  */
> + 	  while (len > 0)
> + 	    {
> + 	      /* Rememer if the argument was written to the stack.  */
> + 	      int stack_used_p = 0;
> + 	      int partial_len = len < MIPS_SAVED_REGSIZE ? 
> + 		len : MIPS_SAVED_REGSIZE;


> + 
> + 	      if (mips_debug)
> + 		fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
> + 				    partial_len);


I believe the below if is wrong.   It should only write to the stack 
when something like:

	!fp_register_arg && argreg > MIPS_LAST_ARG_REGNUM
|| fpregister_arg && fpreg > LAST_FPREGNUM

Odd sized_structs are put in registers (gcc might not though :-()

> + 	      /* Write this portion of the argument to the stack.  */
> + 	      if (argreg > MIPS_LAST_ARG_REGNUM
> + 		  || odd_sized_struct
> + 		  || fp_register_arg_p (typecode, arg_type))


> + 		  write_memory (addr, val, partial_len);
> + 		}



See suggestion at start about re-structuring the code.


> + 	      /* Note!!! This is NOT an else clause.  Odd sized
> + 	         structs may go thru BOTH paths.  Floating point
> + 	         arguments will not.  */
> + 	      /* Write this portion of the argument to a general
> +                  purpose register.  */
> + 	      if (argreg <= MIPS_LAST_ARG_REGNUM
> + 		  && !fp_register_arg_p (typecode, arg_type))

> + 		{
> + 		  LONGEST regval = extract_unsigned_integer (val, partial_len);
> + 
> + 		  /* A non-floating-point argument being passed in a
> + 		     general register.  If a struct or union, and if
> + 		     the remaining length is smaller than the register
> + 		     size, we have to adjust the register value on
> + 		     big endian targets.
> + 
> + 		     It does not seem to be necessary to do the
> + 		     same for integral types.
> + 
> + 		     cagney/2001-07-23: gdb/179: Also, GCC, when
> + 		     outputting LE O32 with sizeof (struct) <
> + 		     MIPS_SAVED_REGSIZE, generates a left shift as
> + 		     part of storing the argument in a register a
> + 		     register (the left shift isn't generated when
> + 		     sizeof (struct) >= MIPS_SAVED_REGSIZE).  Since it
> + 		     is quite possible that this is GCC contradicting
> + 		     the LE/O32 ABI, GDB has not been adjusted to
> + 		     accommodate this.  Either someone needs to
> + 		     demonstrate that the LE/O32 ABI specifies such a
> + 		     left shift OR this new ABI gets identified as
> + 		     such and GDB gets tweaked accordingly.  */
> + 
> + 		  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
> + 		      && partial_len < MIPS_SAVED_REGSIZE
> + 		      && (typecode == TYPE_CODE_STRUCT ||
> + 			  typecode == TYPE_CODE_UNION))
> + 		    regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
> + 				TARGET_CHAR_BIT);
> + 
> + 		  if (mips_debug)
> + 		    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
> + 				      argreg,
> + 				      phex (regval, MIPS_SAVED_REGSIZE));
> + 		  write_register (argreg, regval);
> + 		  argreg++;


The below is wrong for n32/n64.  Even when the general registers have 
run out, FP registers continue to be filled in.

> + 		  /* Prevent subsequent floating point arguments from
> + 		     being passed in floating point registers.  */
> + 		  float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
> + 		}
> + 
> + 	      len -= partial_len;
> + 	      val += partial_len;



> + 	      /* Compute the the offset into the stack at which we
> + 		 will copy the next parameter.
> + 
> + 		 In older ABIs, the caller reserved space for
> + 		 registers that contained arguments.  This was loosely
> + 		 refered to as their "home".  Consequently, space is
> + 		 always allocated.
> + 
> + 	         In N32, the stack_offset only needs to be adjusted
> + 	         when it has been used.  FIXME is this true?  */
> + 
> + 	      if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
> + 		stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
> + 	    }
> + 	}
> +       if (mips_debug)
> + 	fprintf_unfiltered (gdb_stdlog, "\n");
> +     }
> + 
> +   /* Return adjusted stack pointer.  */
> +   return sp;
> + }

Andrew


PS: Not sure what happened here:

> *************** return_value_location (struct type *valt
> *** 3612,3618 ****
>   	  lo->reg_offset = MIPS_SAVED_REGSIZE - len;
>   	  lo->len = len;
>   	  hi->reg_offset = 0;
> ! 	  hi->len = 0;
>   	}
>         else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
>   	       && len > MIPS_SAVED_REGSIZE	/* odd-size structs */
> --- 3910,3916 ----
>   	  lo->reg_offset = MIPS_SAVED_REGSIZE - len;
>   	  lo->len = len;
>   	  hi->reg_offset = 0;
> !   	  hi->len = 0;
>   	}
>         else if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
>   	       && len > MIPS_SAVED_REGSIZE	/* odd-size structs */


Andrew



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

* Re: [RFA] mips_push_arguments gdbarch-ified
  2002-08-08 20:51 ` Andrew Cagney
@ 2002-08-09 18:10   ` Michael Snyder
  2002-08-09 19:36     ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Michael Snyder @ 2002-08-09 18:10 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: gdb-patches

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

Andrew Cagney wrote:
> 
> > These changes fix 16 testsuite failures, based in the Irix native
> > compiler running with -n32 (and produce no regressions for -o32).
> 
> Yes, with tweaks.
> 
> General comment.  You may want to consider restructuring the function to
> read:
> 
> for (argument in arguments)
>    for (argument broken down in to 8 byte chunks)
>      if (fp argument && fnpreg <= num fp arg regs)
>        write argument chunk to fp register
>      else if (!fp argument && reg <= num arg regs)
>        write chunk (carefully aligned) to gp register
>      else
>        write chunk to (carefully aligned) memory

OK, I've checked in, with all of your tweaks except for the above.
Come on, you can't ask me to restructure the whole function  just
to get what was originally a 5-line change in!!!    ;-)

As it is, I've fixed a bunch of bugs that weren't mine, 
just to get this in.  Diffs that went in attached below.

[-- Attachment #2: patch5c.diff --]
[-- Type: text/plain, Size: 20341 bytes --]

2002-08-09  Michael Snyder  <msnyder@redhat.com>

	* mips-tdep.c (ROUND_DOWN, ROUND_UP): Move to global scope.
	(mips_push_arguments): Correct some comments.  Use paddr_nz
	for printing addresses in debug output.  Replace static
	allocation using MAX_REGISTER_RAW_SIZE with alloca.
	(mips_n32n64_push_arguments): New function, cloned from
	mips_push_arguments and tuned for the n32/n64 ABI.
	(mips_push_register): Buffer needs dynamic allocation.
	(mips_print_register): Ditto.
	(do_gp_register_row): Ditto.
	(mips_store_return_value): Ditto.
	(mips_gdbarch_init): Set gdbarch_push_arguments per ABI.

Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.97
diff -c -3 -p -r1.97 mips-tdep.c
*** mips-tdep.c	9 Aug 2002 21:58:14 -0000	1.97
--- mips-tdep.c	10 Aug 2002 00:26:50 -0000
*************** mips_type_needs_double_align (struct typ
*** 2443,2448 ****
--- 2443,2454 ----
    return 0;
  }
  
+ /* Macros to round N up or down to the next A boundary; 
+    A must be a power of two.  */
+ 
+ #define ROUND_DOWN(n,a) ((n) & ~((a)-1))
+ #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+ 
  CORE_ADDR
  mips_push_arguments (int nargs,
  		     struct value **args,
*************** mips_push_arguments (int nargs,
*** 2457,2472 ****
    int stack_offset = 0;
    struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  
-   /* Macros to round N up or down to the next A boundary; A must be
-      a power of two. */
- #define ROUND_DOWN(n,a) ((n) & ~((a)-1))
- #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
- 
    /* First ensure that the stack and structure return address (if any)
!      are properly aligned. The stack has to be at least 64-bit aligned
!      even on 32-bit machines, because doubles must be 64-bit aligned.
!      On at least one MIPS variant, stack frames need to be 128-bit
!      aligned, so we round to this widest known alignment. */
    sp = ROUND_DOWN (sp, 16);
    struct_addr = ROUND_DOWN (struct_addr, 16);
  
--- 2463,2474 ----
    int stack_offset = 0;
    struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  
    /* First ensure that the stack and structure return address (if any)
!      are properly aligned.  The stack has to be at least 64-bit
!      aligned even on 32-bit machines, because doubles must be 64-bit
!      aligned.  For n32 and n64, stack frames need to be 128-bit
!      aligned, so we round to this widest known alignment.  */
! 
    sp = ROUND_DOWN (sp, 16);
    struct_addr = ROUND_DOWN (struct_addr, 16);
  
*************** mips_push_arguments (int nargs,
*** 2478,2485 ****
    sp -= ROUND_UP (len, 16);
  
    if (mips_debug)
!     fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%lx allocated %d\n",
! 			(long) sp, ROUND_UP (len, 16));
  
    /* Initialize the integer and float register pointers.  */
    argreg = A0_REGNUM;
--- 2480,2487 ----
    sp -= ROUND_UP (len, 16);
  
    if (mips_debug)
!     fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%s allocated %d\n",
! 			paddr_nz (sp), ROUND_UP (len, 16));
  
    /* Initialize the integer and float register pointers.  */
    argreg = A0_REGNUM;
*************** mips_push_arguments (int nargs,
*** 2490,2497 ****
      {
        if (mips_debug)
  	fprintf_unfiltered (gdb_stdlog,
! 			    "mips_push_arguments: struct_return reg=%d 0x%lx\n",
! 			    argreg, (long) struct_addr);
        write_register (argreg++, struct_addr);
        if (MIPS_REGS_HAVE_HOME_P)
  	stack_offset += MIPS_STACK_ARGSIZE;
--- 2492,2499 ----
      {
        if (mips_debug)
  	fprintf_unfiltered (gdb_stdlog,
! 			    "mips_push_arguments: struct_return reg=%d 0x%s\n",
! 			    argreg, paddr_nz (struct_addr));
        write_register (argreg++, struct_addr);
        if (MIPS_REGS_HAVE_HOME_P)
  	stack_offset += MIPS_STACK_ARGSIZE;
*************** mips_push_arguments (int nargs,
*** 2503,2509 ****
    for (argnum = 0; argnum < nargs; argnum++)
      {
        char *val;
!       char valbuf[MAX_REGISTER_RAW_SIZE];
        struct value *arg = args[argnum];
        struct type *arg_type = check_typedef (VALUE_TYPE (arg));
        int len = TYPE_LENGTH (arg_type);
--- 2505,2511 ----
    for (argnum = 0; argnum < nargs; argnum++)
      {
        char *val;
!       char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
        struct value *arg = args[argnum];
        struct type *arg_type = check_typedef (VALUE_TYPE (arg));
        int len = TYPE_LENGTH (arg_type);
*************** mips_push_arguments (int nargs,
*** 2675,2684 ****
  
  		  if (mips_debug)
  		    {
! 		      fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%lx",
! 					  (long) stack_offset);
! 		      fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%lx",
! 					  (long) longword_offset);
  		    }
  
  		  addr = sp + stack_offset + longword_offset;
--- 2677,2686 ----
  
  		  if (mips_debug)
  		    {
! 		      fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
! 					  paddr_nz (stack_offset));
! 		      fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
! 					  paddr_nz (longword_offset));
  		    }
  
  		  addr = sp + stack_offset + longword_offset;
*************** mips_push_arguments (int nargs,
*** 2686,2695 ****
  		  if (mips_debug)
  		    {
  		      int i;
! 		      fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
  		      for (i = 0; i < partial_len; i++)
  			{
! 			  fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff);
  			}
  		    }
  		  write_memory (addr, val, partial_len);
--- 2688,2699 ----
  		  if (mips_debug)
  		    {
  		      int i;
! 		      fprintf_unfiltered (gdb_stdlog, " @0x%s ", 
! 					  paddr_nz (addr));
  		      for (i = 0; i < partial_len; i++)
  			{
! 			  fprintf_unfiltered (gdb_stdlog, "%02x", 
! 					      val[i] & 0xff);
  			}
  		    }
  		  write_memory (addr, val, partial_len);
*************** mips_push_arguments (int nargs,
*** 2780,2785 ****
--- 2784,3013 ----
  }
  
  CORE_ADDR
+ mips_n32n64_push_arguments (int nargs,
+ 			    struct value **args,
+ 			    CORE_ADDR sp,
+ 			    int struct_return,
+ 			    CORE_ADDR struct_addr)
+ {
+   int argreg;
+   int float_argreg;
+   int argnum;
+   int len = 0;
+   int stack_offset = 0;
+ 
+   /* First ensure that the stack and structure return address (if any)
+      are properly aligned.  The stack has to be at least 64-bit
+      aligned even on 32-bit machines, because doubles must be 64-bit
+      aligned.  For n32 and n64, stack frames need to be 128-bit
+      aligned, so we round to this widest known alignment.  */
+ 
+   sp = ROUND_DOWN (sp, 16);
+   struct_addr = ROUND_DOWN (struct_addr, 16);
+ 
+   /* Now make space on the stack for the args.  */
+   for (argnum = 0; argnum < nargs; argnum++)
+     len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
+ 		     MIPS_STACK_ARGSIZE);
+   sp -= ROUND_UP (len, 16);
+ 
+   if (mips_debug)
+     fprintf_unfiltered (gdb_stdlog, 
+ 			"mips_n32n64_push_arguments: sp=0x%s allocated %d\n",
+ 			paddr_nz (sp), ROUND_UP (len, 16));
+ 
+   /* Initialize the integer and float register pointers.  */
+   argreg = A0_REGNUM;
+   float_argreg = FPA0_REGNUM;
+ 
+   /* the struct_return pointer occupies the first parameter-passing reg */
+   if (struct_return)
+     {
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog,
+ 			    "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n",
+ 			    argreg, paddr_nz (struct_addr));
+       write_register (argreg++, struct_addr);
+     }
+ 
+   /* Now load as many as possible of the first arguments into
+      registers, and push the rest onto the stack.  Loop thru args
+      from first to last.  */
+   for (argnum = 0; argnum < nargs; argnum++)
+     {
+       char *val;
+       char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+       struct value *arg = args[argnum];
+       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+       int len = TYPE_LENGTH (arg_type);
+       enum type_code typecode = TYPE_CODE (arg_type);
+ 
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog,
+ 			    "mips_n32n64_push_arguments: %d len=%d type=%d",
+ 			    argnum + 1, len, (int) typecode);
+ 
+       val = (char *) VALUE_CONTENTS (arg);
+ 
+       if (fp_register_arg_p (typecode, arg_type)
+ 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ 	{
+ 	  /* This is a floating point value that fits entirely
+ 	     in a single register.  */
+ 	  /* On 32 bit ABI's the float_argreg is further adjusted
+ 	     above to ensure that it is even register aligned.  */
+ 	  LONGEST regval = extract_unsigned_integer (val, len);
+ 	  if (mips_debug)
+ 	    fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ 				float_argreg, phex (regval, len));
+ 	  write_register (float_argreg++, regval);
+ 
+ 	  if (mips_debug)
+ 	    fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ 				argreg, phex (regval, len));
+ 	  write_register (argreg, regval);
+ 	  argreg += 1;
+ 	}
+       else
+ 	{
+ 	  /* Copy the argument to general registers or the stack in
+ 	     register-sized pieces.  Large arguments are split between
+ 	     registers and stack.  */
+ 	  /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ 	     are treated specially: Irix cc passes them in registers
+ 	     where gcc sometimes puts them on the stack.  For maximum
+ 	     compatibility, we will put them in both places.  */
+ 	  int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+ 				  (len % MIPS_SAVED_REGSIZE != 0));
+ 	  /* Note: Floating-point values that didn't fit into an FP
+              register are only written to memory.  */
+ 	  while (len > 0)
+ 	    {
+ 	      /* Rememer if the argument was written to the stack.  */
+ 	      int stack_used_p = 0;
+ 	      int partial_len = len < MIPS_SAVED_REGSIZE ? 
+ 		len : MIPS_SAVED_REGSIZE;
+ 
+ 	      if (mips_debug)
+ 		fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ 				    partial_len);
+ 
+ 	      /* Write this portion of the argument to the stack.  */
+ 	      if (argreg > MIPS_LAST_ARG_REGNUM
+ 		  || odd_sized_struct
+ 		  || fp_register_arg_p (typecode, arg_type))
+ 		{
+ 		  /* Should shorter than int integer values be
+ 		     promoted to int before being stored? */
+ 		  int longword_offset = 0;
+ 		  CORE_ADDR addr;
+ 		  stack_used_p = 1;
+ 		  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ 		    {
+ 		      if (MIPS_STACK_ARGSIZE == 8 &&
+ 			  (typecode == TYPE_CODE_INT ||
+ 			   typecode == TYPE_CODE_PTR ||
+ 			   typecode == TYPE_CODE_FLT) && len <= 4)
+ 			longword_offset = MIPS_STACK_ARGSIZE - len;
+ 		      else if ((typecode == TYPE_CODE_STRUCT ||
+ 				typecode == TYPE_CODE_UNION) &&
+ 			       TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
+ 			longword_offset = MIPS_STACK_ARGSIZE - len;
+ 		    }
+ 
+ 		  if (mips_debug)
+ 		    {
+ 		      fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ 					  paddr_nz (stack_offset));
+ 		      fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ 					  paddr_nz (longword_offset));
+ 		    }
+ 
+ 		  addr = sp + stack_offset + longword_offset;
+ 
+ 		  if (mips_debug)
+ 		    {
+ 		      int i;
+ 		      fprintf_unfiltered (gdb_stdlog, " @0x%s ", 
+ 					  paddr_nz (addr));
+ 		      for (i = 0; i < partial_len; i++)
+ 			{
+ 			  fprintf_unfiltered (gdb_stdlog, "%02x", 
+ 					      val[i] & 0xff);
+ 			}
+ 		    }
+ 		  write_memory (addr, val, partial_len);
+ 		}
+ 
+ 	      /* Note!!! This is NOT an else clause.  Odd sized
+ 	         structs may go thru BOTH paths.  Floating point
+ 	         arguments will not.  */
+ 	      /* Write this portion of the argument to a general
+                  purpose register.  */
+ 	      if (argreg <= MIPS_LAST_ARG_REGNUM
+ 		  && !fp_register_arg_p (typecode, arg_type))
+ 		{
+ 		  LONGEST regval = extract_unsigned_integer (val, partial_len);
+ 
+ 		  /* A non-floating-point argument being passed in a
+ 		     general register.  If a struct or union, and if
+ 		     the remaining length is smaller than the register
+ 		     size, we have to adjust the register value on
+ 		     big endian targets.
+ 
+ 		     It does not seem to be necessary to do the
+ 		     same for integral types.
+ 
+ 		     cagney/2001-07-23: gdb/179: Also, GCC, when
+ 		     outputting LE O32 with sizeof (struct) <
+ 		     MIPS_SAVED_REGSIZE, generates a left shift as
+ 		     part of storing the argument in a register a
+ 		     register (the left shift isn't generated when
+ 		     sizeof (struct) >= MIPS_SAVED_REGSIZE).  Since it
+ 		     is quite possible that this is GCC contradicting
+ 		     the LE/O32 ABI, GDB has not been adjusted to
+ 		     accommodate this.  Either someone needs to
+ 		     demonstrate that the LE/O32 ABI specifies such a
+ 		     left shift OR this new ABI gets identified as
+ 		     such and GDB gets tweaked accordingly.  */
+ 
+ 		  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ 		      && partial_len < MIPS_SAVED_REGSIZE
+ 		      && (typecode == TYPE_CODE_STRUCT ||
+ 			  typecode == TYPE_CODE_UNION))
+ 		    regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
+ 				TARGET_CHAR_BIT);
+ 
+ 		  if (mips_debug)
+ 		    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ 				      argreg,
+ 				      phex (regval, MIPS_SAVED_REGSIZE));
+ 		  write_register (argreg, regval);
+ 		  argreg++;
+ 		}
+ 
+ 	      len -= partial_len;
+ 	      val += partial_len;
+ 
+ 	      /* Compute the the offset into the stack at which we
+ 		 will copy the next parameter.
+ 
+ 	         In N32 (N64?), the stack_offset only needs to be
+ 	         adjusted when it has been used.  */
+ 
+ 	      if (stack_used_p)
+ 		stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ 	    }
+ 	}
+       if (mips_debug)
+ 	fprintf_unfiltered (gdb_stdlog, "\n");
+     }
+ 
+   /* Return adjusted stack pointer.  */
+   return sp;
+ }
+ 
+ CORE_ADDR
  mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
  {
    /* Set the return address register to point to the entry
*************** mips_push_return_address (CORE_ADDR pc, 
*** 2791,2797 ****
  static void
  mips_push_register (CORE_ADDR * sp, int regno)
  {
!   char buffer[MAX_REGISTER_RAW_SIZE];
    int regsize;
    int offset;
    if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
--- 3019,3025 ----
  static void
  mips_push_register (CORE_ADDR * sp, int regno)
  {
!   char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
    int regsize;
    int offset;
    if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
*************** mips_read_fp_register_double (int regno,
*** 3070,3076 ****
  static void
  mips_print_register (int regnum, int all)
  {
!   char raw_buffer[MAX_REGISTER_RAW_SIZE];
  
    /* Get the data in raw format.  */
    if (!frame_register_read (selected_frame, regnum, raw_buffer))
--- 3298,3304 ----
  static void
  mips_print_register (int regnum, int all)
  {
!   char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
  
    /* Get the data in raw format.  */
    if (!frame_register_read (selected_frame, regnum, raw_buffer))
*************** mips_print_register (int regnum, int all
*** 3087,3093 ****
  	  || mips2_fp_compat ())
        && !((regnum - FP0_REGNUM) & 1))
      {
!       char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
  
        mips_read_fp_register_double (regnum, dbuffer);
  
--- 3315,3321 ----
  	  || mips2_fp_compat ())
        && !((regnum - FP0_REGNUM) & 1))
      {
!       char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
  
        mips_read_fp_register_double (regnum, dbuffer);
  
*************** static int
*** 3222,3228 ****
  do_gp_register_row (int regnum)
  {
    /* do values for GP (int) regs */
!   char raw_buffer[MAX_REGISTER_RAW_SIZE];
    int ncols = (MIPS_REGSIZE == 8 ? 4 : 8);	/* display cols per row */
    int col, byte;
    int start_regnum = regnum;
--- 3450,3456 ----
  do_gp_register_row (int regnum)
  {
    /* do values for GP (int) regs */
!   char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
    int ncols = (MIPS_REGSIZE == 8 ? 4 : 8);	/* display cols per row */
    int col, byte;
    int start_regnum = regnum;
*************** mips_extract_return_value (struct type *
*** 3715,3721 ****
  void
  mips_store_return_value (struct type *valtype, char *valbuf)
  {
!   char raw_buffer[MAX_REGISTER_RAW_SIZE];
    struct return_value_word lo;
    struct return_value_word hi;
    return_value_location (valtype, &hi, &lo);
--- 3943,3949 ----
  void
  mips_store_return_value (struct type *valtype, char *valbuf)
  {
!   char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
    struct return_value_word lo;
    struct return_value_word hi;
    return_value_location (valtype, &hi, &lo);
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4547,4552 ****
--- 4775,4781 ----
    switch (mips_abi)
      {
      case MIPS_ABI_O32:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 4;
        tdep->mips_default_stack_argsize = 4;
        tdep->mips_fp_register_double = 0;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4564,4569 ****
--- 4793,4799 ----
  					 mips_o32_use_struct_convention);
        break;
      case MIPS_ABI_O64:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4581,4586 ****
--- 4811,4817 ----
  					 mips_o32_use_struct_convention);
        break;
      case MIPS_ABI_EABI32:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 4;
        tdep->mips_default_stack_argsize = 4;
        tdep->mips_fp_register_double = 0;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4598,4603 ****
--- 4829,4835 ----
  					 mips_eabi_use_struct_convention);
        break;
      case MIPS_ABI_EABI64:
+       set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4615,4620 ****
--- 4847,4853 ----
  					 mips_eabi_use_struct_convention);
        break;
      case MIPS_ABI_N32:
+       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4644,4649 ****
--- 4877,4883 ----
  				       mips_n32n64_reg_struct_has_addr);
        break;
      case MIPS_ABI_N64:
+       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
        tdep->mips_default_saved_regsize = 8;
        tdep->mips_default_stack_argsize = 8;
        tdep->mips_fp_register_double = 1;
*************** mips_gdbarch_init (struct gdbarch_info i
*** 4763,4769 ****
    set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words);
    set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words));
    set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
-   set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
    set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
    set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
  
--- 4997,5002 ----
Index: config/mips/tm-mips.h
===================================================================
RCS file: /cvs/src/src/gdb/config/mips/tm-mips.h,v
retrieving revision 1.30
diff -c -3 -p -r1.30 tm-mips.h
*** config/mips/tm-mips.h	8 Aug 2002 23:32:52 -0000	1.30
--- config/mips/tm-mips.h	10 Aug 2002 00:45:43 -0000
*************** extern int mips_frame_num_args (struct f
*** 312,322 ****
     function calls.  We don't need STACK_ALIGN, PUSH_ARGUMENTS will
     handle it. */
  
- extern CORE_ADDR mips_push_arguments (int, struct value **, CORE_ADDR, int,
- 				      CORE_ADDR);
- #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
-   (mips_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr)))
- 
  extern CORE_ADDR mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp);
  #define PUSH_RETURN_ADDRESS(PC, SP) (mips_push_return_address ((PC), (SP)))
  
--- 312,317 ----

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

* Re: [RFA] mips_push_arguments gdbarch-ified
  2002-08-09 18:10   ` Michael Snyder
@ 2002-08-09 19:36     ` Andrew Cagney
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Cagney @ 2002-08-09 19:36 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches

> Andrew Cagney wrote:
> 
>> 
> 
>> > These changes fix 16 testsuite failures, based in the Irix native
>> > compiler running with -n32 (and produce no regressions for -o32).
> 
>> 
>> Yes, with tweaks.
>> 
>> General comment.  You may want to consider restructuring the function to
>> read:
>> 
>> for (argument in arguments)
>>    for (argument broken down in to 8 byte chunks)
>>      if (fp argument && fnpreg <= num fp arg regs)
>>        write argument chunk to fp register
>>      else if (!fp argument && reg <= num arg regs)
>>        write chunk (carefully aligned) to gp register
>>      else
>>        write chunk to (carefully aligned) memory
> 
> 
> OK, I've checked in, with all of your tweaks except for the above.
> Come on, you can't ask me to restructure the whole function  just
> to get what was originally a 5-line change in!!!    ;-)

If you haven't already, look through the document:
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=bks&srch=&fname=/SGI_Developer/Mpro_n32_ABI/sgi_html/ch02.html
which Kevin cited.  The above was based on that.  With the introduction 
of a new mips_n32n64_push_arguments() unction there is an oportunity to 
start with a clean slate.  To be honest, I think taking that oportunity 
will make getting this working much easier! :-)

> As it is, I've fixed a bunch of bugs that weren't mine, 
> just to get this in.  Diffs that went in attached below.

Oops, I didn't mean for you to touch the old mips_push_arguments() code. 
  That can be left to rot.

> 2002-08-09  Michael Snyder  <msnyder@redhat.com>
> 
> 	* mips-tdep.c (ROUND_DOWN, ROUND_UP): Move to global scope.
> 	(mips_push_arguments): Correct some comments.  Use paddr_nz
> 	for printing addresses in debug output.  Replace static
> 	allocation using MAX_REGISTER_RAW_SIZE with alloca.
> 	(mips_n32n64_push_arguments): New function, cloned from
> 	mips_push_arguments and tuned for the n32/n64 ABI.
> 	(mips_push_register): Buffer needs dynamic allocation.
> 	(mips_print_register): Ditto.
> 	(do_gp_register_row): Ditto.
> 	(mips_store_return_value): Ditto.
> 	(mips_gdbarch_init): Set gdbarch_push_arguments per ABI.

ok, thanks
Andrew



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

end of thread, other threads:[~2002-08-10  2:36 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-08 17:29 [RFA] mips_push_arguments gdbarch-ified Michael Snyder
2002-08-08 20:51 ` Andrew Cagney
2002-08-09 18:10   ` Michael Snyder
2002-08-09 19:36     ` Andrew Cagney

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