Blame SOURCES/gdb-rhbz1182151-ibm-z13-14of22.patch

2c2fa1
commit 80f75320167acb66486124c6b03e715596e9c789
2c2fa1
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
2c2fa1
Date:   Mon Apr 27 11:38:46 2015 +0200
2c2fa1
2c2fa1
    S390: Restructure s390_push_dummy_call
2c2fa1
    
2c2fa1
    Simplify the structure of s390_push_dummy_call and its various helper
2c2fa1
    functions.  This reduces the code and makes it easier to extend.  The
2c2fa1
    new code should be functionally equivalent to the old one, except that
2c2fa1
    copies created by the caller are now always aligned on an 8-byte
2c2fa1
    boundary.
2c2fa1
    
2c2fa1
    gdb/ChangeLog:
2c2fa1
    
2c2fa1
    	* s390-linux-tdep.c
2c2fa1
    	(is_float_singleton): Remove function.  Move the "singleton" part
2c2fa1
    	of the logic...
2c2fa1
    	(s390_effective_inner_type): ...here.  New function.
2c2fa1
    	(is_float_like): Remove function.  Inline its logic...
2c2fa1
    	(s390_function_arg_float): ...here.
2c2fa1
    	(is_pointer_like, is_integer_like, is_struct_like): Remove
2c2fa1
    	functions.  Inline their logic...
2c2fa1
    	(s390_function_arg_integer): ...here.
2c2fa1
    	(s390_function_arg_pass_by_reference): Remove function.
2c2fa1
    	(extend_simple_arg): Remove function.
2c2fa1
    	(alignment_of): Remove function.
2c2fa1
    	(struct s390_arg_state): New structure.
2c2fa1
    	(s390_handle_arg): New function.
2c2fa1
    	(s390_push_dummy_call): Move parameter placement logic to the new
2c2fa1
    	function s390_handle_arg.  Call it for calculating the stack area
2c2fa1
    	sizes first, and again for actually writing the parameters.
2c2fa1
2c2fa1
### a/gdb/ChangeLog
2c2fa1
### b/gdb/ChangeLog
2c2fa1
## -1,5 +1,25 @@
2c2fa1
 2015-04-27  Andreas Arnez  <arnez@linux.vnet.ibm.com>
2c2fa1
 
2c2fa1
+	* s390-linux-tdep.c
2c2fa1
+	(is_float_singleton): Remove function.  Move the "singleton" part
2c2fa1
+	of the logic...
2c2fa1
+	(s390_effective_inner_type): ...here.  New function.
2c2fa1
+	(is_float_like): Remove function.  Inline its logic...
2c2fa1
+	(s390_function_arg_float): ...here.
2c2fa1
+	(is_pointer_like, is_integer_like, is_struct_like): Remove
2c2fa1
+	functions.  Inline their logic...
2c2fa1
+	(s390_function_arg_integer): ...here.
2c2fa1
+	(s390_function_arg_pass_by_reference): Remove function.
2c2fa1
+	(extend_simple_arg): Remove function.
2c2fa1
+	(alignment_of): Remove function.
2c2fa1
+	(struct s390_arg_state): New structure.
2c2fa1
+	(s390_handle_arg): New function.
2c2fa1
+	(s390_push_dummy_call): Move parameter placement logic to the new
2c2fa1
+	function s390_handle_arg.  Call it for calculating the stack area
2c2fa1
+	sizes first, and again for actually writing the parameters.
2c2fa1
+
2c2fa1
+2015-04-27  Andreas Arnez  <arnez@linux.vnet.ibm.com>
2c2fa1
+
2c2fa1
 	* s390-linux-tdep.c (is_power_of_two): Add comment.  Return
2c2fa1
 	  false if the argument is zero.
2c2fa1
 
2c2fa1
Index: gdb-7.6.1/gdb/s390-tdep.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/s390-tdep.c	2016-02-21 22:27:47.198043364 +0100
2c2fa1
+++ gdb-7.6.1/gdb/s390-tdep.c	2016-02-21 22:30:02.980113202 +0100
2c2fa1
@@ -2546,99 +2546,40 @@
2c2fa1
 
2c2fa1
 /* Dummy function calls.  */
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE is an integer-like type, zero otherwise.
2c2fa1
-   "Integer-like" types are those that should be passed the way
2c2fa1
-   integers are: integers, enums, ranges, characters, and booleans.  */
2c2fa1
-static int
2c2fa1
-is_integer_like (struct type *type)
2c2fa1
-{
2c2fa1
-  enum type_code code = TYPE_CODE (type);
2c2fa1
+/* Unwrap any single-field structs in TYPE and return the effective
2c2fa1
+   "inner" type.  E.g., yield "float" for all these cases:
2c2fa1
 
2c2fa1
-  return (code == TYPE_CODE_INT
2c2fa1
-          || code == TYPE_CODE_ENUM
2c2fa1
-          || code == TYPE_CODE_RANGE
2c2fa1
-          || code == TYPE_CODE_CHAR
2c2fa1
-          || code == TYPE_CODE_BOOL);
2c2fa1
-}
2c2fa1
+     float x;
2c2fa1
+     struct { float x };
2c2fa1
+     struct { struct { float x; } x; };
2c2fa1
+     struct { struct { struct { float x; } x; } x; };  */
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE is a pointer-like type, zero otherwise.
2c2fa1
-   "Pointer-like" types are those that should be passed the way
2c2fa1
-   pointers are: pointers and references.  */
2c2fa1
-static int
2c2fa1
-is_pointer_like (struct type *type)
2c2fa1
+static struct type *
2c2fa1
+s390_effective_inner_type (struct type *type)
2c2fa1
 {
2c2fa1
-  enum type_code code = TYPE_CODE (type);
2c2fa1
-
2c2fa1
-  return (code == TYPE_CODE_PTR
2c2fa1
-          || code == TYPE_CODE_REF);
2c2fa1
+  while (TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
+	 && TYPE_NFIELDS (type) == 1)
2c2fa1
+    type = check_typedef (TYPE_FIELD_TYPE (type, 0));
2c2fa1
+  return type;
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Return non-zero if TYPE should be passed like "float" or
2c2fa1
+   "double".  */
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE is a `float singleton' or `double
2c2fa1
-   singleton', zero otherwise.
2c2fa1
-
2c2fa1
-   A `T singleton' is a struct type with one member, whose type is
2c2fa1
-   either T or a `T singleton'.  So, the following are all float
2c2fa1
-   singletons:
2c2fa1
-
2c2fa1
-   struct { float x };
2c2fa1
-   struct { struct { float x; } x; };
2c2fa1
-   struct { struct { struct { float x; } x; } x; };
2c2fa1
-
2c2fa1
-   ... and so on.
2c2fa1
-
2c2fa1
-   All such structures are passed as if they were floats or doubles,
2c2fa1
-   as the (revised) ABI says.  */
2c2fa1
 static int
2c2fa1
-is_float_singleton (struct type *type)
2c2fa1
-{
2c2fa1
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
2c2fa1
-    {
2c2fa1
-      struct type *singleton_type = TYPE_FIELD_TYPE (type, 0);
2c2fa1
-      CHECK_TYPEDEF (singleton_type);
2c2fa1
-
2c2fa1
-      return (TYPE_CODE (singleton_type) == TYPE_CODE_FLT
2c2fa1
-	      || TYPE_CODE (singleton_type) == TYPE_CODE_DECFLOAT
2c2fa1
-	      || is_float_singleton (singleton_type));
2c2fa1
-    }
2c2fa1
-
2c2fa1
-  return 0;
2c2fa1
-}
2c2fa1
-
2c2fa1
-
2c2fa1
-/* Return non-zero if TYPE is a struct-like type, zero otherwise.
2c2fa1
-   "Struct-like" types are those that should be passed as structs are:
2c2fa1
-   structs and unions.
2c2fa1
-
2c2fa1
-   As an odd quirk, not mentioned in the ABI, GCC passes float and
2c2fa1
-   double singletons as if they were a plain float, double, etc.  (The
2c2fa1
-   corresponding union types are handled normally.)  So we exclude
2c2fa1
-   those types here.  *shrug* */
2c2fa1
-static int
2c2fa1
-is_struct_like (struct type *type)
2c2fa1
+s390_function_arg_float (struct type *type)
2c2fa1
 {
2c2fa1
-  enum type_code code = TYPE_CODE (type);
2c2fa1
-
2c2fa1
-  return (code == TYPE_CODE_UNION
2c2fa1
-          || (code == TYPE_CODE_STRUCT && ! is_float_singleton (type)));
2c2fa1
-}
2c2fa1
+  /* Note that long double as well as complex types are intentionally
2c2fa1
+     excluded. */
2c2fa1
+  if (TYPE_LENGTH (type) > 8)
2c2fa1
+    return 0;
2c2fa1
 
2c2fa1
+  /* A struct containing just a float or double is passed like a float
2c2fa1
+     or double.  */
2c2fa1
+  type = s390_effective_inner_type (type);
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE is a float-like type, zero otherwise.
2c2fa1
-   "Float-like" types are those that should be passed as
2c2fa1
-   floating-point values are.
2c2fa1
-
2c2fa1
-   You'd think this would just be floats, doubles, long doubles, etc.
2c2fa1
-   But as an odd quirk, not mentioned in the ABI, GCC passes float and
2c2fa1
-   double singletons as if they were a plain float, double, etc.  (The
2c2fa1
-   corresponding union types are handled normally.)  So we include
2c2fa1
-   those types here.  *shrug* */
2c2fa1
-static int
2c2fa1
-is_float_like (struct type *type)
2c2fa1
-{
2c2fa1
   return (TYPE_CODE (type) == TYPE_CODE_FLT
2c2fa1
-	  || TYPE_CODE (type) == TYPE_CODE_DECFLOAT
2c2fa1
-          || is_float_singleton (type));
2c2fa1
+	  || TYPE_CODE (type) == TYPE_CODE_DECFLOAT);
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Determine whether N is a power of two.  */
2c2fa1
@@ -2649,101 +2590,172 @@
2c2fa1
   return n && ((n & (n - 1)) == 0);
2c2fa1
 }
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE should be passed as a pointer to a copy,
2c2fa1
-   zero otherwise.  */
2c2fa1
-static int
2c2fa1
-s390_function_arg_pass_by_reference (struct type *type)
2c2fa1
-{
2c2fa1
-  if (TYPE_LENGTH (type) > 8)
2c2fa1
-    return 1;
2c2fa1
-
2c2fa1
-  return (is_struct_like (type) && !is_power_of_two (TYPE_LENGTH (type)))
2c2fa1
-	  || TYPE_CODE (type) == TYPE_CODE_COMPLEX
2c2fa1
-	  || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type));
2c2fa1
-}
2c2fa1
-
2c2fa1
-/* Return non-zero if TYPE should be passed in a float register
2c2fa1
-   if possible.  */
2c2fa1
-static int
2c2fa1
-s390_function_arg_float (struct type *type)
2c2fa1
-{
2c2fa1
-  if (TYPE_LENGTH (type) > 8)
2c2fa1
-    return 0;
2c2fa1
-
2c2fa1
-  return is_float_like (type);
2c2fa1
-}
2c2fa1
+/* For an argument whose type is TYPE and which is not passed like a
2c2fa1
+   float, return non-zero if it should be passed like "int" or "long
2c2fa1
+   long".  */
2c2fa1
 
2c2fa1
-/* Return non-zero if TYPE should be passed in an integer register
2c2fa1
-   (or a pair of integer registers) if possible.  */
2c2fa1
 static int
2c2fa1
 s390_function_arg_integer (struct type *type)
2c2fa1
 {
2c2fa1
+  enum type_code code = TYPE_CODE (type);
2c2fa1
+
2c2fa1
   if (TYPE_LENGTH (type) > 8)
2c2fa1
     return 0;
2c2fa1
 
2c2fa1
-   return is_integer_like (type)
2c2fa1
-	  || is_pointer_like (type)
2c2fa1
-	  || (is_struct_like (type) && is_power_of_two (TYPE_LENGTH (type)));
2c2fa1
-}
2c2fa1
-
2c2fa1
-/* Return ARG, a `SIMPLE_ARG', sign-extended or zero-extended to a full
2c2fa1
-   word as required for the ABI.  */
2c2fa1
-static LONGEST
2c2fa1
-extend_simple_arg (struct gdbarch *gdbarch, struct value *arg)
2c2fa1
-{
2c2fa1
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
2c2fa1
-  struct type *type = check_typedef (value_type (arg));
2c2fa1
+  if (code == TYPE_CODE_INT
2c2fa1
+      || code == TYPE_CODE_ENUM
2c2fa1
+      || code == TYPE_CODE_RANGE
2c2fa1
+      || code == TYPE_CODE_CHAR
2c2fa1
+      || code == TYPE_CODE_BOOL
2c2fa1
+      || code == TYPE_CODE_PTR
2c2fa1
+      || code == TYPE_CODE_REF)
2c2fa1
+    return 1;
2c2fa1
 
2c2fa1
-  /* Even structs get passed in the least significant bits of the
2c2fa1
-     register / memory word.  It's not really right to extract them as
2c2fa1
-     an integer, but it does take care of the extension.  */
2c2fa1
-  if (TYPE_UNSIGNED (type))
2c2fa1
-    return extract_unsigned_integer (value_contents (arg),
2c2fa1
-                                     TYPE_LENGTH (type), byte_order);
2c2fa1
-  else
2c2fa1
-    return extract_signed_integer (value_contents (arg),
2c2fa1
-                                   TYPE_LENGTH (type), byte_order);
2c2fa1
+  return ((code == TYPE_CODE_UNION || code == TYPE_CODE_STRUCT)
2c2fa1
+	  && is_power_of_two (TYPE_LENGTH (type)));
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Argument passing state: Internal data structure passed to helper
2c2fa1
+   routines of s390_push_dummy_call.  */
2c2fa1
 
2c2fa1
-/* Return the alignment required by TYPE.  */
2c2fa1
-static int
2c2fa1
-alignment_of (struct type *type)
2c2fa1
+struct s390_arg_state
2c2fa1
+  {
2c2fa1
+    /* Register cache, or NULL, if we are in "preparation mode".  */
2c2fa1
+    struct regcache *regcache;
2c2fa1
+    /* Next available general/floating-point register for argument
2c2fa1
+       passing.  */
2c2fa1
+    int gr, fr;
2c2fa1
+    /* Current pointer to copy area (grows downwards).  */
2c2fa1
+    CORE_ADDR copy;
2c2fa1
+    /* Current pointer to parameter area (grows upwards).  */
2c2fa1
+    CORE_ADDR argp;
2c2fa1
+  };
2c2fa1
+
2c2fa1
+/* Prepare one argument ARG for a dummy call and update the argument
2c2fa1
+   passing state AS accordingly.  If the regcache field in AS is set,
2c2fa1
+   operate in "write mode" and write ARG into the inferior.  Otherwise
2c2fa1
+   run "preparation mode" and skip all updates to the inferior.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+s390_handle_arg (struct s390_arg_state *as, struct value *arg,
2c2fa1
+		 struct gdbarch_tdep *tdep, int word_size,
2c2fa1
+		 enum bfd_endian byte_order)
2c2fa1
 {
2c2fa1
-  int alignment;
2c2fa1
+  struct type *type = check_typedef (value_type (arg));
2c2fa1
+  ULONGEST length = TYPE_LENGTH (type);
2c2fa1
+  int write_mode = as->regcache != NULL;
2c2fa1
 
2c2fa1
-  if (is_integer_like (type)
2c2fa1
-      || is_pointer_like (type)
2c2fa1
-      || TYPE_CODE (type) == TYPE_CODE_FLT
2c2fa1
-      || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
2c2fa1
-    alignment = TYPE_LENGTH (type);
2c2fa1
-  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
-           || TYPE_CODE (type) == TYPE_CODE_UNION)
2c2fa1
+  if (s390_function_arg_float (type))
2c2fa1
+    {
2c2fa1
+      /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass
2c2fa1
+	 arguments.  The GNU/Linux for zSeries ABI uses 0, 2, 4, and
2c2fa1
+	 6.  */
2c2fa1
+      if (as->fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
2c2fa1
+	{
2c2fa1
+	  /* When we store a single-precision value in an FP register,
2c2fa1
+	     it occupies the leftmost bits.  */
2c2fa1
+	  if (write_mode)
2c2fa1
+	    regcache_cooked_write_part (as->regcache,
2c2fa1
+					S390_F0_REGNUM + as->fr,
2c2fa1
+					0, length,
2c2fa1
+					value_contents (arg));
2c2fa1
+	  as->fr += 2;
2c2fa1
+	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  /* When we store a single-precision value in a stack slot,
2c2fa1
+	     it occupies the rightmost bits.  */
2c2fa1
+	  as->argp = align_up (as->argp + length, word_size);
2c2fa1
+	  if (write_mode)
2c2fa1
+	    write_memory (as->argp - length, value_contents (arg),
2c2fa1
+			  length);
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
+  else if (s390_function_arg_integer (type) && length <= word_size)
2c2fa1
     {
2c2fa1
-      int i;
2c2fa1
+      ULONGEST val;
2c2fa1
 
2c2fa1
-      alignment = 1;
2c2fa1
-      for (i = 0; i < TYPE_NFIELDS (type); i++)
2c2fa1
+      if (write_mode)
2c2fa1
         {
2c2fa1
-          int field_alignment
2c2fa1
-	    = alignment_of (check_typedef (TYPE_FIELD_TYPE (type, i)));
2c2fa1
-
2c2fa1
-          if (field_alignment > alignment)
2c2fa1
-            alignment = field_alignment;
2c2fa1
+	  /* Place value in least significant bits of the register or
2c2fa1
+	     memory word and sign- or zero-extend to full word size.
2c2fa1
+	     This also applies to a struct or union.  */
2c2fa1
+	  val = TYPE_UNSIGNED (type)
2c2fa1
+	    ? extract_unsigned_integer (value_contents (arg),
2c2fa1
+					length, byte_order)
2c2fa1
+	    : extract_signed_integer (value_contents (arg),
2c2fa1
+				      length, byte_order);
2c2fa1
+	}
2c2fa1
+
2c2fa1
+      if (as->gr <= 6)
2c2fa1
+	{
2c2fa1
+	  if (write_mode)
2c2fa1
+	    regcache_cooked_write_unsigned (as->regcache,
2c2fa1
+					    S390_R0_REGNUM + as->gr,
2c2fa1
+					    val);
2c2fa1
+	  as->gr++;
2c2fa1
+	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  if (write_mode)
2c2fa1
+	    write_memory_unsigned_integer (as->argp, word_size,
2c2fa1
+					   byte_order, val);
2c2fa1
+	  as->argp += word_size;
2c2fa1
         }
2c2fa1
     }
2c2fa1
+  else if (s390_function_arg_integer (type) && length == 8)
2c2fa1
+    {
2c2fa1
+      if (as->gr <= 5)
2c2fa1
+	{
2c2fa1
+	  if (write_mode)
2c2fa1
+	    {
2c2fa1
+	      regcache_cooked_write (as->regcache,
2c2fa1
+				     S390_R0_REGNUM + as->gr,
2c2fa1
+				     value_contents (arg));
2c2fa1
+	      regcache_cooked_write (as->regcache,
2c2fa1
+				     S390_R0_REGNUM + as->gr + 1,
2c2fa1
+				     value_contents (arg) + word_size);
2c2fa1
+	    }
2c2fa1
+	  as->gr += 2;
2c2fa1
+	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  /* If we skipped r6 because we couldn't fit a DOUBLE_ARG
2c2fa1
+	     in it, then don't go back and use it again later.  */
2c2fa1
+	  as->gr = 7;
2c2fa1
+
2c2fa1
+	  if (write_mode)
2c2fa1
+	    write_memory (as->argp, value_contents (arg), length);
2c2fa1
+	  as->argp += length;
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
   else
2c2fa1
-    alignment = 1;
2c2fa1
-
2c2fa1
-  /* Check that everything we ever return is a power of two.  Lots of
2c2fa1
-     code doesn't want to deal with aligning things to arbitrary
2c2fa1
-     boundaries.  */
2c2fa1
-  gdb_assert ((alignment & (alignment - 1)) == 0);
2c2fa1
-
2c2fa1
-  return alignment;
2c2fa1
+    {
2c2fa1
+      /* This argument type is never passed in registers.  Place the
2c2fa1
+	 value in the copy area and pass a pointer to it.  Use 8-byte
2c2fa1
+	 alignment as a conservative assumption.  */
2c2fa1
+      as->copy = align_down (as->copy - length, 8);
2c2fa1
+      if (write_mode)
2c2fa1
+	write_memory (as->copy, value_contents (arg), length);
2c2fa1
+
2c2fa1
+      if (as->gr <= 6)
2c2fa1
+	{
2c2fa1
+	  if (write_mode)
2c2fa1
+	    regcache_cooked_write_unsigned (as->regcache,
2c2fa1
+					    S390_R0_REGNUM + as->gr,
2c2fa1
+					    as->copy);
2c2fa1
+	  as->gr++;
2c2fa1
+	}
2c2fa1
+      else
2c2fa1
+	{
2c2fa1
+	  if (write_mode)
2c2fa1
+	    write_memory_unsigned_integer (as->argp, word_size,
2c2fa1
+					   byte_order, as->copy);
2c2fa1
+	  as->argp += word_size;
2c2fa1
+	}
2c2fa1
+    }
2c2fa1
 }
2c2fa1
 
2c2fa1
-
2c2fa1
 /* Put the actual parameter values pointed to by ARGS[0..NARGS-1] in
2c2fa1
    place to be passed to a function, as specified by the "GNU/Linux
2c2fa1
    for S/390 ELF Application Binary Interface Supplement".
2c2fa1
@@ -2758,6 +2770,7 @@
2c2fa1
 
2c2fa1
    Our caller has taken care of any type promotions needed to satisfy
2c2fa1
    prototypes or the old K&R argument-passing rules.  */
2c2fa1
+
2c2fa1
 static CORE_ADDR
2c2fa1
 s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
2c2fa1
 		      struct regcache *regcache, CORE_ADDR bp_addr,
2c2fa1
@@ -2768,151 +2781,48 @@
2c2fa1
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
2c2fa1
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
2c2fa1
   int i;
2c2fa1
+  struct s390_arg_state arg_state, arg_prep;
2c2fa1
+  CORE_ADDR param_area_start, new_sp;
2c2fa1
 
2c2fa1
-  /* If the i'th argument is passed as a reference to a copy, then
2c2fa1
-     copy_addr[i] is the address of the copy we made.  */
2c2fa1
-  CORE_ADDR *copy_addr = alloca (nargs * sizeof (CORE_ADDR));
2c2fa1
+  arg_prep.copy = sp;
2c2fa1
+  arg_prep.gr = struct_return ? 3 : 2;
2c2fa1
+  arg_prep.fr = 0;
2c2fa1
+  arg_prep.argp = 0;
2c2fa1
+  arg_prep.regcache = NULL;
2c2fa1
 
2c2fa1
-  /* Reserve space for the reference-to-copy area.  */
2c2fa1
-  for (i = 0; i < nargs; i++)
2c2fa1
-    {
2c2fa1
-      struct value *arg = args[i];
2c2fa1
-      struct type *type = check_typedef (value_type (arg));
2c2fa1
+  /* Initialize arg_state for "preparation mode".  */
2c2fa1
+  arg_state = arg_prep;
2c2fa1
 
2c2fa1
-      if (s390_function_arg_pass_by_reference (type))
2c2fa1
-        {
2c2fa1
-          sp -= TYPE_LENGTH (type);
2c2fa1
-          sp = align_down (sp, alignment_of (type));
2c2fa1
-          copy_addr[i] = sp;
2c2fa1
-        }
2c2fa1
-    }
2c2fa1
+  /* Update arg_state.copy with the start of the reference-to-copy area
2c2fa1
+     and arg_state.argp with the size of the parameter area.  */
2c2fa1
+  for (i = 0; i < nargs; i++)
2c2fa1
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order);
2c2fa1
 
2c2fa1
-  /* Reserve space for the parameter area.  As a conservative
2c2fa1
-     simplification, we assume that everything will be passed on the
2c2fa1
-     stack.  Since every argument larger than 8 bytes will be 
2c2fa1
-     passed by reference, we use this simple upper bound.  */
2c2fa1
-  sp -= nargs * 8;
2c2fa1
-
2c2fa1
-  /* After all that, make sure it's still aligned on an eight-byte
2c2fa1
-     boundary.  */
2c2fa1
-  sp = align_down (sp, 8);
2c2fa1
+  param_area_start = align_down (arg_state.copy - arg_state.argp, 8);
2c2fa1
 
2c2fa1
   /* Allocate the standard frame areas: the register save area, the
2c2fa1
-     word reserved for the compiler (which seems kind of meaningless),
2c2fa1
-     and the back chain pointer.  */
2c2fa1
-  sp -= 16*word_size + 32;
2c2fa1
-
2c2fa1
-  /* Now we have the final SP value.  Make sure we didn't underflow;
2c2fa1
-     on 31-bit, this would result in addresses with the high bit set,
2c2fa1
-     which causes confusion elsewhere.  Note that if we error out
2c2fa1
-     here, stack and registers remain untouched.  */
2c2fa1
-  if (gdbarch_addr_bits_remove (gdbarch, sp) != sp)
2c2fa1
+     word reserved for the compiler, and the back chain pointer.  */
2c2fa1
+  new_sp = param_area_start - (16 * word_size + 32);
2c2fa1
+
2c2fa1
+  /* Now we have the final stack pointer.  Make sure we didn't
2c2fa1
+     underflow; on 31-bit, this would result in addresses with the
2c2fa1
+     high bit set, which causes confusion elsewhere.  Note that if we
2c2fa1
+     error out here, stack and registers remain untouched.  */
2c2fa1
+  if (gdbarch_addr_bits_remove (gdbarch, new_sp) != new_sp)
2c2fa1
     error (_("Stack overflow"));
2c2fa1
 
2c2fa1
+  /* Pass the structure return address in general register 2.  */
2c2fa1
+  if (struct_return)
2c2fa1
+    regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr);
2c2fa1
+
2c2fa1
+  /* Initialize arg_state for "write mode".  */
2c2fa1
+  arg_state = arg_prep;
2c2fa1
+  arg_state.argp = param_area_start;
2c2fa1
+  arg_state.regcache = regcache;
2c2fa1
 
2c2fa1
-  /* Finally, place the actual parameters, working from SP towards
2c2fa1
-     higher addresses.  The code above is supposed to reserve enough
2c2fa1
-     space for this.  */
2c2fa1
-  {
2c2fa1
-    int fr = 0;
2c2fa1
-    int gr = 2;
2c2fa1
-    CORE_ADDR starg = sp + 16*word_size + 32;
2c2fa1
-
2c2fa1
-    /* A struct is returned using general register 2.  */
2c2fa1
-    if (struct_return)
2c2fa1
-      {
2c2fa1
-	regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
2c2fa1
-				        struct_addr);
2c2fa1
-	gr++;
2c2fa1
-      }
2c2fa1
-
2c2fa1
-    for (i = 0; i < nargs; i++)
2c2fa1
-      {
2c2fa1
-        struct value *arg = args[i];
2c2fa1
-        struct type *type = check_typedef (value_type (arg));
2c2fa1
-        ULONGEST length = TYPE_LENGTH (type);
2c2fa1
-
2c2fa1
-	if (s390_function_arg_pass_by_reference (type))
2c2fa1
-	  {
2c2fa1
-	    /* Actually copy the argument contents to the stack slot
2c2fa1
-	       that was reserved above.  */
2c2fa1
-	    write_memory (copy_addr[i], value_contents (arg), length);
2c2fa1
-
2c2fa1
-	    if (gr <= 6)
2c2fa1
-	      {
2c2fa1
-		regcache_cooked_write_unsigned (regcache, S390_R0_REGNUM + gr,
2c2fa1
-					        copy_addr[i]);
2c2fa1
-		gr++;
2c2fa1
-	      }
2c2fa1
-	    else
2c2fa1
-	      {
2c2fa1
-		write_memory_unsigned_integer (starg, word_size, byte_order,
2c2fa1
-					       copy_addr[i]);
2c2fa1
-		starg += word_size;
2c2fa1
-	      }
2c2fa1
-	  }
2c2fa1
-	else if (s390_function_arg_float (type))
2c2fa1
-	  {
2c2fa1
-	    /* The GNU/Linux for S/390 ABI uses FPRs 0 and 2 to pass arguments,
2c2fa1
-	       the GNU/Linux for zSeries ABI uses 0, 2, 4, and 6.  */
2c2fa1
-	    if (fr <= (tdep->abi == ABI_LINUX_S390 ? 2 : 6))
2c2fa1
-	      {
2c2fa1
-		/* When we store a single-precision value in an FP register,
2c2fa1
-		   it occupies the leftmost bits.  */
2c2fa1
-		regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr,
2c2fa1
-					    0, length, value_contents (arg));
2c2fa1
-		fr += 2;
2c2fa1
-	      }
2c2fa1
-	    else
2c2fa1
-	      {
2c2fa1
-		/* When we store a single-precision value in a stack slot,
2c2fa1
-		   it occupies the rightmost bits.  */
2c2fa1
-		starg = align_up (starg + length, word_size);
2c2fa1
-                write_memory (starg - length, value_contents (arg), length);
2c2fa1
-	      }
2c2fa1
-	  }
2c2fa1
-	else if (s390_function_arg_integer (type) && length <= word_size)
2c2fa1
-	  {
2c2fa1
-	    if (gr <= 6)
2c2fa1
-	      {
2c2fa1
-		/* Integer arguments are always extended to word size.  */
2c2fa1
-		regcache_cooked_write_signed (regcache, S390_R0_REGNUM + gr,
2c2fa1
-					      extend_simple_arg (gdbarch,
2c2fa1
-								 arg));
2c2fa1
-		gr++;
2c2fa1
-	      }
2c2fa1
-	    else
2c2fa1
-	      {
2c2fa1
-		/* Integer arguments are always extended to word size.  */
2c2fa1
-		write_memory_signed_integer (starg, word_size, byte_order,
2c2fa1
-                                             extend_simple_arg (gdbarch, arg));
2c2fa1
-                starg += word_size;
2c2fa1
-	      }
2c2fa1
-	  }
2c2fa1
-	else if (s390_function_arg_integer (type) && length == 2*word_size)
2c2fa1
-	  {
2c2fa1
-	    if (gr <= 5)
2c2fa1
-	      {
2c2fa1
-		regcache_cooked_write (regcache, S390_R0_REGNUM + gr,
2c2fa1
-				       value_contents (arg));
2c2fa1
-		regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1,
2c2fa1
-				       value_contents (arg) + word_size);
2c2fa1
-		gr += 2;
2c2fa1
-	      }
2c2fa1
-	    else
2c2fa1
-	      {
2c2fa1
-		/* If we skipped r6 because we couldn't fit a DOUBLE_ARG
2c2fa1
-		   in it, then don't go back and use it again later.  */
2c2fa1
-		gr = 7;
2c2fa1
-
2c2fa1
-		write_memory (starg, value_contents (arg), length);
2c2fa1
-		starg += length;
2c2fa1
-	      }
2c2fa1
-	  }
2c2fa1
-	else
2c2fa1
-	  internal_error (__FILE__, __LINE__, _("unknown argument type"));
2c2fa1
-      }
2c2fa1
-  }
2c2fa1
+  /* Write all parameters.  */
2c2fa1
+  for (i = 0; i < nargs; i++)
2c2fa1
+    s390_handle_arg (&arg_state, args[i], tdep, word_size, byte_order);
2c2fa1
 
2c2fa1
   /* Store return PSWA.  In 31-bit mode, keep addressing mode bit.  */
2c2fa1
   if (word_size == 4)
2c2fa1
@@ -2924,11 +2834,11 @@
2c2fa1
   regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
2c2fa1
 
2c2fa1
   /* Store updated stack pointer.  */
2c2fa1
-  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
2c2fa1
+  regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, new_sp);
2c2fa1
 
2c2fa1
   /* We need to return the 'stack part' of the frame ID,
2c2fa1
      which is actually the top of the register save area.  */
2c2fa1
-  return sp + 16*word_size + 32;
2c2fa1
+  return param_area_start;
2c2fa1
 }
2c2fa1
 
2c2fa1
 /* Assuming THIS_FRAME is a dummy, return the frame ID of that