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


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

[RFA] alpha return value cleanup, type cleanup


I didn't mean to put so much stuff in one patch; I can break it
up if required.  This does several things:

  (1) Update to the regcache based return value methods.

  (2) Use non-language-specific types, eg builtin_type_int64
      instead of builtin_type_long.

  (3) Fix several sign-extension ABI mistakes wrt 32-bit integers.

  (4) Adjust the types assigned to the hard registers.

  (5) Implement complex data types.  Well, GCC's version, not the
      "real" ABI's version.  Fixing GCC has only been possible 
      within the last week or two, and I don't know if I'm going
      to bother given that no one has complained to-date.


Ok?



r~



	* alpha-tdep.c (alpha_register_virtual_type): Set type of
	SP and GP to void_data_ptr; PC to void_func_ptr; floats to
	ieee_double_little; ints to int64.
	(alpha_convert_flt_dbl, alpha_convert_dbl_flt): New.
	(alpha_register_convert_to_virtual): Use alpha-specific constants.
	Use alpha_convert_dbl_flt.
	(alpha_register_convert_to_raw): Similarly.
	(alpha_push_dummy_call): Use non-language-specific types.
	Fix sign-extension of 32-bit ints.  Handle complex values.
	(alpha_extract_return_value): Update to regcache; handle complex.
	(alpha_store_return_value): Likewise.  Fix 32-bit int sign extension.
	(alpha_extract_struct_value_address): Update to regcache.
	(alpha_store_struct_return): Kill.
	(alpha_gdbarch_init): Use non-deprecated return methods.
	* alpha-tdep.h (ALPHA_GP_REGNUM): New.

Index: alpha-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/alpha-tdep.c,v
retrieving revision 1.92
diff -c -p -d -r1.92 alpha-tdep.c
*** alpha-tdep.c	1 Jun 2003 21:46:37 -0000	1.92
--- alpha-tdep.c	2 Jun 2003 01:53:40 -0000
***************
*** 38,43 ****
--- 38,44 ----
  #include "arch-utils.h"
  #include "osabi.h"
  #include "block.h"
+ #include "gdb_assert.h"
  
  #include "elf-bfd.h"
  
*************** alpha_register_convertible (int regno)
*** 88,95 ****
  static struct type *
  alpha_register_virtual_type (int regno)
  {
!   return ((regno >= FP0_REGNUM && regno < (FP0_REGNUM+31))
! 	  ? builtin_type_double : builtin_type_long);
  }
  
  static int
--- 89,105 ----
  static struct type *
  alpha_register_virtual_type (int regno)
  {
!   if (regno == ALPHA_SP_REGNUM || regno == ALPHA_GP_REGNUM)
!     return builtin_type_void_data_ptr;
!   if (regno == ALPHA_PC_REGNUM)
!     return builtin_type_void_func_ptr;
! 
!   /* Don't need to worry about little vs big endian until 
!      some jerk tries to port to alpha-unicosmk.  */
!   if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 31)
!     return builtin_type_ieee_double_little;
! 
!   return builtin_type_int64;
  }
  
  static int
*************** alpha_register_virtual_size (int regno)
*** 117,136 ****
     registers is different. */
  
  static void
  alpha_register_convert_to_virtual (int regnum, struct type *valtype,
  				   char *raw_buffer, char *virtual_buffer)
  {
!   if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
      {
!       memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
        return;
      }
  
    if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
!     {
!       double d = deprecated_extract_floating (raw_buffer, REGISTER_RAW_SIZE (regnum));
!       deprecated_store_floating (virtual_buffer, TYPE_LENGTH (valtype), d);
!     }
    else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
      {
        ULONGEST l;
--- 127,158 ----
     registers is different. */
  
  static void
+ alpha_convert_flt_dbl (void *out, const void *in)
+ {
+   DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_single_little);
+   store_typed_floating (out, builtin_type_ieee_double_little, d);
+ }
+ 
+ static void
+ alpha_convert_dbl_flt (void *out, const void *in)
+ {
+   DOUBLEST d = extract_typed_floating (in, builtin_type_ieee_double_little);
+   store_typed_floating (out, builtin_type_ieee_single_little, d);
+ }
+ 
+ 
+ static void
  alpha_register_convert_to_virtual (int regnum, struct type *valtype,
  				   char *raw_buffer, char *virtual_buffer)
  {
!   if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
      {
!       memcpy (virtual_buffer, raw_buffer, ALPHA_REGISTER_SIZE);
        return;
      }
  
    if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
!     alpha_convert_dbl_flt (virtual_buffer, raw_buffer);
    else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
      {
        ULONGEST l;
*************** static void
*** 146,171 ****
  alpha_register_convert_to_raw (struct type *valtype, int regnum,
  			       char *virtual_buffer, char *raw_buffer)
  {
!   if (TYPE_LENGTH (valtype) >= REGISTER_RAW_SIZE (regnum))
      {
!       memcpy (raw_buffer, virtual_buffer, REGISTER_RAW_SIZE (regnum));
        return;
      }
  
    if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
!     {
!       double d = deprecated_extract_floating (virtual_buffer, TYPE_LENGTH (valtype));
!       deprecated_store_floating (raw_buffer, REGISTER_RAW_SIZE (regnum), d);
!     }
    else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
      {
!       ULONGEST l;
!       if (TYPE_UNSIGNED (valtype))
! 	l = extract_unsigned_integer (virtual_buffer, TYPE_LENGTH (valtype));
!       else
! 	l = extract_signed_integer (virtual_buffer, TYPE_LENGTH (valtype));
        l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
!       store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), l);
      }
    else
      error ("Cannot store value in floating point register");
--- 168,186 ----
  alpha_register_convert_to_raw (struct type *valtype, int regnum,
  			       char *virtual_buffer, char *raw_buffer)
  {
!   if (TYPE_LENGTH (valtype) >= ALPHA_REGISTER_SIZE)
      {
!       memcpy (raw_buffer, virtual_buffer, ALPHA_REGISTER_SIZE);
        return;
      }
  
    if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
!     alpha_convert_flt_dbl (raw_buffer, virtual_buffer);
    else if (TYPE_CODE (valtype) == TYPE_CODE_INT && TYPE_LENGTH (valtype) <= 4)
      {
!       ULONGEST l = unpack_long (valtype, virtual_buffer);
        l = ((l & 0xc0000000) << 32) | ((l & 0x3fffffff) << 29);
!       store_unsigned_integer (raw_buffer, ALPHA_REGISTER_SIZE, l);
      }
    else
      error ("Cannot store value in floating point register");
*************** alpha_push_dummy_call (struct gdbarch *g
*** 225,247 ****
  	case TYPE_CODE_CHAR:
  	case TYPE_CODE_RANGE:
  	case TYPE_CODE_ENUM:
! 	  if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
  	    {
! 	      arg_type = builtin_type_long;
  	      arg = value_cast (arg_type, arg);
  	    }
  	  break;
  	case TYPE_CODE_FLT:
  	  /* "float" arguments loaded in registers must be passed in
  	     register format, aka "double".  */
  	  if (accumulate_size < sizeof (arg_reg_buffer)
  	      && TYPE_LENGTH (arg_type) == 4)
  	    {
! 	      arg_type = builtin_type_double;
  	      arg = value_cast (arg_type, arg);
  	    }
  	  /* Tru64 5.1 has a 128-bit long double, and passes this by
! 	     invisible reference.  No one else uses this data type.  */
  	  else if (TYPE_LENGTH (arg_type) == 16)
  	    {
  	      /* Allocate aligned storage.  */
--- 240,270 ----
  	case TYPE_CODE_CHAR:
  	case TYPE_CODE_RANGE:
  	case TYPE_CODE_ENUM:
! 	  if (TYPE_LENGTH (arg_type) == 4)
  	    {
! 	      /* 32-bit values must be sign-extended to 64 bits
! 		 even if the base data type is unsigned.  */
! 	      arg_type = builtin_type_int32;
! 	      arg = value_cast (arg_type, arg);
! 	    }
! 	  if (TYPE_LENGTH (arg_type) < 8)
! 	    {
! 	      arg_type = builtin_type_int64;
  	      arg = value_cast (arg_type, arg);
  	    }
  	  break;
+ 
  	case TYPE_CODE_FLT:
  	  /* "float" arguments loaded in registers must be passed in
  	     register format, aka "double".  */
  	  if (accumulate_size < sizeof (arg_reg_buffer)
  	      && TYPE_LENGTH (arg_type) == 4)
  	    {
! 	      arg_type = builtin_type_ieee_double_little;
  	      arg = value_cast (arg_type, arg);
  	    }
  	  /* Tru64 5.1 has a 128-bit long double, and passes this by
! 	     invisible reference.  */
  	  else if (TYPE_LENGTH (arg_type) == 16)
  	    {
  	      /* Allocate aligned storage.  */
*************** alpha_push_dummy_call (struct gdbarch *g
*** 255,260 ****
--- 278,305 ----
  	      arg = value_from_pointer (arg_type, sp);
  	    }
  	  break;
+ 
+ 	case TYPE_CODE_COMPLEX:
+ 	  /* ??? The ABI says that complex values are passed as two
+ 	     separate scalar values.  This distinction only matters
+ 	     for complex float.  However, GCC does not implement this.  */
+ 
+ 	  /* Tru64 5.1 has a 128-bit long double, and passes this by
+ 	     invisible reference.  */
+ 	  if (TYPE_LENGTH (arg_type) == 32)
+ 	    {
+ 	      /* Allocate aligned storage.  */
+ 	      sp = (sp & -16) - 16;
+ 
+ 	      /* Write the real data into the stack.  */
+ 	      write_memory (sp, VALUE_CONTENTS (arg), 32);
+ 
+ 	      /* Construct the indirection.  */
+ 	      arg_type = lookup_pointer_type (arg_type);
+ 	      arg = value_from_pointer (arg_type, sp);
+ 	    }
+ 	  break;
+ 
  	default:
  	  break;
  	}
*************** alpha_push_dummy_call (struct gdbarch *g
*** 326,367 ****
    return sp;
  }
  
! /* Given a return value in `regbuf' with a type `valtype', 
!    extract and copy its value into `valbuf'.  */
  
  static void
! alpha_extract_return_value (struct type *valtype,
! 			    char regbuf[ALPHA_REGISTER_BYTES], char *valbuf)
  {
!   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
!     alpha_register_convert_to_virtual (FP0_REGNUM, valtype,
! 				       regbuf + REGISTER_BYTE (FP0_REGNUM),
! 				       valbuf);
!   else
!     memcpy (valbuf, regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
!             TYPE_LENGTH (valtype));
  }
  
! /* Given a return value in `regbuf' with a type `valtype', 
     write its value into the appropriate register.  */
  
  static void
! alpha_store_return_value (struct type *valtype, char *valbuf)
  {
-   char raw_buffer[ALPHA_REGISTER_SIZE];
-   int regnum = ALPHA_V0_REGNUM;
    int length = TYPE_LENGTH (valtype);
  
!   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
      {
!       regnum = FP0_REGNUM;
!       length = ALPHA_REGISTER_SIZE;
!       alpha_register_convert_to_raw (valtype, regnum, valbuf, raw_buffer);
!     }
!   else
!     memcpy (raw_buffer, valbuf, length);
  
!   deprecated_write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, length);
  }
  
  static int
--- 371,539 ----
    return sp;
  }
  
! /* Extract from REGCACHE the value about to be returned from a function
!    and copy it into VALBUF.  */
  
  static void
! alpha_extract_return_value (struct type *valtype, struct regcache *regcache,
! 			    void *valbuf)
  {
!   char raw_buffer[ALPHA_REGISTER_SIZE];
!   ULONGEST l;
!   DOUBLEST d;
! 
!   switch (TYPE_CODE (valtype))
!     {
!     case TYPE_CODE_FLT:
!       switch (TYPE_LENGTH (valtype))
! 	{
! 	case 4:
! 	  regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, raw_buffer);
! 	  alpha_convert_dbl_flt (valbuf, raw_buffer);
! 	  break;
! 
! 	case 8:
! 	  regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  break;
! 
! 	case 16:
! 	  regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
! 	  read_memory (l, valbuf, 16);
! 	  break;
! 
! 	default:
! 	  abort ();
! 	}
!       break;
! 
!     case TYPE_CODE_COMPLEX:
!       switch (TYPE_LENGTH (valtype))
! 	{
! 	case 8:
! 	  /* ??? This isn't correct wrt the ABI, but it's what GCC does.  */
! 	  regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  break;
! 
! 	case 16:
! 	  regcache_cooked_read (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  regcache_cooked_read (regcache, ALPHA_FP0_REGNUM+1,
! 				(char *)valbuf + 8);
! 	  break;
! 
! 	case 32:
! 	  regcache_cooked_read_signed (regcache, ALPHA_V0_REGNUM, &l);
! 	  read_memory (l, valbuf, 32);
! 	  break;
! 
! 	default:
! 	  abort ();
! 	}
!       break;
! 
!     default:
!       /* Assume everything else degenerates to an integer.  */
!       regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &l);
!       store_unsigned_integer (valbuf, TYPE_LENGTH (valtype), l);
!       break;
!     }
  }
  
! /* Extract from REGCACHE the address of a structure about to be returned
!    from a function.  */
! 
! static CORE_ADDR
! alpha_extract_struct_value_address (struct regcache *regcache)
! {
!   ULONGEST addr;
!   regcache_cooked_read_unsigned (regcache, ALPHA_V0_REGNUM, &addr);
!   return addr;
! }
! 
! /* Given a return value in `valbuf' with a type `valtype', 
     write its value into the appropriate register.  */
  
  static void
! alpha_store_return_value (struct type *valtype, struct regcache *regcache,
! 			  const void *valbuf)
  {
    int length = TYPE_LENGTH (valtype);
+   char raw_buffer[2 * ALPHA_REGISTER_SIZE];
+   LONGEST l;
+   DOUBLEST d;
  
!   switch (TYPE_CODE (valtype))
      {
!     case TYPE_CODE_VOID:
!       break;
  
!     case TYPE_CODE_ENUM:
!     case TYPE_CODE_BOOL:
!     case TYPE_CODE_INT:
!     case TYPE_CODE_CHAR:
!     case TYPE_CODE_RANGE:
!       /* 32-bit values must be sign-extended to 64-bits, even if the
! 	 value itself is unsigned.  */
!       if (length == 4)
! 	l = extract_signed_integer (valbuf, length);
!       else
! 	l = unpack_long (valtype, valbuf);
!       regcache_cooked_write_signed (regcache, ALPHA_V0_REGNUM, l);
!       break;
! 
!     case TYPE_CODE_FLT:
!       switch (length)
! 	{
! 	case 4:
! 	  alpha_convert_flt_dbl (raw_buffer, valbuf);
! 	  valbuf = raw_buffer;
! 	  /* FALLTHRU */
! 
! 	case 8:
! 	  regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  break;
! 
! 	case 16:
! 	  /* FIXME: 128-bit long doubles are returned like structures:
! 	     by writing into indirect storage provided by the caller
! 	     as the first argument.  */
! 	  error ("Cannot set a 128-bit long double return value.");
! 
! 	default:
! 	  abort ();
! 	}
!       break;
! 
!     case TYPE_CODE_COMPLEX:
!       switch (length)
! 	{
! 	case 8:
! 	  /* ??? This isn't correct wrt the ABI, but it's what GCC does.  */
! 	  regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  break;
! 
! 	case 16:
! 	  regcache_cooked_write (regcache, ALPHA_FP0_REGNUM, valbuf);
! 	  regcache_cooked_write (regcache, ALPHA_FP0_REGNUM+1,
! 				 (const char *)valbuf + 8);
! 	  break;
! 
! 	case 32:
! 	  /* FIXME: 128-bit long doubles are returned like structures:
! 	     by writing into indirect storage provided by the caller
! 	     as the first argument.  */
! 	  error ("Cannot set a 128-bit long double return value.");
! 
! 	default:
! 	  abort ();
! 	}
!       break;
! 
!     default:
!       /* Assume everything else degenerates to a pointer.  */
!       gdb_assert (length == ALPHA_REGISTER_SIZE);
!       regcache_cooked_write (regcache, ALPHA_V0_REGNUM, valbuf);
!       break;
!     }
  }
  
  static int
*************** alpha_use_struct_convention (int gcc_p, 
*** 371,390 ****
    return 1;
  }
  
- static void
- alpha_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
- {
-   /* Store the address of the place in which to copy the structure the
-      subroutine will return.  Handled by alpha_push_arguments.  */
- }
- 
- static CORE_ADDR
- alpha_extract_struct_value_address (char *regbuf)
- {
-   return (extract_address (regbuf + REGISTER_BYTE (ALPHA_V0_REGNUM),
- 			   REGISTER_RAW_SIZE (ALPHA_V0_REGNUM)));
- }
- 
  
  static const unsigned char *
  alpha_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
--- 543,548 ----
*************** alpha_gdbarch_init (struct gdbarch_info 
*** 1269,1278 ****
                                      generic_frameless_function_invocation_not);
  
    set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention);
!   set_gdbarch_deprecated_extract_return_value (gdbarch, alpha_extract_return_value);
!   set_gdbarch_deprecated_store_struct_return (gdbarch, alpha_store_struct_return);
!   set_gdbarch_deprecated_store_return_value (gdbarch, alpha_store_return_value);
!   set_gdbarch_deprecated_extract_struct_value_address (gdbarch,
  					    alpha_extract_struct_value_address);
  
    /* Settings for calling functions in the inferior.  */
--- 1427,1435 ----
                                      generic_frameless_function_invocation_not);
  
    set_gdbarch_use_struct_convention (gdbarch, alpha_use_struct_convention);
!   set_gdbarch_extract_return_value (gdbarch, alpha_extract_return_value);
!   set_gdbarch_store_return_value (gdbarch, alpha_store_return_value);
!   set_gdbarch_extract_struct_value_address (gdbarch,
  					    alpha_extract_struct_value_address);
  
    /* Settings for calling functions in the inferior.  */
Index: alpha-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/alpha-tdep.h,v
retrieving revision 1.15
diff -c -p -d -r1.15 alpha-tdep.h
*** alpha-tdep.h	1 Jun 2003 21:46:37 -0000	1.15
--- alpha-tdep.h	2 Jun 2003 01:53:40 -0000
***************
*** 43,51 ****
  #define ALPHA_GCC_FP_REGNUM 15  /* Used by gcc as frame register */
  #define ALPHA_A0_REGNUM     16  /* Loc of first arg during a subr call */
  #define ALPHA_T9_REGNUM     23  /* Return address register for OSF/1 __div* */
  #define ALPHA_T12_REGNUM    27  /* Contains start addr of current proc */
  #define ALPHA_SP_REGNUM     30  /* Contains address of top of stack */
- #define ALPHA_RA_REGNUM     26  /* Contains return address value */
  #define ALPHA_ZERO_REGNUM   31  /* Read-only register, always 0 */
  #define ALPHA_FP0_REGNUM    32  /* Floating point register 0 */
  #define ALPHA_FPA0_REGNUM   48  /* First float arg during a subr call */
--- 43,52 ----
  #define ALPHA_GCC_FP_REGNUM 15  /* Used by gcc as frame register */
  #define ALPHA_A0_REGNUM     16  /* Loc of first arg during a subr call */
  #define ALPHA_T9_REGNUM     23  /* Return address register for OSF/1 __div* */
+ #define ALPHA_RA_REGNUM     26  /* Contains return address value */
  #define ALPHA_T12_REGNUM    27  /* Contains start addr of current proc */
+ #define ALPHA_GP_REGNUM     29  /* Contains the global pointer */
  #define ALPHA_SP_REGNUM     30  /* Contains address of top of stack */
  #define ALPHA_ZERO_REGNUM   31  /* Read-only register, always 0 */
  #define ALPHA_FP0_REGNUM    32  /* Floating point register 0 */
  #define ALPHA_FPA0_REGNUM   48  /* First float arg during a subr call */


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