Reviewed and approved by Kevin Buettner <kevinb@redhat.com>
[deliverable/binutils-gdb.git] / gdb / v850-tdep.c
index e1869d04bab8d046266101e818fa02a643d7f649..3752dced66bc804c2af1538a2f7e2a14ab4ed1d5 100644 (file)
@@ -21,7 +21,6 @@
 #include "defs.h"
 #include "frame.h"
 #include "inferior.h"
-#include "obstack.h"
 #include "target.h"
 #include "value.h"
 #include "bfd.h"
@@ -123,6 +122,12 @@ enum
   E_ALL_REGS_SIZE = (E_NUM_REGS) * v850_reg_size
 };
 
+/* Size of return datatype which fits into all return registers. */
+enum
+{
+  E_MAX_RETTYPE_SIZE_IN_REGS = 2 * v850_reg_size
+};
+
 static LONGEST call_dummy_nil[] = {0};
 
 static char *v850_generic_reg_names[] =
@@ -199,7 +204,7 @@ static CORE_ADDR v850_scan_prologue (CORE_ADDR pc, struct prologue_info *fs);
 /* Function: v850_register_name
    Returns the name of the v850/v850e register N. */
 
-static char *
+static const char *
 v850_register_name (int regnum)
 {
   if (regnum < 0 || regnum >= E_NUM_REGS)
@@ -266,11 +271,90 @@ v850_reg_virtual_type (int regnum)
     return builtin_type_int32;
 }
 
+static int
+v850_type_is_scalar (struct type *t)
+{
+  return (TYPE_CODE (t) != TYPE_CODE_STRUCT
+         && TYPE_CODE (t) != TYPE_CODE_UNION
+         && TYPE_CODE (t) != TYPE_CODE_ARRAY);
+}
+
 /* Should call_function allocate stack space for a struct return?  */
-int
+static int
 v850_use_struct_convention (int gcc_p, struct type *type)
 {
-  return (TYPE_NFIELDS (type) > 1 || TYPE_LENGTH (type) > 4);
+  /* According to ABI:
+   * return TYPE_LENGTH (type) > 8);
+   */
+
+  /* Current implementation in gcc: */
+
+  int i;
+  struct type *fld_type, *tgt_type;
+
+  /* 1. The value is greater than 8 bytes -> returned by copying */
+  if (TYPE_LENGTH (type) > 8)
+    return 1;
+
+  /* 2. The value is a single basic type -> returned in register */
+  if (v850_type_is_scalar (type))
+    return 0;
+
+  /* The value is a structure or union with a single element
+   * and that element is either a single basic type or an array of
+   * a single basic type whoes size is greater than or equal to 4
+   * -> returned in register */
+  if ((TYPE_CODE (type) == TYPE_CODE_STRUCT
+       || TYPE_CODE (type) == TYPE_CODE_UNION)
+       && TYPE_NFIELDS (type) == 1)
+    {
+      fld_type = TYPE_FIELD_TYPE (type, 0);
+      if (v850_type_is_scalar (fld_type) && TYPE_LENGTH (fld_type) >= 4)
+       return 0;
+
+      if (TYPE_CODE (fld_type) == TYPE_CODE_ARRAY)
+        {
+         tgt_type = TYPE_TARGET_TYPE (fld_type);
+         if (v850_type_is_scalar (tgt_type) && TYPE_LENGTH (tgt_type) >= 4)
+           return 0;
+       }
+    }
+
+  /* The value is a structure whose first element is an integer or
+   * a float, and which contains no arrays of more than two elements
+   * -> returned in register */
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+      && v850_type_is_scalar (TYPE_FIELD_TYPE (type, 0))
+      && TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == 4)
+    {
+      for (i = 1; i < TYPE_NFIELDS (type); ++i)
+        {
+         fld_type = TYPE_FIELD_TYPE (type, 0);
+         if (TYPE_CODE (fld_type) == TYPE_CODE_ARRAY)
+           {
+             tgt_type = TYPE_TARGET_TYPE (fld_type);
+             if (TYPE_LENGTH (fld_type) >= 0 && TYPE_LENGTH (tgt_type) >= 0
+                 && TYPE_LENGTH (fld_type) / TYPE_LENGTH (tgt_type) > 2)
+               return 1;
+           }
+       }
+      return 0;
+    }
+    
+  /* The value is a union which contains at least one field which
+   * would be returned in registers according to these rules
+   * -> returned in register */
+  if (TYPE_CODE (type) == TYPE_CODE_UNION)
+    {
+      for (i = 0; i < TYPE_NFIELDS (type); ++i)
+        {
+         fld_type = TYPE_FIELD_TYPE (type, 0);
+         if (!v850_use_struct_convention (0, fld_type))
+           return 0;
+       }
+    }
+
+  return 1;
 }
 \f
 
@@ -844,22 +928,22 @@ v850_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
   /* First, just for safety, make sure stack is aligned */
   sp &= ~3;
 
+  /* The offset onto the stack at which we will start copying parameters
+     (after the registers are used up) begins at 16 rather than at zero.
+     I don't really know why, that's just the way it seems to work.  */
+  stack_offset = 16;
+
   /* Now make space on the stack for the args. */
   for (argnum = 0; argnum < nargs; argnum++)
     len += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3);
-  sp -= len;                   /* possibly over-allocating, but it works... */
+  sp -= len + stack_offset;    /* possibly over-allocating, but it works... */
   /* (you might think we could allocate 16 bytes */
   /* less, but the ABI seems to use it all! )  */
-  argreg = E_ARG0_REGNUM;
 
+  argreg = E_ARG0_REGNUM;
   /* the struct_return pointer occupies the first parameter-passing reg */
   if (struct_return)
-    write_register (argreg++, struct_addr);
-
-  stack_offset = 16;
-  /* The offset onto the stack at which we will start copying parameters
-     (after the registers are used up) begins at 16 rather than at zero.
-     I don't really know why, that's just the way it seems to work.  */
+    argreg++;
 
   /* Now load as many as possible of the first arguments into
      registers, and push the rest onto the stack.  There are 16 bytes
@@ -870,8 +954,8 @@ v850_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
       char *val;
       char valbuf[v850_register_raw_size (E_ARG0_REGNUM)];
 
-      if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT
-         && TYPE_LENGTH (VALUE_TYPE (*args)) > 8)
+      if (!v850_type_is_scalar (VALUE_TYPE (*args))
+         && TYPE_LENGTH (VALUE_TYPE (*args)) > E_MAX_RETTYPE_SIZE_IN_REGS)
        {
          store_address (valbuf, 4, VALUE_ADDRESS (*args));
          len = 4;
@@ -966,8 +1050,26 @@ v850_saved_pc_after_call (struct frame_info *ignore)
 static void
 v850_extract_return_value (struct type *type, char *regbuf, char *valbuf)
 {
-  memcpy (valbuf, regbuf + v850_register_byte (E_V0_REGNUM),
-         TYPE_LENGTH (type));
+  CORE_ADDR return_buffer;
+
+  if (!v850_use_struct_convention (0, type))
+    {
+      /* Scalar return values of <= 8 bytes are returned in 
+         E_V0_REGNUM to E_V1_REGNUM. */
+      memcpy (valbuf,
+             &regbuf[REGISTER_BYTE (E_V0_REGNUM)],
+             TYPE_LENGTH (type));
+    }
+  else
+    {
+      /* Aggregates and return values > 8 bytes are returned in memory,
+         pointed to by R6. */
+      return_buffer =
+       extract_address (regbuf + REGISTER_BYTE (E_V0_REGNUM),
+                        REGISTER_RAW_SIZE (E_V0_REGNUM));
+
+      read_memory (return_buffer, valbuf, TYPE_LENGTH (type));
+    }
 }
 
 const static unsigned char *
@@ -988,8 +1090,16 @@ v850_extract_struct_value_address (char *regbuf)
 static void
 v850_store_return_value (struct type *type, char *valbuf)
 {
-  write_register_bytes(v850_register_byte (E_V0_REGNUM), valbuf,
-                      TYPE_LENGTH (type));
+  CORE_ADDR return_buffer;
+
+  if (!v850_use_struct_convention (0, type))
+    write_register_bytes (REGISTER_BYTE (E_V0_REGNUM), valbuf, 
+                         TYPE_LENGTH (type));
+  else
+    {
+      return_buffer = read_register (E_V0_REGNUM);
+      write_memory (return_buffer, valbuf, TYPE_LENGTH (type));
+    }
 }
 
 static void
@@ -1057,8 +1167,9 @@ v850_init_extra_frame_info (int fromleaf, struct frame_info *fi)
 }
 
 static void
-v850_store_struct_return (CORE_ADDR a, CORE_ADDR b)
+v850_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
 {
+  write_register (E_ARG0_REGNUM, addr);
 }
 
 static CORE_ADDR
@@ -1126,7 +1237,7 @@ v850_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_init_extra_frame_info (gdbarch, v850_init_extra_frame_info);
   set_gdbarch_frame_init_saved_regs (gdbarch, v850_frame_init_saved_regs);
   set_gdbarch_frame_chain (gdbarch, v850_frame_chain);
-  set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
+  set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register);
   set_gdbarch_saved_pc_after_call (gdbarch, v850_saved_pc_after_call);
   set_gdbarch_frame_saved_pc (gdbarch, v850_frame_saved_pc);
   set_gdbarch_skip_prologue (gdbarch, v850_skip_prologue);
@@ -1158,12 +1269,12 @@ v850_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
   set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
   set_gdbarch_push_return_address (gdbarch, v850_push_return_address);
-  set_gdbarch_extract_return_value (gdbarch, v850_extract_return_value);
+  set_gdbarch_deprecated_extract_return_value (gdbarch, v850_extract_return_value);
   set_gdbarch_push_arguments (gdbarch, v850_push_arguments);
   set_gdbarch_pop_frame (gdbarch, v850_pop_frame);
   set_gdbarch_store_struct_return (gdbarch, v850_store_struct_return);
-  set_gdbarch_store_return_value (gdbarch, v850_store_return_value);
-  set_gdbarch_extract_struct_value_address (gdbarch, v850_extract_struct_value_address);
+  set_gdbarch_deprecated_store_return_value (gdbarch, v850_store_return_value);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, v850_extract_struct_value_address);
   set_gdbarch_use_struct_convention (gdbarch, v850_use_struct_convention);
   set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
   set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
This page took 0.025501 seconds and 4 git commands to generate.