This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
[PATCH 8/8] sparc: Re-add abi compliant structure support
- From: Richard Henderson <rth at twiddle dot net>
- To: libffi-discuss at sourceware dot org
- Cc: davem at davemloft dot net
- Date: Tue, 28 Oct 2014 12:45:55 -0700
- Subject: [PATCH 8/8] sparc: Re-add abi compliant structure support
- Authentication-results: sourceware.org; auth=none
- References: <1414525555-21256-1-git-send-email-rth at twiddle dot net>
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