mirror of git://gcc.gnu.org/git/gcc.git
ffi.c (ffi_prep_cif_machdep): Handle functions that return long long values.
* src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return long long values. Round stack allocation to a multiple of 8 bytes for ATPCS compatibility. * src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register names. Handle returning long long types. Add Thumb and interworking support. Improve soft-float code. From-SVN: r89681
This commit is contained in:
parent
5ae4c56561
commit
f20459f1b2
|
@ -1,3 +1,12 @@
|
||||||
|
2004-10-27 Richard Earnshaw <rearnsha@arm.com>
|
||||||
|
|
||||||
|
* src/arm/ffi.c (ffi_prep_cif_machdep): Handle functions that return
|
||||||
|
long long values. Round stack allocation to a multiple of 8 bytes
|
||||||
|
for ATPCS compatibility.
|
||||||
|
* src/arm/sysv.S (ffi_call_SYSV): Rework to avoid use of APCS register
|
||||||
|
names. Handle returning long long types. Add Thumb and interworking
|
||||||
|
support. Improve soft-float code.
|
||||||
|
|
||||||
2004-10-27 Richard Earnshaw <rearnsha@arm.com>
|
2004-10-27 Richard Earnshaw <rearnsha@arm.com>
|
||||||
|
|
||||||
* testsuite/lib/libffi-db.exp (load_gcc_lib): New function.
|
* testsuite/lib/libffi-db.exp (load_gcc_lib): New function.
|
||||||
|
|
|
@ -108,6 +108,11 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
|
||||||
/* Perform machine dependent cif processing */
|
/* Perform machine dependent cif processing */
|
||||||
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
{
|
{
|
||||||
|
/* Round the stack up to a multiple of 8 bytes. This isn't needed
|
||||||
|
everywhere, but it is on some platforms, and it doesn't harm anything
|
||||||
|
when it isn't needed. */
|
||||||
|
cif->bytes = (cif->bytes + 7) & ~7;
|
||||||
|
|
||||||
/* Set the return type flag */
|
/* Set the return type flag */
|
||||||
switch (cif->rtype->type)
|
switch (cif->rtype->type)
|
||||||
{
|
{
|
||||||
|
@ -118,6 +123,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||||
cif->flags = (unsigned) cif->rtype->type;
|
cif->flags = (unsigned) cif->rtype->type;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case FFI_TYPE_SINT64:
|
||||||
|
case FFI_TYPE_UINT64:
|
||||||
|
cif->flags = (unsigned) FFI_TYPE_SINT64;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cif->flags = FFI_TYPE_INT;
|
cif->flags = FFI_TYPE_INT;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,87 +40,169 @@
|
||||||
#endif
|
#endif
|
||||||
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
|
#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ELF__
|
||||||
|
#define LSYM(x) .x
|
||||||
|
#else
|
||||||
|
#define LSYM(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We need a better way of testing for this, but for now, this is all
|
||||||
|
we can do. */
|
||||||
|
@ This selects the minimum architecture level required.
|
||||||
|
#define __ARM_ARCH__ 3
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||||
|
# undef __ARM_ARCH__
|
||||||
|
# define __ARM_ARCH__ 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|
||||||
|
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|
||||||
|
|| defined(__ARM_ARCH_5TEJ__)
|
||||||
|
# undef __ARM_ARCH__
|
||||||
|
# define __ARM_ARCH__ 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|
||||||
|
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|
||||||
|
|| defined(__ARM_ARCH_6ZK__)
|
||||||
|
# undef __ARM_ARCH__
|
||||||
|
# define __ARM_ARCH__ 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __ARM_ARCH__ >= 5
|
||||||
|
# define call_reg(x) blx x
|
||||||
|
#elif defined (__ARM_ARCH_4T__)
|
||||||
|
# define call_reg(x) mov lr, pc ; bx x
|
||||||
|
# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
|
||||||
|
# define __INTERWORKING__
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define call_reg(x) mov lr, pc ; mov pc, x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
|
||||||
|
.macro ARM_FUNC_START name
|
||||||
|
.text
|
||||||
|
.align 0
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
ENTRY(\name)
|
||||||
|
bx pc
|
||||||
|
nop
|
||||||
|
.arm
|
||||||
|
/* A hook to tell gdb that we've switched to ARM mode. Also used to call
|
||||||
|
directly from other local arm routines. */
|
||||||
|
_L__\name:
|
||||||
|
.endm
|
||||||
|
#else
|
||||||
|
.macro ARM_FUNC_START name
|
||||||
|
.text
|
||||||
|
.align 0
|
||||||
|
.arm
|
||||||
|
ENTRY(\name)
|
||||||
|
.endm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.macro RETLDM regs=, cond=, dirn=ia
|
||||||
|
#if defined (__INTERWORKING__)
|
||||||
|
.ifc "\regs",""
|
||||||
|
ldr\cond lr, [sp], #4
|
||||||
|
.else
|
||||||
|
ldm\cond\dirn sp!, {\regs, lr}
|
||||||
|
.endif
|
||||||
|
bx\cond lr
|
||||||
|
#else
|
||||||
|
.ifc "\regs",""
|
||||||
|
ldr\cond pc, [sp], #4
|
||||||
|
.else
|
||||||
|
ldm\cond\dirn sp!, {\regs, pc}
|
||||||
|
.endif
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
@ r0: ffi_prep_args
|
||||||
|
@ r1: &ecif
|
||||||
|
@ r2: cif->bytes
|
||||||
|
@ r3: fig->flags
|
||||||
|
@ sp+0: ecif.rvalue
|
||||||
|
@ sp+4: fn
|
||||||
|
|
||||||
|
@ This assumes we are using gas.
|
||||||
|
ARM_FUNC_START ffi_call_SYSV
|
||||||
|
@ Save registers
|
||||||
|
stmfd sp!, {r0-r3, fp, lr}
|
||||||
|
mov fp, sp
|
||||||
|
|
||||||
|
@ Make room for all of the new args.
|
||||||
|
sub sp, fp, r2
|
||||||
|
|
||||||
|
@ Place all of the ffi_prep_args in position
|
||||||
|
mov ip, r0
|
||||||
|
mov r0, sp
|
||||||
|
@ r1 already set
|
||||||
|
|
||||||
|
@ Call ffi_prep_args(stack, &ecif)
|
||||||
|
call_reg(ip)
|
||||||
|
|
||||||
|
@ move first 4 parameters in registers
|
||||||
|
ldmia sp, {r0-r3}
|
||||||
|
|
||||||
|
@ and adjust stack
|
||||||
|
ldr ip, [fp, #8]
|
||||||
|
cmp ip, #16
|
||||||
|
movhs ip, #16
|
||||||
|
add sp, sp, ip
|
||||||
|
|
||||||
|
@ call (fn) (...)
|
||||||
|
ldr ip, [fp, #28]
|
||||||
|
call_reg(ip)
|
||||||
|
|
||||||
.text
|
@ Remove the space we pushed for the args
|
||||||
|
mov sp, fp
|
||||||
|
|
||||||
# a1: ffi_prep_args
|
@ Load r2 with the pointer to storage for the return value
|
||||||
# a2: &ecif
|
ldr r2, [sp, #24]
|
||||||
# a3: cif->bytes
|
|
||||||
# a4: fig->flags
|
|
||||||
# sp+0: ecif.rvalue
|
|
||||||
# sp+4: fn
|
|
||||||
|
|
||||||
# This assumes we are using gas.
|
@ Load r3 with the return type code
|
||||||
ENTRY(ffi_call_SYSV)
|
ldr r3, [sp, #12]
|
||||||
# Save registers
|
|
||||||
stmfd sp!, {a1-a4, fp, lr}
|
|
||||||
mov fp, sp
|
|
||||||
|
|
||||||
# Make room for all of the new args.
|
@ If the return value pointer is NULL, assume no return value.
|
||||||
sub sp, fp, a3
|
cmp r2, #0
|
||||||
|
beq LSYM(Lepilogue)
|
||||||
|
|
||||||
# Place all of the ffi_prep_args in position
|
@ return INT
|
||||||
mov ip, a1
|
cmp r3, #FFI_TYPE_INT
|
||||||
mov a1, sp
|
|
||||||
# a2 already set
|
|
||||||
|
|
||||||
# And call
|
|
||||||
mov lr, pc
|
|
||||||
mov pc, ip
|
|
||||||
|
|
||||||
# move first 4 parameters in registers
|
|
||||||
ldr a1, [sp, #0]
|
|
||||||
ldr a2, [sp, #4]
|
|
||||||
ldr a3, [sp, #8]
|
|
||||||
ldr a4, [sp, #12]
|
|
||||||
|
|
||||||
# and adjust stack
|
|
||||||
ldr ip, [fp, #8]
|
|
||||||
cmp ip, #16
|
|
||||||
movge ip, #16
|
|
||||||
add sp, sp, ip
|
|
||||||
|
|
||||||
# call function
|
|
||||||
mov lr, pc
|
|
||||||
ldr pc, [fp, #28]
|
|
||||||
|
|
||||||
# Remove the space we pushed for the args
|
|
||||||
mov sp, fp
|
|
||||||
|
|
||||||
# Load a3 with the pointer to storage for the return value
|
|
||||||
ldr a3, [sp, #24]
|
|
||||||
|
|
||||||
# Load a4 with the return type code
|
|
||||||
ldr a4, [sp, #12]
|
|
||||||
|
|
||||||
# If the return value pointer is NULL, assume no return value.
|
|
||||||
cmp a3, #0
|
|
||||||
beq epilogue
|
|
||||||
|
|
||||||
# return INT
|
|
||||||
cmp a4, #FFI_TYPE_INT
|
|
||||||
streq a1, [a3]
|
|
||||||
beq epilogue
|
|
||||||
|
|
||||||
# return FLOAT
|
|
||||||
cmp a4, #FFI_TYPE_FLOAT
|
|
||||||
#ifdef __SOFTFP__
|
#ifdef __SOFTFP__
|
||||||
streq a1, [a3]
|
cmpne r3, #FFI_TYPE_FLOAT
|
||||||
#else
|
|
||||||
stfeqs f0, [a3]
|
|
||||||
#endif
|
#endif
|
||||||
beq epilogue
|
streq r0, [r2]
|
||||||
|
beq LSYM(Lepilogue)
|
||||||
|
|
||||||
# return DOUBLE or LONGDOUBLE
|
@ return INT64
|
||||||
cmp a4, #FFI_TYPE_DOUBLE
|
cmp r3, #FFI_TYPE_SINT64
|
||||||
#ifdef __SOFTFP__
|
#ifdef __SOFTFP__
|
||||||
stmeqia a3, {a1, a2}
|
cmpne r3, #FFI_TYPE_DOUBLE
|
||||||
#else
|
#endif
|
||||||
stfeqd f0, [a3]
|
stmeqia r2, {r0, r1}
|
||||||
|
|
||||||
|
#ifndef __SOFTFP__
|
||||||
|
beq LSYM(Lepilogue)
|
||||||
|
|
||||||
|
@ return FLOAT
|
||||||
|
cmp r3, #FFI_TYPE_FLOAT
|
||||||
|
stfeqs f0, [r2]
|
||||||
|
beq LSYM(Lepilogue)
|
||||||
|
|
||||||
|
@ return DOUBLE or LONGDOUBLE
|
||||||
|
cmp r3, #FFI_TYPE_DOUBLE
|
||||||
|
stfeqd f0, [r2]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
epilogue:
|
LSYM(Lepilogue):
|
||||||
ldmfd sp!, {a1-a4, fp, pc}
|
RETLDM "r0-r3,fp"
|
||||||
|
|
||||||
.ffi_call_SYSV_end:
|
.ffi_call_SYSV_end:
|
||||||
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
|
||||||
|
|
Loading…
Reference in New Issue