alpha: Add support for complex types

This commit is contained in:
Richard Henderson
2014-10-17 20:46:48 -07:00
parent 5f917371af
commit f41bec3b57
6 changed files with 253 additions and 57 deletions

View File

@@ -60,18 +60,61 @@ static inline void sts(void *ptr, UINT64 val)
asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
}
ffi_status
ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif *cif)
{
int flags;
size_t bytes = 0;
int flags, i, avn;
ffi_type *rtype, *itype;
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
register argument loading area. */
if (cif->bytes < 6*FFI_SIZEOF_ARG)
cif->bytes = 6*FFI_SIZEOF_ARG;
if (cif->abi != FFI_OSF)
return FFI_BAD_ABI;
/* Compute the size of the argument area. */
for (i = 0, avn = cif->nargs; i < avn; i++)
{
itype = cif->arg_types[i];
switch (itype->type)
{
case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
/* All take one 8 byte slot. */
bytes += 8;
break;
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
/* Passed by value in N slots. */
bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
break;
case FFI_TYPE_COMPLEX:
/* _Complex long double passed by reference; others in 2 slots. */
if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
bytes += 8;
else
bytes += 16;
break;
default:
abort();
}
}
/* Set the return type flag */
switch (cif->rtype->type)
rtype = cif->rtype;
switch (rtype->type)
{
case FFI_TYPE_VOID:
flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
@@ -109,20 +152,81 @@ ffi_prep_cif_machdep(ffi_cif *cif)
/* Passed in memory, with a hidden pointer. */
flags = ALPHA_RET_IN_MEM;
break;
case FFI_TYPE_COMPLEX:
itype = rtype->elements[0];
switch (itype->type)
{
case FFI_TYPE_FLOAT:
flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
break;
case FFI_TYPE_DOUBLE:
flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
break;
default:
if (rtype->size <= 8)
flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
else
flags = ALPHA_RET_IN_MEM;
break;
}
break;
default:
abort();
}
cif->flags = flags;
/* Include the hidden structure pointer in args requirement. */
if (flags == ALPHA_RET_IN_MEM)
bytes += 8;
/* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
if (bytes < 6*8)
bytes = 6*8;
cif->bytes = bytes;
return FFI_OK;
}
static unsigned long
extend_basic_type(void *valp, int type, int argn)
{
switch (type)
{
case FFI_TYPE_SINT8:
return *(SINT8 *)valp;
case FFI_TYPE_UINT8:
return *(UINT8 *)valp;
case FFI_TYPE_SINT16:
return *(SINT16 *)valp;
case FFI_TYPE_UINT16:
return *(UINT16 *)valp;
case FFI_TYPE_FLOAT:
if (argn < 6)
return lds(valp);
/* FALLTHRU */
case FFI_TYPE_INT:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Note that unsigned 32-bit quantities are sign extended. */
return *(SINT32 *)valp;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_DOUBLE:
return *(UINT64 *)valp;
default:
abort();
}
}
void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
unsigned long *stack, *argp;
long i, avn, flags = cif->flags;
unsigned long *argp;
long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
/* If the return value is a struct and we don't have a return
@@ -132,12 +236,12 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
/* Allocate the space for the arguments, plus 4 words of temp
space for ffi_call_osf. */
argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
argp = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
argn = 0;
if (flags == ALPHA_RET_IN_MEM)
*argp++ = (unsigned long)rvalue;
argp[argn++] = (unsigned long)rvalue;
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
@@ -145,67 +249,59 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
ffi_type *ty = arg_types[i];
void *valp = avalue[i];
unsigned long val;
int type = ty->type;
size_t size;
switch (ty->type)
switch (type)
{
case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
val = *(SINT8 *)valp;
break;
case FFI_TYPE_UINT8:
val = *(UINT8 *)valp;
break;
case FFI_TYPE_SINT16:
val = *(SINT16 *)valp;
break;
case FFI_TYPE_UINT16:
val = *(UINT16 *)valp;
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Note that unsigned 32-bit quantities are sign extended. */
val = *(SINT32 *)valp;
break;
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
val = *(UINT64 *)valp;
argp[argn] = extend_basic_type(valp, type, argn);
argn++;
break;
case FFI_TYPE_LONGDOUBLE:
by_reference:
/* Note that 128-bit long double is passed by reference. */
val = (unsigned long)valp;
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 6)
val = lds(valp);
else
val = *(UINT32 *)valp;
argp[argn++] = (unsigned long)valp;
break;
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
size = ty->size;
memcpy(argp, valp, size);
argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
continue;
memcpy(argp + argn, valp, size);
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
break;
case FFI_TYPE_COMPLEX:
type = ty->elements[0]->type;
if (type == FFI_TYPE_LONGDOUBLE)
goto by_reference;
/* Most complex types passed as two separate arguments. */
size = ty->elements[0]->size;
argp[argn] = extend_basic_type(valp, type, argn);
argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
argn += 2;
break;
default:
abort();
}
*argp++ = val;
}
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
ffi_call_osf(stack, cif->bytes, flags, rvalue, fn);
ffi_call_osf(argp, cif->bytes, flags, rvalue, fn);
}
@@ -243,7 +339,6 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
long FFI_HIDDEN
ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
{
@@ -270,11 +365,14 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
/* Grab the addresses of the arguments from the stack frame. */
for (i = 0, avn = cif->nargs; i < avn; i++)
{
size_t size = arg_types[i]->size;
ffi_type *ty = arg_types[i];
int type = ty->type;
void *valp = &argp[argn];
size_t size;
switch (arg_types[i]->type)
switch (type)
{
case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
@@ -284,7 +382,13 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
argn += 1;
break;
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
size = ty->size;
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
break;
case FFI_TYPE_FLOAT:
@@ -295,17 +399,78 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
valp = &argp[argn - 6];
sts(valp, argp[argn - 6]);
}
argn += 1;
break;
case FFI_TYPE_DOUBLE:
if (argn < 6)
valp = &argp[argn - 6];
argn += 1;
break;
case FFI_TYPE_LONGDOUBLE:
by_reference:
/* 128-bit long double is passed by reference. */
valp = (long double *) argp[argn];
size = sizeof (long double *);
valp = (void *)argp[argn];
argn += 1;
break;
case FFI_TYPE_COMPLEX:
type = ty->elements[0]->type;
switch (type)
{
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
/* Passed as separate arguments, but they wind up sequential. */
break;
case FFI_TYPE_INT:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Passed as separate arguments. Disjoint, but there's room
enough in one slot to hold the pair. */
size = ty->elements[0]->size;
memcpy(valp + size, valp + 8, size);
break;
case FFI_TYPE_FLOAT:
/* Passed as separate arguments. Disjoint, and each piece
may need conversion back to float. */
if (argn < 6)
{
valp = &argp[argn - 6];
sts(valp, argp[argn - 6]);
}
if (argn + 1 < 6)
sts(valp + 4, argp[argn + 1 - 6]);
else
*(UINT32 *)(valp + 4) = argp[argn + 1];
break;
case FFI_TYPE_DOUBLE:
/* Passed as separate arguments. Only disjoint if one part
is in fp regs and the other is on the stack. */
if (argn < 5)
valp = &argp[argn - 6];
else if (argn == 5)
{
valp = alloca(16);
((UINT64 *)valp)[0] = argp[5 - 6];
((UINT64 *)valp)[1] = argp[6];
}
break;
case FFI_TYPE_LONGDOUBLE:
goto by_reference;
default:
abort();
}
argn += 2;
break;
default:
@@ -313,7 +478,6 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
}
avalue[i] = valp;
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
/* Invoke the closure. */

View File

@@ -44,6 +44,9 @@ typedef enum ffi_abi {
} ffi_abi;
#endif
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
#define FFI_TARGET_HAS_COMPLEX_TYPE
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1

View File

@@ -2,6 +2,8 @@
#define ALPHA_ST_INT 1
#define ALPHA_ST_FLOAT 2
#define ALPHA_ST_DOUBLE 3
#define ALPHA_ST_CPLXF 4
#define ALPHA_ST_CPLXD 5
#define ALPHA_LD_VOID 0
#define ALPHA_LD_INT64 1
@@ -12,6 +14,8 @@
#define ALPHA_LD_SINT8 6
#define ALPHA_LD_FLOAT 7
#define ALPHA_LD_DOUBLE 8
#define ALPHA_LD_CPLXF 9
#define ALPHA_LD_CPLXD 10
#define ALPHA_ST_SHIFT 0
#define ALPHA_LD_SHIFT 8

View File

@@ -117,6 +117,14 @@ E ALPHA_ST_FLOAT
E ALPHA_ST_DOUBLE
stt $f0, 0($2)
ret
E ALPHA_ST_CPLXF
sts $f0, 0($2)
sts $f1, 4($2)
ret
E ALPHA_ST_CPLXD
stt $f0, 0($2)
stt $f1, 8($2)
ret
cfi_endproc
.end ffi_call_osf
@@ -228,6 +236,16 @@ E ALPHA_LD_DOUBLE
ldt $f0, 16($sp)
epilogue
E ALPHA_LD_CPLXF
lds $f0, 16($sp)
lds $f1, 20($sp)
epilogue
E ALPHA_LD_CPLXD
ldt $f0, 16($sp)
ldt $f1, 24($sp)
epilogue
cfi_endproc
.end ffi_closure_osf

View File

@@ -27,6 +27,7 @@ run-many-tests $tlist ""
# ??? We really should preprocess ffi.h and grep
# for FFI_TARGET_HAS_COMPLEX_TYPE.
if { [istarget aarch64*]
|| [istarget alpha*]
|| [istarget i?86*]
|| [istarget s390*]
|| [istarget x86_64*] } {

View File

@@ -6,5 +6,11 @@
/* { dg-do run } */
/* Alpha splits _Complex into two arguments. It's illegal to pass
float through varargs, so _Complex float goes badly. In sort of
gets passed as _Complex double, but the compiler doesn't agree
with itself on this issue. */
/* { dg-do run { xfail alpha*-*-* } } */
#include "complex_defs_float.inc"
#include "cls_complex_va.inc"