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

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