mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 19:03:59 +08:00
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:
parent
e78b91ce0e
commit
162871481a
@ -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 ...
|
||||||
|
@ -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 *,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user