re PR libffi/31937 (libffi doesn't support ppc without FPU)

2007-12-01  Andreas Tobler  <a.tobler@schweiz.org>

	PR libffi/31937
	* src/powerpc/ffitarget.h: Introduce new ABI FFI_LINUX_SOFT_FLOAT.
	Add local FFI_TYPE_UINT128 to handle soft-float long-double-128.
	* src/powerpc/ffi.c: Distinguish between __NO_FPRS__ and not and
	set the NUM_FPR_ARG_REGISTERS according to.
	Add support for potential soft-float support under hard-float
	architecture.
	(ffi_prep_args_SYSV): Set NUM_FPR_ARG_REGISTERS to 0 in case of
	FFI_LINUX_SOFT_FLOAT, handle float, doubles and long-doubles according
	to the FFI_LINUX_SOFT_FLOAT ABI.
	(ffi_prep_cif_machdep): Likewise.
	(ffi_closure_helper_SYSV): Likewise.
	* src/powerpc/ppc_closure.S: Make sure not to store float/double
	on archs where __NO_FPRS__ is true.
	Add FFI_TYPE_UINT128 support.
	* src/powerpc/sysv.S: Add support for soft-float long-double-128.
	Adjust copyright notice.

From-SVN: r130559
This commit is contained in:
Andreas Tobler 2007-12-01 21:00:04 +00:00 committed by Andreas Tobler
parent e78b91ce0e
commit 162871481a
5 changed files with 222 additions and 40 deletions

View File

@ -1,3 +1,23 @@
2007-12-01 Andreas Tobler <a.tobler@schweiz.org>
PR libffi/31937
* src/powerpc/ffitarget.h: Introduce new ABI FFI_LINUX_SOFT_FLOAT.
Add local FFI_TYPE_UINT128 to handle soft-float long-double-128.
* src/powerpc/ffi.c: Distinguish between __NO_FPRS__ and not and
set the NUM_FPR_ARG_REGISTERS according to.
Add support for potential soft-float support under hard-float
architecture.
(ffi_prep_args_SYSV): Set NUM_FPR_ARG_REGISTERS to 0 in case of
FFI_LINUX_SOFT_FLOAT, handle float, doubles and long-doubles according
to the FFI_LINUX_SOFT_FLOAT ABI.
(ffi_prep_cif_machdep): Likewise.
(ffi_closure_helper_SYSV): Likewise.
* src/powerpc/ppc_closure.S: Make sure not to store float/double
on archs where __NO_FPRS__ is true.
Add FFI_TYPE_UINT128 support.
* src/powerpc/sysv.S: Add support for soft-float long-double-128.
Adjust copyright notice.
2007-11-25 Andreas Tobler <a.tobler@schweiz.org> 2007-11-25 Andreas Tobler <a.tobler@schweiz.org>
* src/closures.c: Move defintion of MAYBE_UNUSED from here to ... * src/closures.c: Move defintion of MAYBE_UNUSED from here to ...

View File

@ -50,10 +50,13 @@ enum {
}; };
/* About the SYSV ABI. */ /* About the SYSV ABI. */
enum { unsigned int NUM_GPR_ARG_REGISTERS = 8;
NUM_GPR_ARG_REGISTERS = 8, #ifndef __NO_FPRS__
NUM_FPR_ARG_REGISTERS = 8 unsigned int NUM_FPR_ARG_REGISTERS = 8;
}; #else
unsigned int NUM_FPR_ARG_REGISTERS = 0;
#endif
enum { ASM_NEEDS_REGISTERS = 4 }; enum { ASM_NEEDS_REGISTERS = 4 };
/* ffi_prep_args_SYSV is called by the assembly routine once stack space /* ffi_prep_args_SYSV is called by the assembly routine once stack space
@ -116,7 +119,7 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
/* 'next_arg' grows up as we put parameters in it. */ /* 'next_arg' grows up as we put parameters in it. */
valp next_arg; valp next_arg;
int i; int i, ii MAYBE_UNUSED;
ffi_type **ptr; ffi_type **ptr;
double double_tmp; double double_tmp;
union { union {
@ -134,6 +137,9 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
size_t struct_copy_size; size_t struct_copy_size;
unsigned gprvalue; unsigned gprvalue;
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
NUM_FPR_ARG_REGISTERS = 0;
stacktop.c = (char *) stack + bytes; stacktop.c = (char *) stack + bytes;
gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS;
intarg_count = 0; intarg_count = 0;
@ -165,6 +171,9 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
switch ((*ptr)->type) switch ((*ptr)->type)
{ {
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_prep;
double_tmp = **p_argv.f; double_tmp = **p_argv.f;
if (fparg_count >= NUM_FPR_ARG_REGISTERS) if (fparg_count >= NUM_FPR_ARG_REGISTERS)
{ {
@ -178,6 +187,9 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
break; break;
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
/* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_double_prep;
double_tmp = **p_argv.d; double_tmp = **p_argv.d;
if (fparg_count >= NUM_FPR_ARG_REGISTERS) if (fparg_count >= NUM_FPR_ARG_REGISTERS)
@ -199,38 +211,75 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (ecif->cif->abi != FFI_LINUX) if ((ecif->cif->abi != FFI_LINUX)
&& (ecif->cif->abi != FFI_LINUX_SOFT_FLOAT))
goto do_struct; goto do_struct;
double_tmp = (*p_argv.d)[0]; /* The soft float ABI for long doubles works like this,
a long double is passed in four consecutive gprs if available.
if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1) A maximum of 2 long doubles can be passed in gprs.
If we do not have 4 gprs left, the long double is passed on the
stack, 4-byte aligned. */
if (ecif->cif->abi == FFI_LINUX_SOFT_FLOAT)
{ {
if (intarg_count >= NUM_GPR_ARG_REGISTERS unsigned int int_tmp = (*p_argv.ui)[0];
&& intarg_count % 2 != 0) if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3)
{ {
intarg_count++; if (intarg_count < NUM_GPR_ARG_REGISTERS)
intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
*next_arg.u = int_tmp;
next_arg.u++; next_arg.u++;
for (ii = 1; ii < 4; ii++)
{
int_tmp = (*p_argv.ui)[ii];
*next_arg.u = int_tmp;
next_arg.u++;
}
} }
*next_arg.d = double_tmp; else
next_arg.u += 2; {
double_tmp = (*p_argv.d)[1]; *gpr_base.u++ = int_tmp;
*next_arg.d = double_tmp; for (ii = 1; ii < 4; ii++)
next_arg.u += 2; {
int_tmp = (*p_argv.ui)[ii];
*gpr_base.u++ = int_tmp;
}
}
intarg_count +=4;
} }
else else
{ {
*fpr_base.d++ = double_tmp; double_tmp = (*p_argv.d)[0];
double_tmp = (*p_argv.d)[1];
*fpr_base.d++ = double_tmp;
}
fparg_count += 2; if (fparg_count >= NUM_FPR_ARG_REGISTERS - 1)
FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); {
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; break;
#endif #endif
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
soft_double_prep:
if (intarg_count == NUM_GPR_ARG_REGISTERS-1) if (intarg_count == NUM_GPR_ARG_REGISTERS-1)
intarg_count++; intarg_count++;
if (intarg_count >= NUM_GPR_ARG_REGISTERS) if (intarg_count >= NUM_GPR_ARG_REGISTERS)
@ -293,6 +342,8 @@ ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack)
case FFI_TYPE_UINT32: case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32: case FFI_TYPE_SINT32:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
soft_float_prep:
gprvalue = **p_argv.ui; gprvalue = **p_argv.ui;
putgpr: putgpr:
@ -546,6 +597,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
unsigned type = cif->rtype->type; unsigned type = cif->rtype->type;
unsigned size = cif->rtype->size; unsigned size = cif->rtype->size;
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
NUM_FPR_ARG_REGISTERS = 0;
if (cif->abi != FFI_LINUX64) if (cif->abi != FFI_LINUX64)
{ {
/* All the machine-independent calculation of cif->bytes will be wrong. /* All the machine-independent calculation of cif->bytes will be wrong.
@ -582,14 +636,16 @@ ffi_prep_cif_machdep (ffi_cif *cif)
For LINUX64: For LINUX64:
- integer values in gpr3; - integer values in gpr3;
- Structures/Unions by reference; - Structures/Unions by reference;
- Single/double FP values in fpr1, long double in fpr1,fpr2. */ - Single/double FP values in fpr1, long double in fpr1,fpr2.
- soft-float float/doubles are treated as UINT32/UINT64 respectivley.
- soft-float long doubles are returned in gpr3-gpr6. */
switch (type) switch (type)
{ {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64) if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX64
&& cif->abi != FFI_LINUX_SOFT_FLOAT)
goto byref; goto byref;
flags |= FLAG_RETURNS_128BITS; flags |= FLAG_RETURNS_128BITS;
/* Fall through. */ /* Fall through. */
#endif #endif
@ -597,7 +653,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
flags |= FLAG_RETURNS_64BITS; flags |= FLAG_RETURNS_64BITS;
/* Fall through. */ /* Fall through. */
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
flags |= FLAG_RETURNS_FP; /* With FFI_LINUX_SOFT_FLOAT no fp registers are used. */
if (cif->abi != FFI_LINUX_SOFT_FLOAT)
flags |= FLAG_RETURNS_FP;
break; break;
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
@ -660,18 +718,36 @@ ffi_prep_cif_machdep (ffi_cif *cif)
switch ((*ptr)->type) switch ((*ptr)->type)
{ {
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_cif;
fparg_count++; fparg_count++;
/* floating singles are not 8-aligned on stack */ /* floating singles are not 8-aligned on stack */
break; break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX) if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
goto do_struct; goto do_struct;
fparg_count++; if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{
if (intarg_count >= NUM_GPR_ARG_REGISTERS - 3
|| intarg_count < NUM_GPR_ARG_REGISTERS)
/* A long double in FFI_LINUX_SOFT_FLOAT can use only
a set of four consecutive gprs. If we have not enough,
we have to adjust the intarg_count value. */
intarg_count += NUM_GPR_ARG_REGISTERS - intarg_count;
intarg_count += 4;
break;
}
else
fparg_count++;
/* Fall thru */ /* Fall thru */
#endif #endif
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
/* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_double_cif;
fparg_count++; fparg_count++;
/* If this FP arg is going on the stack, it must be /* If this FP arg is going on the stack, it must be
8-byte-aligned. */ 8-byte-aligned. */
@ -683,6 +759,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
soft_double_cif:
/* 'long long' arguments are passed as two words, but /* 'long long' arguments are passed as two words, but
either both words must fit in registers or both go either both words must fit in registers or both go
on the stack. If they go on the stack, they must on the stack. If they go on the stack, they must
@ -710,6 +787,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
/* Fall through (allocate space for the pointer). */ /* Fall through (allocate space for the pointer). */
default: default:
soft_float_cif:
/* Everything else is passed as a 4-byte word in a GPR, either /* Everything else is passed as a 4-byte word in a GPR, either
the object itself or a pointer to it. */ the object itself or a pointer to it. */
intarg_count++; intarg_count++;
@ -723,8 +801,13 @@ ffi_prep_cif_machdep (ffi_cif *cif)
{ {
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
fparg_count += 2; if (cif->abi == FFI_LINUX_SOFT_FLOAT)
intarg_count += 2; intarg_count += 4;
else
{
fparg_count += 2;
intarg_count += 2;
}
break; break;
#endif #endif
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
@ -818,6 +901,7 @@ ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
case FFI_SYSV: case FFI_SYSV:
case FFI_GCC_SYSV: case FFI_GCC_SYSV:
case FFI_LINUX: case FFI_LINUX:
case FFI_LINUX_SOFT_FLOAT:
ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn);
break; break;
#else #else
@ -942,7 +1026,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
&& !((cif->abi == FFI_SYSV) && (size <= 8))) && !((cif->abi == FFI_SYSV) && (size <= 8)))
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
|| (cif->rtype->type == FFI_TYPE_LONGDOUBLE || (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX) && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
#endif #endif
) )
{ {
@ -995,6 +1079,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
case FFI_TYPE_SINT32: case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32: case FFI_TYPE_UINT32:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
soft_float_closure:
/* there are 8 gpr registers used to pass values */ /* there are 8 gpr registers used to pass values */
if (ng < 8) if (ng < 8)
{ {
@ -1030,6 +1115,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
soft_double_closure:
/* passing long long ints are complex, they must /* passing long long ints are complex, they must
* be passed in suitable register pairs such as * be passed in suitable register pairs such as
* (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10)
@ -1061,6 +1147,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
break; break;
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
/* With FFI_LINUX_SOFT_FLOAT floats are handled like UINT32. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_float_closure;
/* unfortunately float values are stored as doubles /* unfortunately float values are stored as doubles
* in the ffi_closure_SYSV code (since we don't check * in the ffi_closure_SYSV code (since we don't check
* the type in that routine). * the type in that routine).
@ -1089,6 +1178,9 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
break; break;
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
/* With FFI_LINUX_SOFT_FLOAT doubles are handled like UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
goto soft_double_closure;
/* On the outgoing stack all values are aligned to 8 */ /* On the outgoing stack all values are aligned to 8 */
/* there are 8 64bit floating point registers */ /* there are 8 64bit floating point registers */
@ -1109,9 +1201,24 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE: case FFI_TYPE_LONGDOUBLE:
if (cif->abi != FFI_LINUX) if (cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
goto do_struct; goto do_struct;
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{ /* Test if for the whole long double, 4 gprs are available.
otherwise the stuff ends up on the stack. */
if (ng < 5)
{
avalue[i] = pgr;
pgr += 4;
ng += 4;
}
else
{
avalue[i] = pst;
pst += 4;
}
break;
}
if (nf < 7) if (nf < 7)
{ {
avalue[i] = pfr; avalue[i] = pfr;
@ -1147,10 +1254,34 @@ ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
return FFI_SYSV_TYPE_SMALL_STRUCT + size; return FFI_SYSV_TYPE_SMALL_STRUCT + size;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE else if (cif->rtype->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_LINUX) && cif->abi != FFI_LINUX && cif->abi != FFI_LINUX_SOFT_FLOAT)
return FFI_TYPE_STRUCT; return FFI_TYPE_STRUCT;
#endif #endif
return cif->rtype->type; /* With FFI_LINUX_SOFT_FLOAT floats and doubles are handled like UINT32
respectivley UINT64. */
if (cif->abi == FFI_LINUX_SOFT_FLOAT)
{
switch (cif->rtype->type)
{
case FFI_TYPE_FLOAT:
return FFI_TYPE_UINT32;
break;
case FFI_TYPE_DOUBLE:
return FFI_TYPE_UINT64;
break;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
case FFI_TYPE_LONGDOUBLE:
return FFI_TYPE_UINT128;
break;
#endif
default:
return cif->rtype->type;
}
}
else
{
return cif->rtype->type;
}
} }
int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *,

View File

@ -1,5 +1,6 @@
/* -----------------------------------------------------------------*-C-*- /* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
Copyright (C) 2007 Free Software Foundation, Inc
Target configuration macros for PowerPC. Target configuration macros for PowerPC.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
@ -44,13 +45,18 @@ typedef enum ffi_abi {
FFI_GCC_SYSV, FFI_GCC_SYSV,
FFI_LINUX64, FFI_LINUX64,
FFI_LINUX, FFI_LINUX,
FFI_LINUX_SOFT_FLOAT,
# ifdef POWERPC64 # ifdef POWERPC64
FFI_DEFAULT_ABI = FFI_LINUX64, FFI_DEFAULT_ABI = FFI_LINUX64,
# else # else
# if __LDBL_MANT_DIG__ == 106 # if (!defined(__NO_FPRS__) && (__LDBL_MANT_DIG__ == 106))
FFI_DEFAULT_ABI = FFI_LINUX, FFI_DEFAULT_ABI = FFI_LINUX,
# else # else
# ifdef __NO_FPRS__
FFI_DEFAULT_ABI = FFI_LINUX_SOFT_FLOAT,
# else
FFI_DEFAULT_ABI = FFI_GCC_SYSV, FFI_DEFAULT_ABI = FFI_GCC_SYSV,
# endif
# endif # endif
# endif # endif
#endif #endif
@ -83,8 +89,14 @@ typedef enum ffi_abi {
#define FFI_CLOSURES 1 #define FFI_CLOSURES 1
#define FFI_NATIVE_RAW_API 0 #define FFI_NATIVE_RAW_API 0
/* For additional types like the below, take care about the order in
ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
/* Needed for soft-float long-double-128 support. */
#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
/* Needed for FFI_SYSV small structure returns. */ /* Needed for FFI_SYSV small structure returns. */
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST) #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
#if defined(POWERPC64) || defined(POWERPC_AIX) #if defined(POWERPC64) || defined(POWERPC_AIX)
#define FFI_TRAMPOLINE_SIZE 24 #define FFI_TRAMPOLINE_SIZE 24

View File

@ -28,6 +28,7 @@ ENTRY(ffi_closure_SYSV)
stw %r9, 40(%r1) stw %r9, 40(%r1)
stw %r10,44(%r1) stw %r10,44(%r1)
#ifndef __NO_FPRS__
# next save fpr 1 to fpr 8 (aligned to 8) # next save fpr 1 to fpr 8 (aligned to 8)
stfd %f1, 48(%r1) stfd %f1, 48(%r1)
stfd %f2, 56(%r1) stfd %f2, 56(%r1)
@ -37,6 +38,7 @@ ENTRY(ffi_closure_SYSV)
stfd %f6, 88(%r1) stfd %f6, 88(%r1)
stfd %f7, 96(%r1) stfd %f7, 96(%r1)
stfd %f8, 104(%r1) stfd %f8, 104(%r1)
#endif
# set up registers for the routine that actually does the work # set up registers for the routine that actually does the work
# get the context pointer from the trampoline # get the context pointer from the trampoline
@ -171,6 +173,12 @@ ENTRY(ffi_closure_SYSV)
addi %r1,%r1,144 addi %r1,%r1,144
blr blr
# case FFI_TYPE_UINT128
lwz %r3,112+0(%r1)
lwz %r4,112+4(%r1)
lwz %r5,112+8(%r1)
bl .Luint128
# The return types below are only used when the ABI type is FFI_SYSV. # The return types below are only used when the ABI type is FFI_SYSV.
# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct. # case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
lbz %r3,112+0(%r1) lbz %r3,112+0(%r1)
@ -230,6 +238,12 @@ ENTRY(ffi_closure_SYSV)
addi %r1,%r1,144 addi %r1,%r1,144
blr blr
.Luint128:
lwz %r6,112+12(%r1)
mtlr %r0
addi %r1,%r1,144
blr
END(ffi_closure_SYSV) END(ffi_closure_SYSV)
.section ".eh_frame",EH_FRAME_FLAGS,@progbits .section ".eh_frame",EH_FRAME_FLAGS,@progbits

View File

@ -1,5 +1,6 @@
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
sysv.h - Copyright (c) 1998 Geoffrey Keating sysv.S - Copyright (c) 1998 Geoffrey Keating
Copyright (C) 2007 Free Software Foundation, Inc
PowerPC Assembly glue. PowerPC Assembly glue.
@ -98,13 +99,17 @@ ENTRY(ffi_call_SYSV)
bctrl bctrl
/* Now, deal with the return value. */ /* Now, deal with the return value. */
mtcrf 0x01,%r31 mtcrf 0x01,%r31 /* cr7 */
bt- 31,L(small_struct_return_value) bt- 31,L(small_struct_return_value)
bt- 30,L(done_return_value) bt- 30,L(done_return_value)
bt- 29,L(fp_return_value) bt- 29,L(fp_return_value)
stw %r3,0(%r30) stw %r3,0(%r30)
bf+ 28,L(done_return_value) bf+ 28,L(done_return_value)
stw %r4,4(%r30) stw %r4,4(%r30)
mtcrf 0x02,%r31 /* cr6 */
bf 27,L(done_return_value)
stw %r5,8(%r30)
stw %r6,12(%r30)
/* Fall through... */ /* Fall through... */
L(done_return_value): L(done_return_value):