Blob Blame History Raw
From fcf256ceeab4b0b74cf1e18122e894aafce94fdc Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Thu, 30 Aug 2012 01:37:23 +0200
Subject: [PATCH] PPC64 passes floating point equivalent structures in
 registers as well

Extract the structure unpacking code from s390 back end into the generic
type module.  Call this from both s390 and ppc back ends.
---
 sysdeps/linux-gnu/ppc/fetch.c  |   21 +++++++++++++++++++--
 sysdeps/linux-gnu/s390/fetch.c |   31 +------------------------------
 type.c                         |   34 ++++++++++++++++++++++++++++++++++
 type.h                         |    7 +++++++
 4 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
index 44cd056..40c91d9 100644
--- a/sysdeps/linux-gnu/ppc/fetch.c
+++ b/sysdeps/linux-gnu/ppc/fetch.c
@@ -340,13 +340,30 @@ allocate_argument(struct fetch_context *ctx, struct Process *proc,
 	while (slots-- > 0) {
 		struct value val;
 		value_init(&val, proc, NULL, long_info, 0);
-		int rc = allocate_gpr(ctx, proc, long_info, &val);
+
+		/* Floating point registers [...] are used [...] to
+		   pass [...] one member aggregates passed by value
+		   containing a floating point value[.]  Note that for
+		   one member aggregates, "containing" extends to
+		   aggregates within aggregates ad infinitum.  */
+		int rc;
+		struct arg_type_info *fp_info
+			= type_get_fp_equivalent(valuep->type);
+		if (fp_info != NULL)
+			rc = allocate_float(ctx, proc, fp_info, &val);
+		else
+			rc = allocate_gpr(ctx, proc, long_info, &val);
+
 		if (rc >= 0) {
 			memcpy(ptr, value_get_data(&val, NULL), width);
 			ptr += width;
 		}
 		value_destroy(&val);
-		if (rc < 0)
+
+		/* Bail out if we failed or if we are dealing with
+		 * FP-equivalent.  Those don't need the adjustments
+		 * made below.  */
+		if (rc < 0 || fp_info != NULL)
 			return rc;
 	}
 
diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c
index 5d26b35..c46ef7c 100644
--- a/sysdeps/linux-gnu/s390/fetch.c
+++ b/sysdeps/linux-gnu/s390/fetch.c
@@ -61,35 +61,6 @@ s390x(struct fetch_context *ctx)
 }
 
 static int
-fp_equivalent(struct arg_type_info *info)
-{
-	switch (info->type) {
-	case ARGTYPE_VOID:
-	case ARGTYPE_INT:
-	case ARGTYPE_UINT:
-	case ARGTYPE_LONG:
-	case ARGTYPE_ULONG:
-	case ARGTYPE_CHAR:
-	case ARGTYPE_SHORT:
-	case ARGTYPE_USHORT:
-	case ARGTYPE_ARRAY:
-	case ARGTYPE_POINTER:
-		return 0;
-
-	case ARGTYPE_FLOAT:
-	case ARGTYPE_DOUBLE:
-		return 1;
-
-	case ARGTYPE_STRUCT:
-		if (type_struct_size(info) != 1)
-			return 0;
-		return fp_equivalent(type_element(info, 0));
-	}
-	assert(info->type != info->type);
-	abort();
-}
-
-static int
 fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
 {
 	ptrace_area parea;
@@ -256,7 +227,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
 		return 0;
 
 	case ARGTYPE_STRUCT:
-		if (fp_equivalent(info))
+		if (type_get_fp_equivalent(info) != NULL)
 			/* fall through */
 	case ARGTYPE_FLOAT:
 	case ARGTYPE_DOUBLE:
diff --git a/type.c b/type.c
index 6341042..4b9a645 100644
--- a/type.c
+++ b/type.c
@@ -513,3 +513,37 @@ type_is_signed(enum arg_type type)
 	}
 	abort();
 }
+
+struct arg_type_info *
+type_get_fp_equivalent(struct arg_type_info *info)
+{
+	/* Extract innermost structure.  Give up early if any
+	 * component has more than one element.  */
+	while (info->type == ARGTYPE_STRUCT) {
+		if (type_struct_size(info) != 1)
+			return NULL;
+		info = type_element(info, 0);
+	}
+
+	switch (info->type) {
+	case ARGTYPE_CHAR:
+	case ARGTYPE_SHORT:
+	case ARGTYPE_INT:
+	case ARGTYPE_LONG:
+	case ARGTYPE_UINT:
+	case ARGTYPE_ULONG:
+	case ARGTYPE_USHORT:
+	case ARGTYPE_VOID:
+	case ARGTYPE_ARRAY:
+	case ARGTYPE_POINTER:
+		return NULL;
+
+	case ARGTYPE_FLOAT:
+	case ARGTYPE_DOUBLE:
+		return info;
+
+	case ARGTYPE_STRUCT:
+		abort();
+	}
+	abort();
+}
diff --git a/type.h b/type.h
index 545173c..53123b8 100644
--- a/type.h
+++ b/type.h
@@ -130,4 +130,11 @@ int type_is_integral(enum arg_type type);
 /* Whether TYPE, which shall be integral, is a signed type.  */
 int type_is_signed(enum arg_type type);
 
+/* If INFO is floating point equivalent type, return the corresponding
+ * floating point type.  Otherwise return NULL.  Floating point
+ * equivalent types are either ARGTYPE_FLOAT, or ARGTYPE_DOUBLE, or
+ * ARGTYPE_STRUCT whose sole member is a floating point equivalent
+ * type.  */
+struct arg_type_info *type_get_fp_equivalent(struct arg_type_info *info);
+
 #endif /* TYPE_H */
-- 
1.7.6.5