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: [RFA] sh-tdep.c: Fix float handling


Corinna Vinschen writes:
 > Hi,
 > 
 > the below patch solves a problem which was unfortunately hidden by using
 > the sh-hms-sim.exp baseboard file.  Removing the following line from
 > dejagnu/baseboards/sh-hms-sim.exp:
 > 
 >   set_board_info gdb,cannot_call_functions 1
 > 
 > uncovered that the current implementation doesn't get the ABI of floating
 > point CPUs (sh2e, sh3e, sh4) right.
 > 

Please add this expanation as a comment. I find cleared than your
shorter comments. Just add it before the helper function.

>From here....

 > First, in contrast to non-FPU CPUs, arguments are never split between
 > registers and stack.  If an argument doesn't fit in the remaining registers
 > it's always pushed entirely on the stack.  My testing led me to the wrong
 > assumption that just types > 16 bytes are pushed entirely on the stack.
 > 
 > Second, the FPU ABIs have a special way how to treat types as float types.
 > Structures with exactly one member, which is of type float or double, are
 > treated exactly as the base types float or double:
 > 
 >   struct sf {
 >     float f;
 >   };
 > 
 >   struct sd {
 >     double d;
 >   };
 > 
 > are handled the same way as just
 > 
 >   float f;
 > 
 >   double d;
 > 
 > As a result, arguments of these struct types are pushed into floating point
 > registers exactly as floats or doubles, using the same decision algorithm.
 > 
 > The same is valid if these types are used as function return types.  The
 > above structs are returned in fr0 resp. fr0,fr1 instead of in r0, r0,r1
 > or even using struct convention as it is for other structs.
 > 

....to here.

 > The below patch fixes this by adding a helper function sh_treat_as_flt(),

Since this is a predicate, can you call it sh_treat_as_flt_p .

 > which evaluates if a type is treated as float type.  The result of this
 > function is then used in sh_push_dummy_call_fpu(),
 > sh3e_sh4_extract_return_value() and sh3e_sh4_store_return_value() to
 > push resp. return these structs correctly.
 > 
 > Over all, including the sh_use_struct_convention patch send 20 minutes ago
 > the FAIL count is lowered by 1 FAIL on non-FPU ABIs and 5 FAILs on FPU
 > ABIs, but that's only visible when tweaking sh-hms-sim.exp appropriately.
 > 
 
Ok otherwise.

BTW, what multilibs are you testing?

elena


 > 
 > Corinna
 > 
 > 
 > 	* sh-tdep.c (sh_treat_as_flt): New function to recognize float
 > 	types correctly.
 > 	(sh_push_dummy_call_fpu): Fix argument passing rules.
 > 	(sh3e_sh4_extract_return_value): Call sh_treat_as_flt to recognize
 > 	float types.
 > 	(sh3e_sh4_store_return_value): Ditto.
 > 
 > Index: sh-tdep.c
 > ===================================================================
 > RCS file: /cvs/src/src/gdb/sh-tdep.c,v
 > retrieving revision 1.145
 > diff -u -p -r1.145 sh-tdep.c
 > --- sh-tdep.c	3 Oct 2003 08:13:37 -0000	1.145
 > +++ sh-tdep.c	4 Oct 2003 11:32:00 -0000
 > @@ -732,6 +749,33 @@ sh_next_flt_argreg (int len)
 >    return FLOAT_ARG0_REGNUM + argreg;
 >  }
 >  
 > +/* Helper function which figures out, if a type is treated like a float type.
 > +   The FPU based calling conventions (sh2e, sh3e, sh4, ...) are handling
 > +   structs with exactly one member, which is of type float or double the same
 > +   way as a simple float or double.  That determines if such data is passed
 > +   in float or general registers both, as argument or as return value.  */
 > +static int
 > +sh_treat_as_flt (struct type *type)
 > +{
 > +  int len = TYPE_LENGTH (type);
 > +
 > +  /* Ordinary float types are obviously treated as float.  */
 > +  if (TYPE_CODE (type) == TYPE_CODE_FLT)
 > +    return 1;
 > +  /* Otherwise non-struct types are not treated as float.  */
 > +  if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
 > +    return 0;
 > +  /* Otherwise structs with more than one memeber are not treated as float.  */
 > +  if (TYPE_NFIELDS (type) != 1)
 > +    return 0;
 > +  /* Otherwise if the type of that member is float, the whole type is
 > +     treated as float.  */
 > +  if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT)
 > +    return 1;
 > +  /* Otherwise it's not treated as float.  */
 > +  return 0;
 > +}
 > +
 >  static CORE_ADDR
 >  sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
 >  			CORE_ADDR func_addr,
 > @@ -749,7 +793,8 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >    CORE_ADDR regval;
 >    char *val;
 >    int len, reg_size = 0;
 > -  int pass_on_stack;
 > +  int pass_on_stack = 0;
 > +  int treat_as_flt;
 >  
 >    /* first force sp to a 4-byte alignment */
 >    sp = sh_frame_align (gdbarch, sp);
 > @@ -776,43 +821,41 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >        /* 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)
 > +      treat_as_flt = sh_treat_as_flt (type);
 > +      if (treat_as_flt)
 >  	flt_argreg = sh_next_flt_argreg (len);
 > +      /* No data is passed partially in registers.  */
 > +      else if (len > ((ARGLAST_REGNUM - argreg + 1) * 4))
 > +	pass_on_stack = 1;
 >  
 >        while (len > 0)
 >  	{
 > -	  if ((TYPE_CODE (type) == TYPE_CODE_FLT
 > -	       && flt_argreg > FLOAT_ARGLAST_REGNUM)
 > -	      || argreg > ARGLAST_REGNUM || pass_on_stack)
 > +	  if ((treat_as_flt && flt_argreg > FLOAT_ARGLAST_REGNUM)
 > +	      || (!treat_as_flt && (argreg > ARGLAST_REGNUM
 > +	                            || pass_on_stack)))
 >  	    {
 > -	      /* The remainder of the data goes entirely on the stack,
 > -	         4-byte aligned. */
 > +	      /* The data goes entirely on the stack, 4-byte aligned. */
 >  	      reg_size = (len + 3) & ~3;
 >  	      write_memory (sp + stack_offset, val, reg_size);
 >  	      stack_offset += reg_size;
 >  	    }
 > -	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
 > -		   && flt_argreg <= FLOAT_ARGLAST_REGNUM)
 > +	  else if (treat_as_flt && flt_argreg <= FLOAT_ARGLAST_REGNUM)
 >  	    {
 >  	      /* Argument goes in a float argument register.  */
 >  	      reg_size = register_size (gdbarch, flt_argreg);
 >  	      regval = extract_unsigned_integer (val, reg_size);
 >  	      regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
 >  	    }
 > -	  else if (argreg <= ARGLAST_REGNUM)
 > +	  else if (!treat_as_flt && argreg <= ARGLAST_REGNUM)
 >  	    {
 >  	      /* there's room in a register */
 >  	      reg_size = register_size (gdbarch, argreg);
 >  	      regval = extract_unsigned_integer (val, reg_size);
 >  	      regcache_cooked_write_unsigned (regcache, argreg++, regval);
 >  	    }
 > -	  /* Store the value reg_size bytes at a time.  This means that things
 > -	     larger than reg_size bytes may go partly in registers and partly
 > -	     on the stack.  */
 > +	  /* Store the value one register at a time or in one step on stack.  */
 >  	  len -= reg_size;
 >  	  val += reg_size;
 >  	}
 > @@ -930,7 +973,7 @@ static void
 >  sh3e_sh4_extract_return_value (struct type *type, struct regcache *regcache,
 >  			       void *valbuf)
 >  {
 > -  if (TYPE_CODE (type) == TYPE_CODE_FLT)
 > +  if (sh_treat_as_flt (type))
 >      {
 >        int len = TYPE_LENGTH (type);
 >        int i, regnum = FP0_REGNUM;
 > @@ -971,7 +1014,7 @@ static void
 >  sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache,
 >  			     const void *valbuf)
 >  {
 > -  if (TYPE_CODE (type) == TYPE_CODE_FLT)
 > +  if (sh_treat_as_flt (type))
 >      {
 >        int len = TYPE_LENGTH (type);
 >        int i, regnum = FP0_REGNUM;
 > 
 > 
 > 
 > -- 
 > 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]