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

01917d
commit cc0e89c519912e0e4e75a2fc0d836f715cdc6806
01917d
Author: Ulrich Weigand <ulrich.weigand@de.ibm.com>
01917d
Date:   Tue Feb 4 18:42:35 2014 +0100
01917d
01917d
    PowerPC64 ELFv2 ABI: structure passing / return
01917d
    
01917d
    Another significant difference in the ELFv2 ABI is that "homogeneous"
01917d
    floating-point and vector aggregates, i.e. aggregates the consist
01917d
    (recursively) only of members of the same floating-point or vector type,
01917d
    are passed in a series of floating-point / vector registers, as if they
01917d
    were seperate parameters.  (This is similar to the ARM ABI.)  This
01917d
    applies to both calls and returns.
01917d
    
01917d
    In addition when returning any aggregate of up to 16 bytes, ELFv2 now
01917d
    used general-purpose registers.
01917d
    
01917d
    This patch adds support for these aspects of the ABI, which is relatively
01917d
    straightforward after the refactoring patch to ppc-sysv-tdep.c.
01917d
    
01917d
    gdb/ChangeLog:
01917d
    
01917d
    	* ppc-sysv-tdep.c (ppc64_aggregate_candidate): New routine.
01917d
    	(ppc64_elfv2_abi_homogeneous_aggregate): Likewise.
01917d
    	(ppc64_sysv_abi_push_param): Handle ELFv2 homogeneous structs.
01917d
    	(ppc64_sysv_abi_return_value): Likewise.  Also, handle small
01917d
    	structures returned in GPRs.
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
@@ -1100,6 +1100,160 @@ convert_code_addr_to_desc_addr (CORE_ADD
01917d
   return 1;
01917d
 }
01917d
 
01917d
+/* Walk down the type tree of TYPE counting consecutive base elements.
01917d
+   If *FIELD_TYPE is NULL, then set it to the first valid floating point
01917d
+   or vector type.  If a non-floating point or vector type is found, or
01917d
+   if a floating point or vector type that doesn't match a non-NULL
01917d
+   *FIELD_TYPE is found, then return -1, otherwise return the count in the
01917d
+   sub-tree.  */
01917d
+
01917d
+static LONGEST
01917d
+ppc64_aggregate_candidate (struct type *type,
01917d
+			   struct type **field_type)
01917d
+{
01917d
+  type = check_typedef (type);
01917d
+
01917d
+  switch (TYPE_CODE (type))
01917d
+    {
01917d
+    case TYPE_CODE_FLT:
01917d
+    case TYPE_CODE_DECFLOAT:
01917d
+      if (!*field_type)
01917d
+	*field_type = type;
01917d
+      if (TYPE_CODE (*field_type) == TYPE_CODE (type)
01917d
+	  && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
01917d
+	return 1;
01917d
+      break;
01917d
+
01917d
+    case TYPE_CODE_COMPLEX:
01917d
+      type = TYPE_TARGET_TYPE (type);
01917d
+      if (TYPE_CODE (type) == TYPE_CODE_FLT
01917d
+	  || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
01917d
+	{
01917d
+	  if (!*field_type)
01917d
+	    *field_type = type;
01917d
+	  if (TYPE_CODE (*field_type) == TYPE_CODE (type)
01917d
+	      && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
01917d
+	    return 2;
01917d
+	}
01917d
+      break;
01917d
+
01917d
+    case TYPE_CODE_ARRAY:
01917d
+      if (TYPE_VECTOR (type))
01917d
+	{
01917d
+	  if (!*field_type)
01917d
+	    *field_type = type;
01917d
+	  if (TYPE_CODE (*field_type) == TYPE_CODE (type)
01917d
+	      && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
01917d
+	    return 1;
01917d
+	}
01917d
+      else
01917d
+	{
01917d
+	  LONGEST count, low_bound, high_bound;
01917d
+
01917d
+	  count = ppc64_aggregate_candidate
01917d
+		   (TYPE_TARGET_TYPE (type), field_type);
01917d
+	  if (count == -1)
01917d
+	    return -1;
01917d
+
01917d
+	  if (!get_array_bounds (type, &low_bound, &high_bound))
01917d
+	    return -1;
01917d
+	  count *= high_bound - low_bound;
01917d
+
01917d
+	  /* There must be no padding.  */
01917d
+	  if (count == 0)
01917d
+	    return TYPE_LENGTH (type) == 0 ? 0 : -1;
01917d
+	  else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
01917d
+	    return -1;
01917d
+
01917d
+	  return count;
01917d
+	}
01917d
+      break;
01917d
+
01917d
+    case TYPE_CODE_STRUCT:
01917d
+    case TYPE_CODE_UNION:
01917d
+	{
01917d
+	  LONGEST count = 0;
01917d
+	  int i;
01917d
+
01917d
+	  for (i = 0; i < TYPE_NFIELDS (type); i++)
01917d
+	    {
01917d
+	      LONGEST sub_count;
01917d
+
01917d
+	      if (field_is_static (&TYPE_FIELD (type, i)))
01917d
+		continue;
01917d
+
01917d
+	      sub_count = ppc64_aggregate_candidate
01917d
+			   (TYPE_FIELD_TYPE (type, i), field_type);
01917d
+	      if (sub_count == -1)
01917d
+		return -1;
01917d
+
01917d
+	      if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
01917d
+		count += sub_count;
01917d
+	      else
01917d
+		count = max (count, sub_count);
01917d
+	    }
01917d
+
01917d
+	  /* There must be no padding.  */
01917d
+	  if (count == 0)
01917d
+	    return TYPE_LENGTH (type) == 0 ? 0 : -1;
01917d
+	  else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
01917d
+	    return -1;
01917d
+
01917d
+	  return count;
01917d
+	}
01917d
+      break;
01917d
+
01917d
+    default:
01917d
+      break;
01917d
+    }
01917d
+
01917d
+  return -1;
01917d
+}
01917d
+
01917d
+/* If an argument of type TYPE is a homogeneous float or vector aggregate
01917d
+   that shall be passed in FP/vector registers according to the ELFv2 ABI,
01917d
+   return the homogeneous element type in *ELT_TYPE and the number of
01917d
+   elements in *N_ELTS, and return non-zero.  Otherwise, return zero.  */
01917d
+
01917d
+static int
01917d
+ppc64_elfv2_abi_homogeneous_aggregate (struct type *type,
01917d
+				       struct type **elt_type, int *n_elts)
01917d
+{
01917d
+  /* Complex types at the top level are treated separately.  However,
01917d
+     complex types can be elements of homogeneous aggregates.  */
01917d
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
01917d
+      || TYPE_CODE (type) == TYPE_CODE_UNION
01917d
+      || (TYPE_CODE (type) == TYPE_CODE_ARRAY && !TYPE_VECTOR (type)))
01917d
+    {
01917d
+      struct type *field_type = NULL;
01917d
+      LONGEST field_count = ppc64_aggregate_candidate (type, &field_type);
01917d
+
01917d
+      if (field_count > 0)
01917d
+	{
01917d
+	  int n_regs = ((TYPE_CODE (field_type) == TYPE_CODE_FLT
01917d
+			 || TYPE_CODE (field_type) == TYPE_CODE_DECFLOAT)?
01917d
+			(TYPE_LENGTH (field_type) + 7) >> 3 : 1);
01917d
+
01917d
+	  /* The ELFv2 ABI allows homogeneous aggregates to occupy
01917d
+	     up to 8 registers.  */
01917d
+	  if (field_count * n_regs <= 8)
01917d
+	    {
01917d
+	      if (elt_type)
01917d
+		*elt_type = field_type;
01917d
+	      if (n_elts)
01917d
+		*n_elts = (int) field_count;
01917d
+	      /* Note that field_count is LONGEST since it may hold the size
01917d
+		 of an array, while *n_elts is int since its value is bounded
01917d
+		 by the number of registers used for argument passing.  The
01917d
+		 cast cannot overflow due to the bounds checking above.  */
01917d
+	      return 1;
01917d
+	    }
01917d
+	}
01917d
+    }
01917d
+
01917d
+  return 0;
01917d
+}
01917d
+
01917d
 /* Structure holding the next argument position.  */
01917d
 struct ppc64_sysv_argpos
01917d
   {
01917d
@@ -1388,6 +1542,29 @@ ppc64_sysv_abi_push_param (struct gdbarc
01917d
 	  if (TYPE_CODE (type) == TYPE_CODE_FLT)
01917d
 	    ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
01917d
 	}
01917d
+
01917d
+      /* In the ELFv2 ABI, homogeneous floating-point or vector
01917d
+	 aggregates are passed in a series of registers.  */
01917d
+      if (tdep->elf_abi == POWERPC_ELF_V2)
01917d
+	{
01917d
+	  struct type *eltype;
01917d
+	  int i, nelt;
01917d
+
01917d
+	  if (ppc64_elfv2_abi_homogeneous_aggregate (type, &eltype, &nelt))
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
+		    || TYPE_CODE (eltype) == TYPE_CODE_DECFLOAT)
01917d
+		  ppc64_sysv_abi_push_freg (gdbarch, eltype, elval, argpos);
01917d
+		else if (TYPE_CODE (eltype) == TYPE_CODE_ARRAY
01917d
+			 && TYPE_VECTOR (eltype)
01917d
+			 && tdep->vector_abi == POWERPC_VEC_ALTIVEC
01917d
+			 && TYPE_LENGTH (eltype) == 16)
01917d
+		  ppc64_sysv_abi_push_vreg (gdbarch, elval, argpos);
01917d
+	      }
01917d
+	}
01917d
     }
01917d
 }
01917d
 
01917d
@@ -1833,6 +2010,72 @@ ppc64_sysv_abi_return_value (struct gdba
01917d
       return RETURN_VALUE_REGISTER_CONVENTION;
01917d
     }
01917d
 
01917d
+  /* In the ELFv2 ABI, homogeneous floating-point or vector
01917d
+     aggregates are returned in registers.  */
01917d
+  if (tdep->elf_abi == POWERPC_ELF_V2
01917d
+      && ppc64_elfv2_abi_homogeneous_aggregate (valtype, &eltype, &nelt))
01917d
+    {
01917d
+      for (i = 0; i < nelt; i++)
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
+
01917d
+      return RETURN_VALUE_REGISTER_CONVENTION;
01917d
+    }
01917d
+
01917d
+  /* In the ELFv2 ABI, aggregate types of up to 16 bytes are
01917d
+     returned in registers r3:r4.  */
01917d
+  if (tdep->elf_abi == POWERPC_ELF_V2
01917d
+      && TYPE_LENGTH (valtype) <= 16
01917d
+      && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
01917d
+	  || TYPE_CODE (valtype) == TYPE_CODE_UNION
01917d
+	  || (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
01917d
+	      && !TYPE_VECTOR (valtype))))
01917d
+    {
01917d
+      int n_regs = ((TYPE_LENGTH (valtype) + tdep->wordsize - 1)
01917d
+		    / tdep->wordsize);
01917d
+      int i;
01917d
+
01917d
+      for (i = 0; i < n_regs; i++)
01917d
+	{
01917d
+	  gdb_byte regval[MAX_REGISTER_SIZE];
01917d
+	  int regnum = tdep->ppc_gp0_regnum + 3 + i;
01917d
+	  int offset = i * tdep->wordsize;
01917d
+	  int len = TYPE_LENGTH (valtype) - offset;
01917d
+
01917d
+	  if (len > tdep->wordsize)
01917d
+	    len = tdep->wordsize;
01917d
+
01917d
+	  if (writebuf != NULL)
01917d
+	    {
01917d
+	      memset (regval, 0, sizeof regval);
01917d
+	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
01917d
+		  && offset == 0)
01917d
+		memcpy (regval + tdep->wordsize - len, writebuf, len);
01917d
+	      else
01917d
+		memcpy (regval, writebuf + offset, len);
01917d
+	      regcache_cooked_write (regcache, regnum, regval);
01917d
+	    }
01917d
+	  if (readbuf != NULL)
01917d
+	    {
01917d
+	      regcache_cooked_read (regcache, regnum, regval);
01917d
+	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
01917d
+		  && offset == 0)
01917d
+		memcpy (readbuf, regval + tdep->wordsize - len, len);
01917d
+	      else
01917d
+		memcpy (readbuf + offset, regval, len);
01917d
+	    }
01917d
+	}
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))