This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: SH follow up, part 1 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)


Corinna Vinschen writes:
 > On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
 > > I think this patch has too much stuff in it. Can you change it to fix
 > > the gcc abi (the fpu stuff), and then add the rest for the renesas
 > > variant?
 > 
 > Ok, step 1:
 > 

Seems ok, are there diffs in the test results before&after?  Are these
explanations also in the code? If not, can you please add them?


 > - To simplify the sh_push_dummy_call*() functions, I created two helper
 >   functions which took the part of right-justifying values < 4 byte,
 >   called sh_justify_value_in_reg(), and to count the number of bytes
 >   to be allocated on stack for all arguments, called sh_stack_allocsize().
 > 
 > - Two new functions are now used to evaluate the next floating point
 >   register to use for an argument:
 > 
 >   - gcc passes floats in little-endian mode using regsters criss-crossing,
 >     fr5, fr4, fr7, fr6, fr9, fr8 ...  In big-endian mode the order is simple
 >     fr4, fr5, fr6, ...
 > 
 >   - Doubles are passed in even register pairs, fr4/fr5, fr6/fr7, ...
 >     Example:
 > 
 >       void foo(float a, double b, float c);
 > 
 >     a is passed in fr4, b then skips the odd-numbered fr5 register, so it's
 >     passed in fr6/fr7 and c is then passed in the next free register, fr8.
 > 
 > - I renamed the flag `odd_sized_struct' to a more descriptive name,
 >   `pass_on_stack' since the old name does in no way reflect how the
 >   decision about passing on stack or in register is actually made.  The
 >   actual decision is as follows:
 > 
 >   - On FPU CPUs, pass in registers unless the datatype is bigger than 16 bytes.
 > 
 >   - On non-FPU CPUs, no special case exists.
 > 
 >   - On all CPUs, everything else is passed in registers until the argument
 >     registers are filled up, the remaining arguments are passed on stack. 
 >     If an argument doesn't fit entirely in the remaining registers, it's
 >     split between regs and stack as see fit.
 > 
 > - The code and comment that some data is sometimes passed in registers
 >   *and* stack simultaneously is dropped.  That's not how it works.
 > 
 > > Actually this is part of the original port as contributed by Steve
 > > Chamberlain. Is this true of gcc or of the original hitachi abi?
 > 
 > Neither, nor.  It must have been some sort of misunderstanding or a bug
 > in an ancient gcc.  I talked about this with Alexandre Oliva and he has
 > no idea when this has ever been the case for gcc at all.
 > 
 > - Also in sh_push_dummy_call*(), the code which adds 4 for every 4 bytes
 >   managed, is changed from e.g.
 > 
 >     len -= register_size (gdbarch, argreg);
 > 
 >   to
 >   
 >     len -= 4;
 > 
 >   The reason is that the original line is not exactly correct.  It adds the
 >   register_size of the *next* register, not the register actually filled
 >   with data.  Since all data and registers in question are 4 byte regs (and
 >   the target specific code should know that anyway), I've simplified the
 >   affected code.
 > 
 > > I don't like to have harcoded register sizes, if argreg is wrong, is
 > > there a way to get the correct parameter?
 > 
 > All registers are always 4 byte.  It's easy enough and an additional comment
 > would be sufficient.
 > 
 > If you don't like that and want to use register_size correctly in that case,
 > it would have to look like this:
 > 

Yes please.

When you are done with this rewrite, it would be good to pass the file
through gdb_indent.sh.

elena


 > --- sh-tdep.c	2003-09-24 11:29:00.000000000 +0200
 > +++ sh-tdep.c.weia	2003-09-24 11:46:28.000000000 +0200
 > @@ -1046,7 +1046,7@@ sh_push_dummy_call_fpu (struct gdbarch *
 >    struct type *type;
 >    CORE_ADDR regval;
 >    char *val;
 > -  int len;
 > +  int len, reg_size;
 >    int pass_on_stack;
 >  
 >    /* first force sp to a 4-byte alignment */
 > @@ -1098,6 +1098,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  		   && flt_argreg <= FLOAT_ARGLAST_REGNUM)
 >  	    {
 >  	      /* Argument goes in a float argument register.  */
 > +	      reg_size = register_size (gdbarch, flt_argreg);
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 >  	      regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
 > @@ -1105,6 +1106,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  	  else if (argreg <= ARGLAST_REGNUM)
 >  	    {
 >  	      /* there's room in a register */
 > +	      reg_size = register_size (gdbarch, argreg);
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 >  	      regcache_cooked_write_unsigned (regcache, argreg++, regval);
 > @@ -1112,8 +1114,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  	  /* Store the value 4 bytes at a time.  This means that things
 >  	     larger than 4 bytes may go partly in registers and partly
 >  	     on the stack.  */
 > -	  len -= 4;
 > -	  val += 4;
 > +	  len -= reg_size;
 > +	  val += reg_size;
 >  	}
 >      }
 > 
 > Corinna
 > 
 > 
 > ChangeLog:
 > ==========
 > 
 > 	* sh-tdep.c (sh_justify_value_in_reg): New function.
 > 	(sh_stack_allocsize): Ditto.
 > 	(flt_argreg_array): New array used for floating point argument
 > 	passing.
 > 	(sh_init_flt_argreg): New function.
 > 	(sh_next_flt_argreg): Ditto.
 > 	(sh_push_dummy_call_fpu): Simplify. Rename "odd_sized_struct" to
 > 	"pass_on_stack". Use new helper functions.  Accomodate Renesas ABI.
 > 	Fix argument passing strategy.
 > 	(sh_push_dummy_call_nofpu): Ditto.
 > 
 > Index: sh-tdep.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/sh-tdep.c,v
 > retrieving revision 1.141
 > diff -u -p -r1.141 sh-tdep.c
 > --- sh-tdep.c	16 Sep 2003 18:56:35 -0000	1.141
 > +++ sh-tdep.c	24 Sep 2003 09:29:10 -0000
 > @@ -938,6 +938,98 @@ sh_frame_align (struct gdbarch *ignore, 
 >     not displace any of the other arguments passed in via registers R4
 >     to R7.   */
 >  
 > +/* Helper function to justify value in register according to endianess. */
 > +static char *
 > +sh_justify_value_in_reg (struct value *val, int len)
 > +{
 > +  static char valbuf[4];
 > +
 > +  memset (valbuf, 0, sizeof (valbuf)); 
 > +  if (len < 4)
 > +    {
 > +      /* value gets right-justified in the register or stack word */
 > +      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
 > +	memcpy (valbuf + (4 - len), (char *) VALUE_CONTENTS (val), len);
 > +      else
 > +	memcpy (valbuf, (char *) VALUE_CONTENTS (val), len);
 > +      return valbuf;
 > +    }
 > +  return (char *) VALUE_CONTENTS (val);
 > +} 
 > +
 > +/* Helper function to eval number of bytes to allocate on stack. */
 > +static CORE_ADDR
 > +sh_stack_allocsize (int nargs, struct value **args)
 > +{
 > +  int stack_alloc = 0;
 > +  while (nargs-- > 0)
 > +    stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[nargs])) + 3) & ~3);
 > +  return stack_alloc;
 > +}
 > +
 > +/* Helper functions for getting the float arguments right.  Registers usage
 > +   depends on the ABI and the endianess.  The comments should enlighten how
 > +   it's intended to work. */
 > +
 > +/* This array stores which of the float arg registers are already in use. */
 > +static int flt_argreg_array[FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM + 1];
 > +
 > +/* This function just resets the above array to "no reg used so far". */
 > +static void
 > +sh_init_flt_argreg (void)
 > +{
 > +  memset (flt_argreg_array, 0, sizeof flt_argreg_array);
 > +}
 > +
 > +/* This function returns the next register to use for float arg passing.
 > +   It returns either a valid value between FLOAT_ARG0_REGNUM and
 > +   FLOAT_ARGLAST_REGNUM if a register is available, otherwise it returns 
 > +   FLOAT_ARGLAST_REGNUM + 1 to indicate that no register is available.
 > +
 > +   Note that register number 0 in flt_argreg_array corresponds with the
 > +   real float register fr4.  In contrast to FLOAT_ARG0_REGNUM (value is
 > +   29) the parity of the register number is preserved, which is important
 > +   for the double register passing test (see the "argreg & 1" test below). */
 > +static int
 > +sh_next_flt_argreg (int len)
 > +{
 > +  int argreg;
 > +
 > +  /* First search for the next free register. */
 > +  for (argreg = 0; argreg <= FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM; ++argreg)
 > +    if (!flt_argreg_array[argreg])
 > +      break;
 > +
 > +  /* No register left? */
 > +  if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
 > +    return FLOAT_ARGLAST_REGNUM + 1;
 > +
 > +  if (len == 8)
 > +    {
 > +      /* Doubles are always starting in a even register number. */
 > +      if (argreg & 1)
 > +        {
 > +	  flt_argreg_array[argreg] = 1;
 > +
 > +	  ++argreg;
 > +
 > +          /* No register left? */
 > +	  if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
 > +	    return FLOAT_ARGLAST_REGNUM + 1;
 > +	}
 > +      /* Also mark the next register as used. */
 > +      flt_argreg_array[argreg + 1] = 1;
 > +    }
 > +  else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
 > +    {
 > +      /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
 > +      if (!flt_argreg_array[argreg + 1])
 > +	++argreg;
 > +    }
 > +  flt_argreg_array[argreg] = 1;
 > +  return FLOAT_ARG0_REGNUM + argreg;
 > +}
 > +
 >  static CORE_ADDR
 >  sh_push_dummy_call_fpu (struct gdbarch *gdbarch, 
 >  			CORE_ADDR func_addr,
 > @@ -947,15 +1039,15 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  			CORE_ADDR sp, int struct_return,
 >  			CORE_ADDR struct_addr)
 >  {
 > -  int stack_offset, stack_alloc;
 > -  int argreg, flt_argreg;
 > +  int stack_offset = 0;
 > +  int argreg = ARG0_REGNUM;
 > +  int flt_argreg;
 >    int argnum;
 >    struct type *type;
 >    CORE_ADDR regval;
 >    char *val;
 > -  char valbuf[4];
 >    int len;
 > -  int odd_sized_struct;
 > +  int pass_on_stack;
 >  
 >    /* first force sp to a 4-byte alignment */
 >    sp = sh_frame_align (gdbarch, sp);
 > @@ -967,65 +1059,51 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  				    STRUCT_RETURN_REGNUM, 
 >  				    struct_addr);
 >  
 > -  /* Now make sure there's space on the stack */
 > -  for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
 > -    stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
 > -  sp -= stack_alloc;		/* make room on stack for args */
 > +  /* make room on stack for args */
 > +  sp -= sh_stack_allocsize (nargs, args);
 > +
 > +  /* Initialize float argument mechanism. */
 > +  sh_init_flt_argreg ();
 >  
 >    /* Now load as many as possible of the first arguments into
 >       registers, and push the rest onto the stack.  There are 16 bytes
 >       in four registers available.  Loop thru args from first to last.  */
 > -
 > -  argreg = ARG0_REGNUM;
 > -  flt_argreg = FLOAT_ARG0_REGNUM;
 > -  for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
 > +  for (argnum = 0; argnum < nargs; argnum++)
 >      {
 >        type = VALUE_TYPE (args[argnum]);
 >        len = TYPE_LENGTH (type);
 > -      memset (valbuf, 0, sizeof (valbuf));
 > -      if (len < 4)
 > -	{
 > -	  /* value gets right-justified in the register or stack word */
 > -	  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
 > -	    memcpy (valbuf + (4 - len),
 > -		    (char *) VALUE_CONTENTS (args[argnum]), len);
 > -	  else
 > -	    memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
 > -	  val = valbuf;
 > -	}
 > -      else
 > -	val = (char *) VALUE_CONTENTS (args[argnum]);
 > +      val = sh_justify_value_in_reg (args[argnum], len);
 > +
 > +      /* Some decisions have to be made how various types are handled.
 > +         This also differs in different ABIs. */
 > +      pass_on_stack = 0;
 > +      if (len > 16)
 > +        pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
 > +
 > +      /* Find out the next register to use for a floating point value. */
 > +      if (TYPE_CODE (type) == TYPE_CODE_FLT)
 > +        flt_argreg = sh_next_flt_argreg (len);
 >  
 > -      if (len > 4 && (len & 3) != 0)
 > -	odd_sized_struct = 1;	/* Such structs go entirely on stack.  */
 > -      else if (len > 16)
 > -	odd_sized_struct = 1;	/* So do aggregates bigger than 4 words.  */
 > -      else
 > -	odd_sized_struct = 0;
 >        while (len > 0)
 >  	{
 >  	  if ((TYPE_CODE (type) == TYPE_CODE_FLT 
 > -	       && flt_argreg > FLOAT_ARGLAST_REGNUM) 
 > +	       && flt_argreg > FLOAT_ARGLAST_REGNUM)
 >  	      || argreg > ARGLAST_REGNUM
 > -	      || odd_sized_struct)
 > -	    {			
 > -	      /* must go on the stack */
 > +	      || pass_on_stack)
 > +	    {                    
 >  	      write_memory (sp + stack_offset, val, 4);
 >  	      stack_offset += 4;
 >  	    }
 > -	  /* NOTE WELL!!!!!  This is not an "else if" clause!!!
 > -	     That's because some *&^%$ things get passed on the stack
 > -	     AND in the registers!   */
 > -	  if (TYPE_CODE (type) == TYPE_CODE_FLT &&
 > -	      flt_argreg > 0 && flt_argreg <= FLOAT_ARGLAST_REGNUM)
 > +	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
 > +		   && flt_argreg <= FLOAT_ARGLAST_REGNUM)
 >  	    {
 > -	      /* Argument goes in a single-precision fp reg.  */
 > +	      /* Argument goes in a float argument register.  */
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 >  	      regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
 >  	    }
 >  	  else if (argreg <= ARGLAST_REGNUM)
 > -	    {			
 > +	    {
 >  	      /* there's room in a register */
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 > @@ -1034,8 +1112,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  	  /* Store the value 4 bytes at a time.  This means that things
 >  	     larger than 4 bytes may go partly in registers and partly
 >  	     on the stack.  */
 > -	  len -= register_size (gdbarch, argreg);
 > -	  val += register_size (gdbarch, argreg);
 > +	  len -= 4;
 > +	  val += 4;
 >  	}
 >      }
 >  
 > @@ -1057,15 +1135,13 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >  			  CORE_ADDR sp, int struct_return, 
 >  			  CORE_ADDR struct_addr)
 >  {
 > -  int stack_offset, stack_alloc;
 > -  int argreg;
 > +  int stack_offset = 0;
 > +  int argreg = ARG0_REGNUM;
 >    int argnum;
 >    struct type *type;
 >    CORE_ADDR regval;
 >    char *val;
 > -  char valbuf[4];
 >    int len;
 > -  int odd_sized_struct;
 >  
 >    /* first force sp to a 4-byte alignment */
 >    sp = sh_frame_align (gdbarch, sp);
 > @@ -1077,52 +1153,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >  				    STRUCT_RETURN_REGNUM,
 >  				    struct_addr);
 >  
 > -  /* Now make sure there's space on the stack */
 > -  for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++)
 > -    stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
 > -  sp -= stack_alloc;		/* make room on stack for args */
 > +  /* make room on stack for args */
 > +  sp -= sh_stack_allocsize (nargs, args);
 >  
 >    /* Now load as many as possible of the first arguments into
 >       registers, and push the rest onto the stack.  There are 16 bytes
 >       in four registers available.  Loop thru args from first to last.  */
 > -
 > -  argreg = ARG0_REGNUM;
 > -  for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++)
 > -    {
 > +  for (argnum = 0; argnum < nargs; argnum++)
 > +    { 
 >        type = VALUE_TYPE (args[argnum]);
 >        len = TYPE_LENGTH (type);
 > -      memset (valbuf, 0, sizeof (valbuf));
 > -      if (len < 4)
 > -	{
 > -	  /* value gets right-justified in the register or stack word */
 > -	  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
 > -	    memcpy (valbuf + (4 - len),
 > -		    (char *) VALUE_CONTENTS (args[argnum]), len);
 > -	  else
 > -	    memcpy (valbuf, (char *) VALUE_CONTENTS (args[argnum]), len);
 > -	  val = valbuf;
 > -	}
 > -      else
 > -	val = (char *) VALUE_CONTENTS (args[argnum]);
 > +      val = sh_justify_value_in_reg (args[argnum], len);
 >  
 > -      if (len > 4 && (len & 3) != 0)
 > -	odd_sized_struct = 1;	/* such structs go entirely on stack */
 > -      else
 > -	odd_sized_struct = 0;
 >        while (len > 0)
 >  	{
 > -	  if (argreg > ARGLAST_REGNUM
 > -	      || odd_sized_struct)
 > -	    {			
 > -	      /* must go on the stack */
 > +	  if (argreg > ARGLAST_REGNUM)
 > +	    {                   
 >  	      write_memory (sp + stack_offset, val, 4);
 > -	      stack_offset += 4;
 > +	      stack_offset += 4; 
 >  	    }
 > -	  /* NOTE WELL!!!!!  This is not an "else if" clause!!!
 > -	     That's because some *&^%$ things get passed on the stack
 > -	     AND in the registers!   */
 > -	  if (argreg <= ARGLAST_REGNUM)
 > -	    {			
 > +	  else if (argreg <= ARGLAST_REGNUM)
 > +	    {                   
 >  	      /* there's room in a register */
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 > @@ -1131,8 +1182,8 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >  	  /* Store the value 4 bytes at a time.  This means that things
 >  	     larger than 4 bytes may go partly in registers and partly
 >  	     on the stack.  */
 > -	  len -= register_size (gdbarch, argreg);
 > -	  val += register_size (gdbarch, argreg);
 > +	  len -= 4;
 > +	  val += 4;
 >  	}
 >      }
 >  
 > -- 
 > Corinna Vinschen
 > Cygwin Developer
 > Red Hat, Inc.


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