* [PATCH 0/4] Go closures for alpha
@ 2014-10-30 3:54 Richard Henderson
2014-10-30 3:54 ` [PATCH 1/4] alpha: Reorganize cif flags Richard Henderson
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Richard Henderson @ 2014-10-30 3:54 UTC (permalink / raw)
To: libffi-discuss
A couple of minor bug fixes, then complex suppot, then Go closures.
r~
Richard Henderson (4):
alpha: Reorganize cif flags
alpha: Clean up conversion of float values
alpha: Add support for complex types
alpha: Add support for Go closures
src/alpha/ffi.c | 429 +++++++++++++++++++++------
src/alpha/ffitarget.h | 4 +
src/alpha/internal.h | 23 ++
src/alpha/osf.S | 427 ++++++++++----------------
testsuite/libffi.call/call.exp | 10 +-
testsuite/libffi.call/cls_complex_va_float.c | 6 +
6 files changed, 528 insertions(+), 371 deletions(-)
create mode 100644 src/alpha/internal.h
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] alpha: Clean up conversion of float values
2014-10-30 3:54 [PATCH 0/4] Go closures for alpha Richard Henderson
2014-10-30 3:54 ` [PATCH 1/4] alpha: Reorganize cif flags Richard Henderson
@ 2014-10-30 3:54 ` Richard Henderson
2014-10-30 3:54 ` [PATCH 4/4] alpha: Add support for Go closures Richard Henderson
2014-10-30 3:54 ` [PATCH 3/4] alpha: Add support for complex types Richard Henderson
3 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2014-10-30 3:54 UTC (permalink / raw)
To: libffi-discuss
Don't use "real" conversion to double, lest we raise
exceptions when passing signalling nans.
---
src/alpha/ffi.c | 95 +++++++++++++++++++++++++++++++--------------------------
1 file changed, 51 insertions(+), 44 deletions(-)
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 519bd2c..2f9e7e5 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -45,6 +45,20 @@ extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void)
FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
+/* Promote a float value to its in-register double representation.
+ Unlike actually casting to double, this does not trap on NaN. */
+static inline UINT64 lds(void *ptr)
+{
+ UINT64 ret;
+ asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
+ return ret;
+}
+
+/* And the reverse. */
+static inline void sts(void *ptr, UINT64 val)
+{
+ asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
+}
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
@@ -127,71 +141,67 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
avn = cif->nargs;
arg_types = cif->arg_types;
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
- size_t size = (*arg_types)->size;
+ ffi_type *ty = arg_types[i];
+ void *valp = avalue[i];
+ unsigned long val;
+ size_t size;
- switch ((*arg_types)->type)
+ switch (ty->type)
{
case FFI_TYPE_SINT8:
- *(SINT64 *) argp = *(SINT8 *)(* avalue);
+ val = *(SINT8 *)valp;
break;
case FFI_TYPE_UINT8:
- *(SINT64 *) argp = *(UINT8 *)(* avalue);
+ val = *(UINT8 *)valp;
break;
case FFI_TYPE_SINT16:
- *(SINT64 *) argp = *(SINT16 *)(* avalue);
+ val = *(SINT16 *)valp;
break;
case FFI_TYPE_UINT16:
- *(SINT64 *) argp = *(UINT16 *)(* avalue);
+ val = *(UINT16 *)valp;
break;
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
/* Note that unsigned 32-bit quantities are sign extended. */
- *(SINT64 *) argp = *(SINT32 *)(* avalue);
+ val = *(SINT32 *)valp;
break;
-
+
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
- *(UINT64 *) argp = *(UINT64 *)(* avalue);
+ case FFI_TYPE_DOUBLE:
+ val = *(UINT64 *)valp;
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ /* Note that 128-bit long double is passed by reference. */
+ val = (unsigned long)valp;
break;
case FFI_TYPE_FLOAT:
if (argp - stack < 6)
- {
- /* Note the conversion -- all the fp regs are loaded as
- doubles. The in-register format is the same. */
- *(double *) argp = *(float *)(* avalue);
- }
+ val = lds(valp);
else
- *(float *) argp = *(float *)(* avalue);
- break;
-
- case FFI_TYPE_DOUBLE:
- *(double *) argp = *(double *)(* avalue);
- break;
-
- case FFI_TYPE_LONGDOUBLE:
- /* 128-bit long double is passed by reference. */
- *(long double **) argp = (long double *)(* avalue);
- size = sizeof (long double *);
+ val = *(UINT32 *)valp;
break;
case FFI_TYPE_STRUCT:
- memcpy(argp, *avalue, (*arg_types)->size);
- break;
+ size = ty->size;
+ memcpy(argp, valp, size);
+ argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ continue;
default:
- FFI_ASSERT(0);
+ abort();
}
- argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++, arg_types++, avalue++;
+ *argp++ = val;
}
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
@@ -255,14 +265,13 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
argn = 1;
}
- i = 0;
- avn = cif->nargs;
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
- while (i < avn)
+ for (i = 0, avn = cif->nargs; i < avn; i++)
{
size_t size = arg_types[i]->size;
+ void *valp = &argp[argn];
switch (arg_types[i]->type)
{
@@ -276,28 +285,26 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
case FFI_TYPE_STRUCT:
- avalue[i] = &argp[argn];
break;
case FFI_TYPE_FLOAT:
+ /* Floats coming from registers need conversion from double
+ back to float format. */
if (argn < 6)
{
- /* Floats coming from registers need conversion from double
- back to float format. */
- *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
- avalue[i] = &argp[argn - 6];
+ valp = &argp[argn - 6];
+ sts(valp, argp[argn - 6]);
}
- else
- avalue[i] = &argp[argn];
break;
case FFI_TYPE_DOUBLE:
- avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
+ if (argn < 6)
+ valp = &argp[argn - 6];
break;
case FFI_TYPE_LONGDOUBLE:
/* 128-bit long double is passed by reference. */
- avalue[i] = (long double *) argp[argn];
+ valp = (long double *) argp[argn];
size = sizeof (long double *);
break;
@@ -305,8 +312,8 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
abort ();
}
+ avalue[i] = valp;
argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
- i++;
}
/* Invoke the closure. */
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] alpha: Add support for complex types
2014-10-30 3:54 [PATCH 0/4] Go closures for alpha Richard Henderson
` (2 preceding siblings ...)
2014-10-30 3:54 ` [PATCH 4/4] alpha: Add support for Go closures Richard Henderson
@ 2014-10-30 3:54 ` Richard Henderson
3 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2014-10-30 3:54 UTC (permalink / raw)
To: libffi-discuss
---
src/alpha/ffi.c | 278 +++++++++++++++++++++------
src/alpha/ffitarget.h | 3 +
src/alpha/internal.h | 4 +
src/alpha/osf.S | 18 ++
testsuite/libffi.call/call.exp | 10 +-
testsuite/libffi.call/cls_complex_va_float.c | 6 +
6 files changed, 255 insertions(+), 64 deletions(-)
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 2f9e7e5..1e5187e 100644
--- a/src/alpha/ffi.c
+++ b/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;
+
+ 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;
- /* 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;
+ 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. */
diff --git a/src/alpha/ffitarget.h b/src/alpha/ffitarget.h
index af145bc..60f92fd 100644
--- a/src/alpha/ffitarget.h
+++ b/src/alpha/ffitarget.h
@@ -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
diff --git a/src/alpha/internal.h b/src/alpha/internal.h
index 664a2a6..44da192 100644
--- a/src/alpha/internal.h
+++ b/src/alpha/internal.h
@@ -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
diff --git a/src/alpha/osf.S b/src/alpha/osf.S
index fb9c595..4059f82 100644
--- a/src/alpha/osf.S
+++ b/src/alpha/osf.S
@@ -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
diff --git a/testsuite/libffi.call/call.exp b/testsuite/libffi.call/call.exp
index 5177f07..09f6965 100644
--- a/testsuite/libffi.call/call.exp
+++ b/testsuite/libffi.call/call.exp
@@ -24,16 +24,12 @@ set ctlist [lsearch -inline -all -glob [lsort [glob -nocomplain -- $srcdir/$subd
run-many-tests $tlist ""
-if { ![istarget s390*] } {
-
+if { [istarget s390*] || [istarget alpha*] } {
+ run-many-tests $ctlist ""
+} else {
foreach test $ctlist {
unsupported "$test"
}
-
-} else {
-
- run-many-tests $ctlist ""
-
}
dg-finish
diff --git a/testsuite/libffi.call/cls_complex_va_float.c b/testsuite/libffi.call/cls_complex_va_float.c
index 0b79979..2b17826 100644
--- a/testsuite/libffi.call/cls_complex_va_float.c
+++ b/testsuite/libffi.call/cls_complex_va_float.c
@@ -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"
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] alpha: Reorganize cif flags
2014-10-30 3:54 [PATCH 0/4] Go closures for alpha Richard Henderson
@ 2014-10-30 3:54 ` Richard Henderson
2014-10-30 3:54 ` [PATCH 2/4] alpha: Clean up conversion of float values Richard Henderson
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2014-10-30 3:54 UTC (permalink / raw)
To: libffi-discuss
Unties the backend from changes to FFI_TYPE_* constants, and allows
compilation to succeed after the addition of FFI_TYPE_COMPLEX.
Delete the hand-written unwind info.
---
src/alpha/ffi.c | 63 +++++++---
src/alpha/internal.h | 19 +++
src/alpha/osf.S | 341 ++++++++++++++-------------------------------------
3 files changed, 160 insertions(+), 263 deletions(-)
create mode 100644 src/alpha/internal.h
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 192f691..519bd2c 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -28,6 +28,7 @@
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
+#include "internal.h"
/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
all further uses in this file will refer to the 128-bit type. */
@@ -48,6 +49,8 @@ extern void ffi_closure_osf(void) FFI_HIDDEN;
ffi_status
ffi_prep_cif_machdep(ffi_cif *cif)
{
+ int flags;
+
/* Adjust cif->bytes to represent a minimum 6 words for the temporary
register argument loading area. */
if (cif->bytes < 6*FFI_SIZEOF_ARG)
@@ -56,21 +59,46 @@ ffi_prep_cif_machdep(ffi_cif *cif)
/* Set the return type flag */
switch (cif->rtype->type)
{
- case FFI_TYPE_STRUCT:
+ case FFI_TYPE_VOID:
+ flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
+ break;
case FFI_TYPE_FLOAT:
+ flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
+ break;
case FFI_TYPE_DOUBLE:
- cif->flags = cif->rtype->type;
+ flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
+ break;
+ case FFI_TYPE_UINT8:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
+ break;
+ case FFI_TYPE_SINT8:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
+ break;
+ case FFI_TYPE_UINT16:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
+ break;
+ case FFI_TYPE_SINT16:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
+ break;
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
break;
-
case FFI_TYPE_LONGDOUBLE:
- /* 128-bit long double is returned in memory, like a struct. */
- cif->flags = FFI_TYPE_STRUCT;
+ case FFI_TYPE_STRUCT:
+ /* Passed in memory, with a hidden pointer. */
+ flags = ALPHA_RET_IN_MEM;
break;
-
default:
- cif->flags = FFI_TYPE_INT;
- break;
+ abort();
}
+ cif->flags = flags;
return FFI_OK;
}
@@ -80,20 +108,20 @@ void
ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
unsigned long *stack, *argp;
- long i, avn;
+ long i, avn, 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 && cif->flags == FFI_TYPE_STRUCT)
+ if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
rvalue = alloca(cif->rtype->size);
/* 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);
- if (cif->flags == FFI_TYPE_STRUCT)
- *(void **) argp++ = rvalue;
+ if (flags == ALPHA_RET_IN_MEM)
+ *argp++ = (unsigned long)rvalue;
i = 0;
avn = cif->nargs;
@@ -166,7 +194,8 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
i++, arg_types++, avalue++;
}
- ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
+ flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
+ ffi_call_osf(stack, cif->bytes, flags, rvalue, fn);
}
@@ -211,16 +240,16 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
- long i, avn, argn;
+ long i, avn, argn, flags;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
-
+ flags = cif->flags;
argn = 0;
/* Copy the caller's structure return address to that the closure
returns the data directly to the caller. */
- if (cif->flags == FFI_TYPE_STRUCT)
+ if (flags == ALPHA_RET_IN_MEM)
{
rvalue = (void *) argp[0];
argn = 1;
@@ -284,5 +313,5 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
closure->fun (cif, rvalue, avalue, closure->user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
- return cif->rtype->type;
+ return (flags >> ALPHA_LD_SHIFT) & 0xff;
}
diff --git a/src/alpha/internal.h b/src/alpha/internal.h
new file mode 100644
index 0000000..664a2a6
--- /dev/null
+++ b/src/alpha/internal.h
@@ -0,0 +1,19 @@
+#define ALPHA_ST_VOID 0
+#define ALPHA_ST_INT 1
+#define ALPHA_ST_FLOAT 2
+#define ALPHA_ST_DOUBLE 3
+
+#define ALPHA_LD_VOID 0
+#define ALPHA_LD_INT64 1
+#define ALPHA_LD_INT32 2
+#define ALPHA_LD_UINT16 3
+#define ALPHA_LD_SINT16 4
+#define ALPHA_LD_UINT8 5
+#define ALPHA_LD_SINT8 6
+#define ALPHA_LD_FLOAT 7
+#define ALPHA_LD_DOUBLE 8
+
+#define ALPHA_ST_SHIFT 0
+#define ALPHA_LD_SHIFT 8
+#define ALPHA_RET_IN_MEM 0x10000
+#define ALPHA_FLAGS(S, L) (((L) << ALPHA_LD_SHIFT) | (S))
diff --git a/src/alpha/osf.S b/src/alpha/osf.S
index 6b9f4df..fb9c595 100644
--- a/src/alpha/osf.S
+++ b/src/alpha/osf.S
@@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
- osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011 Red Hat
-
- Alpha/OSF Foreign Function Interface
+ osf.S - Copyright (c) 1998, 2001, 2007, 2008, 2011, 2014 Red Hat
+
+ Alpha/OSF Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -24,13 +24,21 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#define LIBFFI_ASM
+#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
+#include <ffi_cfi.h>
+#include "internal.h"
.arch ev6
.text
+/* Aid in building a direct addressed jump table, 4 insns per entry. */
+.macro E index
+ .align 4
+ .org 99b + \index * 16
+.endm
+
/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)(void));
@@ -38,7 +46,7 @@
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
- .align 3
+ .align 4
.globl ffi_call_osf
.ent ffi_call_osf
FFI_HIDDEN(ffi_call_osf)
@@ -46,15 +54,17 @@
ffi_call_osf:
.frame $15, 32, $26, 0
.mask 0x4008000, -32
-$LFB1:
+ cfi_startproc
addq $16,$17,$1
mov $16, $30
stq $26, 0($1)
stq $15, 8($1)
stq $18, 16($1)
mov $1, $15
-$LCFI1:
.prologue 0
+ cfi_def_cfa($15, 32)
+ cfi_rel_offset($26, 0)
+ cfi_rel_offset($15, 8)
stq $19, 24($1)
mov $20, $27
@@ -77,71 +87,61 @@ $LCFI1:
lda $30, 48($30)
jsr $26, ($27), 0
- ldgp $29, 0($26)
-
- # If the return value pointer is NULL, assume no return value.
- ldq $19, 24($15)
- ldq $18, 16($15)
+0:
+ ldah $29, 0($26) !gpdisp!1
+ ldq $2, 24($15)
+ lda $29, 0($29) !gpdisp!1
+ ldq $3, 16($15)
+ lda $1, 99f-0b($26)
ldq $26, 0($15)
-$LCFI2:
- beq $19, $noretval
-
- # Store the return value out in the proper type.
- cmpeq $18, FFI_TYPE_INT, $1
- bne $1, $retint
- cmpeq $18, FFI_TYPE_FLOAT, $2
- bne $2, $retfloat
- cmpeq $18, FFI_TYPE_DOUBLE, $3
- bne $3, $retdouble
-
- .align 3
-$noretval:
ldq $15, 8($15)
- ret
+ cfi_restore($26)
+ cfi_restore($15)
+ cfi_def_cfa($sp, 0)
+ cmoveq $2, ALPHA_ST_VOID, $3 # mash null return to void
+ addq $3, $3, $3
+ s8addq $3, $1, $1 # 99f + stcode * 16
+ jmp $31, ($1), $st_int
.align 4
-$retint:
- stq $0, 0($19)
- nop
- ldq $15, 8($15)
+99:
+E ALPHA_ST_VOID
ret
-
- .align 4
-$retfloat:
- sts $f0, 0($19)
- nop
- ldq $15, 8($15)
+E ALPHA_ST_INT
+$st_int:
+ stq $0, 0($2)
ret
-
- .align 4
-$retdouble:
- stt $f0, 0($19)
- nop
- ldq $15, 8($15)
+E ALPHA_ST_FLOAT
+ sts $f0, 0($2)
+ ret
+E ALPHA_ST_DOUBLE
+ stt $f0, 0($2)
ret
-$LFE1:
+ cfi_endproc
.end ffi_call_osf
/* ffi_closure_osf(...)
Receives the closure argument in $1. */
- .align 3
+#define CLOSURE_FS (16*8)
+
+ .align 4
.globl ffi_closure_osf
.ent ffi_closure_osf
FFI_HIDDEN(ffi_closure_osf)
ffi_closure_osf:
- .frame $30, 16*8, $26, 0
- .mask 0x4000000, -16*8
-$LFB2:
+ .frame $30, CLOSURE_FS, $26, 0
+ .mask 0x4000000, -CLOSURE_FS
+ cfi_startproc
ldgp $29, 0($27)
- subq $30, 16*8, $30
-$LCFI5:
+ subq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(CLOSURE_FS)
stq $26, 0($30)
-$LCFI6:
.prologue 1
+ cfi_rel_offset($26, 0)
# Store all of the potential argument registers in va_list format.
stt $f16, 4*8($30)
@@ -162,225 +162,74 @@ $LCFI6:
lda $17, 2*8($30)
lda $18, 10*8($30)
jsr $26, ffi_closure_osf_inner
- ldgp $29, 0($26)
+0:
+ ldah $29, 0($26) !gpdisp!2
+ lda $2, 99f-0b($26)
+ s4addq $0, 0, $1 # ldcode * 4
+ ldq $0, 16($30) # preload return value
+ s4addq $1, $2, $1 # 99f + ldcode * 16
+ lda $29, 0($29) !gpdisp!2
ldq $26, 0($30)
-
- # Load up the return value in the proper type.
- lda $1, $load_table
- s4addq $0, $1, $1
- ldl $1, 0($1)
- addq $1, $29, $1
+ cfi_restore($26)
jmp $31, ($1), $load_32
- .align 4
-$load_none:
- addq $30, 16*8, $30
+.macro epilogue
+ addq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(-CLOSURE_FS)
ret
+ .align 4
+ cfi_adjust_cfa_offset(CLOSURE_FS)
+.endm
.align 4
-$load_float:
- lds $f0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+99:
+E ALPHA_LD_VOID
+ epilogue
- .align 4
-$load_double:
- ldt $f0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_INT64
+ epilogue
- .align 4
-$load_u8:
-#ifdef __alpha_bwx__
- ldbu $0, 16($30)
- nop
-#else
- ldq $0, 16($30)
- and $0, 255, $0
-#endif
- addq $30, 16*8, $30
- ret
-
- .align 4
-$load_s8:
-#ifdef __alpha_bwx__
- ldbu $0, 16($30)
- sextb $0, $0
-#else
- ldq $0, 16($30)
- sll $0, 56, $0
- sra $0, 56, $0
-#endif
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_INT32
+$load_32:
+ sextl $0, $0
+ epilogue
- .align 4
-$load_u16:
-#ifdef __alpha_bwx__
- ldwu $0, 16($30)
- nop
-#else
- ldq $0, 16($30)
+E ALPHA_LD_UINT16
zapnot $0, 3, $0
-#endif
- addq $30, 16*8, $30
- ret
+ epilogue
- .align 4
-$load_s16:
+E ALPHA_LD_SINT16
#ifdef __alpha_bwx__
- ldwu $0, 16($30)
sextw $0, $0
#else
- ldq $0, 16($30)
sll $0, 48, $0
sra $0, 48, $0
#endif
- addq $30, 16*8, $30
- ret
+ epilogue
- .align 4
-$load_32:
- ldl $0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
+E ALPHA_LD_UINT8
+ and $0, 0xff, $0
+ epilogue
- .align 4
-$load_64:
- ldq $0, 16($30)
- nop
- addq $30, 16*8, $30
- ret
-$LFE2:
-
- .end ffi_closure_osf
-
-#ifdef __ELF__
-.section .rodata
+E ALPHA_LD_SINT8
+#ifdef __alpha_bwx__
+ sextb $0, $0
#else
-.rdata
-#endif
-$load_table:
- .gprel32 $load_none # FFI_TYPE_VOID
- .gprel32 $load_32 # FFI_TYPE_INT
- .gprel32 $load_float # FFI_TYPE_FLOAT
- .gprel32 $load_double # FFI_TYPE_DOUBLE
- .gprel32 $load_none # FFI_TYPE_LONGDOUBLE
- .gprel32 $load_u8 # FFI_TYPE_UINT8
- .gprel32 $load_s8 # FFI_TYPE_SINT8
- .gprel32 $load_u16 # FFI_TYPE_UINT16
- .gprel32 $load_s16 # FFI_TYPE_SINT16
- .gprel32 $load_32 # FFI_TYPE_UINT32
- .gprel32 $load_32 # FFI_TYPE_SINT32
- .gprel32 $load_64 # FFI_TYPE_UINT64
- .gprel32 $load_64 # FFI_TYPE_SINT64
- .gprel32 $load_none # FFI_TYPE_STRUCT
- .gprel32 $load_64 # FFI_TYPE_POINTER
-
-/* Assert that the table above is in sync with ffi.h. */
-
-#if FFI_TYPE_FLOAT != 2 \
- || FFI_TYPE_DOUBLE != 3 \
- || FFI_TYPE_UINT8 != 5 \
- || FFI_TYPE_SINT8 != 6 \
- || FFI_TYPE_UINT16 != 7 \
- || FFI_TYPE_SINT16 != 8 \
- || FFI_TYPE_UINT32 != 9 \
- || FFI_TYPE_SINT32 != 10 \
- || FFI_TYPE_UINT64 != 11 \
- || FFI_TYPE_SINT64 != 12 \
- || FFI_TYPE_STRUCT != 13 \
- || FFI_TYPE_POINTER != 14 \
- || FFI_TYPE_LAST != 14
-#error "osf.S out of sync with ffi.h"
+ sll $0, 56, $0
+ sra $0, 56, $0
#endif
+ epilogue
-#ifdef __ELF__
-# define UA_SI .4byte
-# define FDE_ENCODING 0x1b /* pcrel sdata4 */
-# define FDE_ENCODE(X) .4byte X-.
-# define FDE_ARANGE(X) .4byte X
-#elif defined __osf__
-# define UA_SI .align 0; .long
-# define FDE_ENCODING 0x50 /* aligned absolute */
-# define FDE_ENCODE(X) .align 3; .quad X
-# define FDE_ARANGE(X) .align 0; .quad X
-#endif
+E ALPHA_LD_FLOAT
+ lds $f0, 16($sp)
+ epilogue
-#ifdef __ELF__
- .section .eh_frame,EH_FRAME_FLAGS,@progbits
-#elif defined __osf__
- .data
- .align 3
- .globl _GLOBAL__F_ffi_call_osf
-_GLOBAL__F_ffi_call_osf:
-#endif
-__FRAME_BEGIN__:
- UA_SI $LECIE1-$LSCIE1 # Length of Common Information Entry
-$LSCIE1:
- UA_SI 0x0 # CIE Identifier Tag
- .byte 0x1 # CIE Version
- .ascii "zR\0" # CIE Augmentation
- .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor
- .byte 0x78 # sleb128 -8; CIE Data Alignment Factor
- .byte 26 # CIE RA Column
- .byte 0x1 # uleb128 0x1; Augmentation size
- .byte FDE_ENCODING # FDE Encoding
- .byte 0xc # DW_CFA_def_cfa
- .byte 30 # uleb128 column 30
- .byte 0 # uleb128 offset 0
- .align 3
-$LECIE1:
-$LSFDE1:
- UA_SI $LEFDE1-$LASFDE1 # FDE Length
-$LASFDE1:
- UA_SI $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset
- FDE_ENCODE($LFB1) # FDE initial location
- FDE_ARANGE($LFE1-$LFB1) # FDE address range
- .byte 0x0 # uleb128 0x0; Augmentation size
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI1-$LFB1
- .byte 0x9a # DW_CFA_offset, column 26
- .byte 4 # uleb128 4*-8
- .byte 0x8f # DW_CFA_offset, column 15
- .byte 0x3 # uleb128 3*-8
- .byte 0xc # DW_CFA_def_cfa
- .byte 15 # uleb128 column 15
- .byte 32 # uleb128 offset 32
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI2-$LCFI1
- .byte 0xda # DW_CFA_restore, column 26
- .align 3
-$LEFDE1:
-
-$LSFDE3:
- UA_SI $LEFDE3-$LASFDE3 # FDE Length
-$LASFDE3:
- UA_SI $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset
- FDE_ENCODE($LFB2) # FDE initial location
- FDE_ARANGE($LFE2-$LFB2) # FDE address range
- .byte 0x0 # uleb128 0x0; Augmentation size
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI5-$LFB2
- .byte 0xe # DW_CFA_def_cfa_offset
- .byte 0x80,0x1 # uleb128 128
-
- .byte 0x4 # DW_CFA_advance_loc4
- UA_SI $LCFI6-$LCFI5
- .byte 0x9a # DW_CFA_offset, column 26
- .byte 16 # uleb128 offset 16*-8
- .align 3
-$LEFDE3:
-#if defined __osf__
- .align 0
- .long 0 # End of Table
-#endif
+E ALPHA_LD_DOUBLE
+ ldt $f0, 16($sp)
+ epilogue
+
+ cfi_endproc
+ .end ffi_closure_osf
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] alpha: Add support for Go closures
2014-10-30 3:54 [PATCH 0/4] Go closures for alpha Richard Henderson
2014-10-30 3:54 ` [PATCH 1/4] alpha: Reorganize cif flags Richard Henderson
2014-10-30 3:54 ` [PATCH 2/4] alpha: Clean up conversion of float values Richard Henderson
@ 2014-10-30 3:54 ` Richard Henderson
2014-10-30 3:54 ` [PATCH 3/4] alpha: Add support for complex types Richard Henderson
3 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2014-10-30 3:54 UTC (permalink / raw)
To: libffi-discuss
---
src/alpha/ffi.c | 53 ++++++++++++++++++++++++++-------
src/alpha/ffitarget.h | 1 +
src/alpha/osf.S | 82 ++++++++++++++++++++++++++++++++++-----------------
3 files changed, 99 insertions(+), 37 deletions(-)
diff --git a/src/alpha/ffi.c b/src/alpha/ffi.c
index 1e5187e..efae4cc 100644
--- a/src/alpha/ffi.c
+++ b/src/alpha/ffi.c
@@ -41,9 +41,11 @@
# define FFI_TYPE_LONGDOUBLE 4
#endif
-extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)(void))
- FFI_HIDDEN;
+extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fn)(void), void *closure)
+ FFI_HIDDEN;
extern void ffi_closure_osf(void) FFI_HIDDEN;
+extern void ffi_go_closure_osf(void) FFI_HIDDEN;
/* Promote a float value to its in-register double representation.
Unlike actually casting to double, this does not trap on NaN. */
@@ -222,12 +224,14 @@ extend_basic_type(void *valp, int type, int argn)
}
}
-void
-ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+static void
+ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
{
unsigned long *argp;
long i, avn, argn, flags = cif->flags;
ffi_type **arg_types;
+ void *frame;
/* If the return value is a struct and we don't have a return
value address then we need to make one. */
@@ -236,7 +240,8 @@ 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 = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
+ frame += cif->bytes;
argn = 0;
if (flags == ALPHA_RET_IN_MEM)
@@ -301,9 +306,21 @@ ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
- ffi_call_osf(argp, cif->bytes, flags, rvalue, fn);
+ ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
+}
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
}
+void
+ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
@@ -339,15 +356,31 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ if (cif->abi != FFI_OSF)
+ return FFI_BAD_ABI;
+
+ closure->tramp = (void *)ffi_go_closure_osf;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
long FFI_HIDDEN
-ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
+ffi_closure_osf_inner (ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *rvalue, unsigned long *argp)
{
- ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn, argn, flags;
- cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
flags = cif->flags;
argn = 0;
@@ -481,7 +514,7 @@ ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
}
/* Invoke the closure. */
- closure->fun (cif, rvalue, avalue, closure->user_data);
+ fun (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_osf how to perform return type promotions. */
return (flags >> ALPHA_LD_SHIFT) & 0xff;
diff --git a/src/alpha/ffitarget.h b/src/alpha/ffitarget.h
index 60f92fd..a02dbd0 100644
--- a/src/alpha/ffitarget.h
+++ b/src/alpha/ffitarget.h
@@ -50,6 +50,7 @@ typedef enum ffi_abi {
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
+#define FFI_GO_CLOSURES 1
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
diff --git a/src/alpha/osf.S b/src/alpha/osf.S
index 4059f82..b031828 100644
--- a/src/alpha/osf.S
+++ b/src/alpha/osf.S
@@ -39,10 +39,10 @@
.org 99b + \index * 16
.endm
-/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags,
- void *raddr, void (*fnaddr)(void));
+/* ffi_call_osf (void *stack, void *frame, unsigned flags,
+ void *raddr, void (*fnaddr)(void), void *closure)
- Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
+ Bit o trickiness here -- FRAME is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
@@ -52,22 +52,21 @@
FFI_HIDDEN(ffi_call_osf)
ffi_call_osf:
- .frame $15, 32, $26, 0
- .mask 0x4008000, -32
cfi_startproc
- addq $16,$17,$1
+ cfi_def_cfa($17, 32)
mov $16, $30
- stq $26, 0($1)
- stq $15, 8($1)
- stq $18, 16($1)
- mov $1, $15
+ stq $26, 0($17)
+ stq $15, 8($17)
+ mov $17, $15
.prologue 0
- cfi_def_cfa($15, 32)
+ cfi_def_cfa_register($15)
cfi_rel_offset($26, 0)
cfi_rel_offset($15, 8)
- stq $19, 24($1)
- mov $20, $27
+ stq $18, 16($17) # save flags into frame
+ stq $19, 24($17) # save rvalue into frame
+ mov $20, $27 # fn into place for call
+ mov $21, $1 # closure into static chain
# Load up all of the (potential) argument registers.
ldq $16, 0($30)
@@ -89,16 +88,16 @@ ffi_call_osf:
jsr $26, ($27), 0
0:
ldah $29, 0($26) !gpdisp!1
- ldq $2, 24($15)
+ ldq $2, 24($15) # reload rvalue
lda $29, 0($29) !gpdisp!1
- ldq $3, 16($15)
+ ldq $3, 16($15) # reload flags
lda $1, 99f-0b($26)
ldq $26, 0($15)
ldq $15, 8($15)
cfi_restore($26)
cfi_restore($15)
cfi_def_cfa($sp, 0)
- cmoveq $2, ALPHA_ST_VOID, $3 # mash null return to void
+ cmoveq $2, ALPHA_ST_VOID, $3 # mash null rvalue to void
addq $3, $3, $3
s8addq $3, $1, $1 # 99f + stcode * 16
jmp $31, ($1), $st_int
@@ -136,13 +135,37 @@ E ALPHA_ST_CPLXD
#define CLOSURE_FS (16*8)
.align 4
+ .globl ffi_go_closure_osf
+ .ent ffi_go_closure_osf
+ FFI_HIDDEN(ffi_go_closure_osf)
+
+ffi_go_closure_osf:
+ cfi_startproc
+ ldgp $29, 0($27)
+ subq $30, CLOSURE_FS, $30
+ cfi_adjust_cfa_offset(CLOSURE_FS)
+ stq $26, 0($30)
+ .prologue 1
+ cfi_rel_offset($26, 0)
+
+ stq $16, 10*8($30)
+ stq $17, 11*8($30)
+ stq $18, 12*8($30)
+
+ ldq $16, 8($1) # load cif
+ ldq $17, 16($1) # load fun
+ mov $1, $18 # closure is user_data
+ br $do_closure
+
+ cfi_endproc
+ .end ffi_go_closure_osf
+
+ .align 4
.globl ffi_closure_osf
.ent ffi_closure_osf
FFI_HIDDEN(ffi_closure_osf)
ffi_closure_osf:
- .frame $30, CLOSURE_FS, $26, 0
- .mask 0x4000000, -CLOSURE_FS
cfi_startproc
ldgp $29, 0($27)
subq $30, CLOSURE_FS, $30
@@ -152,23 +175,28 @@ ffi_closure_osf:
cfi_rel_offset($26, 0)
# Store all of the potential argument registers in va_list format.
- stt $f16, 4*8($30)
- stt $f17, 5*8($30)
- stt $f18, 6*8($30)
- stt $f19, 7*8($30)
- stt $f20, 8*8($30)
- stt $f21, 9*8($30)
stq $16, 10*8($30)
stq $17, 11*8($30)
stq $18, 12*8($30)
+
+ ldq $16, 24($1) # load cif
+ ldq $17, 32($1) # load fun
+ ldq $18, 40($1) # load user_data
+
+$do_closure:
stq $19, 13*8($30)
stq $20, 14*8($30)
stq $21, 15*8($30)
+ stt $f16, 4*8($30)
+ stt $f17, 5*8($30)
+ stt $f18, 6*8($30)
+ stt $f19, 7*8($30)
+ stt $f20, 8*8($30)
+ stt $f21, 9*8($30)
# Call ffi_closure_osf_inner to do the bulk of the work.
- mov $1, $16
- lda $17, 2*8($30)
- lda $18, 10*8($30)
+ lda $19, 2*8($30)
+ lda $20, 10*8($30)
jsr $26, ffi_closure_osf_inner
0:
ldah $29, 0($26) !gpdisp!2
--
1.9.3
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-10-30 3:54 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-30 3:54 [PATCH 0/4] Go closures for alpha Richard Henderson
2014-10-30 3:54 ` [PATCH 1/4] alpha: Reorganize cif flags Richard Henderson
2014-10-30 3:54 ` [PATCH 2/4] alpha: Clean up conversion of float values Richard Henderson
2014-10-30 3:54 ` [PATCH 4/4] alpha: Add support for Go closures Richard Henderson
2014-10-30 3:54 ` [PATCH 3/4] alpha: Add support for complex types Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).