alpha: Add support for complex types
This commit is contained in:
278
src/alpha/ffi.c
278
src/alpha/ffi.c
@@ -1,8 +1,8 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2012 Anthony Green
|
||||
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
||||
|
||||
Alpha Foreign Function Interface
|
||||
Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
|
||||
|
||||
Alpha Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@@ -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,22 +152,83 @@ 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
|
||||
value address then we need to make one. */
|
||||
if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
|
||||
@@ -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)
|
||||
{
|
||||
@@ -266,15 +361,18 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
|
||||
}
|
||||
|
||||
arg_types = cif->arg_types;
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user