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:
@@ -66,7 +66,8 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||||||
break;
|
break;
|
||||||
case FFI_TYPE_LONGDOUBLE:
|
case FFI_TYPE_LONGDOUBLE:
|
||||||
case FFI_TYPE_STRUCT:
|
case FFI_TYPE_STRUCT:
|
||||||
flags = SPARC_RET_STRUCT;
|
flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
|
||||||
|
flags |= SPARC_RET_STRUCT;
|
||||||
break;
|
break;
|
||||||
case FFI_TYPE_SINT8:
|
case FFI_TYPE_SINT8:
|
||||||
flags = SPARC_RET_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 (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.
|
/* Since we pass the pointer to the callee, we need a value.
|
||||||
We allowed for this space in ffi_call, before ffi_call_v8
|
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
|
/* 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. */
|
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);
|
bytes += ALIGN (cif->rtype->size, 8);
|
||||||
|
|
||||||
ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
|
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 *));
|
avalue = alloca(nargs * sizeof(void *));
|
||||||
|
|
||||||
/* Copy the caller's structure return address so that the closure
|
/* Copy the caller's structure return address so that the closure
|
||||||
returns the data directly to the caller. */
|
returns the data directly to the caller. Also install it so we
|
||||||
if (flags == SPARC_RET_STRUCT)
|
can return the address in %o0. */
|
||||||
rvalue = (void *)*argp;
|
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. */
|
/* Always skip the structure return address. */
|
||||||
argp++;
|
argp++;
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ ffi_prep_cif_machdep(ffi_cif *cif)
|
|||||||
int all_mask = (1 << word_size) - 1;
|
int all_mask = (1 << word_size) - 1;
|
||||||
int fp_mask = size_mask >> 8;
|
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
|
/* For special cases of all-int or all-fp, we can return
|
||||||
the value directly without popping through a struct copy. */
|
the value directly without popping through a struct copy. */
|
||||||
|
|||||||
@@ -23,4 +23,4 @@
|
|||||||
#define SPARC_FLAG_RET_IN_MEM 32
|
#define SPARC_FLAG_RET_IN_MEM 32
|
||||||
#define SPARC_FLAG_FP_ARGS 64
|
#define SPARC_FLAG_FP_ARGS 64
|
||||||
|
|
||||||
#define SPARC_FLTMASK_SHIFT 8
|
#define SPARC_SIZEMASK_SHIFT 8
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ C(ffi_call_v8):
|
|||||||
|
|
||||||
add %sp, 32, %sp ! deallocate prep frame
|
add %sp, 32, %sp ! deallocate prep frame
|
||||||
and %o0, SPARC_FLAG_RET_MASK, %l0 ! save return type
|
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+4], %o0 ! load all argument registers
|
||||||
ld [%sp+64+8], %o1
|
ld [%sp+64+8], %o1
|
||||||
ld [%sp+64+12], %o2
|
ld [%sp+64+12], %o2
|
||||||
@@ -182,14 +183,6 @@ E SPARC_RET_F_1
|
|||||||
ret
|
ret
|
||||||
restore
|
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
|
.align 8
|
||||||
9: sth %o0, [%i2]
|
9: sth %o0, [%i2]
|
||||||
ret
|
ret
|
||||||
@@ -199,6 +192,27 @@ E SPARC_RET_F_1
|
|||||||
ret
|
ret
|
||||||
restore
|
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
|
cfi_endproc
|
||||||
.size C(ffi_call_v8),. - C(ffi_call_v8)
|
.size C(ffi_call_v8),. - C(ffi_call_v8)
|
||||||
|
|
||||||
@@ -275,6 +289,7 @@ E SPARC_RET_VOID
|
|||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
E SPARC_RET_STRUCT
|
E SPARC_RET_STRUCT
|
||||||
|
ld [%i2], %i0
|
||||||
jmp %i7+12
|
jmp %i7+12
|
||||||
restore
|
restore
|
||||||
E SPARC_RET_UINT8
|
E SPARC_RET_UINT8
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ E SPARC_RET_F_1
|
|||||||
std %f6, [%l2+56]
|
std %f6, [%l2+56]
|
||||||
|
|
||||||
! Copy the structure into place.
|
! 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 %i2, %o1 ! load dst
|
||||||
mov %l2, %o2 ! load src_gp
|
mov %l2, %o2 ! load src_gp
|
||||||
call C(ffi_struct_float_copy)
|
call C(ffi_struct_float_copy)
|
||||||
|
|||||||
Reference in New Issue
Block a user