summaryrefslogtreecommitdiff
path: root/libffi/src/ia64
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/ia64')
-rw-r--r--libffi/src/ia64/ffi.c671
-rw-r--r--libffi/src/ia64/ffitarget.h58
-rw-r--r--libffi/src/ia64/ia64_flags.h62
-rw-r--r--libffi/src/ia64/unix.S326
4 files changed, 1117 insertions, 0 deletions
diff --git a/libffi/src/ia64/ffi.c b/libffi/src/ia64/ffi.c
new file mode 100644
index 0000000..1dc27db
--- /dev/null
+++ b/libffi/src/ia64/ffi.c
@@ -0,0 +1,671 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1998 Red Hat, Inc.
+ Copyright (c) 2000 Hewlett Packard Company
+
+ IA64 Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "ia64_flags.h"
+
+/* Memory image of fp register contents. Should eventually be an fp */
+/* type long enough to hold an entire register. For now we use double. */
+typedef double float80;
+
+/* The stack layout at call to ffi_prep_args. Other_args will remain */
+/* on the stack for the actual call. Everything else we be transferred */
+/* to registers and popped by the assembly code. */
+
+struct ia64_args {
+ long scratch[2]; /* Two scratch words at top of stack. */
+ /* Allows sp to be passed as arg pointer. */
+ void * r8_contents; /* Value to be passed in r8 */
+ long spare; /* Not used. */
+ float80 fp_regs[8]; /* Contents of 8 floating point argument */
+ /* registers. */
+ long out_regs[8]; /* Contents of the 8 out registers used */
+ /* for integer parameters. */
+ long other_args[0]; /* Arguments passed on stack, variable size */
+ /* Treated as continuation of out_regs. */
+};
+
+static size_t float_type_size(unsigned short tp)
+{
+ switch(tp) {
+ case FFI_TYPE_FLOAT:
+ return sizeof(float);
+ case FFI_TYPE_DOUBLE:
+ return sizeof(double);
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+ case FFI_TYPE_LONGDOUBLE:
+ return sizeof(long double);
+#endif
+ default:
+ FFI_ASSERT(0);
+ }
+}
+
+/*
+ * Is type a struct containing at most n floats, doubles, or extended
+ * doubles, all of the same fp type?
+ * If so, set *element_type to the fp type.
+ */
+static bool is_homogeneous_fp_aggregate(ffi_type * type, int n,
+ unsigned short * element_type)
+{
+ ffi_type **ptr;
+ unsigned short element, struct_element;
+
+ int type_set = 0;
+
+ FFI_ASSERT(type != NULL);
+
+ FFI_ASSERT(type->elements != NULL);
+
+ ptr = &(type->elements[0]);
+
+ while ((*ptr) != NULL)
+ {
+ switch((*ptr) -> type) {
+ case FFI_TYPE_FLOAT:
+ if (type_set && element != FFI_TYPE_FLOAT) return 0;
+ if (--n < 0) return false;
+ type_set = 1;
+ element = FFI_TYPE_FLOAT;
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (type_set && element != FFI_TYPE_DOUBLE) return 0;
+ if (--n < 0) return false;
+ type_set = 1;
+ element = FFI_TYPE_DOUBLE;
+ break;
+ case FFI_TYPE_STRUCT:
+ if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
+ return false;
+ if (type_set && struct_element != element) return false;
+ n -= (type -> size)/float_type_size(element);
+ element = struct_element;
+ if (n < 0) return false;
+ break;
+ /* case FFI_TYPE_LONGDOUBLE:
+ Not yet implemented. */
+ default:
+ return false;
+ }
+ ptr++;
+ }
+ *element_type = element;
+ return true;
+
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments. It fills in
+ the arguments in the structure referenced by stack. Returns nonzero
+ if fp registers are used for arguments. */
+
+static bool
+ffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes)
+{
+ register long i, avn;
+ register void **p_argv;
+ register long *argp = stack -> out_regs;
+ register float80 *fp_argp = stack -> fp_regs;
+ register ffi_type **p_arg;
+
+ /* For big return structs, r8 needs to contain the target address. */
+ /* Since r8 is otherwise dead, we set it unconditionally. */
+ stack -> r8_contents = ecif -> rvalue;
+ i = 0;
+ avn = ecif->cif->nargs;
+ p_arg = ecif->cif->arg_types;
+ p_argv = ecif->avalue;
+ while (i < avn)
+ {
+ size_t z; /* z is in units of arg slots or words, not bytes. */
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ z = 1;
+ *(SINT64 *) argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ z = 1;
+ *(UINT64 *) argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ z = 1;
+ *(SINT64 *) argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ z = 1;
+ *(UINT64 *) argp = *(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ z = 1;
+ *(SINT64 *) argp = *(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ z = 1;
+ *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ z = 1;
+ *(UINT64 *) argp = *(UINT64 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ z = 1;
+ if (fp_argp - stack->fp_regs < 8)
+ {
+ /* Note the conversion -- all the fp regs are loaded as
+ doubles. */
+ *fp_argp++ = *(float *)(* p_argv);
+ }
+ /* Also put it into the integer registers or memory: */
+ *(UINT64 *) argp = *(UINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ z = 1;
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = *(double *)(* p_argv);
+ /* Also put it into the integer registers or memory: */
+ *(double *) argp = *(double *)(* p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = (*p_arg)->size;
+ unsigned short element_type;
+ z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
+ if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+ int i;
+ int nelements = sz/float_type_size(element_type);
+ for (i = 0; i < nelements; ++i) {
+ switch (element_type) {
+ case FFI_TYPE_FLOAT:
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = ((float *)(* p_argv))[i];
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (fp_argp - stack->fp_regs < 8)
+ *fp_argp++ = ((double *)(* p_argv))[i];
+ break;
+ default:
+ /* Extended precision not yet implemented. */
+ abort();
+ }
+ }
+ }
+ /* And pass it in integer registers as a struct, with */
+ /* its actual field sizes packed into registers. */
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ }
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argp += z;
+ i++, p_arg++, p_argv++;
+ }
+ return (fp_argp != stack -> fp_regs);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ long i, avn;
+ bool is_simple = true;
+ long simple_flag = FFI_SIMPLE_V;
+ /* Adjust cif->bytes to include space for the 2 scratch words,
+ r8 register contents, spare word,
+ the 8 fp register contents, and all 8 integer register contents.
+ This will be removed before the call, though 2 scratch words must
+ remain. */
+
+ cif->bytes += 4*sizeof(long) + 8 *sizeof(float80);
+ if (cif->bytes < sizeof(struct ia64_args))
+ cif->bytes = sizeof(struct ia64_args);
+
+ /* The stack must be double word aligned, so round bytes up
+ appropriately. */
+
+ cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
+
+ avn = cif->nargs;
+ if (avn <= 2) {
+ for (i = 0; i < avn; ++i) {
+ switch(cif -> arg_types[i] -> type) {
+ case FFI_TYPE_SINT32:
+ simple_flag = FFI_ADD_INT_ARG(simple_flag);
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ simple_flag = FFI_ADD_LONG_ARG(simple_flag);
+ break;
+ default:
+ is_simple = false;
+ }
+ }
+ } else {
+ is_simple = false;
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ cif->flags = FFI_TYPE_VOID;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = cif -> rtype -> size;
+ unsigned short element_type;
+
+ is_simple = false;
+ if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) {
+ int nelements = sz/float_type_size(element_type);
+ if (nelements <= 1) {
+ if (0 == nelements) {
+ cif -> flags = FFI_TYPE_VOID;
+ } else {
+ cif -> flags = element_type;
+ }
+ } else {
+ switch(element_type) {
+ case FFI_TYPE_FLOAT:
+ cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
+ break;
+ case FFI_TYPE_DOUBLE:
+ cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
+ break;
+ default:
+ /* long double NYI */
+ abort();
+ }
+ }
+ break;
+ }
+ if (sz <= 32) {
+ if (sz <= 8) {
+ cif->flags = FFI_TYPE_INT;
+ } else if (sz <= 16) {
+ cif->flags = FFI_IS_SMALL_STRUCT2;
+ } else if (sz <= 24) {
+ cif->flags = FFI_IS_SMALL_STRUCT3;
+ } else {
+ cif->flags = FFI_IS_SMALL_STRUCT4;
+ }
+ } else {
+ cif->flags = FFI_TYPE_STRUCT;
+ }
+ }
+ break;
+
+ case FFI_TYPE_FLOAT:
+ is_simple = false;
+ cif->flags = FFI_TYPE_FLOAT;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ is_simple = false;
+ cif->flags = FFI_TYPE_DOUBLE;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ /* This seems to depend on little endian mode, and the fact that */
+ /* the return pointer always points to at least 8 bytes. But */
+ /* that also seems to be true for other platforms. */
+ break;
+ }
+
+ if (is_simple) cif -> flags |= simple_flag;
+ return FFI_OK;
+}
+
+extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+ long simple = cif -> flags & FFI_SIMPLE;
+
+ /* Should this also check for Unix ABI? */
+ /* This is almost, but not quite, machine independent. Note that */
+ /* we can get away with not caring about length of the result because */
+ /* we assume we are little endian, and the result buffer is large */
+ /* enough. */
+ /* This needs work for HP/UX. */
+ if (simple) {
+ long (*lfn)() = (long (*)())fn;
+ long result;
+ switch(simple) {
+ case FFI_SIMPLE_V:
+ result = lfn();
+ break;
+ case FFI_SIMPLE_I:
+ result = lfn(*(int *)avalue[0]);
+ break;
+ case FFI_SIMPLE_L:
+ result = lfn(*(long *)avalue[0]);
+ break;
+ case FFI_SIMPLE_II:
+ result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
+ break;
+ case FFI_SIMPLE_IL:
+ result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
+ break;
+ case FFI_SIMPLE_LI:
+ result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
+ break;
+ case FFI_SIMPLE_LL:
+ result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
+ break;
+ }
+ if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
+ * (long *)rvalue = result;
+ }
+ return;
+ }
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+
+ /* 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->rtype->type == FFI_TYPE_STRUCT)
+ ecif.rvalue = alloca(cif->rtype->size);
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_UNIX:
+ ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, rvalue, fn);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+/*
+ * Closures represent a pair consisting of a function pointer, and
+ * some user data. A closure is invoked by reinterpreting the closure
+ * as a function pointer, and branching to it. Thus we can make an
+ * interpreted function callable as a C function: We turn the interpreter
+ * itself, together with a pointer specifying the interpreted procedure,
+ * into a closure.
+ * On X86, the first few words of the closure structure actually contain code,
+ * which will do the right thing. On most other architectures, this
+ * would raise some Icache/Dcache coherence issues (which can be solved, but
+ * often not cheaply).
+ * For IA64, function pointer are already pairs consisting of a code
+ * pointer, and a gp pointer. The latter is needed to access global variables.
+ * Here we set up such a pair as the first two words of the closure (in
+ * the "trampoline" area), but we replace the gp pointer with a pointer
+ * to the closure itself. We also add the real gp pointer to the
+ * closure. This allows the function entry code to both retrieve the
+ * user data, and to restire the correct gp pointer.
+ */
+
+static void
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+ void **avalue, ffi_cif *cif);
+
+/* This function is entered with the doctored gp (r1) value.
+ * This code is extremely gcc specific. There is some argument that
+ * it should really be written in assembly code, since it depends on
+ * gcc properties that might change over time.
+ */
+
+/* ffi_closure_UNIX is an assembly routine, which copies the register */
+/* state into a struct ia64_args, and then invokes */
+/* ffi_closure_UNIX_inner. It also recovers the closure pointer */
+/* from its fake gp pointer. */
+void ffi_closure_UNIX();
+
+#ifndef __GNUC__
+# error This requires gcc
+#endif
+void
+ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
+/* Hopefully declaring this as a varargs function will force all args */
+/* to memory. */
+{
+ // this is our return value storage
+ long double res;
+
+ // our various things...
+ ffi_cif *cif;
+ unsigned short rtype;
+ void *resp;
+ void **arg_area;
+
+ resp = (void*)&res;
+ cif = closure->cif;
+ arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+ /* this call will initialize ARG_AREA, such that each
+ * element in that array points to the corresponding
+ * value on the stack; and if the function returns
+ * a structure, it will re-set RESP to point to the
+ * structure return address. */
+
+ ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
+
+ (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+ rtype = cif->flags;
+
+ /* now, do a generic return based on the value of rtype */
+ if (rtype == FFI_TYPE_INT)
+ {
+ asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
+ }
+ else if (rtype == FFI_TYPE_FLOAT)
+ {
+ asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
+ }
+ else if (rtype == FFI_TYPE_DOUBLE)
+ {
+ asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT2)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
+ : : "r" (resp), "r" (resp+8) : "r8","r9");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT3)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
+ : : "r" (resp), "r" (resp+8), "r" (resp+16)
+ : "r8","r9","r10");
+ }
+ else if (rtype == FFI_IS_SMALL_STRUCT4)
+ {
+ asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
+ : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
+ : "r8","r9","r10","r11");
+ }
+ else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
+ {
+ /* Can only happen for homogeneous FP aggregates? */
+ abort();
+ }
+}
+
+static void
+ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
+ void **avalue, ffi_cif *cif)
+{
+ register unsigned int i;
+ register unsigned int avn;
+ register void **p_argv;
+ register long *argp = args -> out_regs;
+ unsigned fp_reg_num = 0;
+ register ffi_type **p_arg;
+
+ avn = cif->nargs;
+ p_argv = avalue;
+
+ for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
+ {
+ size_t z; /* In units of words or argument slots. */
+
+ switch ((*p_arg)->type)
+ {
+ 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:
+ z = 1;
+ *p_argv = (void *)argp;
+ break;
+
+ case FFI_TYPE_FLOAT:
+ z = 1;
+ /* Convert argument back to float in place from the saved value */
+ if (argp - args->out_regs < 8 && fp_reg_num < 8) {
+ *(float *)argp = args -> fp_regs[fp_reg_num++];
+ }
+ *p_argv = (void *)argp;
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ z = 1;
+ if (argp - args->out_regs < 8 && fp_reg_num < 8) {
+ *p_argv = args -> fp_regs + fp_reg_num++;
+ } else {
+ *p_argv = (void *)argp;
+ }
+ break;
+
+ case FFI_TYPE_STRUCT:
+ {
+ size_t sz = (*p_arg)->size;
+ unsigned short element_type;
+ z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
+ if (argp - args->out_regs < 8
+ && is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
+ int nelements = sz/float_type_size(element_type);
+ if (nelements + fp_reg_num >= 8) {
+ /* hard case NYI. */
+ abort();
+ }
+ if (element_type == FFI_TYPE_DOUBLE) {
+ *p_argv = args -> fp_regs + fp_reg_num;
+ fp_reg_num += nelements;
+ break;
+ }
+ if (element_type == FFI_TYPE_FLOAT) {
+ int j;
+ for (j = 0; j < nelements; ++ j) {
+ ((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];
+ }
+ *p_argv = (void *)argp;
+ fp_reg_num += nelements;
+ break;
+ }
+ abort(); /* Other fp types NYI */
+ }
+ }
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+
+ argp += z;
+ p_argv++;
+
+ }
+
+ return;
+}
+
+
+/* Fill in a closure to refer to the specified fun and user_data. */
+/* cif specifies the argument and result types for fun. */
+/* the cif must already be prep'ed */
+
+/* The layout of a function descriptor. A C function pointer really */
+/* points to one of these. */
+typedef struct ia64_fd_struct {
+ void *code_pointer;
+ void *gp;
+} ia64_fd;
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ struct ffi_ia64_trampoline_struct *tramp =
+ (struct ffi_ia64_trampoline_struct *) (closure -> tramp);
+ ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;
+
+ FFI_ASSERT (cif->abi == FFI_UNIX);
+
+ tramp -> code_pointer = fd -> code_pointer;
+ tramp -> real_gp = fd -> gp;
+ tramp -> fake_gp = closure;
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+
diff --git a/libffi/src/ia64/ffitarget.h b/libffi/src/ia64/ffitarget.h
new file mode 100644
index 0000000..3b78654
--- /dev/null
+++ b/libffi/src/ia64/ffitarget.h
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for IA-64.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_UNIX, /* Linux and all Unix variants use the same conventions */
+ FFI_DEFAULT_ABI = FFI_UNIX,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */
+ /* can be interpreted as a C function */
+ /* descriptor: */
+
+#ifndef LIBFFI_ASM
+struct ffi_ia64_trampoline_struct {
+ void * code_pointer; /* Pointer to ffi_closure_UNIX */
+ void * fake_gp; /* Pointer to closure, installed as gp */
+ void * real_gp; /* Real gp value, reinstalled by */
+ /* ffi_closure_UNIX. */
+};
+#endif
+
+#endif
+
diff --git a/libffi/src/ia64/ia64_flags.h b/libffi/src/ia64/ia64_flags.h
new file mode 100644
index 0000000..23dbd3e
--- /dev/null
+++ b/libffi/src/ia64/ia64_flags.h
@@ -0,0 +1,62 @@
+/* -----------------------------------------------------------------------
+ ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company
+
+ IA64/unix Foreign Function Interface
+
+ Original author: Hans Boehm, HP Labs
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+
+/* Homogeneous Floating Point Aggregates (HFAs) which are returned */
+/* in FP registers. The least significant bits specify the size in */
+/* words. */
+#define FFI_IS_FLOAT_FP_AGGREGATE 0x1000
+#define FFI_IS_DOUBLE_FP_AGGREGATE 0x0800
+#define FLOAT_FP_AGGREGATE_BIT 12
+#define DOUBLE_FP_AGGREGATE_BIT 11
+
+/* Small structures containing N words. If N=1, they are returned */
+/* as though they were integers. */
+#define FFI_IS_SMALL_STRUCT2 0x40 /* Struct > 8, <=16 bytes */
+#define FFI_IS_SMALL_STRUCT3 0x41 /* Struct > 16 <= 24 bytes */
+#define FFI_IS_SMALL_STRUCT4 0x42 /* Struct > 24, <=32 bytes */
+
+/* Flag values identifying particularly simple cases, which are */
+/* handled specially. We treat functions as simple if they take all */
+/* arguments can be passed as 32 or 64 bit integer quantities, there is */
+/* either no return value or it can be treated as a 64bit integer, and */
+/* if there are at most 2 arguments. */
+/* This is OR'ed with the normal flag values. */
+#define FFI_SIMPLE_V 0x10000 /* () -> X */
+#define FFI_SIMPLE_I 0x20000 /* (int) -> X */
+#define FFI_SIMPLE_L 0x30000 /* (long) -> X */
+#define FFI_SIMPLE_II 0x40000 /* (int,int) -> X */
+#define FFI_SIMPLE_IL 0x50000 /* (int,long) -> X */
+#define FFI_SIMPLE_LI 0x60000 /* (long,int) -> X */
+#define FFI_SIMPLE_LL 0x70000 /* (long,long) -> X */
+
+/* Mask for all of the FFI_SIMPLE bits: */
+#define FFI_SIMPLE 0xf0000
+
+/* An easy way to build FFI_SIMPLE flags from FFI_SIMPLE_V: */
+#define FFI_ADD_LONG_ARG(flag) (((flag) << 1) | 0x10000)
+#define FFI_ADD_INT_ARG(flag) ((flag) << 1)
diff --git a/libffi/src/ia64/unix.S b/libffi/src/ia64/unix.S
new file mode 100644
index 0000000..c0c5058
--- /dev/null
+++ b/libffi/src/ia64/unix.S
@@ -0,0 +1,326 @@
+/* -----------------------------------------------------------------------
+ unix.S - Copyright (c) 1998 Red Hat, Inc.
+ Copyright (c) 2000 Hewlett Packard Company
+
+ IA64/unix Foreign Function Interface
+
+ Primary author: Hans Boehm, HP Labs
+
+ Loosely modeled on Cygnus code for other platforms.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include "ia64_flags.h"
+
+/* parameters: */
+#define callback in0
+#define ecifp in1
+#define bytes in2
+#define flags in3
+#define raddr in4
+#define fn in5
+
+#define FLOAT_SZ 8 /* in-memory size of fp operands */
+
+/* Allocate an ia64_args structure on the stack; call ffi_prep_args */
+/* to fill it in with argument values; copy those to the real */
+/* registers, leaving overflow arguments on the stack. Then call fn */
+/* and move the result from registers into *raddr. */
+ .pred.safe_across_calls p1-p5,p16-p63
+.text
+ .align 16
+ .global ffi_call_unix
+ .proc ffi_call_unix
+ffi_call_unix:
+ .prologue
+ .save ar.pfs,r38 /* loc0 */
+ alloc loc0=ar.pfs,6,6,8,0
+ .save rp,loc1
+ mov loc1=b0;
+ .vframe loc5
+ mov loc5=sp;
+ .body
+ sub sp=sp,bytes
+ mov loc4=r1 /* Save gp */
+ ld8 r8=[callback],8 /* code address of callback */
+ ;;
+ mov out0=sp
+ mov out1=ecifp
+ mov out2=bytes
+ ld8 r1=[callback] /* Set up gp for callback. Unnecessary? */
+ mov b6=r8
+ ;;
+ br.call.sptk.many b0 = b6 /* call ffi_prep_args */
+ cmp.eq p6,p0=0,r8 /* r8 nonzero ==> need fp regs */
+ ;;
+(p6) add loc2=32+8*FLOAT_SZ,sp
+(p6) br.cond.dptk.many fp_done
+ ;; /* Quiets warning; needed? */
+ add loc2=32,sp
+ add loc3=32+FLOAT_SZ,sp
+ ;;
+ ldfd f8=[loc2],2*FLOAT_SZ
+ ldfd f9=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f10=[loc2],2*FLOAT_SZ
+ ldfd f11=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f12=[loc2],2*FLOAT_SZ
+ ldfd f13=[loc3],2*FLOAT_SZ
+ ;;
+ ldfd f14=[loc2],2*FLOAT_SZ
+ ldfd f15=[loc3]
+fp_done:
+ add r9=16,sp /* Pointer to r8_contents */
+ /* loc2 points at first integer register value. */
+ add loc3=8,loc2
+ ;;
+ ld8 r8=[r9] /* Just in case we return large struct */
+ ld8 out0=[loc2],16
+ ld8 out1=[loc3],16
+ ;;
+ ld8 out2=[loc2],16
+ ld8 out3=[loc3],16
+ ;;
+ ld8 out4=[loc2],16
+ ld8 out5=[loc3],16
+ ;;
+ ld8 out6=[loc2]
+ ld8 out7=[loc3]
+ /* Set sp to 16 bytes below the first stack parameter. This */
+ /* is the value currently in loc2. */
+ mov sp=loc2
+
+ ld8 r8=[fn],8
+ ;;
+ ld8 r1=[fn] /* Set up gp */
+ mov b6=r8;;
+ br.call.sptk.many b0 = b6 /* call fn */
+
+ /* Handle return value. */
+ cmp.eq p6,p0=0,raddr
+ cmp.eq p7,p0=FFI_TYPE_INT,flags
+ cmp.eq p10,p0=FFI_IS_SMALL_STRUCT2,flags
+ cmp.eq p11,p0=FFI_IS_SMALL_STRUCT3,flags
+ cmp.eq p12,p0=FFI_IS_SMALL_STRUCT4,flags
+ ;;
+(p6) br.cond.dpnt.few done /* Dont copy ret values if raddr = 0 */
+(p7) br.cond.dptk.few copy1
+(p10) br.cond.dpnt.few copy2
+(p11) br.cond.dpnt.few copy3
+(p12) br.cond.dpnt.few copy4
+ cmp.eq p8,p0=FFI_TYPE_FLOAT,flags
+ cmp.eq p9,p0=FFI_TYPE_DOUBLE,flags
+ tbit.nz p6,p0=flags,FLOAT_FP_AGGREGATE_BIT
+ tbit.nz p7,p0=flags,DOUBLE_FP_AGGREGATE_BIT
+ ;;
+(p8) stfs [raddr]=f8
+(p9) stfd [raddr]=f8
+ ;;
+ .label_state 1
+(p6) br.cond.dpnt.few handle_float_hfa
+(p7) br.cond.dpnt.few handle_double_hfa
+ br done
+
+copy4:
+ add loc3=24,raddr
+ ;;
+ st8 [loc3]=r11
+copy3:
+ add loc3=16,raddr
+ ;;
+ st8 [loc3]=r10
+copy2:
+ add loc3=8,raddr
+ ;;
+ st8 [loc3]=r9
+copy1:
+ st8 [raddr]=r8
+ /* In the big struct case, raddr was passed as an argument. */
+ /* In the void case there was nothing to do. */
+
+done:
+ mov r1=loc4 /* Restore gp */
+ mov ar.pfs = loc0
+ mov b0 = loc1
+ .restore sp
+ mov sp = loc5
+ br.ret.sptk.many b0
+
+handle_double_hfa:
+ .body
+ .copy_state 1
+ /* Homogeneous floating point array of doubles is returned in */
+ /* registers f8-f15. Save one at a time to return area. */
+ and flags=0xf,flags /* Retrieve size */
+ ;;
+ cmp.eq p6,p0=2,flags
+ cmp.eq p7,p0=3,flags
+ cmp.eq p8,p0=4,flags
+ cmp.eq p9,p0=5,flags
+ cmp.eq p10,p0=6,flags
+ cmp.eq p11,p0=7,flags
+ cmp.eq p12,p0=8,flags
+ ;;
+(p6) br.cond.dptk.few dhfa2
+(p7) br.cond.dptk.few dhfa3
+(p8) br.cond.dptk.few dhfa4
+(p9) br.cond.dptk.few dhfa5
+(p10) br.cond.dptk.few dhfa6
+(p11) br.cond.dptk.few dhfa7
+dhfa8: add loc3=7*8,raddr
+ ;;
+ stfd [loc3]=f15
+dhfa7: add loc3=6*8,raddr
+ ;;
+ stfd [loc3]=f14
+dhfa6: add loc3=5*8,raddr
+ ;;
+ stfd [loc3]=f13
+dhfa5: add loc3=4*8,raddr
+ ;;
+ stfd [loc3]=f12
+dhfa4: add loc3=3*8,raddr
+ ;;
+ stfd [loc3]=f11
+dhfa3: add loc3=2*8,raddr
+ ;;
+ stfd [loc3]=f10
+dhfa2: add loc3=1*8,raddr
+ ;;
+ stfd [loc3]=f9
+ stfd [raddr]=f8
+ br done
+
+handle_float_hfa:
+ /* Homogeneous floating point array of floats is returned in */
+ /* registers f8-f15. Save one at a time to return area. */
+ and flags=0xf,flags /* Retrieve size */
+ ;;
+ cmp.eq p6,p0=2,flags
+ cmp.eq p7,p0=3,flags
+ cmp.eq p8,p0=4,flags
+ cmp.eq p9,p0=5,flags
+ cmp.eq p10,p0=6,flags
+ cmp.eq p11,p0=7,flags
+ cmp.eq p12,p0=8,flags
+ ;;
+(p6) br.cond.dptk.few shfa2
+(p7) br.cond.dptk.few shfa3
+(p8) br.cond.dptk.few shfa4
+(p9) br.cond.dptk.few shfa5
+(p10) br.cond.dptk.few shfa6
+(p11) br.cond.dptk.few shfa7
+shfa8: add loc3=7*4,raddr
+ ;;
+ stfd [loc3]=f15
+shfa7: add loc3=6*4,raddr
+ ;;
+ stfd [loc3]=f14
+shfa6: add loc3=5*4,raddr
+ ;;
+ stfd [loc3]=f13
+shfa5: add loc3=4*4,raddr
+ ;;
+ stfd [loc3]=f12
+shfa4: add loc3=3*4,raddr
+ ;;
+ stfd [loc3]=f11
+shfa3: add loc3=2*4,raddr
+ ;;
+ stfd [loc3]=f10
+shfa2: add loc3=1*4,raddr
+ ;;
+ stfd [loc3]=f9
+ stfd [raddr]=f8
+ br done
+
+ .endp ffi_call_unix
+
+
+ .pred.safe_across_calls p1-p5,p16-p63
+.text
+ .align 16
+ .global ffi_closure_UNIX
+ .proc ffi_closure_UNIX
+ffi_closure_UNIX:
+ .prologue
+ .save ar.pfs,r40 /* loc0 */
+ alloc loc0=ar.pfs,8,3,2,0
+ .save rp,loc1
+ mov loc1=b0
+ .vframe loc2
+ mov loc2=sp
+ /* Retrieve closure pointer and real gp. */
+ mov out0=gp
+ add gp=16,gp
+ ;;
+ ld8 gp=[gp]
+ /* Reserve a structia64_args on the stack such that arguments */
+ /* past the first 8 are automatically placed in the right */
+ /* slot. Note that when we start the sp points at 2 8-byte */
+ /* scratch words, followed by the extra arguments. */
+# define BASIC_ARGS_SZ (8*FLOAT_SZ+8*8+2*8)
+# define FIRST_FP_OFFSET (4*8)
+ add r14=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET),sp
+ add r15=-(BASIC_ARGS_SZ-FIRST_FP_OFFSET-FLOAT_SZ),sp
+ add sp=-BASIC_ARGS_SZ,sp
+ /* r14 points to fp_regs[0], r15 points to fp_regs[1] */
+ ;;
+ stfd [r14]=f8,2*FLOAT_SZ
+ stfd [r15]=f9,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f10,2*FLOAT_SZ
+ stfd [r15]=f11,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f12,2*FLOAT_SZ
+ stfd [r15]=f13,2*FLOAT_SZ
+ ;;
+ stfd [r14]=f14,FLOAT_SZ+8
+ stfd [r15]=f15,2*8
+ ;;
+ /* r14 points to first parameter register area, r15 to second. */
+ st8 [r14]=in0,2*8
+ st8 [r15]=in1,2*8
+ ;;
+ st8 [r14]=in2,2*8
+ st8 [r15]=in3,2*8
+ ;;
+ st8 [r14]=in4,2*8
+ st8 [r15]=in5,2*8
+ ;;
+ st8 [r14]=in6,2*8
+ st8 [r15]=in7,2*8
+ /* Call ffi_closure_UNIX_inner */
+ mov out1=sp
+ br.call.sptk.many b0=ffi_closure_UNIX_inner
+ ;;
+ mov b0=loc1
+ mov ar.pfs=loc0
+ .restore sp
+ mov sp=loc2
+ br.ret.sptk.many b0
+ .endp ffi_closure_UNIX
+
+