IEEE754 binary128 long double support for PowerPC64 (#526)

* powerpc: Adjust flags to make room for vector types

* powerpc64 ELFv2 IEEE128 long double support
This commit is contained in:
Samuel Holland
2019-11-17 08:22:25 -05:00
committed by Anthony Green
parent b58bd77236
commit 73dd43afc8
6 changed files with 335 additions and 52 deletions
+3 -2
View File
@@ -85,8 +85,9 @@ ffi_call_int (ffi_cif *cif,
can write r3 and r4 to memory without worrying about struct size. can write r3 and r4 to memory without worrying about struct size.
For ELFv2 ABI, use a bounce buffer for homogeneous structs too, For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
for similar reasons. */ for similar reasons. This bounce buffer must be aligned to 16
unsigned long smst_buffer[8]; bytes for use with homogeneous structs of vectors (float128). */
float128 smst_buffer[8];
extended_cif ecif; extended_cif ecif;
ecif.cif = cif; ecif.cif = cif;
+154 -8
View File
@@ -38,7 +38,8 @@
/* About the LINUX64 ABI. */ /* About the LINUX64 ABI. */
enum { enum {
NUM_GPR_ARG_REGISTERS64 = 8, NUM_GPR_ARG_REGISTERS64 = 8,
NUM_FPR_ARG_REGISTERS64 = 13 NUM_FPR_ARG_REGISTERS64 = 13,
NUM_VEC_ARG_REGISTERS64 = 12,
}; };
enum { ASM_NEEDS_REGISTERS64 = 4 }; enum { ASM_NEEDS_REGISTERS64 = 4 };
@@ -81,11 +82,12 @@ discover_homogeneous_aggregate (ffi_abi abi,
of FPRs, but according to the ABI must be considered of FPRs, but according to the ABI must be considered
distinct from doubles. They are also limited to a distinct from doubles. They are also limited to a
maximum of four members in a homogeneous aggregate. */ maximum of four members in a homogeneous aggregate. */
else else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0)
{ {
*elnum = 2; *elnum = 2;
return FFI_TYPE_LONGDOUBLE; return FFI_TYPE_LONGDOUBLE;
} }
/* Fall through. */
#endif #endif
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE: case FFI_TYPE_DOUBLE:
@@ -130,13 +132,23 @@ ffi_prep_cif_linux64_core (ffi_cif *cif)
{ {
ffi_type **ptr; ffi_type **ptr;
unsigned bytes; unsigned bytes;
unsigned i, fparg_count = 0, intarg_count = 0; unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0;
unsigned flags = cif->flags; unsigned flags = cif->flags;
unsigned elt, elnum, rtype; unsigned elt, elnum, rtype;
#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
/* If compiled without long double support.. */ /* If compiled without long double support... */
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 ||
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
return FFI_BAD_ABI;
#elif !defined(__VEC__)
/* If compiled without vector register support (used by assembly)... */
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
return FFI_BAD_ABI;
#else
/* If the IEEE128 flag is set, but long double is only 64 bits wide... */
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 &&
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
return FFI_BAD_ABI; return FFI_BAD_ABI;
#endif #endif
@@ -166,6 +178,11 @@ homogeneous:
{ {
#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_LONG_DOUBLE_IEEE128) != 0)
{
flags |= FLAG_RETURNS_VEC;
break;
}
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
flags |= FLAG_RETURNS_128BITS; flags |= FLAG_RETURNS_128BITS;
/* Fall through. */ /* Fall through. */
@@ -221,6 +238,15 @@ homogeneous:
{ {
#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_LONG_DOUBLE_IEEE128) != 0)
{
vecarg_count++;
/* Align to 16 bytes, plus the 16-byte argument. */
intarg_count = (intarg_count + 3) & ~0x1;
if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
flags |= FLAG_ARG_NEEDS_PSAVE;
break;
}
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{ {
fparg_count++; fparg_count++;
@@ -248,6 +274,17 @@ homogeneous:
} }
intarg_count += ((*ptr)->size + 7) / 8; intarg_count += ((*ptr)->size + 7) / 8;
elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum); elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum);
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (elt == FFI_TYPE_LONGDOUBLE &&
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
{
vecarg_count += elnum;
if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
flags |= FLAG_ARG_NEEDS_PSAVE;
break;
}
else
#endif
if (elt) if (elt)
{ {
fparg_count += elnum; fparg_count += elnum;
@@ -286,10 +323,17 @@ homogeneous:
flags |= FLAG_FP_ARGUMENTS; flags |= FLAG_FP_ARGUMENTS;
if (intarg_count > 4) if (intarg_count > 4)
flags |= FLAG_4_GPR_ARGUMENTS; flags |= FLAG_4_GPR_ARGUMENTS;
if (vecarg_count != 0)
flags |= FLAG_VEC_ARGUMENTS;
/* Space for the FPR registers, if needed. */ /* Space for the FPR registers, if needed. */
if (fparg_count != 0) if (fparg_count != 0)
bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
/* Space for the vector registers, if needed, aligned to 16 bytes. */
if (vecarg_count != 0) {
bytes = (bytes + 15) & ~0xF;
bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128);
}
/* Stack space. */ /* Stack space. */
#if _CALL_ELF == 2 #if _CALL_ELF == 2
@@ -372,6 +416,8 @@ ffi_prep_cif_linux64_var (ffi_cif *cif,
|--------------------------------------------| | |--------------------------------------------| |
| FPR registers f1-f13 (optional) 13*8 | | | FPR registers f1-f13 (optional) 13*8 | |
|--------------------------------------------| | |--------------------------------------------| |
| VEC registers v2-v13 (optional) 12*16 | |
|--------------------------------------------| |
| Parameter save area | | | Parameter save area | |
|--------------------------------------------| | |--------------------------------------------| |
| TOC save area 8 | | | TOC save area 8 | |
@@ -401,6 +447,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
unsigned long *ul; unsigned long *ul;
float *f; float *f;
double *d; double *d;
float128 *f128;
size_t p; size_t p;
} valp; } valp;
@@ -419,6 +466,11 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
valp fpr_base; valp fpr_base;
unsigned int fparg_count; unsigned int fparg_count;
/* 'vec_base' points at the space for v2, and grows upwards as
we use vector registers. */
valp vec_base;
unsigned int vecarg_count;
unsigned int i, words, nargs, nfixedargs; unsigned int i, words, nargs, nfixedargs;
ffi_type **ptr; ffi_type **ptr;
double double_tmp; double double_tmp;
@@ -435,6 +487,7 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
unsigned long **ul; unsigned long **ul;
float **f; float **f;
double **d; double **d;
float128 **f128;
} p_argv; } p_argv;
unsigned long gprvalue; unsigned long gprvalue;
unsigned long align; unsigned long align;
@@ -449,11 +502,21 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
#endif #endif
fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
fparg_count = 0; fparg_count = 0;
/* Place the vector args below the FPRs, if used, else the GPRs. */
if (ecif->cif->flags & FLAG_FP_ARGUMENTS)
vec_base.p = fpr_base.p & ~0xF;
else
vec_base.p = gpr_base.p;
vec_base.f128 -= NUM_VEC_ARG_REGISTERS64;
vecarg_count = 0;
next_arg.ul = gpr_base.ul; next_arg.ul = gpr_base.ul;
/* Check that everything starts aligned properly. */ /* Check that everything starts aligned properly. */
FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
FFI_ASSERT (((unsigned long) gpr_base.c & 0xF) == 0);
FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0);
FFI_ASSERT (((unsigned long) vec_base.c & 0xF) == 0);
FFI_ASSERT ((bytes & 0xF) == 0); FFI_ASSERT ((bytes & 0xF) == 0);
/* Deal with return values that are actually pass-by-reference. */ /* Deal with return values that are actually pass-by-reference. */
@@ -478,6 +541,22 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *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_LONG_DOUBLE_IEEE128) != 0)
{
next_arg.p = FFI_ALIGN (next_arg.p, 16);
if (next_arg.ul == gpr_end.ul)
next_arg.ul = rest.ul;
if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs)
*vec_base.f128++ = **p_argv.f128;
else
*next_arg.f128 = **p_argv.f128;
if (++next_arg.f128 == gpr_end.f128)
next_arg.f128 = rest.f128;
vecarg_count++;
FFI_ASSERT (__LDBL_MANT_DIG__ == 113);
FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS);
break;
}
if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{ {
double_tmp = (*p_argv.d)[0]; double_tmp = (*p_argv.d)[0];
@@ -589,9 +668,29 @@ ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
void *v; void *v;
float *f; float *f;
double *d; double *d;
float128 *f128;
} arg; } arg;
arg.v = *p_argv.v; arg.v = *p_argv.v;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (elt == FFI_TYPE_LONGDOUBLE &&
(ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
{
do
{
if (vecarg_count < NUM_VEC_ARG_REGISTERS64
&& i < nfixedargs)
*vec_base.f128++ = *arg.f128++;
else
*next_arg.f128 = *arg.f128++;
if (++next_arg.f128 == gpr_end.f128)
next_arg.f128 = rest.f128;
vecarg_count++;
}
while (--elnum != 0);
}
else
#endif
if (elt == FFI_TYPE_FLOAT) if (elt == FFI_TYPE_FLOAT)
{ {
do do
@@ -762,17 +861,20 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
void *user_data, void *user_data,
void *rvalue, void *rvalue,
unsigned long *pst, unsigned long *pst,
ffi_dblfl *pfr) ffi_dblfl *pfr,
float128 *pvec)
{ {
/* rvalue is the pointer to space for return value in closure assembly */ /* rvalue is the pointer to space for return value in closure assembly */
/* pst is the pointer to parameter save area /* pst is the pointer to parameter save area
(r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
/* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
/* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */
void **avalue; void **avalue;
ffi_type **arg_types; ffi_type **arg_types;
unsigned long i, avn, nfixedargs; unsigned long i, avn, nfixedargs;
ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64;
unsigned long align; unsigned long align;
avalue = alloca (cif->nargs * sizeof (void *)); avalue = alloca (cif->nargs * sizeof (void *));
@@ -851,6 +953,7 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
unsigned long *ul; unsigned long *ul;
float *f; float *f;
double *d; double *d;
float128 *f128;
size_t p; size_t p;
} to, from; } to, from;
@@ -858,6 +961,17 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
aggregate size is not greater than the space taken by aggregate size is not greater than the space taken by
the registers so store back to the register/parameter the registers so store back to the register/parameter
save arrays. */ save arrays. */
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (elt == FFI_TYPE_LONGDOUBLE &&
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
{
if (pvec + elnum <= end_pvec)
to.v = pvec;
else
to.v = pst;
}
else
#endif
if (pfr + elnum <= end_pfr) if (pfr + elnum <= end_pfr)
to.v = pfr; to.v = pfr;
else else
@@ -865,6 +979,23 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
avalue[i] = to.v; avalue[i] = to.v;
from.ul = pst; from.ul = pst;
#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
if (elt == FFI_TYPE_LONGDOUBLE &&
(cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
{
do
{
if (pvec < end_pvec && i < nfixedargs)
*to.f128 = *pvec++;
else
*to.f128 = *from.f128;
to.f128++;
from.f128++;
}
while (--elnum != 0);
}
else
#endif
if (elt == FFI_TYPE_FLOAT) if (elt == FFI_TYPE_FLOAT)
{ {
do do
@@ -920,7 +1051,18 @@ ffi_closure_helper_LINUX64 (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:
if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0) if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
{
if (((unsigned long) pst & 0xF) != 0)
++pst;
if (pvec < end_pvec && i < nfixedargs)
avalue[i] = pvec++;
else
avalue[i] = pst;
pst += 2;
break;
}
else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
{ {
if (pfr + 1 < end_pfr && i + 1 < nfixedargs) if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
{ {
@@ -995,13 +1137,17 @@ ffi_closure_helper_LINUX64 (ffi_cif *cif,
/* Tell ffi_closure_LINUX64 how to perform return type promotions. */ /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
if ((cif->flags & FLAG_RETURNS_SMST) != 0) if ((cif->flags & FLAG_RETURNS_SMST) != 0)
{ {
if ((cif->flags & FLAG_RETURNS_FP) == 0) if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0)
return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1; return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
else if ((cif->flags & FLAG_RETURNS_VEC) != 0)
return FFI_V2_TYPE_VECTOR_HOMOG;
else if ((cif->flags & FLAG_RETURNS_64BITS) != 0) else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
return FFI_V2_TYPE_DOUBLE_HOMOG; return FFI_V2_TYPE_DOUBLE_HOMOG;
else else
return FFI_V2_TYPE_FLOAT_HOMOG; return FFI_V2_TYPE_FLOAT_HOMOG;
} }
if ((cif->flags & FLAG_RETURNS_VEC) != 0)
return FFI_V2_TYPE_VECTOR;
return cif->rtype->type; return cif->rtype->type;
} }
#endif #endif
+18 -7
View File
@@ -31,22 +31,24 @@
enum { enum {
/* The assembly depends on these exact flags. */ /* The assembly depends on these exact flags. */
/* These go in cr7 */ /* These go in cr7 */
FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */
FLAG_RETURNS_NOTHING = 1 << (31-30), FLAG_RETURNS_NOTHING = 1 << (31-30),
FLAG_RETURNS_FP = 1 << (31-29), FLAG_RETURNS_FP = 1 << (31-29),
FLAG_RETURNS_64BITS = 1 << (31-28), FLAG_RETURNS_VEC = 1 << (31-28),
/* This goes in cr6 */ /* These go in cr6 */
FLAG_RETURNS_128BITS = 1 << (31-27), FLAG_RETURNS_64BITS = 1 << (31-27),
FLAG_RETURNS_128BITS = 1 << (31-26),
FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */ FLAG_COMPAT = 1 << (31- 8), /* Not used by assembly */
/* These go in cr1 */ /* These go in cr1 */
FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */ FLAG_ARG_NEEDS_COPY = 1 << (31- 7), /* Used by sysv code */
FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */ FLAG_ARG_NEEDS_PSAVE = FLAG_ARG_NEEDS_COPY, /* Used by linux64 code */
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
FLAG_RETVAL_REFERENCE = 1 << (31- 4) FLAG_RETVAL_REFERENCE = 1 << (31- 4),
FLAG_VEC_ARGUMENTS = 1 << (31- 3),
}; };
typedef union typedef union
@@ -55,6 +57,14 @@ typedef union
double d; double d;
} ffi_dblfl; } ffi_dblfl;
#if defined(__FLOAT128_TYPE__)
typedef _Float128 float128;
#elif defined(__FLOAT128__)
typedef __float128 float128;
#else
typedef __int128 float128;
#endif
void FFI_HIDDEN ffi_closure_SYSV (void); void FFI_HIDDEN ffi_closure_SYSV (void);
void FFI_HIDDEN ffi_go_closure_sysv (void); void FFI_HIDDEN ffi_go_closure_sysv (void);
void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *, void FFI_HIDDEN ffi_call_SYSV(extended_cif *, void (*)(void), void *,
@@ -91,4 +101,5 @@ int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_cif *,
void (*) (ffi_cif *, void *, void (*) (ffi_cif *, void *,
void **, void *), void **, void *),
void *, void *, void *, void *,
unsigned long *, ffi_dblfl *); unsigned long *, ffi_dblfl *,
float128 *);
+10 -4
View File
@@ -91,15 +91,19 @@ typedef enum ffi_abi {
/* This and following bits can reuse FFI_COMPAT values. */ /* This and following bits can reuse FFI_COMPAT values. */
FFI_LINUX_STRUCT_ALIGN = 1, FFI_LINUX_STRUCT_ALIGN = 1,
FFI_LINUX_LONG_DOUBLE_128 = 2, FFI_LINUX_LONG_DOUBLE_128 = 2,
FFI_LINUX_LONG_DOUBLE_IEEE128 = 4,
FFI_DEFAULT_ABI = (FFI_LINUX FFI_DEFAULT_ABI = (FFI_LINUX
# ifdef __STRUCT_PARM_ALIGN__ # ifdef __STRUCT_PARM_ALIGN__
| FFI_LINUX_STRUCT_ALIGN | FFI_LINUX_STRUCT_ALIGN
# endif # endif
# ifdef __LONG_DOUBLE_128__ # ifdef __LONG_DOUBLE_128__
| FFI_LINUX_LONG_DOUBLE_128 | FFI_LINUX_LONG_DOUBLE_128
# ifdef __LONG_DOUBLE_IEEE128__
| FFI_LINUX_LONG_DOUBLE_IEEE128
# endif
# endif # endif
), ),
FFI_LAST_ABI = 12 FFI_LAST_ABI = 16
# else # else
/* This bit, always set in new code, must not be set in any of the /* This bit, always set in new code, must not be set in any of the
@@ -167,9 +171,11 @@ typedef enum ffi_abi {
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2) #define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 2)
/* Used by ELFv2 for homogenous structure returns. */ /* Used by ELFv2 for homogenous structure returns. */
#define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 1) #define FFI_V2_TYPE_VECTOR (FFI_PPC_TYPE_LAST + 1)
#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 2) #define FFI_V2_TYPE_VECTOR_HOMOG (FFI_PPC_TYPE_LAST + 2)
#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 3) #define FFI_V2_TYPE_FLOAT_HOMOG (FFI_PPC_TYPE_LAST + 3)
#define FFI_V2_TYPE_DOUBLE_HOMOG (FFI_PPC_TYPE_LAST + 4)
#define FFI_V2_TYPE_SMALL_STRUCT (FFI_PPC_TYPE_LAST + 5)
#if _CALL_ELF == 2 #if _CALL_ELF == 2
# define FFI_TRAMPOLINE_SIZE 32 # define FFI_TRAMPOLINE_SIZE 32
+83 -28
View File
@@ -101,40 +101,70 @@ ffi_call_LINUX64:
ld %r2, 8(%r29) ld %r2, 8(%r29)
# endif # endif
/* Now do the call. */ /* Now do the call. */
/* Set up cr1 with bits 4-7 of the flags. */ /* Set up cr1 with bits 3-7 of the flags. */
mtcrf 0x40, %r31 mtcrf 0xc0, %r31
/* Get the address to call into CTR. */ /* Get the address to call into CTR. */
mtctr %r12 mtctr %r12
/* Load all those argument registers. */ /* Load all those argument registers. */
ld %r3, -32-(8*8)(%r28) addi %r29, %r28, -32-(8*8)
ld %r4, -32-(7*8)(%r28) ld %r3, (0*8)(%r29)
ld %r5, -32-(6*8)(%r28) ld %r4, (1*8)(%r29)
ld %r6, -32-(5*8)(%r28) ld %r5, (2*8)(%r29)
ld %r6, (3*8)(%r29)
bf- 5, 1f bf- 5, 1f
ld %r7, -32-(4*8)(%r28) ld %r7, (4*8)(%r29)
ld %r8, -32-(3*8)(%r28) ld %r8, (5*8)(%r29)
ld %r9, -32-(2*8)(%r28) ld %r9, (6*8)(%r29)
ld %r10, -32-(1*8)(%r28) ld %r10, (7*8)(%r29)
1: 1:
/* Load all the FP registers. */ /* Load all the FP registers. */
bf- 6, 2f bf- 6, 2f
lfd %f1, -32-(21*8)(%r28) addi %r29, %r29, -(14*8)
lfd %f2, -32-(20*8)(%r28) lfd %f1, ( 1*8)(%r29)
lfd %f3, -32-(19*8)(%r28) lfd %f2, ( 2*8)(%r29)
lfd %f4, -32-(18*8)(%r28) lfd %f3, ( 3*8)(%r29)
lfd %f5, -32-(17*8)(%r28) lfd %f4, ( 4*8)(%r29)
lfd %f6, -32-(16*8)(%r28) lfd %f5, ( 5*8)(%r29)
lfd %f7, -32-(15*8)(%r28) lfd %f6, ( 6*8)(%r29)
lfd %f8, -32-(14*8)(%r28) lfd %f7, ( 7*8)(%r29)
lfd %f9, -32-(13*8)(%r28) lfd %f8, ( 8*8)(%r29)
lfd %f10, -32-(12*8)(%r28) lfd %f9, ( 9*8)(%r29)
lfd %f11, -32-(11*8)(%r28) lfd %f10, (10*8)(%r29)
lfd %f12, -32-(10*8)(%r28) lfd %f11, (11*8)(%r29)
lfd %f13, -32-(9*8)(%r28) lfd %f12, (12*8)(%r29)
lfd %f13, (13*8)(%r29)
2: 2:
/* Load all the vector registers. */
bf- 3, 3f
addi %r29, %r29, -16
lvx %v13, 0, %r29
addi %r29, %r29, -16
lvx %v12, 0, %r29
addi %r29, %r29, -16
lvx %v11, 0, %r29
addi %r29, %r29, -16
lvx %v10, 0, %r29
addi %r29, %r29, -16
lvx %v9, 0, %r29
addi %r29, %r29, -16
lvx %v8, 0, %r29
addi %r29, %r29, -16
lvx %v7, 0, %r29
addi %r29, %r29, -16
lvx %v6, 0, %r29
addi %r29, %r29, -16
lvx %v5, 0, %r29
addi %r29, %r29, -16
lvx %v4, 0, %r29
addi %r29, %r29, -16
lvx %v3, 0, %r29
addi %r29, %r29, -16
lvx %v2, 0, %r29
3:
/* Make the call. */ /* Make the call. */
ld %r11, 8(%r28) ld %r11, 8(%r28)
bctrl bctrl
@@ -152,6 +182,7 @@ ffi_call_LINUX64:
bt 31, .Lstruct_return_value bt 31, .Lstruct_return_value
bt 30, .Ldone_return_value bt 30, .Ldone_return_value
bt 29, .Lfp_return_value bt 29, .Lfp_return_value
bt 28, .Lvec_return_value
std %r3, 0(%r30) std %r3, 0(%r30)
/* Fall through... */ /* Fall through... */
@@ -167,12 +198,16 @@ ffi_call_LINUX64:
ld %r31, -8(%r1) ld %r31, -8(%r1)
blr blr
.Lvec_return_value:
stvx %v2, 0, %r30
b .Ldone_return_value
.Lfp_return_value: .Lfp_return_value:
.cfi_def_cfa_register 28 .cfi_def_cfa_register 28
bf 28, .Lfloat_return_value
stfd %f1, 0(%r30)
mtcrf 0x02, %r31 /* cr6 */ mtcrf 0x02, %r31 /* cr6 */
bf 27, .Ldone_return_value bf 27, .Lfloat_return_value
stfd %f1, 0(%r30)
bf 26, .Ldone_return_value
stfd %f2, 8(%r30) stfd %f2, 8(%r30)
b .Ldone_return_value b .Ldone_return_value
.Lfloat_return_value: .Lfloat_return_value:
@@ -180,8 +215,9 @@ ffi_call_LINUX64:
b .Ldone_return_value b .Ldone_return_value
.Lstruct_return_value: .Lstruct_return_value:
bf 29, .Lsmall_struct bf 29, .Lvec_homog_or_small_struct
bf 28, .Lfloat_homog_return_value mtcrf 0x02, %r31 /* cr6 */
bf 27, .Lfloat_homog_return_value
stfd %f1, 0(%r30) stfd %f1, 0(%r30)
stfd %f2, 8(%r30) stfd %f2, 8(%r30)
stfd %f3, 16(%r30) stfd %f3, 16(%r30)
@@ -203,6 +239,25 @@ ffi_call_LINUX64:
stfs %f8, 28(%r30) stfs %f8, 28(%r30)
b .Ldone_return_value b .Ldone_return_value
.Lvec_homog_or_small_struct:
bf 28, .Lsmall_struct
stvx %v2, 0, %r30
addi %r30, %r30, 16
stvx %v3, 0, %r30
addi %r30, %r30, 16
stvx %v4, 0, %r30
addi %r30, %r30, 16
stvx %v5, 0, %r30
addi %r30, %r30, 16
stvx %v6, 0, %r30
addi %r30, %r30, 16
stvx %v7, 0, %r30
addi %r30, %r30, 16
stvx %v8, 0, %r30
addi %r30, %r30, 16
stvx %v9, 0, %r30
b .Ldone_return_value
.Lsmall_struct: .Lsmall_struct:
std %r3, 0(%r30) std %r3, 0(%r30)
std %r4, 8(%r30) std %r4, 8(%r30)
+67 -3
View File
@@ -61,9 +61,15 @@ ffi_closure_LINUX64:
# endif # endif
# if _CALL_ELF == 2 # if _CALL_ELF == 2
# 32 byte special reg save area + 64 byte parm save area # ifdef __VEC__
# + 64 byte retval area + 13*8 fpr save area + round to 16 # 32 byte special reg save area + 64 byte parm save area
# define STACKFRAME 272 # + 128 byte retval area + 13*8 fpr save area + 12*16 vec save area + round to 16
# define STACKFRAME 528
# else
# 32 byte special reg save area + 64 byte parm save area
# + 64 byte retval area + 13*8 fpr save area + round to 16
# define STACKFRAME 272
# endif
# define PARMSAVE 32 # define PARMSAVE 32
# define RETVAL PARMSAVE+64 # define RETVAL PARMSAVE+64
# else # else
@@ -146,6 +152,35 @@ ffi_closure_LINUX64:
# load up the pointer to the saved fpr registers # load up the pointer to the saved fpr registers
addi %r8, %r1, -104 addi %r8, %r1, -104
# ifdef __VEC__
# load up the pointer to the saved vector registers
# 8 bytes padding for 16-byte alignment at -112(%r1)
addi %r9, %r8, -24
stvx %v13, 0, %r9
addi %r9, %r9, -16
stvx %v12, 0, %r9
addi %r9, %r9, -16
stvx %v11, 0, %r9
addi %r9, %r9, -16
stvx %v10, 0, %r9
addi %r9, %r9, -16
stvx %v9, 0, %r9
addi %r9, %r9, -16
stvx %v8, 0, %r9
addi %r9, %r9, -16
stvx %v7, 0, %r9
addi %r9, %r9, -16
stvx %v6, 0, %r9
addi %r9, %r9, -16
stvx %v5, 0, %r9
addi %r9, %r9, -16
stvx %v4, 0, %r9
addi %r9, %r9, -16
stvx %v3, 0, %r9
addi %r9, %r9, -16
stvx %v2, 0, %r9
# endif
# load up the pointer to the result storage # load up the pointer to the result storage
addi %r6, %r1, -STACKFRAME+RETVAL addi %r6, %r1, -STACKFRAME+RETVAL
@@ -313,6 +348,16 @@ ffi_closure_LINUX64:
.cfi_def_cfa_offset 0 .cfi_def_cfa_offset 0
blr blr
.cfi_def_cfa_offset STACKFRAME .cfi_def_cfa_offset STACKFRAME
# case FFI_V2_TYPE_VECTOR
addi %r3, %r1, RETVAL
lvx %v2, 0, %r3
mtlr %r0
b .Lfinish
# case FFI_V2_TYPE_VECTOR_HOMOG
addi %r3, %r1, RETVAL
lvx %v2, 0, %r3
addi %r3, %r3, 16
b .Lmorevector
# case FFI_V2_TYPE_FLOAT_HOMOG # case FFI_V2_TYPE_FLOAT_HOMOG
lfs %f1, RETVAL+0(%r1) lfs %f1, RETVAL+0(%r1)
lfs %f2, RETVAL+4(%r1) lfs %f2, RETVAL+4(%r1)
@@ -332,6 +377,25 @@ ffi_closure_LINUX64:
.cfi_def_cfa_offset 0 .cfi_def_cfa_offset 0
blr blr
.cfi_def_cfa_offset STACKFRAME .cfi_def_cfa_offset STACKFRAME
.Lmorevector:
lvx %v3, 0, %r3
addi %r3, %r3, 16
lvx %v4, 0, %r3
addi %r3, %r3, 16
lvx %v5, 0, %r3
mtlr %r0
addi %r3, %r3, 16
lvx %v6, 0, %r3
addi %r3, %r3, 16
lvx %v7, 0, %r3
addi %r3, %r3, 16
lvx %v8, 0, %r3
addi %r3, %r3, 16
lvx %v9, 0, %r3
addi %r1, %r1, STACKFRAME
.cfi_def_cfa_offset 0
blr
.cfi_def_cfa_offset STACKFRAME
.Lmorefloat: .Lmorefloat:
lfs %f4, RETVAL+12(%r1) lfs %f4, RETVAL+12(%r1)
mtlr %r0 mtlr %r0