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.
This commit is contained in:
Richard Henderson
2014-10-26 15:29:04 -07:00
parent 92022496ef
commit 6eec410f15
5 changed files with 39 additions and 17 deletions

View File

@@ -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++;

View File

@@ -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. */

View File

@@ -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

View File

@@ -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,14 +183,6 @@ 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
ret
restore
.align 8
9: sth %o0, [%i2]
ret
@@ -199,6 +192,27 @@ E SPARC_RET_F_1
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
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

View File

@@ -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)