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

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