ffitarget.h (enum ffi_abi): Add FFI_LINUX.

* src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX.  Default
	for 32-bit using IBM extended double format.  Fix FFI_LAST_ABI.
	* src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
	FFI_TYPE_LONGDOUBLE.
	(ffi_prep_args64): Assert using IBM extended double.
	(ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
	Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
	(ffi_call): Handle FFI_LINUX.
	(ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
	gpr3 return pointer as for struct return.  Handle FFI_LINUX
	FFI_TYPE_LONGDOUBLE return and args.  Don't increment "nf"
	unnecessarily.
	* src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
	for FFI_TYPE_LONGDOUBLE.  Move epilogue insns into case table.
	Don't use r6 as pointer to results, instead use sp offset.  Don't
	make a special call to load lr with case table address, instead
	use offset from previous call.
	* src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
	* src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
	return.

From-SVN: r112340
This commit is contained in:
Alan Modra 2006-03-23 23:15:46 +00:00 committed by Alan Modra
parent 5b314bb3ef
commit 75b8b1becb
6 changed files with 275 additions and 219 deletions

View File

@ -1,3 +1,26 @@
2006-03-24 Alan Modra <amodra@bigpond.net.au>
* src/powerpc/ffitarget.h (enum ffi_abi): Add FFI_LINUX. Default
for 32-bit using IBM extended double format. Fix FFI_LAST_ABI.
* src/powerpc/ffi.c (ffi_prep_args_SYSV): Handle linux variant of
FFI_TYPE_LONGDOUBLE.
(ffi_prep_args64): Assert using IBM extended double.
(ffi_prep_cif_machdep): Don't munge FFI_TYPE_LONGDOUBLE type.
Handle FFI_LINUX FFI_TYPE_LONGDOUBLE return and args.
(ffi_call): Handle FFI_LINUX.
(ffi_closure_helper_SYSV): Non FFI_LINUX long double return needs
gpr3 return pointer as for struct return. Handle FFI_LINUX
FFI_TYPE_LONGDOUBLE return and args. Don't increment "nf"
unnecessarily.
* src/powerpc/ppc_closure.S (ffi_closure_SYSV): Load both f1 and f2
for FFI_TYPE_LONGDOUBLE. Move epilogue insns into case table.
Don't use r6 as pointer to results, instead use sp offset. Don't
make a special call to load lr with case table address, instead
use offset from previous call.
* src/powerpc/sysv.S (ffi_call_SYSV): Save long double return.
* src/powerpc/linux64.S (ffi_call_LINUX64): Simplify long double
return.
2006-03-15 Kaz Kojima <kkojima@gcc.gnu.org>
* src/sh64/ffi.c (ffi_prep_cif_machdep): Handle float arguments

View File

@ -197,6 +197,38 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (ecif->cif->abi != FFI_LINUX)
goto do_struct;
double_tmp = (*p_argv.d)[0];
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
{
if (intarg_count >= NUM_GPR_ARG_REGISTERS
&& intarg_count % 2 != 0)
{
intarg_count++;
next_arg.u++;
}
*next_arg.d = double_tmp;
next_arg.u += 2;
double_tmp = (*p_argv.d)[1];
*next_arg.d = double_tmp;
next_arg.u += 2;
}
else
{
*fpr_base.d++ = double_tmp;
double_tmp = (*p_argv.d)[1];
*fpr_base.d++ = double_tmp;
}
fparg_count += 2;
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
#endif
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
@ -232,7 +264,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
do_struct:
#endif
struct_copy_size = ((*ptr)->size + 15) & ~0xF;
copy_space.c -= struct_copy_size;
@ -433,6 +465,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
if (fparg_count < NUM_FPR_ARG_REGISTERS64)
*fpr_base.d++ = double_tmp;
fparg_count++;
FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
break;
#endif
@ -536,11 +569,6 @@ ffi_prep_cif_machdep (ffi_cif *cif)
/* Space for the mandatory parm save area and general registers. */
bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (type == FFI_TYPE_LONGDOUBLE)
type = FFI_TYPE_DOUBLE;
#endif
}
/* Return value handling. The rules for SYSV are as follows:
@ -549,14 +577,24 @@ ffi_prep_cif_machdep (ffi_cif *cif)
- 64-bit integer values and structures between 5 and 8 bytes are returned
in gpr3 and gpr4;
- Single/double FP values are returned in fpr1;
- Larger structures and long double (if not equivalent to double) values
are allocated space and a pointer is passed as the first argument.
- Larger structures are allocated space and a pointer is passed as
the first argument.
- long doubles (if not equivalent to double) are returned in
fpr1,fpr2 for Linux and as for large structs for SysV.
For LINUX64:
- integer values in gpr3;
- Structures/Unions by reference;
- Single/double FP values in fpr1, long double in fpr1,fpr2. */
switch (type)
{
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64)
goto byref;
flags |= FLAG_RETURNS_128BITS;
/* Fall through. */
#endif
case FFI_TYPE_DOUBLE:
flags |= FLAG_RETURNS_64BITS;
/* Fall through. */
@ -598,15 +636,8 @@ ffi_prep_cif_machdep (ffi_cif *cif)
}
}
}
/* else fall through. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (type == FFI_TYPE_LONGDOUBLE && cif->abi == FFI_LINUX64)
{
flags |= FLAG_RETURNS_128BITS;
flags |= FLAG_RETURNS_FP;
break;
}
byref:
#endif
intarg_count++;
flags |= FLAG_RETVAL_REFERENCE;
@ -635,6 +666,13 @@ ffi_prep_cif_machdep (ffi_cif *cif)
/* floating singles are not 8-aligned on stack */
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX)
goto do_struct;
fparg_count++;
/* Fall thru */
#endif
case FFI_TYPE_DOUBLE:
fparg_count++;
/* If this FP arg is going on the stack, it must be
@ -664,7 +702,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
do_struct:
#endif
/* We must allocate space for a copy of these to enforce
pass-by-value. Pad the space up to a multiple of 16
@ -793,6 +831,7 @@ ffi_call(/*@dependent@*/ ffi_cif *cif,
#ifndef POWERPC64
case FFI_SYSV:
case FFI_GCC_SYSV:
case FFI_LINUX:
/*@-usedef@*/
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
@ -920,14 +959,17 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
For FFI_SYSV the result is passed in r3/r4 if the struct size is less
or equal 8 bytes. */
if (cif->rtype->type == FFI_TYPE_STRUCT)
if ((cif->rtype->type == FFI_TYPE_STRUCT
&& !((cif->abi == FFI_SYSV) && (size <= 8)))
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX)
#endif
)
{
if (!((cif->abi == FFI_SYSV) && (size <= 8)))
{
rvalue = (void *) *pgr;
ng++;
pgr++;
}
rvalue = (void *) *pgr;
ng++;
pgr++;
}
i = 0;
@ -989,6 +1031,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
break;
case FFI_TYPE_STRUCT:
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
do_struct:
#endif
/* Structs are passed by reference. The address will appear in a
gpr if it is one of the first 8 arguments. */
if (ng < 8)
@ -1060,7 +1105,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
* naughty thing to do but...
*/
avalue[i] = pst;
nf++;
pst += 1;
}
break;
@ -1080,11 +1124,32 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
nf++;
pst += 2;
}
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX)
goto do_struct;
if (nf < 7)
{
avalue[i] = pfr;
pfr += 2;
nf += 2;
}
else
{
if (((long) pst) & 4)
pst++;
avalue[i] = pst;
pst += 4;
nf = 8;
}
break;
#endif
default:
FFI_ASSERT (0);
}
@ -1101,8 +1166,12 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT
&& size <= 8)
return FFI_SYSV_TYPE_SMALL_STRUCT + size;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX)
return FFI_TYPE_STRUCT;
#endif
return cif->rtype->type;
}
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,

View File

@ -43,10 +43,15 @@ typedef enum ffi_abi {
FFI_SYSV,
FFI_GCC_SYSV,
FFI_LINUX64,
FFI_LINUX,
# ifdef POWERPC64
FFI_DEFAULT_ABI = FFI_LINUX64,
# else
# if __LDBL_MANT_DIG__ == 106
FFI_DEFAULT_ABI = FFI_LINUX,
# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV,
# endif
# endif
#endif
@ -69,7 +74,7 @@ typedef enum ffi_abi {
FFI_DEFAULT_ABI = FFI_SYSV,
#endif
FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
FFI_LAST_ABI
} ffi_abi;
#endif

View File

@ -120,12 +120,9 @@ ffi_call_LINUX64:
blr
.Lfp_return_value:
bt 27, .Lfd_return_value
bf 28, .Lfloat_return_value
stfd %f1, 0(%r30)
b .Ldone_return_value
.Lfd_return_value:
stfd %f1, 0(%r30)
bf 27, .Ldone_return_value
stfd %f2, 8(%r30)
b .Ldone_return_value
.Lfloat_return_value:

View File

@ -58,218 +58,178 @@ ENTRY(ffi_closure_SYSV)
# make the call
bl ffi_closure_helper_SYSV@local
.Lret:
# now r3 contains the return type
# so use it to look up in a table
# so we know how to deal with each type
# look up the proper starting point in table
# by using return type as offset
addi %r6,%r1,112 # get pointer to results area
bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR
mflr %r4 # move to r4
slwi %r3,%r3,4 # now multiply return type by 16
add %r3,%r3,%r4 # add contents of table to table address
mflr %r4 # move address of .Lret to r4
slwi %r3,%r3,4 # now multiply return type by 16
addi %r4, %r4, .Lret_type0 - .Lret
lwz %r0,148(%r1)
add %r3,%r3,%r4 # add contents of table to table address
mtctr %r3
bctr # jump to it
bctr # jump to it
.LFE1:
# Each of the ret_typeX code fragments has to be exactly 16 bytes long
# (4 instructions). For cache effectiveness we align to a 16 byte boundary
# first.
.align 4
nop
nop
nop
.Lget_ret_type0_addr:
blrl
# case FFI_TYPE_VOID
.Lret_type0:
b .Lfinish
nop
nop
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_INT
.Lret_type1:
lwz %r3,0(%r6)
b .Lfinish
nop
nop
lwz %r3,112+0(%r1)
mtlr %r0
.Lfinish:
addi %r1,%r1,144
blr
# case FFI_TYPE_FLOAT
.Lret_type2:
lfs %f1,0(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_DOUBLE
.Lret_type3:
lfd %f1,0(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_LONGDOUBLE
.Lret_type4:
lfd %f1,0(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_UINT8
.Lret_type5:
lbz %r3,3(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_SINT8
.Lret_type6:
lbz %r3,3(%r6)
extsb %r3,%r3
b .Lfinish
nop
# case FFI_TYPE_UINT16
.Lret_type7:
lhz %r3,2(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_SINT16
.Lret_type8:
lha %r3,2(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_UINT32
.Lret_type9:
lwz %r3,0(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_SINT32
.Lret_type10:
lwz %r3,0(%r6)
b .Lfinish
nop
nop
# case FFI_TYPE_UINT64
.Lret_type11:
lwz %r3,0(%r6)
lwz %r4,4(%r6)
b .Lfinish
nop
# case FFI_TYPE_SINT64
.Lret_type12:
lwz %r3,0(%r6)
lwz %r4,4(%r6)
b .Lfinish
nop
# case FFI_TYPE_STRUCT
.Lret_type13:
b .Lfinish
nop
nop
nop
# case FFI_TYPE_POINTER
.Lret_type14:
lwz %r3,0(%r6)
b .Lfinish
nop
nop
# The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
.Lret_type15:
# fall through.
lbz %r3,0(%r6)
b .Lfinish
nop
nop
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
.Lret_type16:
# fall through.
lhz %r3,0(%r6)
b .Lfinish
nop
nop
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
.Lret_type17:
# fall through.
lwz %r3,0(%r6)
srwi %r3,%r3,8
b .Lfinish
nop
# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
.Lret_type18:
# this one handles the structs from above too.
lwz %r3,0(%r6)
b .Lfinish
nop
nop
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
.Lret_type19:
# fall through.
lwz %r3,0(%r6)
lwz %r4,4(%r6)
li %r5,24
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
.Lret_type20:
# fall through.
lwz %r3,0(%r6)
lwz %r4,4(%r6)
li %r5,16
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
.Lret_type21:
# fall through.
lwz %r3,0(%r6)
lwz %r4,4(%r6)
li %r5,8
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
.Lret_type22:
# this one handles the above unhandled structs.
lwz %r3,0(%r6)
lwz %r4,4(%r6)
b .Lfinish
nop
# case done
.Lfinish:
lwz %r0,148(%r1)
lfs %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
.Lstruct567:
subfic %r0,%r5,32
srw %r4,%r4,%r5
slw %r0,%r3,%r0
srw %r3,%r3,%r5
or %r4,%r0,%r4
# case FFI_TYPE_DOUBLE
lfd %f1,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_LONGDOUBLE
lfd %f1,112+0(%r1)
lfd %f2,112+8(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT8
lbz %r3,112+3(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT8
lbz %r3,112+3(%r1)
extsb %r3,%r3
mtlr %r0
b .Lfinish
# case FFI_TYPE_UINT16
lhz %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT16
lha %r3,112+2(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_SINT32
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_TYPE_UINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_SINT64
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
# case FFI_TYPE_STRUCT
mtlr %r0
addi %r1,%r1,144
blr
nop
# case FFI_TYPE_POINTER
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
lbz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
lhz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
lwz %r3,112+0(%r1)
srwi %r3,%r3,8
mtlr %r0
b .Lfinish
# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
lwz %r3,112+0(%r1)
mtlr %r0
addi %r1,%r1,144
blr
# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,24
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,16
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
li %r5,8
b .Lstruct567
# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
mtlr %r0
b .Lfinish
.Lstruct567:
subfic %r6,%r5,32
srw %r4,%r4,%r5
slw %r6,%r3,%r6
srw %r3,%r3,%r5
or %r4,%r6,%r4
mtlr %r0
addi %r1,%r1,144
blr
END(ffi_closure_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits

View File

@ -121,6 +121,8 @@ L(done_return_value):
L(fp_return_value):
bf 28,L(float_return_value)
stfd %f1,0(%r30)
bf 27,L(done_return_value)
stfd %f2,8(%r30)
b L(done_return_value)
L(float_return_value):
stfs %f1,0(%r30)