Blame SOURCES/gdb-rhbz1125820-ppc64le-enablement-23of37.patch

2c2fa1
commit e765b44c3853ed228506fc22c276becd63198238
2c2fa1
Author: Ulrich Weigand <ulrich.weigand@de.ibm.com>
2c2fa1
Date:   Tue Feb 4 18:24:42 2014 +0100
2c2fa1
2c2fa1
    Refactor ppc64 function call and return value handling
2c2fa1
    
2c2fa1
    This patch refactors the ppc64 function call and return value handling code
2c2fa1
    in ppc-sysv-tdep.c.  The main problem to be addressed by this refactoring
2c2fa1
    is the code duplication caused by certain aggregate types:
2c2fa1
    
2c2fa1
    According to the ABI, some types are to be decomposed into component types
2c2fa1
    for parameter and return value handling.  For example, complex types are
2c2fa1
    to be passed as if the real and imaginary component were separate arguments.
2c2fa1
    Similarly, certain OpenCL vector types are passed as if they were multiple
2c2fa1
    separate arguments of the vector element type.  With the new ELFv2 ABI,
2c2fa1
    there is another case: "homogeneous aggregates" (e.g. a struct containing
2c2fa1
    4 floats) are passed in multiple floating point registers as well.
2c2fa1
    
2c2fa1
    Unfortunately, the current code is not structured to easily model these
2c2fa1
    ABI properties.  For example, code to pass complex values re-implements
2c2fa1
    code to pass the underlying (floating-point) type.  This has already
2c2fa1
    led to some unfortunate code duplication, and with the addition of
2c2fa1
    ELFv2 ABI support, I would have had to add yet more such duplication.
2c2fa1
    
2c2fa1
    To avoid that, I've decided to refactor the code in order to re-use
2c2fa1
    subroutines that handle the "base" types when handling those aggregate
2c2fa1
    types.  This was not intended to cause any difference on current
2c2fa1
    (ELFv1) ABI code, but in fact it fixes a bug:
2c2fa1
    
2c2fa1
    FAIL: gdb.base/varargs.exp: print find_max_float_real(4, fc1, fc2, fc3, fc4)
2c2fa1
    
2c2fa1
    This was caused by the old code in ppc64_sysv_abi_push_float incorrectly
2c2fa1
    handling floating-point arguments to vararg routines, which just happens
2c2fa1
    to work out correctly automatically in the refactored code ...
2c2fa1
    
2c2fa1
    gdb/ChangeLog:
2c2fa1
    
2c2fa1
    	* ppc-sysv-tdep.c (get_decimal_float_return_value): Update comment.
2c2fa1
    	(struct ppc64_sysv_argpos): New data structure.
2c2fa1
    	(ppc64_sysv_abi_push_float): Remove.
2c2fa1
    	(ppc64_sysv_abi_push_val): New function.
2c2fa1
    	(ppc64_sysv_abi_push_integer): Likewise.
2c2fa1
    	(ppc64_sysv_abi_push_freg): Likewise.
2c2fa1
    	(ppc64_sysv_abi_push_vreg): Likewise.
2c2fa1
    	(ppc64_sysv_abi_push_param): Likewise.
2c2fa1
    	(ppc64_sysv_abi_push_dummy_call): Refactor to use those new routines.
2c2fa1
    	(ppc64_sysv_abi_return_value_base): New function.
2c2fa1
    	(ppc64_sysv_abi_return_value): Refactor to use it.
2c2fa1
2c2fa1
Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c
2c2fa1
+++ gdb-7.6.1/gdb/ppc-sysv-tdep.c
2c2fa1
@@ -609,8 +609,7 @@ ppc_sysv_abi_push_dummy_call (struct gdb
2c2fa1
   return sp;
2c2fa1
 }
2c2fa1
 
2c2fa1
-/* Handle the return-value conventions for Decimal Floating Point values
2c2fa1
-   in both ppc32 and ppc64, which are the same.  */
2c2fa1
+/* Handle the return-value conventions for Decimal Floating Point values.  */
2c2fa1
 static int
2c2fa1
 get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype,
2c2fa1
 				struct regcache *regcache, gdb_byte *readbuf,
2c2fa1
@@ -1101,80 +1100,287 @@ convert_code_addr_to_desc_addr (CORE_ADD
2c2fa1
   return 1;
2c2fa1
 }
2c2fa1
 
2c2fa1
-/* Push a float in either registers, or in the stack.  Using the ppc 64 bit
2c2fa1
-   SysV ABI.
2c2fa1
+/* Structure holding the next argument position.  */
2c2fa1
+struct ppc64_sysv_argpos
2c2fa1
+  {
2c2fa1
+    /* Register cache holding argument registers.  If this is NULL,
2c2fa1
+       we only simulate argument processing without actually updating
2c2fa1
+       any registers or memory.  */
2c2fa1
+    struct regcache *regcache;
2c2fa1
+    /* Next available general-purpose argument register.  */
2c2fa1
+    int greg;
2c2fa1
+    /* Next available floating-point argument register.  */
2c2fa1
+    int freg;
2c2fa1
+    /* Next available vector argument register.  */
2c2fa1
+    int vreg;
2c2fa1
+    /* The address, at which the next general purpose parameter
2c2fa1
+       (integer, struct, float, vector, ...) should be saved.  */
2c2fa1
+    CORE_ADDR gparam;
2c2fa1
+    /* The address, at which the next by-reference parameter
2c2fa1
+       (non-Altivec vector, variably-sized type) should be saved.  */
2c2fa1
+    CORE_ADDR refparam;
2c2fa1
+  };
2c2fa1
+
2c2fa1
+/* VAL is a value of length LEN.  Store it into the argument area on the
2c2fa1
+   stack and load it into the corresponding general-purpose registers
2c2fa1
+   required by the ABI, and update ARGPOS.
2c2fa1
 
2c2fa1
-   This implements a dumbed down version of the ABI.  It always writes
2c2fa1
-   values to memory, GPR and FPR, even when not necessary.  Doing this
2c2fa1
-   greatly simplifies the logic.  */
2c2fa1
+   If ALIGN is nonzero, it specifies the minimum alignment required
2c2fa1
+   for the on-stack copy of the argument.  */
2c2fa1
 
2c2fa1
 static void
2c2fa1
-ppc64_sysv_abi_push_float (struct gdbarch *gdbarch, struct regcache *regcache,
2c2fa1
-			   struct gdbarch_tdep *tdep, struct type *type, 
2c2fa1
-			   const bfd_byte *val, int freg, int greg,
2c2fa1
-			   CORE_ADDR gparam)
2c2fa1
+ppc64_sysv_abi_push_val (struct gdbarch *gdbarch,
2c2fa1
+			 const bfd_byte *val, int len, int align,
2c2fa1
+			 struct ppc64_sysv_argpos *argpos)
2c2fa1
 {
2c2fa1
-  gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-  const gdb_byte *p;
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+  int offset = 0;
2c2fa1
 
2c2fa1
-  if (TYPE_LENGTH (type) <= 8)
2c2fa1
+  /* Enforce alignment of stack location, if requested.  */
2c2fa1
+  if (align > tdep->wordsize)
2c2fa1
+    {
2c2fa1
+      CORE_ADDR aligned_gparam = align_up (argpos->gparam, align);
2c2fa1
+
2c2fa1
+      argpos->greg += (aligned_gparam - argpos->gparam) / tdep->wordsize;
2c2fa1
+      argpos->gparam = aligned_gparam;
2c2fa1
+    }
2c2fa1
+
2c2fa1
+  /* The ABI (version 1.9) specifies that values smaller than one
2c2fa1
+     doubleword are right-aligned and those larger are left-aligned.
2c2fa1
+     GCC versions before 3.4 implemented this incorrectly; see
2c2fa1
+     <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>.  */
2c2fa1
+  if (len < tdep->wordsize)
2c2fa1
+    offset = tdep->wordsize - len;
2c2fa1
+
2c2fa1
+  if (argpos->regcache)
2c2fa1
+    write_memory (argpos->gparam + offset, val, len);
2c2fa1
+  argpos->gparam = align_up (argpos->gparam + len, tdep->wordsize);
2c2fa1
+
2c2fa1
+  while (len >= tdep->wordsize)
2c2fa1
     {
2c2fa1
-      /* Version 1.7 of the 64-bit PowerPC ELF ABI says:
2c2fa1
+      if (argpos->regcache && argpos->greg <= 10)
2c2fa1
+	regcache_cooked_write (argpos->regcache,
2c2fa1
+			       tdep->ppc_gp0_regnum + argpos->greg, val);
2c2fa1
+      argpos->greg++;
2c2fa1
+      len -= tdep->wordsize;
2c2fa1
+      val += tdep->wordsize;
2c2fa1
+    }
2c2fa1
+
2c2fa1
+  if (len > 0)
2c2fa1
+    {
2c2fa1
+      if (argpos->regcache && argpos->greg <= 10)
2c2fa1
+	regcache_cooked_write_part (argpos->regcache,
2c2fa1
+				    tdep->ppc_gp0_regnum + argpos->greg,
2c2fa1
+				    offset, len, val);
2c2fa1
+      argpos->greg++;
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* The same as ppc64_sysv_abi_push_val, but using a single-word integer
2c2fa1
+   value VAL as argument.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+ppc64_sysv_abi_push_integer (struct gdbarch *gdbarch, ULONGEST val,
2c2fa1
+			     struct ppc64_sysv_argpos *argpos)
2c2fa1
+{
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
2c2fa1
+  gdb_byte buf[MAX_REGISTER_SIZE];
2c2fa1
 
2c2fa1
-	 "Single precision floating point values are mapped to
2c2fa1
-	 the first word in a single doubleword."
2c2fa1
+  if (argpos->regcache)
2c2fa1
+    store_unsigned_integer (buf, tdep->wordsize, byte_order, val);
2c2fa1
+  ppc64_sysv_abi_push_val (gdbarch, buf, tdep->wordsize, 0, argpos);
2c2fa1
+}
2c2fa1
 
2c2fa1
-	 And version 1.9 says:
2c2fa1
+/* VAL is a value of TYPE, a (binary or decimal) floating-point type.
2c2fa1
+   Load it into a floating-point register if required by the ABI,
2c2fa1
+   and update ARGPOS.  */
2c2fa1
 
2c2fa1
-	 "Single precision floating point values are mapped to
2c2fa1
-	 the second word in a single doubleword."
2c2fa1
+static void
2c2fa1
+ppc64_sysv_abi_push_freg (struct gdbarch *gdbarch,
2c2fa1
+			  struct type *type, const bfd_byte *val,
2c2fa1
+			  struct ppc64_sysv_argpos *argpos)
2c2fa1
+{
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+  if (tdep->soft_float)
2c2fa1
+    return;
2c2fa1
 
2c2fa1
-	 GDB then writes single precision floating point values
2c2fa1
-	 at both words in a doubleword, to support both ABIs.  */
2c2fa1
-      if (TYPE_LENGTH (type) == 4)
2c2fa1
+  if (TYPE_LENGTH (type) <= 8
2c2fa1
+      && TYPE_CODE (type) == TYPE_CODE_FLT)
2c2fa1
+    {
2c2fa1
+      /* Floats and doubles go in f1 .. f13.  32-bit floats are converted
2c2fa1
+ 	 to double first.  */
2c2fa1
+      if (argpos->regcache && argpos->freg <= 13)
2c2fa1
 	{
2c2fa1
-	  memcpy (regval, val, 4);
2c2fa1
-	  memcpy (regval + 4, val, 4);
2c2fa1
-	  p = regval;
2c2fa1
+	  int regnum = tdep->ppc_fp0_regnum + argpos->freg;
2c2fa1
+	  struct type *regtype = register_type (gdbarch, regnum);
2c2fa1
+	  gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
+
2c2fa1
+	  convert_typed_floating (val, type, regval, regtype);
2c2fa1
+	  regcache_cooked_write (argpos->regcache, regnum, regval);
2c2fa1
 	}
2c2fa1
-      else
2c2fa1
-	p = val;
2c2fa1
 
2c2fa1
-      /* Write value in the stack's parameter save area.  */
2c2fa1
-      write_memory (gparam, p, 8);
2c2fa1
+      argpos->freg++;
2c2fa1
+    }
2c2fa1
+  else if (TYPE_LENGTH (type) <= 8
2c2fa1
+	   && TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
2c2fa1
+    {
2c2fa1
+      /* Floats and doubles go in f1 .. f13.  32-bit decimal floats are
2c2fa1
+	 placed in the least significant word.  */
2c2fa1
+      if (argpos->regcache && argpos->freg <= 13)
2c2fa1
+	{
2c2fa1
+	  int regnum = tdep->ppc_fp0_regnum + argpos->freg;
2c2fa1
+	  int offset = 8 - TYPE_LENGTH (type);
2c2fa1
 
2c2fa1
-      /* Floats and Doubles go in f1 .. f13.  They also consume a left aligned
2c2fa1
-	 GREG, and can end up in memory.  */
2c2fa1
-      if (freg <= 13)
2c2fa1
+	  regcache_cooked_write_part (argpos->regcache, regnum,
2c2fa1
+				      offset, TYPE_LENGTH (type), val);
2c2fa1
+	}
2c2fa1
+
2c2fa1
+      argpos->freg++;
2c2fa1
+    }
2c2fa1
+  else if (TYPE_LENGTH (type) == 16
2c2fa1
+	   && TYPE_CODE (type) == TYPE_CODE_FLT
2c2fa1
+	   && (gdbarch_long_double_format (gdbarch)
2c2fa1
+	       == floatformats_ibm_long_double))
2c2fa1
+    {
2c2fa1
+      /* IBM long double stored in two consecutive FPRs.  */
2c2fa1
+      if (argpos->regcache && argpos->freg <= 13)
2c2fa1
 	{
2c2fa1
-	  struct type *regtype;
2c2fa1
+	  int regnum = tdep->ppc_fp0_regnum + argpos->freg;
2c2fa1
 
2c2fa1
-	  regtype = register_type (gdbarch, tdep->ppc_fp0_regnum + freg);
2c2fa1
-	  convert_typed_floating (val, type, regval, regtype);
2c2fa1
-	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval);
2c2fa1
+	  regcache_cooked_write (argpos->regcache, regnum, val);
2c2fa1
+	  if (argpos->freg <= 12)
2c2fa1
+	    regcache_cooked_write (argpos->regcache, regnum + 1, val + 8);
2c2fa1
+	}
2c2fa1
+
2c2fa1
+      argpos->freg += 2;
2c2fa1
+    }
2c2fa1
+  else if (TYPE_LENGTH (type) == 16
2c2fa1
+	   && TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
2c2fa1
+    {
2c2fa1
+      /* 128-bit decimal floating-point values are stored in and even/odd
2c2fa1
+	 pair of FPRs, with the even FPR holding the most significant half.  */
2c2fa1
+      argpos->freg += argpos->freg & 1;
2c2fa1
+
2c2fa1
+      if (argpos->regcache && argpos->freg <= 12)
2c2fa1
+	{
2c2fa1
+	  int regnum = tdep->ppc_fp0_regnum + argpos->freg;
2c2fa1
+
2c2fa1
+	  regcache_cooked_write (argpos->regcache, regnum, val);
2c2fa1
+	  regcache_cooked_write (argpos->regcache, regnum + 1, val + 8);
2c2fa1
+	}
2c2fa1
+
2c2fa1
+      argpos->freg += 2;
2c2fa1
+    }
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* VAL is a value of AltiVec vector type.  Load it into a vector register
2c2fa1
+   if required by the ABI, and update ARGPOS.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+ppc64_sysv_abi_push_vreg (struct gdbarch *gdbarch, const bfd_byte *val,
2c2fa1
+			  struct ppc64_sysv_argpos *argpos)
2c2fa1
+{
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+
2c2fa1
+  if (argpos->regcache && argpos->vreg <= 13)
2c2fa1
+    regcache_cooked_write (argpos->regcache,
2c2fa1
+			   tdep->ppc_vr0_regnum + argpos->vreg, val);
2c2fa1
+
2c2fa1
+  argpos->vreg++;
2c2fa1
+}
2c2fa1
+
2c2fa1
+/* VAL is a value of TYPE.  Load it into memory and/or registers
2c2fa1
+   as required by the ABI, and update ARGPOS.  */
2c2fa1
+
2c2fa1
+static void
2c2fa1
+ppc64_sysv_abi_push_param (struct gdbarch *gdbarch,
2c2fa1
+			   struct type *type, const bfd_byte *val,
2c2fa1
+			   struct ppc64_sysv_argpos *argpos)
2c2fa1
+{
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+
2c2fa1
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
2c2fa1
+      || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
2c2fa1
+    {
2c2fa1
+      /* Floating-point scalars are passed in floating-point registers.  */
2c2fa1
+      ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos);
2c2fa1
+      ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
2c2fa1
+    }
2c2fa1
+  else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
2c2fa1
+	   && tdep->vector_abi == POWERPC_VEC_ALTIVEC
2c2fa1
+	   && TYPE_LENGTH (type) == 16)
2c2fa1
+    {
2c2fa1
+      /* AltiVec vectors are passed aligned, and in vector registers.  */
2c2fa1
+      ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 16, argpos);
2c2fa1
+      ppc64_sysv_abi_push_vreg (gdbarch, val, argpos);
2c2fa1
+    }
2c2fa1
+  else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
2c2fa1
+	   && TYPE_LENGTH (type) >= 16)
2c2fa1
+    {
2c2fa1
+      /* Non-Altivec vectors are passed by reference.  */
2c2fa1
+
2c2fa1
+      /* Copy value onto the stack ...  */
2c2fa1
+      CORE_ADDR addr = align_up (argpos->refparam, 16);
2c2fa1
+      if (argpos->regcache)
2c2fa1
+	write_memory (addr, val, TYPE_LENGTH (type));
2c2fa1
+      argpos->refparam = align_up (addr + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
+
2c2fa1
+      /* ... and pass a pointer to the copy as parameter.  */
2c2fa1
+      ppc64_sysv_abi_push_integer (gdbarch, addr, argpos);
2c2fa1
+    }
2c2fa1
+  else if ((TYPE_CODE (type) == TYPE_CODE_INT
2c2fa1
+	    || TYPE_CODE (type) == TYPE_CODE_ENUM
2c2fa1
+	    || TYPE_CODE (type) == TYPE_CODE_BOOL
2c2fa1
+	    || TYPE_CODE (type) == TYPE_CODE_CHAR
2c2fa1
+	    || TYPE_CODE (type) == TYPE_CODE_PTR
2c2fa1
+	    || TYPE_CODE (type) == TYPE_CODE_REF)
2c2fa1
+	   && TYPE_LENGTH (type) <= tdep->wordsize)
2c2fa1
+    {
2c2fa1
+      ULONGEST word = 0;
2c2fa1
+
2c2fa1
+      if (argpos->regcache)
2c2fa1
+	{
2c2fa1
+	  /* Sign extend the value, then store it unsigned.  */
2c2fa1
+	  word = unpack_long (type, val);
2c2fa1
+
2c2fa1
+	  /* Convert any function code addresses into descriptors.  */
2c2fa1
+	  if (TYPE_CODE (type) == TYPE_CODE_PTR
2c2fa1
+	      || TYPE_CODE (type) == TYPE_CODE_REF)
2c2fa1
+	    {
2c2fa1
+	      struct type *target_type
2c2fa1
+		= check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
+
2c2fa1
+	      if (TYPE_CODE (target_type) == TYPE_CODE_FUNC
2c2fa1
+		  || TYPE_CODE (target_type) == TYPE_CODE_METHOD)
2c2fa1
+		{
2c2fa1
+		  CORE_ADDR desc = word;
2c2fa1
+
2c2fa1
+		  convert_code_addr_to_desc_addr (word, &desc);
2c2fa1
+		  word = desc;
2c2fa1
+		}
2c2fa1
+	    }
2c2fa1
 	}
2c2fa1
-      if (greg <= 10)
2c2fa1
-	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval);
2c2fa1
+
2c2fa1
+      ppc64_sysv_abi_push_integer (gdbarch, word, argpos);
2c2fa1
     }
2c2fa1
   else
2c2fa1
     {
2c2fa1
-      /* IBM long double stored in two doublewords of the
2c2fa1
-	 parameter save area and corresponding registers.  */
2c2fa1
-      if (!tdep->soft_float && freg <= 13)
2c2fa1
-	{
2c2fa1
-	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val);
2c2fa1
-	  if (freg <= 12)
2c2fa1
-	    regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1,
2c2fa1
-				   val + 8);
2c2fa1
-	}
2c2fa1
-      if (greg <= 10)
2c2fa1
-	{
2c2fa1
-	  regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val);
2c2fa1
-	  if (greg <= 9)
2c2fa1
-	    regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1,
2c2fa1
-				   val + 8);
2c2fa1
+      ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos);
2c2fa1
+
2c2fa1
+      /* The ABI (version 1.9) specifies that structs containing a
2c2fa1
+	 single floating-point value, at any level of nesting of
2c2fa1
+	 single-member structs, are passed in floating-point registers.  */
2c2fa1
+      if (TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
+	  && TYPE_NFIELDS (type) == 1)
2c2fa1
+	{
2c2fa1
+	  while (TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
+		 && TYPE_NFIELDS (type) == 1)
2c2fa1
+	    type = check_typedef (TYPE_FIELD_TYPE (type, 0));
2c2fa1
+
2c2fa1
+	  if (TYPE_CODE (type) == TYPE_CODE_FLT)
2c2fa1
+	    ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
2c2fa1
 	}
2c2fa1
-      write_memory (gparam, val, TYPE_LENGTH (type));
2c2fa1
     }
2c2fa1
 }
2c2fa1
 
2c2fa1
@@ -1236,20 +1442,11 @@ ppc64_sysv_abi_push_dummy_call (struct g
2c2fa1
   for (write_pass = 0; write_pass < 2; write_pass++)
2c2fa1
     {
2c2fa1
       int argno;
2c2fa1
-      /* Next available floating point register for float and double
2c2fa1
-         arguments.  */
2c2fa1
-      int freg = 1;
2c2fa1
-      /* Next available general register for non-vector (but possibly
2c2fa1
-         float) arguments.  */
2c2fa1
-      int greg = 3;
2c2fa1
-      /* Next available vector register for vector arguments.  */
2c2fa1
-      int vreg = 2;
2c2fa1
-      /* The address, at which the next general purpose parameter
2c2fa1
-         (integer, struct, float, vector, ...) should be saved.  */
2c2fa1
-      CORE_ADDR gparam;
2c2fa1
-      /* The address, at which the next by-reference parameter
2c2fa1
-	 (non-Altivec vector, variably-sized type) should be saved.  */
2c2fa1
-      CORE_ADDR refparam;
2c2fa1
+
2c2fa1
+      struct ppc64_sysv_argpos argpos;
2c2fa1
+      argpos.greg = 3;
2c2fa1
+      argpos.freg = 1;
2c2fa1
+      argpos.vreg = 2;
2c2fa1
 
2c2fa1
       if (!write_pass)
2c2fa1
 	{
2c2fa1
@@ -1257,19 +1454,21 @@ ppc64_sysv_abi_push_dummy_call (struct g
2c2fa1
 	     offsets (start address zero) than addresses.  That way
2c2fa1
 	     they accumulate the total stack space each region
2c2fa1
 	     requires.  */
2c2fa1
-	  gparam = 0;
2c2fa1
-	  refparam = 0;
2c2fa1
+	  argpos.regcache = NULL;
2c2fa1
+	  argpos.gparam = 0;
2c2fa1
+	  argpos.refparam = 0;
2c2fa1
 	}
2c2fa1
       else
2c2fa1
 	{
2c2fa1
 	  /* Decrement the stack pointer making space for the Altivec
2c2fa1
 	     and general on-stack parameters.  Set refparam and gparam
2c2fa1
 	     to their corresponding regions.  */
2c2fa1
-	  refparam = align_down (sp - refparam_size, 16);
2c2fa1
-	  gparam = align_down (refparam - gparam_size, 16);
2c2fa1
+	  argpos.regcache = regcache;
2c2fa1
+	  argpos.refparam = align_down (sp - refparam_size, 16);
2c2fa1
+	  argpos.gparam = align_down (argpos.refparam - gparam_size, 16);
2c2fa1
 	  /* Add in space for the TOC, link editor double word,
2c2fa1
 	     compiler double word, LR save area, CR save area.  */
2c2fa1
-	  sp = align_down (gparam - 48, 16);
2c2fa1
+	  sp = align_down (argpos.gparam - 48, 16);
2c2fa1
 	}
2c2fa1
 
2c2fa1
       /* If the function is returning a `struct', then there is an
2c2fa1
@@ -1278,14 +1477,7 @@ ppc64_sysv_abi_push_dummy_call (struct g
2c2fa1
          should advance one word and start from r4 register to copy
2c2fa1
          parameters.  This also consumes one on-stack parameter slot.  */
2c2fa1
       if (struct_return)
2c2fa1
-	{
2c2fa1
-	  if (write_pass)
2c2fa1
-	    regcache_cooked_write_signed (regcache,
2c2fa1
-					  tdep->ppc_gp0_regnum + greg,
2c2fa1
-					  struct_addr);
2c2fa1
-	  greg++;
2c2fa1
-	  gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
2c2fa1
-	}
2c2fa1
+	ppc64_sysv_abi_push_integer (gdbarch, struct_addr, &argpos);
2c2fa1
 
2c2fa1
       for (argno = 0; argno < nargs; argno++)
2c2fa1
 	{
2c2fa1
@@ -1293,432 +1485,54 @@ ppc64_sysv_abi_push_dummy_call (struct g
2c2fa1
 	  struct type *type = check_typedef (value_type (arg));
2c2fa1
 	  const bfd_byte *val = value_contents (arg);
2c2fa1
 
2c2fa1
-	  if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
2c2fa1
-	    {
2c2fa1
-	      if (write_pass)
2c2fa1
-		  ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
2c2fa1
-					     val, freg, greg, gparam);
2c2fa1
-
2c2fa1
-	      freg++;
2c2fa1
-	      greg++;
2c2fa1
-	      /* Always consume parameter stack space.  */
2c2fa1
-	      gparam = align_up (gparam + 8, tdep->wordsize);
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_CODE (type) == TYPE_CODE_FLT
2c2fa1
-		   && TYPE_LENGTH (type) == 16
2c2fa1
-		   && (gdbarch_long_double_format (gdbarch)
2c2fa1
-		       == floatformats_ibm_long_double))
2c2fa1
-	    {
2c2fa1
-	      if (write_pass)
2c2fa1
-		ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
2c2fa1
-					   val, freg, greg, gparam);
2c2fa1
-	      freg += 2;
2c2fa1
-	      greg += 2;
2c2fa1
-	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
2c2fa1
-	      && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16))
2c2fa1
-	    {
2c2fa1
-	      int i;
2c2fa1
-
2c2fa1
-	      for (i = 0; i < 2; i++)
2c2fa1
-		{
2c2fa1
-		  if (write_pass)
2c2fa1
-		    {
2c2fa1
-		      struct type *target_type;
2c2fa1
-
2c2fa1
-		      target_type = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
-		      ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
2c2fa1
-						 target_type, val + i *
2c2fa1
-						 TYPE_LENGTH (target_type),
2c2fa1
-						 freg, greg, gparam);
2c2fa1
-		    }
2c2fa1
-		  freg++;
2c2fa1
-		  greg++;
2c2fa1
-		  /* Always consume parameter stack space.  */
2c2fa1
-		  gparam = align_up (gparam + 8, tdep->wordsize);
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
2c2fa1
-		   && TYPE_LENGTH (type) == 32
2c2fa1
-		   && (gdbarch_long_double_format (gdbarch)
2c2fa1
-		       == floatformats_ibm_long_double))
2c2fa1
-	    {
2c2fa1
-	      int i;
2c2fa1
-
2c2fa1
-	      for (i = 0; i < 2; i++)
2c2fa1
-		{
2c2fa1
-		  struct type *target_type;
2c2fa1
-
2c2fa1
-		  target_type = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
-		  if (write_pass)
2c2fa1
-		    ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
2c2fa1
-					       target_type, val + i *
2c2fa1
-					       TYPE_LENGTH (target_type),
2c2fa1
-					       freg, greg, gparam);
2c2fa1
-		  freg += 2;
2c2fa1
-		  greg += 2;
2c2fa1
-		  gparam = align_up (gparam + TYPE_LENGTH (target_type),
2c2fa1
-				     tdep->wordsize);
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT
2c2fa1
-		   && TYPE_LENGTH (type) <= 8)
2c2fa1
-	    {
2c2fa1
-	      /* 32-bit and 64-bit decimal floats go in f1 .. f13.  They can
2c2fa1
-	         end up in memory.  */
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-		  const gdb_byte *p;
2c2fa1
-
2c2fa1
-		  /* 32-bit decimal floats are right aligned in the
2c2fa1
-		     doubleword.  */
2c2fa1
-		  if (TYPE_LENGTH (type) == 4)
2c2fa1
-		    {
2c2fa1
-		      memcpy (regval + 4, val, 4);
2c2fa1
-		      p = regval;
2c2fa1
-		    }
2c2fa1
-		  else
2c2fa1
-		    p = val;
2c2fa1
-
2c2fa1
-		  /* Write value in the stack's parameter save area.  */
2c2fa1
-		  write_memory (gparam, p, 8);
2c2fa1
-
2c2fa1
-		  if (freg <= 13)
2c2fa1
-		    regcache_cooked_write (regcache,
2c2fa1
-					   tdep->ppc_fp0_regnum + freg, p);
2c2fa1
-		}
2c2fa1
-
2c2fa1
-	      freg++;
2c2fa1
-	      greg++;
2c2fa1
-	      /* Always consume parameter stack space.  */
2c2fa1
-	      gparam = align_up (gparam + 8, tdep->wordsize);
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT &&
2c2fa1
-		   TYPE_LENGTH (type) == 16)
2c2fa1
+	  if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
2c2fa1
 	    {
2c2fa1
-	      /* 128-bit decimal floats go in f2 .. f12, always in even/odd
2c2fa1
-	         pairs.  They can end up in memory, using two doublewords.  */
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  if (freg <= 12)
2c2fa1
-		    {
2c2fa1
-		      /* Make sure freg is even.  */
2c2fa1
-		      freg += freg & 1;
2c2fa1
-		      regcache_cooked_write (regcache,
2c2fa1
-                                             tdep->ppc_fp0_regnum + freg, val);
2c2fa1
-		      regcache_cooked_write (regcache,
2c2fa1
-			  tdep->ppc_fp0_regnum + freg + 1, val + 8);
2c2fa1
-		    }
2c2fa1
-
2c2fa1
-		  write_memory (gparam, val, TYPE_LENGTH (type));
2c2fa1
-		}
2c2fa1
+	      /* Complex types are passed as if two independent scalars.  */
2c2fa1
+	      struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
 
2c2fa1
-	      freg += 2;
2c2fa1
-	      greg += 2;
2c2fa1
-	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
+	      ppc64_sysv_abi_push_param (gdbarch, eltype, val, &argpos);
2c2fa1
+	      ppc64_sysv_abi_push_param (gdbarch, eltype,
2c2fa1
+					 val + TYPE_LENGTH (eltype), &argpos);
2c2fa1
 	    }
2c2fa1
-	  else if (TYPE_LENGTH (type) < 16
2c2fa1
-		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
2c2fa1
-		   && TYPE_VECTOR (type)
2c2fa1
+	  else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
2c2fa1
 		   && opencl_abi)
2c2fa1
 	    {
2c2fa1
 	      /* OpenCL vectors shorter than 16 bytes are passed as if
2c2fa1
-		 a series of independent scalars.  */
2c2fa1
-	      struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
-	      int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
2c2fa1
+		 a series of independent scalars; OpenCL vectors 16 bytes
2c2fa1
+		 or longer are passed as if a series of AltiVec vectors.  */
2c2fa1
+	      struct type *eltype;
2c2fa1
+	      int i, nelt;
2c2fa1
+
2c2fa1
+	      if (TYPE_LENGTH (type) < 16)
2c2fa1
+		eltype = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
+	      else
2c2fa1
+		eltype = register_type (gdbarch, tdep->ppc_vr0_regnum);
2c2fa1
 
2c2fa1
+	      nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
2c2fa1
 	      for (i = 0; i < nelt; i++)
2c2fa1
 		{
2c2fa1
 		  const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
2c2fa1
 
2c2fa1
-		  if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
2c2fa1
-		    {
2c2fa1
-		      if (write_pass)
2c2fa1
-			{
2c2fa1
-			  gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-			  const gdb_byte *p;
2c2fa1
-
2c2fa1
-			  if (TYPE_LENGTH (eltype) == 4)
2c2fa1
-			    {
2c2fa1
-			      memcpy (regval, elval, 4);
2c2fa1
-			      memcpy (regval + 4, elval, 4);
2c2fa1
-			      p = regval;
2c2fa1
-			    }
2c2fa1
-			  else
2c2fa1
-			    p = elval;
2c2fa1
-
2c2fa1
-			  write_memory (gparam, p, 8);
2c2fa1
-
2c2fa1
-			  if (freg <= 13)
2c2fa1
-			    {
2c2fa1
-			      int regnum = tdep->ppc_fp0_regnum + freg;
2c2fa1
-			      struct type *regtype
2c2fa1
-				= register_type (gdbarch, regnum);
2c2fa1
-
2c2fa1
-			      convert_typed_floating (elval, eltype,
2c2fa1
-						      regval, regtype);
2c2fa1
-			      regcache_cooked_write (regcache, regnum, regval);
2c2fa1
-			    }
2c2fa1
-
2c2fa1
-			  if (greg <= 10)
2c2fa1
-			    regcache_cooked_write (regcache,
2c2fa1
-						   tdep->ppc_gp0_regnum + greg,
2c2fa1
-						   regval);
2c2fa1
-			}
2c2fa1
-
2c2fa1
-		      freg++;
2c2fa1
-		      greg++;
2c2fa1
-		      gparam = align_up (gparam + 8, tdep->wordsize);
2c2fa1
-		    }
2c2fa1
-		  else
2c2fa1
-		    {
2c2fa1
-		      if (write_pass)
2c2fa1
-			{
2c2fa1
-			  ULONGEST word = unpack_long (eltype, elval);
2c2fa1
-			  if (greg <= 10)
2c2fa1
-			    regcache_cooked_write_unsigned
2c2fa1
-			      (regcache, tdep->ppc_gp0_regnum + greg, word);
2c2fa1
-
2c2fa1
-			  write_memory_unsigned_integer
2c2fa1
-			    (gparam, tdep->wordsize, byte_order, word);
2c2fa1
-			}
2c2fa1
-
2c2fa1
-		      greg++;
2c2fa1
-		      gparam = align_up (gparam + TYPE_LENGTH (eltype),
2c2fa1
-					 tdep->wordsize);
2c2fa1
-		    }
2c2fa1
+		  ppc64_sysv_abi_push_param (gdbarch, eltype, elval, &argpos);
2c2fa1
 		}
2c2fa1
 	    }
2c2fa1
-	  else if (TYPE_LENGTH (type) >= 16
2c2fa1
-		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
2c2fa1
-		   && TYPE_VECTOR (type)
2c2fa1
-		   && opencl_abi)
2c2fa1
-	    {
2c2fa1
-	      /* OpenCL vectors 16 bytes or longer are passed as if
2c2fa1
-		 a series of AltiVec vectors.  */
2c2fa1
-	      int i;
2c2fa1
-
2c2fa1
-	      for (i = 0; i < TYPE_LENGTH (type) / 16; i++)
2c2fa1
-		{
2c2fa1
-		  const gdb_byte *elval = val + i * 16;
2c2fa1
-
2c2fa1
-		  gparam = align_up (gparam, 16);
2c2fa1
-		  greg += greg & 1;
2c2fa1
-
2c2fa1
-		  if (write_pass)
2c2fa1
-		    {
2c2fa1
-		      if (vreg <= 13)
2c2fa1
-			regcache_cooked_write (regcache,
2c2fa1
-					       tdep->ppc_vr0_regnum + vreg,
2c2fa1
-					       elval);
2c2fa1
-
2c2fa1
-		      write_memory (gparam, elval, 16);
2c2fa1
-		    }
2c2fa1
-
2c2fa1
-		  greg += 2;
2c2fa1
-		  vreg++;
2c2fa1
-		  gparam += 16;
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
2c2fa1
-		   && TYPE_CODE (type) == TYPE_CODE_ARRAY
2c2fa1
-		   && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
2c2fa1
-	    {
2c2fa1
-	      /* In the Altivec ABI, vectors go in the vector registers
2c2fa1
-		 v2 .. v13, as well as the parameter area -- always at
2c2fa1
-		 16-byte aligned addresses.  */
2c2fa1
-
2c2fa1
-	      gparam = align_up (gparam, 16);
2c2fa1
-	      greg += greg & 1;
2c2fa1
-
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  if (vreg <= 13)
2c2fa1
-		    regcache_cooked_write (regcache,
2c2fa1
-					   tdep->ppc_vr0_regnum + vreg, val);
2c2fa1
-
2c2fa1
-		  write_memory (gparam, val, TYPE_LENGTH (type));
2c2fa1
-		}
2c2fa1
-
2c2fa1
-	      greg += 2;
2c2fa1
-	      vreg++;
2c2fa1
-	      gparam += 16;
2c2fa1
-	    }
2c2fa1
-	  else if (TYPE_LENGTH (type) >= 16 && TYPE_VECTOR (type)
2c2fa1
-		   && TYPE_CODE (type) == TYPE_CODE_ARRAY)
2c2fa1
-	    {
2c2fa1
-	      /* Non-Altivec vectors are passed by reference.  */
2c2fa1
-
2c2fa1
-	      /* Copy value onto the stack ...  */
2c2fa1
-	      refparam = align_up (refparam, 16);
2c2fa1
-	      if (write_pass)
2c2fa1
-		write_memory (refparam, val, TYPE_LENGTH (type));
2c2fa1
-
2c2fa1
-	      /* ... and pass a pointer to the copy as parameter.  */
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  if (greg <= 10)
2c2fa1
-		    regcache_cooked_write_unsigned (regcache,
2c2fa1
-						    tdep->ppc_gp0_regnum +
2c2fa1
-						    greg, refparam);
2c2fa1
-		  write_memory_unsigned_integer (gparam, tdep->wordsize,
2c2fa1
-						 byte_order, refparam);
2c2fa1
-		}
2c2fa1
-	      greg++;
2c2fa1
-	      gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
2c2fa1
-	      refparam = align_up (refparam + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
-	    }
2c2fa1
-	  else if ((TYPE_CODE (type) == TYPE_CODE_INT
2c2fa1
-		    || TYPE_CODE (type) == TYPE_CODE_ENUM
2c2fa1
-		    || TYPE_CODE (type) == TYPE_CODE_BOOL
2c2fa1
-		    || TYPE_CODE (type) == TYPE_CODE_CHAR
2c2fa1
-		    || TYPE_CODE (type) == TYPE_CODE_PTR
2c2fa1
-		    || TYPE_CODE (type) == TYPE_CODE_REF)
2c2fa1
-		   && TYPE_LENGTH (type) <= 8)
2c2fa1
-	    {
2c2fa1
-	      /* Scalars and Pointers get sign[un]extended and go in
2c2fa1
-	         gpr3 .. gpr10.  They can also end up in memory.  */
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  /* Sign extend the value, then store it unsigned.  */
2c2fa1
-		  ULONGEST word = unpack_long (type, val);
2c2fa1
-		  /* Convert any function code addresses into
2c2fa1
-		     descriptors.  */
2c2fa1
-		  if (TYPE_CODE (type) == TYPE_CODE_PTR
2c2fa1
-		      || TYPE_CODE (type) == TYPE_CODE_REF)
2c2fa1
-		    {
2c2fa1
-		      struct type *target_type;
2c2fa1
-		      target_type = check_typedef (TYPE_TARGET_TYPE (type));
2c2fa1
-
2c2fa1
-		      if (TYPE_CODE (target_type) == TYPE_CODE_FUNC
2c2fa1
-			  || TYPE_CODE (target_type) == TYPE_CODE_METHOD)
2c2fa1
-			{
2c2fa1
-			  CORE_ADDR desc = word;
2c2fa1
-			  convert_code_addr_to_desc_addr (word, &desc);
2c2fa1
-			  word = desc;
2c2fa1
-			}
2c2fa1
-		    }
2c2fa1
-		  if (greg <= 10)
2c2fa1
-		    regcache_cooked_write_unsigned (regcache,
2c2fa1
-						    tdep->ppc_gp0_regnum +
2c2fa1
-						    greg, word);
2c2fa1
-		  write_memory_unsigned_integer (gparam, tdep->wordsize,
2c2fa1
-						 byte_order, word);
2c2fa1
-		}
2c2fa1
-	      greg++;
2c2fa1
-	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
-	    }
2c2fa1
 	  else
2c2fa1
 	    {
2c2fa1
-	      ssize_t byte;
2c2fa1
-	      for (byte = 0; byte < TYPE_LENGTH (type);
2c2fa1
-		   byte += tdep->wordsize)
2c2fa1
-		{
2c2fa1
-		  if (write_pass && greg <= 10)
2c2fa1
-		    {
2c2fa1
-		      gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-		      ssize_t len = TYPE_LENGTH (type) - byte;
2c2fa1
-		      if (len > tdep->wordsize)
2c2fa1
-			len = tdep->wordsize;
2c2fa1
-		      memset (regval, 0, sizeof regval);
2c2fa1
-		      /* The ABI (version 1.9) specifies that values
2c2fa1
-			 smaller than one doubleword are right-aligned
2c2fa1
-			 and those larger are left-aligned.  GCC
2c2fa1
-			 versions before 3.4 implemented this
2c2fa1
-			 incorrectly; see
2c2fa1
-			 <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>.  */
2c2fa1
-		      if (byte == 0)
2c2fa1
-			memcpy (regval + tdep->wordsize - len,
2c2fa1
-				val + byte, len);
2c2fa1
-		      else
2c2fa1
-			memcpy (regval, val + byte, len);
2c2fa1
-		      regcache_cooked_write (regcache, greg, regval);
2c2fa1
-		    }
2c2fa1
-		  greg++;
2c2fa1
-		}
2c2fa1
-	      if (write_pass)
2c2fa1
-		{
2c2fa1
-		  /* WARNING: cagney/2003-09-21: Strictly speaking, this
2c2fa1
-		     isn't necessary, unfortunately, GCC appears to get
2c2fa1
-		     "struct convention" parameter passing wrong putting
2c2fa1
-		     odd sized structures in memory instead of in a
2c2fa1
-		     register.  Work around this by always writing the
2c2fa1
-		     value to memory.  Fortunately, doing this
2c2fa1
-		     simplifies the code.  */
2c2fa1
-		  ssize_t len = TYPE_LENGTH (type);
2c2fa1
-		  if (len < tdep->wordsize)
2c2fa1
-		    write_memory (gparam + tdep->wordsize - len, val, len);
2c2fa1
-		  else
2c2fa1
-		    write_memory (gparam, val, len);
2c2fa1
-		}
2c2fa1
-	      if (freg <= 13
2c2fa1
-		  && TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
-		  && TYPE_NFIELDS (type) == 1
2c2fa1
-		  && TYPE_LENGTH (type) <= 16)
2c2fa1
-		{
2c2fa1
-		  /* The ABI (version 1.9) specifies that structs
2c2fa1
-		     containing a single floating-point value, at any
2c2fa1
-		     level of nesting of single-member structs, are
2c2fa1
-		     passed in floating-point registers.  */
2c2fa1
-		  while (TYPE_CODE (type) == TYPE_CODE_STRUCT
2c2fa1
-			 && TYPE_NFIELDS (type) == 1)
2c2fa1
-		    type = check_typedef (TYPE_FIELD_TYPE (type, 0));
2c2fa1
-		  if (TYPE_CODE (type) == TYPE_CODE_FLT)
2c2fa1
-		    {
2c2fa1
-		      if (TYPE_LENGTH (type) <= 8)
2c2fa1
-			{
2c2fa1
-			  if (write_pass)
2c2fa1
-			    {
2c2fa1
-			      gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-			      struct type *regtype
2c2fa1
-				= register_type (gdbarch,
2c2fa1
-						 tdep->ppc_fp0_regnum);
2c2fa1
-			      convert_typed_floating (val, type, regval,
2c2fa1
-						      regtype);
2c2fa1
-			      regcache_cooked_write (regcache,
2c2fa1
-						     (tdep->ppc_fp0_regnum
2c2fa1
-						      + freg),
2c2fa1
-						     regval);
2c2fa1
-			    }
2c2fa1
-			  freg++;
2c2fa1
-			}
2c2fa1
-		      else if (TYPE_LENGTH (type) == 16
2c2fa1
-			       && (gdbarch_long_double_format (gdbarch)
2c2fa1
-				   == floatformats_ibm_long_double))
2c2fa1
-			{
2c2fa1
-			  if (write_pass)
2c2fa1
-			    {
2c2fa1
-			      regcache_cooked_write (regcache,
2c2fa1
-						     (tdep->ppc_fp0_regnum
2c2fa1
-						      + freg),
2c2fa1
-						     val);
2c2fa1
-			      if (freg <= 12)
2c2fa1
-				regcache_cooked_write (regcache,
2c2fa1
-						       (tdep->ppc_fp0_regnum
2c2fa1
-							+ freg + 1),
2c2fa1
-						       val + 8);
2c2fa1
-			    }
2c2fa1
-			  freg += 2;
2c2fa1
-			}
2c2fa1
-		    }
2c2fa1
-		}
2c2fa1
-	      /* Always consume parameter stack space.  */
2c2fa1
-	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
2c2fa1
+	      /* All other types are passed as single arguments.  */
2c2fa1
+	      ppc64_sysv_abi_push_param (gdbarch, type, val, &argpos);
2c2fa1
 	    }
2c2fa1
 	}
2c2fa1
 
2c2fa1
       if (!write_pass)
2c2fa1
 	{
2c2fa1
 	  /* Save the true region sizes ready for the second pass.  */
2c2fa1
-	  refparam_size = refparam;
2c2fa1
+	  refparam_size = argpos.refparam;
2c2fa1
 	  /* Make certain that the general parameter save area is at
2c2fa1
 	     least the minimum 8 registers (or doublewords) in size.  */
2c2fa1
-	  if (greg < 8)
2c2fa1
+	  if (argpos.greg < 8)
2c2fa1
 	    gparam_size = 8 * tdep->wordsize;
2c2fa1
 	  else
2c2fa1
-	    gparam_size = gparam;
2c2fa1
+	    gparam_size = argpos.gparam;
2c2fa1
 	}
2c2fa1
     }
2c2fa1
 
2c2fa1
@@ -1754,271 +1568,252 @@ ppc64_sysv_abi_push_dummy_call (struct g
2c2fa1
   return sp;
2c2fa1
 }
2c2fa1
 
2c2fa1
+/* Subroutine of ppc64_sysv_abi_return_value that handles "base" types:
2c2fa1
+   integer, floating-point, and AltiVec vector types.
2c2fa1
 
2c2fa1
-/* The 64 bit ABI return value convention.
2c2fa1
+   This routine also handles components of aggregate return types;
2c2fa1
+   INDEX describes which part of the aggregate is to be handled.
2c2fa1
 
2c2fa1
-   Return non-zero if the return-value is stored in a register, return
2c2fa1
-   0 if the return-value is instead stored on the stack (a.k.a.,
2c2fa1
-   struct return convention).
2c2fa1
-
2c2fa1
-   For a return-value stored in a register: when WRITEBUF is non-NULL,
2c2fa1
-   copy the buffer to the corresponding register return-value location
2c2fa1
-   location; when READBUF is non-NULL, fill the buffer from the
2c2fa1
-   corresponding register return-value location.  */
2c2fa1
-enum return_value_convention
2c2fa1
-ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
2c2fa1
-			     struct type *valtype, struct regcache *regcache,
2c2fa1
-			     gdb_byte *readbuf, const gdb_byte *writebuf)
2c2fa1
+   Returns true if VALTYPE is some such base type that could be handled,
2c2fa1
+   false otherwise.  */
2c2fa1
+static int
2c2fa1
+ppc64_sysv_abi_return_value_base (struct gdbarch *gdbarch, struct type *valtype,
2c2fa1
+				  struct regcache *regcache, gdb_byte *readbuf,
2c2fa1
+				  const gdb_byte *writebuf, int index)
2c2fa1
 {
2c2fa1
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
2c2fa1
-  struct type *func_type = function ? value_type (function) : NULL;
2c2fa1
-  int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
2c2fa1
 
2c2fa1
-  /* This function exists to support a calling convention that
2c2fa1
-     requires floating-point registers.  It shouldn't be used on
2c2fa1
-     processors that lack them.  */
2c2fa1
-  gdb_assert (ppc_floating_point_unit_p (gdbarch));
2c2fa1
+  /* Integers live in GPRs starting at r3.  */
2c2fa1
+  if ((TYPE_CODE (valtype) == TYPE_CODE_INT
2c2fa1
+       || TYPE_CODE (valtype) == TYPE_CODE_ENUM
2c2fa1
+       || TYPE_CODE (valtype) == TYPE_CODE_CHAR
2c2fa1
+       || TYPE_CODE (valtype) == TYPE_CODE_BOOL)
2c2fa1
+      && TYPE_LENGTH (valtype) <= 8)
2c2fa1
+    {
2c2fa1
+      int regnum = tdep->ppc_gp0_regnum + 3 + index;
2c2fa1
 
2c2fa1
-  /* Floats and doubles in F1.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
2c2fa1
+      if (writebuf != NULL)
2c2fa1
+	{
2c2fa1
+	  /* Be careful to sign extend the value.  */
2c2fa1
+	  regcache_cooked_write_unsigned (regcache, regnum,
2c2fa1
+					  unpack_long (valtype, writebuf));
2c2fa1
+	}
2c2fa1
+      if (readbuf != NULL)
2c2fa1
+	{
2c2fa1
+	  /* Extract the integer from GPR.  Since this is truncating the
2c2fa1
+	     value, there isn't a sign extension problem.  */
2c2fa1
+	  ULONGEST regval;
2c2fa1
+
2c2fa1
+	  regcache_cooked_read_unsigned (regcache, regnum, &regval);
2c2fa1
+	  store_unsigned_integer (readbuf, TYPE_LENGTH (valtype),
2c2fa1
+				  gdbarch_byte_order (gdbarch), regval);
2c2fa1
+	}
2c2fa1
+      return 1;
2c2fa1
+    }
2c2fa1
+
2c2fa1
+  /* Floats and doubles go in f1 .. f13.  32-bit floats are converted
2c2fa1
+     to double first.  */
2c2fa1
+  if (TYPE_LENGTH (valtype) <= 8
2c2fa1
+      && TYPE_CODE (valtype) == TYPE_CODE_FLT)
2c2fa1
     {
2c2fa1
+      int regnum = tdep->ppc_fp0_regnum + 1 + index;
2c2fa1
+      struct type *regtype = register_type (gdbarch, regnum);
2c2fa1
       gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-      struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
2c2fa1
+
2c2fa1
       if (writebuf != NULL)
2c2fa1
 	{
2c2fa1
 	  convert_typed_floating (writebuf, valtype, regval, regtype);
2c2fa1
-	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
2c2fa1
+	  regcache_cooked_write (regcache, regnum, regval);
2c2fa1
 	}
2c2fa1
       if (readbuf != NULL)
2c2fa1
 	{
2c2fa1
-	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
2c2fa1
+	  regcache_cooked_read (regcache, regnum, regval);
2c2fa1
 	  convert_typed_floating (regval, regtype, readbuf, valtype);
2c2fa1
 	}
2c2fa1
-      return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
+      return 1;
2c2fa1
     }
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
2c2fa1
-    return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf,
2c2fa1
-					   writebuf);
2c2fa1
-  /* Integers in r3.  */
2c2fa1
-  if ((TYPE_CODE (valtype) == TYPE_CODE_INT
2c2fa1
-       || TYPE_CODE (valtype) == TYPE_CODE_ENUM
2c2fa1
-       || TYPE_CODE (valtype) == TYPE_CODE_CHAR
2c2fa1
-       || TYPE_CODE (valtype) == TYPE_CODE_BOOL)
2c2fa1
-      && TYPE_LENGTH (valtype) <= 8)
2c2fa1
+
2c2fa1
+  /* Floats and doubles go in f1 .. f13.  32-bit decimal floats are
2c2fa1
+     placed in the least significant word.  */
2c2fa1
+  if (TYPE_LENGTH (valtype) <= 8
2c2fa1
+      && TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
2c2fa1
     {
2c2fa1
+      int regnum = tdep->ppc_fp0_regnum + 1 + index;
2c2fa1
+      int offset = 8 - TYPE_LENGTH (valtype);
2c2fa1
+
2c2fa1
+      if (writebuf != NULL)
2c2fa1
+	regcache_cooked_write_part (regcache, regnum,
2c2fa1
+				    offset, TYPE_LENGTH (valtype), writebuf);
2c2fa1
+      if (readbuf != NULL)
2c2fa1
+	regcache_cooked_read_part (regcache, regnum,
2c2fa1
+				   offset, TYPE_LENGTH (valtype), readbuf);
2c2fa1
+      return 1;
2c2fa1
+    }
2c2fa1
+
2c2fa1
+  /* IBM long double stored in two consecutive FPRs.  */
2c2fa1
+  if (TYPE_LENGTH (valtype) == 16
2c2fa1
+      && TYPE_CODE (valtype) == TYPE_CODE_FLT
2c2fa1
+      && (gdbarch_long_double_format (gdbarch)
2c2fa1
+	  == floatformats_ibm_long_double))
2c2fa1
+    {
2c2fa1
+      int regnum = tdep->ppc_fp0_regnum + 1 + 2 * index;
2c2fa1
+
2c2fa1
       if (writebuf != NULL)
2c2fa1
 	{
2c2fa1
-	  /* Be careful to sign extend the value.  */
2c2fa1
-	  regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
2c2fa1
-					  unpack_long (valtype, writebuf));
2c2fa1
+	  regcache_cooked_write (regcache, regnum, writebuf);
2c2fa1
+	  regcache_cooked_write (regcache, regnum + 1, writebuf + 8);
2c2fa1
 	}
2c2fa1
       if (readbuf != NULL)
2c2fa1
 	{
2c2fa1
-	  /* Extract the integer from r3.  Since this is truncating the
2c2fa1
-	     value, there isn't a sign extension problem.  */
2c2fa1
-	  ULONGEST regval;
2c2fa1
-	  regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
2c2fa1
-					 &regval);
2c2fa1
-	  store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), byte_order,
2c2fa1
-				  regval);
2c2fa1
+	  regcache_cooked_read (regcache, regnum, readbuf);
2c2fa1
+	  regcache_cooked_read (regcache, regnum + 1, readbuf + 8);
2c2fa1
 	}
2c2fa1
-      return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
+      return 1;
2c2fa1
     }
2c2fa1
-  /* All pointers live in r3.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_PTR
2c2fa1
-      || TYPE_CODE (valtype) == TYPE_CODE_REF)
2c2fa1
+
2c2fa1
+  /* 128-bit decimal floating-point values are stored in an even/odd
2c2fa1
+     pair of FPRs, with the even FPR holding the most significant half.  */
2c2fa1
+  if (TYPE_LENGTH (valtype) == 16
2c2fa1
+      && TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
2c2fa1
     {
2c2fa1
-      /* All pointers live in r3.  */
2c2fa1
+      int regnum = tdep->ppc_fp0_regnum + 2 + 2 * index;
2c2fa1
+
2c2fa1
       if (writebuf != NULL)
2c2fa1
-	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
2c2fa1
+	{
2c2fa1
+	  regcache_cooked_write (regcache, regnum, writebuf);
2c2fa1
+	  regcache_cooked_write (regcache, regnum + 1, writebuf + 8);
2c2fa1
+	}
2c2fa1
       if (readbuf != NULL)
2c2fa1
-	regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
2c2fa1
-      return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
+	{
2c2fa1
+	  regcache_cooked_read (regcache, regnum, readbuf);
2c2fa1
+	  regcache_cooked_read (regcache, regnum + 1, readbuf + 8);
2c2fa1
+	}
2c2fa1
+      return 1;
2c2fa1
     }
2c2fa1
-  /* OpenCL vectors < 16 bytes are returned as distinct
2c2fa1
-     scalars in f1..f2 or r3..r10.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
2c2fa1
-      && TYPE_VECTOR (valtype)
2c2fa1
-      && TYPE_LENGTH (valtype) < 16
2c2fa1
-      && opencl_abi)
2c2fa1
+
2c2fa1
+  /* AltiVec vectors are returned in VRs starting at v2.  */
2c2fa1
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
2c2fa1
+      && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
2c2fa1
     {
2c2fa1
-      struct type *eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
2c2fa1
-      int i, nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
2c2fa1
+      int regnum = tdep->ppc_vr0_regnum + 2 + index;
2c2fa1
 
2c2fa1
-      for (i = 0; i < nelt; i++)
2c2fa1
-	{
2c2fa1
-	  int offset = i * TYPE_LENGTH (eltype);
2c2fa1
+      if (writebuf != NULL)
2c2fa1
+	regcache_cooked_write (regcache, regnum, writebuf);
2c2fa1
+      if (readbuf != NULL)
2c2fa1
+	regcache_cooked_read (regcache, regnum, readbuf);
2c2fa1
+      return 1;
2c2fa1
+    }
2c2fa1
 
2c2fa1
-	  if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
2c2fa1
-	    {
2c2fa1
-	      int regnum = tdep->ppc_fp0_regnum + 1 + i;
2c2fa1
-	      gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-	      struct type *regtype = register_type (gdbarch, regnum);
2c2fa1
+  return 0;
2c2fa1
+}
2c2fa1
 
2c2fa1
-	      if (writebuf != NULL)
2c2fa1
-		{
2c2fa1
-		  convert_typed_floating (writebuf + offset, eltype,
2c2fa1
-					  regval, regtype);
2c2fa1
-		  regcache_cooked_write (regcache, regnum, regval);
2c2fa1
-		}
2c2fa1
-	      if (readbuf != NULL)
2c2fa1
-		{
2c2fa1
-		  regcache_cooked_read (regcache, regnum, regval);
2c2fa1
-		  convert_typed_floating (regval, regtype,
2c2fa1
-					  readbuf + offset, eltype);
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	  else
2c2fa1
-	    {
2c2fa1
-	      int regnum = tdep->ppc_gp0_regnum + 3 + i;
2c2fa1
-	      ULONGEST regval;
2c2fa1
+/* The 64 bit ABI return value convention.
2c2fa1
 
2c2fa1
-	      if (writebuf != NULL)
2c2fa1
-		{
2c2fa1
-		  regval = unpack_long (eltype, writebuf + offset);
2c2fa1
-		  regcache_cooked_write_unsigned (regcache, regnum, regval);
2c2fa1
-		}
2c2fa1
-	      if (readbuf != NULL)
2c2fa1
-		{
2c2fa1
-		  regcache_cooked_read_unsigned (regcache, regnum, &regval);
2c2fa1
-		  store_unsigned_integer (readbuf + offset,
2c2fa1
-					  TYPE_LENGTH (eltype), byte_order,
2c2fa1
-					  regval);
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	}
2c2fa1
+   Return non-zero if the return-value is stored in a register, return
2c2fa1
+   0 if the return-value is instead stored on the stack (a.k.a.,
2c2fa1
+   struct return convention).
2c2fa1
 
2c2fa1
-      return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
-    }
2c2fa1
-  /* OpenCL vectors >= 16 bytes are returned in v2..v9.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
2c2fa1
-      && TYPE_VECTOR (valtype)
2c2fa1
-      && TYPE_LENGTH (valtype) >= 16
2c2fa1
-      && opencl_abi)
2c2fa1
+   For a return-value stored in a register: when WRITEBUF is non-NULL,
2c2fa1
+   copy the buffer to the corresponding register return-value location
2c2fa1
+   location; when READBUF is non-NULL, fill the buffer from the
2c2fa1
+   corresponding register return-value location.  */
2c2fa1
+enum return_value_convention
2c2fa1
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
2c2fa1
+			     struct type *valtype, struct regcache *regcache,
2c2fa1
+			     gdb_byte *readbuf, const gdb_byte *writebuf)
2c2fa1
+{
2c2fa1
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
2c2fa1
+  struct type *func_type = function ? value_type (function) : NULL;
2c2fa1
+  int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
2c2fa1
+  struct type *eltype;
2c2fa1
+  int nelt, i, ok;
2c2fa1
+
2c2fa1
+  /* This function exists to support a calling convention that
2c2fa1
+     requires floating-point registers.  It shouldn't be used on
2c2fa1
+     processors that lack them.  */
2c2fa1
+  gdb_assert (ppc_floating_point_unit_p (gdbarch));
2c2fa1
+
2c2fa1
+  /* Complex types are returned as if two independent scalars.  */
2c2fa1
+  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX)
2c2fa1
     {
2c2fa1
-      int n_regs = TYPE_LENGTH (valtype) / 16;
2c2fa1
-      int i;
2c2fa1
+      eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
2c2fa1
 
2c2fa1
-      for (i = 0; i < n_regs; i++)
2c2fa1
+      for (i = 0; i < 2; i++)
2c2fa1
 	{
2c2fa1
-	  int offset = i * 16;
2c2fa1
-	  int regnum = tdep->ppc_vr0_regnum + 2 + i;
2c2fa1
+	  ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
2c2fa1
+						 readbuf, writebuf, i);
2c2fa1
+	  gdb_assert (ok);
2c2fa1
 
2c2fa1
-	  if (writebuf != NULL)
2c2fa1
-	    regcache_cooked_write (regcache, regnum, writebuf + offset);
2c2fa1
-	  if (readbuf != NULL)
2c2fa1
-	    regcache_cooked_read (regcache, regnum, readbuf + offset);
2c2fa1
+	  if (readbuf)
2c2fa1
+	    readbuf += TYPE_LENGTH (eltype);
2c2fa1
+	  if (writebuf)
2c2fa1
+	    writebuf += TYPE_LENGTH (eltype);
2c2fa1
 	}
2c2fa1
-
2c2fa1
       return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
     }
2c2fa1
-  /* Array type has more than one use.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
2c2fa1
-    {
2c2fa1
-      /* Small character arrays are returned, right justified, in r3.  */
2c2fa1
-      if (TYPE_LENGTH (valtype) <= 8
2c2fa1
-        && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
2c2fa1
-        && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
2c2fa1
-        {
2c2fa1
-          int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
2c2fa1
-                       - TYPE_LENGTH (valtype));
2c2fa1
-          if (writebuf != NULL)
2c2fa1
-           regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
2c2fa1
-                                      offset, TYPE_LENGTH (valtype), writebuf);
2c2fa1
-          if (readbuf != NULL)
2c2fa1
-           regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
2c2fa1
-                                      offset, TYPE_LENGTH (valtype), readbuf);
2c2fa1
-          return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
-	}
2c2fa1
-      /* A VMX vector is returned in v2.  */
2c2fa1
-      if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
2c2fa1
-	  && TYPE_VECTOR (valtype)
2c2fa1
-	  && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
2c2fa1
-        {
2c2fa1
-          if (readbuf)
2c2fa1
-            regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
2c2fa1
-          if (writebuf)
2c2fa1
-            regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2,
2c2fa1
-				   writebuf);
2c2fa1
-          return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
-        }
2c2fa1
-    }
2c2fa1
-  /* Big floating point values get stored in adjacent floating
2c2fa1
-     point registers, starting with F1.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_FLT
2c2fa1
-      && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
2c2fa1
+
2c2fa1
+  /* OpenCL vectors shorter than 16 bytes are returned as if
2c2fa1
+     a series of independent scalars; OpenCL vectors 16 bytes
2c2fa1
+     or longer are returned as if a series of AltiVec vectors.  */
2c2fa1
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
2c2fa1
+      && opencl_abi)
2c2fa1
     {
2c2fa1
-      if (writebuf || readbuf != NULL)
2c2fa1
+      if (TYPE_LENGTH (valtype) < 16)
2c2fa1
+	eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
2c2fa1
+      else
2c2fa1
+	eltype = register_type (gdbarch, tdep->ppc_vr0_regnum);
2c2fa1
+
2c2fa1
+      nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
2c2fa1
+      for (i = 0; i < nelt; i++)
2c2fa1
 	{
2c2fa1
-	  int i;
2c2fa1
-	  for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
2c2fa1
-	    {
2c2fa1
-	      if (writebuf != NULL)
2c2fa1
-		regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-				       (const bfd_byte *) writebuf + i * 8);
2c2fa1
-	      if (readbuf != NULL)
2c2fa1
-		regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-				      (bfd_byte *) readbuf + i * 8);
2c2fa1
-	    }
2c2fa1
+	  ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
2c2fa1
+						 readbuf, writebuf, i);
2c2fa1
+	  gdb_assert (ok);
2c2fa1
+
2c2fa1
+	  if (readbuf)
2c2fa1
+	    readbuf += TYPE_LENGTH (eltype);
2c2fa1
+	  if (writebuf)
2c2fa1
+	    writebuf += TYPE_LENGTH (eltype);
2c2fa1
 	}
2c2fa1
       return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
     }
2c2fa1
-  /* Complex values get returned in f1:f2, need to convert.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
2c2fa1
-      && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
2c2fa1
+
2c2fa1
+  /* All pointers live in r3.  */
2c2fa1
+  if (TYPE_CODE (valtype) == TYPE_CODE_PTR
2c2fa1
+      || TYPE_CODE (valtype) == TYPE_CODE_REF)
2c2fa1
     {
2c2fa1
-      if (regcache != NULL)
2c2fa1
-	{
2c2fa1
-	  int i;
2c2fa1
-	  for (i = 0; i < 2; i++)
2c2fa1
-	    {
2c2fa1
-	      gdb_byte regval[MAX_REGISTER_SIZE];
2c2fa1
-	      struct type *regtype =
2c2fa1
-		register_type (gdbarch, tdep->ppc_fp0_regnum);
2c2fa1
-	      struct type *target_type;
2c2fa1
-	      target_type = check_typedef (TYPE_TARGET_TYPE (valtype));
2c2fa1
-	      if (writebuf != NULL)
2c2fa1
-		{
2c2fa1
-		  convert_typed_floating ((const bfd_byte *) writebuf +
2c2fa1
-					  i * TYPE_LENGTH (target_type), 
2c2fa1
-					  target_type, regval, regtype);
2c2fa1
-		  regcache_cooked_write (regcache,
2c2fa1
-                                         tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-					 regval);
2c2fa1
-		}
2c2fa1
-	      if (readbuf != NULL)
2c2fa1
-		{
2c2fa1
-		  regcache_cooked_read (regcache,
2c2fa1
-                                        tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-                                        regval);
2c2fa1
-		  convert_typed_floating (regval, regtype,
2c2fa1
-					  (bfd_byte *) readbuf +
2c2fa1
-					  i * TYPE_LENGTH (target_type),
2c2fa1
-					  target_type);
2c2fa1
-		}
2c2fa1
-	    }
2c2fa1
-	}
2c2fa1
+      int regnum = tdep->ppc_gp0_regnum + 3;
2c2fa1
+
2c2fa1
+      if (writebuf != NULL)
2c2fa1
+	regcache_cooked_write (regcache, regnum, writebuf);
2c2fa1
+      if (readbuf != NULL)
2c2fa1
+	regcache_cooked_read (regcache, regnum, readbuf);
2c2fa1
       return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
     }
2c2fa1
-  /* Big complex values get stored in f1:f4.  */
2c2fa1
-  if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32)
2c2fa1
+
2c2fa1
+  /* Small character arrays are returned, right justified, in r3.  */
2c2fa1
+  if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
2c2fa1
+      && TYPE_LENGTH (valtype) <= 8
2c2fa1
+      && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
2c2fa1
+      && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
2c2fa1
     {
2c2fa1
-      if (regcache != NULL)
2c2fa1
-	{
2c2fa1
-	  int i;
2c2fa1
-	  for (i = 0; i < 4; i++)
2c2fa1
-	    {
2c2fa1
-	      if (writebuf != NULL)
2c2fa1
-		regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-				       (const bfd_byte *) writebuf + i * 8);
2c2fa1
-	      if (readbuf != NULL)
2c2fa1
-		regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
2c2fa1
-				      (bfd_byte *) readbuf + i * 8);
2c2fa1
-	    }
2c2fa1
-	}
2c2fa1
+      int regnum = tdep->ppc_gp0_regnum + 3;
2c2fa1
+      int offset = (register_size (gdbarch, regnum) - TYPE_LENGTH (valtype));
2c2fa1
+
2c2fa1
+      if (writebuf != NULL)
2c2fa1
+	regcache_cooked_write_part (regcache, regnum,
2c2fa1
+				    offset, TYPE_LENGTH (valtype), writebuf);
2c2fa1
+      if (readbuf != NULL)
2c2fa1
+	regcache_cooked_read_part (regcache, regnum,
2c2fa1
+				   offset, TYPE_LENGTH (valtype), readbuf);
2c2fa1
       return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
     }
2c2fa1
+
2c2fa1
+  /* Handle plain base types.  */
2c2fa1
+  if (ppc64_sysv_abi_return_value_base (gdbarch, valtype, regcache,
2c2fa1
+					readbuf, writebuf, 0))
2c2fa1
+    return RETURN_VALUE_REGISTER_CONVENTION;
2c2fa1
+
2c2fa1
   return RETURN_VALUE_STRUCT_CONVENTION;
2c2fa1
 }
2c2fa1