This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 8/8] sparc: Re-add abi compliant structure support


The original code, removed in the "rewrite" patch, was incorrect for
large structures, and required dynamic allocation of a trampoline on
every ffi_call.

Instead, allocate a 4k entry table of all possible structure returns.
The table is 80k, but is read-only and dynamically paged, which ought
to be better than allocating the trampoline.

This is difficult to test with gcc.  One can only use -O0 at present.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63668.
---
 src/sparc/ffi.c      | 19 +++++++++++++------
 src/sparc/ffi64.c    |  2 +-
 src/sparc/internal.h |  2 +-
 src/sparc/v8.S       | 29 ++++++++++++++++++++++-------
 src/sparc/v9.S       |  2 +-
 5 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/src/sparc/ffi.c b/src/sparc/ffi.c
index 19c3586..d5212d8 100644
--- a/src/sparc/ffi.c
+++ b/src/sparc/ffi.c
@@ -66,7 +66,8 @@ ffi_prep_cif_machdep(ffi_cif *cif)
       break;
     case FFI_TYPE_LONGDOUBLE:
     case FFI_TYPE_STRUCT:
-      flags = SPARC_RET_STRUCT;
+      flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
+      flags |= SPARC_RET_STRUCT;
       break;
     case FFI_TYPE_SINT8:
       flags = SPARC_RET_SINT8;
@@ -187,7 +188,7 @@ ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
 
   if (rvalue == NULL)
     {
-      if (flags == SPARC_RET_STRUCT)
+      if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
 	{
 	  /* Since we pass the pointer to the callee, we need a value.
 	     We allowed for this space in ffi_call, before ffi_call_v8
@@ -290,7 +291,8 @@ ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
 
   /* If we've not got a return value, we need to create one if we've
      got to pass the return value to the callee.  Otherwise ignore it.  */
-  if (rvalue == NULL && cif->flags == SPARC_RET_STRUCT)
+  if (rvalue == NULL
+      && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
     bytes += ALIGN (cif->rtype->size, 8);
 
   ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
@@ -382,9 +384,14 @@ ffi_closure_sparc_inner_v8(ffi_cif *cif,
   avalue = alloca(nargs * sizeof(void *));
 
   /* Copy the caller's structure return address so that the closure
-     returns the data directly to the caller.  */
-  if (flags == SPARC_RET_STRUCT)
-    rvalue = (void *)*argp;
+     returns the data directly to the caller.  Also install it so we
+     can return the address in %o0.  */
+  if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
+    {
+      void *new_rvalue = (void *)*argp;
+      *(void **)rvalue = new_rvalue;
+      rvalue = new_rvalue;
+    }
 
   /* Always skip the structure return address.  */
   argp++;
diff --git a/src/sparc/ffi64.c b/src/sparc/ffi64.c
index 02f3d75..a4e41d2 100644
--- a/src/sparc/ffi64.c
+++ b/src/sparc/ffi64.c
@@ -197,7 +197,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
 	  int all_mask = (1 << word_size) - 1;
 	  int fp_mask = size_mask >> 8;
 
-	  flags = (size_mask << SPARC_FLTMASK_SHIFT) | SPARC_RET_STRUCT;
+	  flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
 
 	  /* For special cases of all-int or all-fp, we can return
 	     the value directly without popping through a struct copy.  */
diff --git a/src/sparc/internal.h b/src/sparc/internal.h
index f9387d4..0a66472 100644
--- a/src/sparc/internal.h
+++ b/src/sparc/internal.h
@@ -23,4 +23,4 @@
 #define SPARC_FLAG_RET_IN_MEM	32
 #define SPARC_FLAG_FP_ARGS	64
 
-#define SPARC_FLTMASK_SHIFT	8
+#define SPARC_SIZEMASK_SHIFT	8
diff --git a/src/sparc/v8.S b/src/sparc/v8.S
index 66cf76f..3a811ef 100644
--- a/src/sparc/v8.S
+++ b/src/sparc/v8.S
@@ -91,6 +91,7 @@ C(ffi_call_v8):
 
 	add	%sp, 32, %sp		! deallocate prep frame
 	and	%o0, SPARC_FLAG_RET_MASK, %l0	! save return type
+	srl	%o0, SPARC_SIZEMASK_SHIFT, %l1	! save return size
 	ld	[%sp+64+4], %o0		! load all argument registers
 	ld	[%sp+64+8], %o1
 	ld	[%sp+64+12], %o2
@@ -182,22 +183,35 @@ E SPARC_RET_F_1
 	ret
 	 restore
 
-	! Struct returning functions expect and skip the unimp here.
 	.align	8
-8:	call	%i1
-	 mov	%i5, %g2		! load static chain
-	unimp	4
+9:	sth	%o0, [%i2]
 	ret
 	 restore
-
 	.align	8
-9:	sth	%o0, [%i2]
+10:	stb	%o0, [%i2]
 	ret
 	 restore
+
+	! Struct returning functions expect and skip the unimp here.
+	! To make it worse, conforming callees examine the unimp and
+	! make sure the low 12 bits of the unimp match the size of
+	! the struct being returned.
 	.align	8
-10:	stb	%o0, [%i2]
+8:	call	1f				! load pc in %o7
+	 sll	%l1, 2, %l0			! size * 4
+1:	sll	%l1, 4, %l1			! size * 16
+	add	%l0, %l1, %l0			! size * 20
+	add	%o7, %l0, %o7			! o7 = 0b + size*20
+	jmp	%o7+(2f-8b)
+	 mov	%i5, %g2			! load static chain
+2:
+.rept	0x1000
+	call	%i1
+	 nop
+	unimp	(. - 2b) / 20
 	ret
 	 restore
+.endr
 
 	cfi_endproc
 	.size	C(ffi_call_v8),. - C(ffi_call_v8)
@@ -275,6 +289,7 @@ E SPARC_RET_VOID
 	ret
 	 restore
 E SPARC_RET_STRUCT
+	ld	[%i2], %i0
 	jmp	%i7+12
 	 restore
 E SPARC_RET_UINT8
diff --git a/src/sparc/v9.S b/src/sparc/v9.S
index d848f9a..52732d3 100644
--- a/src/sparc/v9.S
+++ b/src/sparc/v9.S
@@ -188,7 +188,7 @@ E SPARC_RET_F_1
 	std	%f6, [%l2+56]
 
 	! Copy the structure into place.
-	srl	%l0, SPARC_FLTMASK_SHIFT, %o0	! load size_mask
+	srl	%l0, SPARC_SIZEMASK_SHIFT, %o0	! load size_mask
 	mov	%i2, %o1			! load dst
 	mov	%l2, %o2			! load src_gp
 	call	C(ffi_struct_float_copy)
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]