aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1/libffi/src/mips
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1/libffi/src/mips')
-rw-r--r--gcc-4.2.1/libffi/src/mips/ffi.c648
-rw-r--r--gcc-4.2.1/libffi/src/mips/ffitarget.h167
-rw-r--r--gcc-4.2.1/libffi/src/mips/n32.S320
-rw-r--r--gcc-4.2.1/libffi/src/mips/o32.S377
4 files changed, 1512 insertions, 0 deletions
diff --git a/gcc-4.2.1/libffi/src/mips/ffi.c b/gcc-4.2.1/libffi/src/mips/ffi.c
new file mode 100644
index 000000000..73bc95218
--- /dev/null
+++ b/gcc-4.2.1/libffi/src/mips/ffi.c
@@ -0,0 +1,648 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 1996 Red Hat, Inc.
+
+ MIPS 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 <sys/cachectl.h>
+
+#if _MIPS_SIM == _ABIN32
+#define FIX_ARGP \
+FFI_ASSERT(argp <= &stack[bytes]); \
+if (argp == &stack[bytes]) \
+{ \
+ argp = stack; \
+ ffi_stop_here(); \
+}
+#else
+#define FIX_ARGP
+#endif
+
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+static void ffi_prep_args(char *stack,
+ extended_cif *ecif,
+ int bytes,
+ int flags)
+{
+ int i;
+ void **p_argv;
+ char *argp;
+ ffi_type **p_arg;
+
+#if _MIPS_SIM == _ABIN32
+ /* If more than 8 double words are used, the remainder go
+ on the stack. We reorder stuff on the stack here to
+ support this easily. */
+ if (bytes > 8 * sizeof(ffi_arg))
+ argp = &stack[bytes - (8 * sizeof(ffi_arg))];
+ else
+ argp = stack;
+#else
+ argp = stack;
+#endif
+
+ memset(stack, 0, bytes);
+
+#if _MIPS_SIM == _ABIN32
+ if ( ecif->cif->rstruct_flag != 0 )
+#else
+ if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
+#endif
+ {
+ *(ffi_arg *) argp = (ffi_arg) ecif->rvalue;
+ argp += sizeof(ffi_arg);
+ FIX_ARGP;
+ }
+
+ p_argv = ecif->avalue;
+
+ for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
+ {
+ size_t z;
+ unsigned int a;
+
+ /* Align if necessary. */
+ a = (*p_arg)->alignment;
+ if (a < sizeof(ffi_arg))
+ a = sizeof(ffi_arg);
+
+ if ((a - 1) & (unsigned int) argp)
+ {
+ argp = (char *) ALIGN(argp, a);
+ FIX_ARGP;
+ }
+
+ z = (*p_arg)->size;
+ if (z <= sizeof(ffi_arg))
+ {
+ z = sizeof(ffi_arg);
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(ffi_arg *)argp = *(SINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(ffi_arg *)argp = *(UINT8 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(ffi_arg *)argp = *(SINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(ffi_arg *)argp = *(UINT16 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ *(ffi_arg *)argp = *(SINT32 *)(* p_argv);
+ break;
+
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_POINTER:
+ *(ffi_arg *)argp = *(UINT32 *)(* p_argv);
+ break;
+
+ /* This can only happen with 64bit slots. */
+ case FFI_TYPE_FLOAT:
+ *(float *) argp = *(float *)(* p_argv);
+ break;
+
+ /* Handle small structures. */
+ case FFI_TYPE_STRUCT:
+ default:
+ memcpy(argp, *p_argv, (*p_arg)->size);
+ break;
+ }
+ }
+ else
+ {
+#if _MIPS_SIM == _ABIO32
+ memcpy(argp, *p_argv, z);
+#else
+ {
+ unsigned end = (unsigned) argp+z;
+ unsigned cap = (unsigned) stack+bytes;
+
+ /* Check if the data will fit within the register space.
+ Handle it if it doesn't. */
+
+ if (end <= cap)
+ memcpy(argp, *p_argv, z);
+ else
+ {
+ unsigned portion = end - cap;
+
+ memcpy(argp, *p_argv, portion);
+ argp = stack;
+ memcpy(argp,
+ (void*)((unsigned)(*p_argv)+portion), z - portion);
+ }
+ }
+#endif
+ }
+ p_argv++;
+ argp += z;
+ FIX_ARGP;
+ }
+}
+
+#if _MIPS_SIM == _ABIN32
+
+/* The n32 spec says that if "a chunk consists solely of a double
+ float field (but not a double, which is part of a union), it
+ is passed in a floating point register. Any other chunk is
+ passed in an integer register". This code traverses structure
+ definitions and generates the appropriate flags. */
+
+unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
+{
+ unsigned flags = 0;
+ unsigned index = 0;
+
+ ffi_type *e;
+
+ while (e = arg->elements[index])
+ {
+ if (e->type == FFI_TYPE_DOUBLE)
+ {
+ flags += (FFI_TYPE_DOUBLE << *shift);
+ *shift += FFI_FLAG_BITS;
+ }
+ else if (e->type == FFI_TYPE_STRUCT)
+ flags += calc_n32_struct_flags(e, shift);
+ else
+ *shift += FFI_FLAG_BITS;
+
+ index++;
+ }
+
+ return flags;
+}
+
+unsigned calc_n32_return_struct_flags(ffi_type *arg)
+{
+ unsigned flags = 0;
+ unsigned index = 0;
+ unsigned small = FFI_TYPE_SMALLSTRUCT;
+ ffi_type *e;
+
+ /* Returning structures under n32 is a tricky thing.
+ A struct with only one or two floating point fields
+ is returned in $f0 (and $f2 if necessary). Any other
+ struct results at most 128 bits are returned in $2
+ (the first 64 bits) and $3 (remainder, if necessary).
+ Larger structs are handled normally. */
+
+ if (arg->size > 16)
+ return 0;
+
+ if (arg->size > 8)
+ small = FFI_TYPE_SMALLSTRUCT2;
+
+ e = arg->elements[0];
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
+
+ if (flags && (e = arg->elements[1]))
+ {
+ if (e->type == FFI_TYPE_DOUBLE)
+ flags += FFI_TYPE_DOUBLE;
+ else if (e->type == FFI_TYPE_FLOAT)
+ flags += FFI_TYPE_FLOAT;
+ else
+ return small;
+
+ if (flags && (arg->elements[2]))
+ {
+ /* There are three arguments and the first two are
+ floats! This must be passed the old way. */
+ return small;
+ }
+ }
+ else
+ if (!flags)
+ return small;
+
+ return flags;
+}
+
+#endif
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ cif->flags = 0;
+
+#if _MIPS_SIM == _ABIO32
+ /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT
+ * does not have special handling for floating point args.
+ */
+
+ if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32)
+ {
+ if (cif->nargs > 0)
+ {
+ switch ((cif->arg_types)[0]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += (cif->arg_types)[0]->type;
+ break;
+
+ default:
+ break;
+ }
+
+ if (cif->nargs > 1)
+ {
+ /* Only handle the second argument if the first
+ is a float or double. */
+ if (cif->flags)
+ {
+ switch ((cif->arg_types)[1]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Set the return type flag */
+
+ if (cif->abi == FFI_O32_SOFT_FLOAT)
+ {
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
+ break;
+
+ case FFI_TYPE_FLOAT:
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
+ break;
+ }
+ }
+ else
+ {
+ /* FFI_O32 */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_STRUCT:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
+ break;
+
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2);
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
+ break;
+ }
+ }
+#endif
+
+#if _MIPS_SIM == _ABIN32
+ /* Set the flags necessary for N32 processing */
+ {
+ unsigned shift = 0;
+ unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
+ unsigned index = 0;
+
+ unsigned struct_flags = 0;
+
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ struct_flags = calc_n32_return_struct_flags(cif->rtype);
+
+ if (struct_flags == 0)
+ {
+ /* This means that the structure is being passed as
+ a hidden argument */
+
+ shift = FFI_FLAG_BITS;
+ count = (cif->nargs < 7) ? cif->nargs : 7;
+
+ cif->rstruct_flag = !0;
+ }
+ else
+ cif->rstruct_flag = 0;
+ }
+ else
+ cif->rstruct_flag = 0;
+
+ while (count-- > 0)
+ {
+ switch ((cif->arg_types)[index]->type)
+ {
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += ((cif->arg_types)[index]->type << shift);
+ shift += FFI_FLAG_BITS;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
+ &shift);
+ break;
+
+ default:
+ shift += FFI_FLAG_BITS;
+ }
+
+ index++;
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ {
+ if (struct_flags == 0)
+ {
+ /* The structure is returned through a hidden
+ first argument. Do nothing, 'cause FFI_TYPE_VOID
+ is 0 */
+ }
+ else
+ {
+ /* The structure is returned via some tricky
+ mechanism */
+ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
+ cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
+ }
+ break;
+ }
+
+ case FFI_TYPE_VOID:
+ /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
+ break;
+
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
+ break;
+
+ default:
+ cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
+ break;
+ }
+ }
+#endif
+
+ return FFI_OK;
+}
+
+/* Low level routine for calling O32 functions */
+extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+/* Low level routine for calling N32 functions */
+extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
+ extended_cif *, unsigned,
+ unsigned, unsigned *, void (*)());
+
+void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
+{
+ extended_cif ecif;
+
+ 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)
+ {
+#if _MIPS_SIM == _ABIO32
+ case FFI_O32:
+ case FFI_O32_SOFT_FLOAT:
+ ffi_call_O32(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ break;
+#endif
+
+#if _MIPS_SIM == _ABIN32
+ case FFI_N32:
+ ffi_call_N32(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, ecif.rvalue, fn);
+ break;
+#endif
+
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */
+#if defined(FFI_MIPS_O32)
+extern void ffi_closure_O32(void);
+#endif /* FFI_MIPS_O32 */
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+ unsigned int fn;
+ unsigned int ctx = (unsigned int) closure;
+
+#if defined(FFI_MIPS_O32)
+ FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT);
+ fn = (unsigned int) ffi_closure_O32;
+#else /* FFI_MIPS_N32 */
+ FFI_ASSERT(cif->abi == FFI_N32);
+ FFI_ASSERT(!"not implemented");
+#endif /* FFI_MIPS_O32 */
+
+ tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */
+ tramp[1] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */
+ tramp[2] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */
+ tramp[3] = 0x03200008; /* jr $25 */
+ tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* XXX this is available on Linux, but anything else? */
+ cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE);
+
+ return FFI_OK;
+}
+
+/*
+ * Decodes the arguments to a function, which will be stored on the
+ * stack. AR is the pointer to the beginning of the integer arguments
+ * (and, depending upon the arguments, some floating-point arguments
+ * as well). FPR is a pointer to the area where floating point
+ * registers have been saved, if any.
+ *
+ * RVALUE is the location where the function return value will be
+ * stored. CLOSURE is the prepared closure to invoke.
+ *
+ * This function should only be called from assembly, which is in
+ * turn called from a trampoline.
+ *
+ * Returns the function return type.
+ *
+ * Based on the similar routine for sparc.
+ */
+int
+ffi_closure_mips_inner_O32 (ffi_closure *closure,
+ void *rvalue, ffi_arg *ar,
+ double *fpr)
+{
+ ffi_cif *cif;
+ void **avaluep;
+ ffi_arg *avalue;
+ ffi_type **arg_types;
+ int i, avn, argn, seen_int;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (ffi_arg));
+ avaluep = alloca (cif->nargs * sizeof (ffi_arg));
+
+ seen_int = (cif->abi == FFI_O32_SOFT_FLOAT);
+ argn = 0;
+
+ if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT)
+ {
+ rvalue = (void *) ar[0];
+ argn = 1;
+ }
+
+ i = 0;
+ avn = cif->nargs;
+ arg_types = cif->arg_types;
+
+ while (i < avn)
+ {
+ if (i < 2 && !seen_int &&
+ (arg_types[i]->type == FFI_TYPE_FLOAT ||
+ arg_types[i]->type == FFI_TYPE_DOUBLE))
+ {
+#ifdef __MIPSEB__
+ if (arg_types[i]->type == FFI_TYPE_FLOAT)
+ avaluep[i] = ((char *) &fpr[i]) + sizeof (float);
+ else
+#endif
+ avaluep[i] = (char *) &fpr[i];
+ }
+ else
+ {
+ if (arg_types[i]->alignment == 8 && (argn & 0x1))
+ argn++;
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ avaluep[i] = &avalue[i];
+ *(SINT8 *) &avalue[i] = (SINT8) ar[argn];
+ break;
+
+ case FFI_TYPE_UINT8:
+ avaluep[i] = &avalue[i];
+ *(UINT8 *) &avalue[i] = (UINT8) ar[argn];
+ break;
+
+ case FFI_TYPE_SINT16:
+ avaluep[i] = &avalue[i];
+ *(SINT16 *) &avalue[i] = (SINT16) ar[argn];
+ break;
+
+ case FFI_TYPE_UINT16:
+ avaluep[i] = &avalue[i];
+ *(UINT16 *) &avalue[i] = (UINT16) ar[argn];
+ break;
+
+ default:
+ avaluep[i] = (char *) &ar[argn];
+ break;
+ }
+ seen_int = 1;
+ }
+ argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+ i++;
+ }
+
+ /* Invoke the closure. */
+ (closure->fun) (cif, rvalue, avaluep, closure->user_data);
+
+ if (cif->abi == FFI_O32_SOFT_FLOAT)
+ {
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_FLOAT:
+ return FFI_TYPE_INT;
+ case FFI_TYPE_DOUBLE:
+ return FFI_TYPE_UINT64;
+ default:
+ return cif->rtype->type;
+ }
+ }
+ else
+ {
+ return cif->rtype->type;
+ }
+}
+
+#endif /* FFI_CLOSURES */
diff --git a/gcc-4.2.1/libffi/src/mips/ffitarget.h b/gcc-4.2.1/libffi/src/mips/ffitarget.h
new file mode 100644
index 000000000..e61074569
--- /dev/null
+++ b/gcc-4.2.1/libffi/src/mips/ffitarget.h
@@ -0,0 +1,167 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for MIPS.
+
+ 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
+
+#if !defined(_MIPS_SIM)
+-- something is very wrong --
+#else
+# if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64))
+# define FFI_MIPS_N32
+# else
+# if (_MIPS_SIM==_ABIO32 && defined(_ABIO32))
+# define FFI_MIPS_O32
+# else
+-- this is an unsupported platform --
+# endif
+# endif
+#endif
+
+#ifdef FFI_MIPS_O32
+/* O32 stack frames have 32bit integer args */
+#define FFI_SIZEOF_ARG 4
+#else
+/* N32 and N64 frames have 64bit integer args */
+#define FFI_SIZEOF_ARG 8
+#endif
+
+#define FFI_FLAG_BITS 2
+
+/* SGI's strange assembler requires that we multiply by 4 rather
+ than shift left by FFI_FLAG_BITS */
+
+#define FFI_ARGS_D FFI_TYPE_DOUBLE
+#define FFI_ARGS_F FFI_TYPE_FLOAT
+#define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE
+#define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT
+#define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT
+#define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE
+
+/* Needed for N32 structure returns */
+#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8
+#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8
+
+#if 0
+/* The SGI assembler can't handle this.. */
+#define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT
+/* (and so on) */
+#else
+/* ...so we calculate these by hand! */
+#define FFI_TYPE_STRUCT_D 61
+#define FFI_TYPE_STRUCT_F 45
+#define FFI_TYPE_STRUCT_DD 253
+#define FFI_TYPE_STRUCT_FF 173
+#define FFI_TYPE_STRUCT_FD 237
+#define FFI_TYPE_STRUCT_DF 189
+#define FFI_TYPE_STRUCT_SMALL 93
+#define FFI_TYPE_STRUCT_SMALL2 109
+#endif
+
+#ifdef LIBFFI_ASM
+#define v0 $2
+#define v1 $3
+#define a0 $4
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define a4 $8
+#define a5 $9
+#define a6 $10
+#define a7 $11
+#define t0 $8
+#define t1 $9
+#define t2 $10
+#define t3 $11
+#define t4 $12
+#define t5 $13
+#define t6 $14
+#define t7 $15
+#define t8 $24
+#define t9 $25
+#define ra $31
+
+#ifdef FFI_MIPS_O32
+#define REG_L lw
+#define REG_S sw
+#define SUBU subu
+#define ADDU addu
+#define SRL srl
+#define LI li
+#else /* !FFI_MIPS_O32 */
+#define REG_L ld
+#define REG_S sd
+#define SUBU dsubu
+#define ADDU daddu
+#define SRL dsrl
+#define LI dli
+#endif /* !FFI_MIPS_O32 */
+#else /* !LIBFFI_ASM */
+#ifdef FFI_MIPS_O32
+/* O32 stack frames have 32bit integer args */
+typedef unsigned int ffi_arg __attribute__((__mode__(__SI__)));
+typedef signed int ffi_sarg __attribute__((__mode__(__SI__)));
+#else
+/* N32 and N64 frames have 64bit integer args */
+typedef unsigned int ffi_arg __attribute__((__mode__(__DI__)));
+typedef signed int ffi_sarg __attribute__((__mode__(__DI__)));
+#endif
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_O32,
+ FFI_N32,
+ FFI_N64,
+ FFI_O32_SOFT_FLOAT,
+
+#ifdef FFI_MIPS_O32
+#ifdef __mips_soft_float
+ FFI_DEFAULT_ABI = FFI_O32_SOFT_FLOAT,
+#else
+ FFI_DEFAULT_ABI = FFI_O32,
+#endif
+#else
+ FFI_DEFAULT_ABI = FFI_N32,
+#endif
+
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+
+#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag
+#endif /* !LIBFFI_ASM */
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#if defined(FFI_MIPS_O32)
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 20
+#else
+/* N32/N64 not implemented yet. */
+#define FFI_CLOSURES 0
+#endif /* FFI_MIPS_O32 */
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/gcc-4.2.1/libffi/src/mips/n32.S b/gcc-4.2.1/libffi/src/mips/n32.S
new file mode 100644
index 000000000..358cfd7e4
--- /dev/null
+++ b/gcc-4.2.1/libffi/src/mips/n32.S
@@ -0,0 +1,320 @@
+/* -----------------------------------------------------------------------
+ n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
+
+ MIPS 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+/* Only build this code if we are compiling for n32 */
+
+#if defined(FFI_MIPS_N32)
+
+#define callback a0
+#define bytes a2
+#define flags a3
+#define raddr a4
+#define fn a5
+
+#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG )
+
+ .abicalls
+ .text
+ .align 2
+ .globl ffi_call_N32
+ .ent ffi_call_N32
+ffi_call_N32:
+
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+ REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer
+ REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address
+ move $fp, $sp
+
+ move t9, callback # callback function pointer
+ REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes
+ REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags
+ REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr
+ REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn
+
+ # Allocate at least 4 words in the argstack
+ move v0, bytes
+ bge bytes, 4 * FFI_SIZEOF_ARG, bigger
+ LI v0, 4 * FFI_SIZEOF_ARG
+ b sixteen
+
+ bigger:
+ ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned
+ and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry.
+
+sixteen:
+ SUBU $sp, $sp, v0 # move the stack pointer to reflect the
+ # arg space
+
+ ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG
+ ADDU a3, $fp, 3 * FFI_SIZEOF_ARG
+
+ # Call ffi_prep_args
+ jal t9
+
+ # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+
+ # Copy the stack pointer to t9
+ move t9, $sp
+
+ # Fix the stack if there are more than 8 64bit slots worth
+ # of arguments.
+
+ # Load the number of bytes
+ REG_L t6, 2*FFI_SIZEOF_ARG($fp)
+
+ # Is it bigger than 8 * FFI_SIZEOF_ARG?
+ dadd t7, $0, 8 * FFI_SIZEOF_ARG
+ dsub t8, t6, t7
+ bltz t8, loadregs
+
+ add t9, t9, t8
+
+loadregs:
+
+ REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word
+ add t6, t4, 0 # and copy it into t6
+
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg1_floatp
+ REG_L a0, 0*FFI_SIZEOF_ARG(t9)
+ b arg1_next
+arg1_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg1_doublep
+ l.s $f12, 0*FFI_SIZEOF_ARG(t9)
+ b arg1_next
+arg1_doublep:
+ l.d $f12, 0*FFI_SIZEOF_ARG(t9)
+arg1_next:
+
+ add t4, t6, 0
+ SRL t4, 1*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg2_floatp
+ REG_L a1, 1*FFI_SIZEOF_ARG(t9)
+ b arg2_next
+arg2_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg2_doublep
+ l.s $f13, 1*FFI_SIZEOF_ARG(t9)
+ b arg2_next
+arg2_doublep:
+ l.d $f13, 1*FFI_SIZEOF_ARG(t9)
+arg2_next:
+
+ add t4, t6, 0
+ SRL t4, 2*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg3_floatp
+ REG_L a2, 2*FFI_SIZEOF_ARG(t9)
+ b arg3_next
+arg3_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg3_doublep
+ l.s $f14, 2*FFI_SIZEOF_ARG(t9)
+ b arg3_next
+arg3_doublep:
+ l.d $f14, 2*FFI_SIZEOF_ARG(t9)
+arg3_next:
+
+ add t4, t6, 0
+ SRL t4, 3*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg4_floatp
+ REG_L a3, 3*FFI_SIZEOF_ARG(t9)
+ b arg4_next
+arg4_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg4_doublep
+ l.s $f15, 3*FFI_SIZEOF_ARG(t9)
+ b arg4_next
+arg4_doublep:
+ l.d $f15, 3*FFI_SIZEOF_ARG(t9)
+arg4_next:
+
+ add t4, t6, 0
+ SRL t4, 4*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg5_floatp
+ REG_L a4, 4*FFI_SIZEOF_ARG(t9)
+ b arg5_next
+arg5_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg5_doublep
+ l.s $f16, 4*FFI_SIZEOF_ARG(t9)
+ b arg5_next
+arg5_doublep:
+ l.d $f16, 4*FFI_SIZEOF_ARG(t9)
+arg5_next:
+
+ add t4, t6, 0
+ SRL t4, 5*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg6_floatp
+ REG_L a5, 5*FFI_SIZEOF_ARG(t9)
+ b arg6_next
+arg6_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg6_doublep
+ l.s $f17, 5*FFI_SIZEOF_ARG(t9)
+ b arg6_next
+arg6_doublep:
+ l.d $f17, 5*FFI_SIZEOF_ARG(t9)
+arg6_next:
+
+ add t4, t6, 0
+ SRL t4, 6*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg7_floatp
+ REG_L a6, 6*FFI_SIZEOF_ARG(t9)
+ b arg7_next
+arg7_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg7_doublep
+ l.s $f18, 6*FFI_SIZEOF_ARG(t9)
+ b arg7_next
+arg7_doublep:
+ l.d $f18, 6*FFI_SIZEOF_ARG(t9)
+arg7_next:
+
+ add t4, t6, 0
+ SRL t4, 7*FFI_FLAG_BITS
+ and t4, ((1<<FFI_FLAG_BITS)-1)
+ bnez t4, arg8_floatp
+ REG_L a7, 7*FFI_SIZEOF_ARG(t9)
+ b arg8_next
+arg8_floatp:
+ bne t4, FFI_TYPE_FLOAT, arg8_doublep
+ l.s $f19, 7*FFI_SIZEOF_ARG(t9)
+ b arg8_next
+arg8_doublep:
+ l.d $f19, 7*FFI_SIZEOF_ARG(t9)
+arg8_next:
+
+callit:
+ # Load the function pointer
+ REG_L t9, 5*FFI_SIZEOF_ARG($fp)
+
+ # If the return value pointer is NULL, assume no return value.
+ REG_L t5, 4*FFI_SIZEOF_ARG($fp)
+ beqz t5, noretval
+
+ # Shift the return type flag over
+ SRL t6, 8*FFI_FLAG_BITS
+
+ bne t6, FFI_TYPE_INT, retfloat
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ b epilogue
+
+retfloat:
+ bne t6, FFI_TYPE_FLOAT, retdouble
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ b epilogue
+
+retdouble:
+ bne t6, FFI_TYPE_DOUBLE, retstruct_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ b epilogue
+
+retstruct_d:
+ bne t6, FFI_TYPE_STRUCT_D, retstruct_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ b epilogue
+
+retstruct_f:
+ bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ b epilogue
+
+retstruct_d_d:
+ bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ s.d $f2, 8(t4)
+ b epilogue
+
+retstruct_f_f:
+ bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ s.s $f2, 4(t4)
+ b epilogue
+
+retstruct_d_f:
+ bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t4)
+ s.s $f2, 8(t4)
+ b epilogue
+
+retstruct_f_d:
+ bne t6, FFI_TYPE_STRUCT_FD, retstruct_small
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t4)
+ s.d $f2, 8(t4)
+ b epilogue
+
+retstruct_small:
+ bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ b epilogue
+
+retstruct_small2:
+ bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct
+ jal t9
+ REG_L t4, 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t4)
+ REG_S v1, 8(t4)
+ b epilogue
+
+retstruct:
+noretval:
+ jal t9
+
+ # Epilogue
+epilogue:
+ move $sp, $fp
+ REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer
+ REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
+ j ra
+
+ .end ffi_call_N32
+
+#endif
diff --git a/gcc-4.2.1/libffi/src/mips/o32.S b/gcc-4.2.1/libffi/src/mips/o32.S
new file mode 100644
index 000000000..63f3d1463
--- /dev/null
+++ b/gcc-4.2.1/libffi/src/mips/o32.S
@@ -0,0 +1,377 @@
+/* -----------------------------------------------------------------------
+ o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc.
+
+ MIPS 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.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+/* Only build this code if we are compiling for o32 */
+
+#if defined(FFI_MIPS_O32)
+
+#define callback a0
+#define bytes a2
+#define flags a3
+
+#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG)
+#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG)
+#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG)
+#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG)
+
+ .abicalls
+ .text
+ .align 2
+ .globl ffi_call_O32
+ .ent ffi_call_O32
+ffi_call_O32:
+$LFB0:
+ # Prologue
+ SUBU $sp, SIZEOF_FRAME # Frame size
+$LCFI0:
+ REG_S $fp, FP_OFF($sp) # Save frame pointer
+$LCFI1:
+ REG_S ra, RA_OFF($sp) # Save return address
+$LCFI2:
+ move $fp, $sp
+
+$LCFI3:
+ move t9, callback # callback function pointer
+ REG_S flags, A3_OFF($fp) # flags
+
+ # Allocate at least 4 words in the argstack
+ LI v0, 4 * FFI_SIZEOF_ARG
+ blt bytes, v0, sixteen
+
+ ADDU v0, bytes, 7 # make sure it is aligned
+ and v0, -8 # to an 8 byte boundry
+
+sixteen:
+ SUBU $sp, v0 # move the stack pointer to reflect the
+ # arg space
+
+ ADDU a0, $sp, 4 * FFI_SIZEOF_ARG
+
+ jalr t9
+
+ REG_L t0, A3_OFF($fp) # load the flags word
+ SRL t2, t0, 4 # shift our arg info
+ and t0, ((1<<4)-1) # mask out the return type
+
+ ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args
+
+ bnez t0, pass_d # make it quick for int
+ REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the
+ REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs.
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d:
+ bne t0, FFI_ARGS_D, pass_f
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_f:
+ bne t0, FFI_ARGS_F, pass_d_d
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d_d:
+ bne t0, FFI_ARGS_DD, pass_f_f
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles
+ b call_it
+
+pass_f_f:
+ bne t0, FFI_ARGS_FF, pass_d_f
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats
+ REG_L a2, 2*FFI_SIZEOF_ARG($sp)
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_d_f:
+ bne t0, FFI_ARGS_DF, pass_f_d
+ l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+ REG_L a3, 3*FFI_SIZEOF_ARG($sp)
+ b call_it
+
+pass_f_d:
+ # assume that the only other combination must be float then double
+ # bne t0, FFI_ARGS_F_D, call_it
+ l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args
+ l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float
+
+call_it:
+ # Load the function pointer
+ REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp)
+
+ # If the return value pointer is NULL, assume no return value.
+ REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ beqz t1, noretval
+
+ bne t2, FFI_TYPE_INT, retlonglong
+ jalr t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ REG_S v0, 0(t0)
+ b epilogue
+
+retlonglong:
+ # Really any 64-bit int, signed or not.
+ bne t2, FFI_TYPE_UINT64, retfloat
+ jalr t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ REG_S v1, 4(t0)
+ REG_S v0, 0(t0)
+ b epilogue
+
+retfloat:
+ bne t2, FFI_TYPE_FLOAT, retdouble
+ jalr t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ s.s $f0, 0(t0)
+ b epilogue
+
+retdouble:
+ bne t2, FFI_TYPE_DOUBLE, noretval
+ jalr t9
+ REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp)
+ s.d $f0, 0(t0)
+ b epilogue
+
+noretval:
+ jalr t9
+
+ # Epilogue
+epilogue:
+ move $sp, $fp
+ REG_L $fp, FP_OFF($sp) # Restore frame pointer
+ REG_L ra, RA_OFF($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME # Fix stack pointer
+ j ra
+
+$LFE0:
+ .end ffi_call_O32
+
+
+/* ffi_closure_O32. Expects address of the passed-in ffi_closure
+ in t0. Stores any arguments passed in registers onto the
+ stack, then calls ffi_closure_mips_inner_O32, which
+ then decodes them.
+
+ Stack layout:
+
+ 14 - Start of parameters, original sp
+ 13 - ra save
+ 12 - fp save
+ 11 - $16 (s0) save
+ 10 - cprestore
+ 9 - return value high (v1)
+ 8 - return value low (v0)
+ 7 - f14 (le high, be low)
+ 6 - f14 (le low, be high)
+ 5 - f12 (le high, be low)
+ 4 - f12 (le low, be high)
+ 3 - Called function a3 save
+ 2 - Called function a2 save
+ 1 - Called function a1 save
+ 0 - Called function a0 save our sp, fp point here
+ */
+
+#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG)
+#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG)
+#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG)
+#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG)
+#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG)
+#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG)
+#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG)
+#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG)
+#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG)
+#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG)
+#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG)
+#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG)
+#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG)
+#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG)
+#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG)
+
+ .text
+ .align 2
+ .globl ffi_closure_O32
+ .ent ffi_closure_O32
+ffi_closure_O32:
+$LFB1:
+ # Prologue
+ .frame $fp, SIZEOF_FRAME2, ra
+ .set noreorder
+ .cpload t9
+ .set reorder
+ SUBU $sp, SIZEOF_FRAME2
+ .cprestore GP_OFF2
+$LCFI4:
+ REG_S $16, S0_OFF2($sp) # Save s0
+ REG_S $fp, FP_OFF2($sp) # Save frame pointer
+ REG_S ra, RA_OFF2($sp) # Save return address
+$LCFI6:
+ move $fp, $sp
+
+$LCFI7:
+ # Store all possible argument registers. If there are more than
+ # four arguments, then they are stored above where we put a3.
+ REG_S a0, A0_OFF2($fp)
+ REG_S a1, A1_OFF2($fp)
+ REG_S a2, A2_OFF2($fp)
+ REG_S a3, A3_OFF2($fp)
+
+ # Load ABI enum to s0
+ REG_L $16, 20($8) # cif pointer follows tramp.
+ REG_L $16, 0($16) # abi is first member.
+
+ li $13, 1 # FFI_O32
+ bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT
+
+ # Store all possible float/double registers.
+ s.d $f12, FA_0_0_OFF2($fp)
+ s.d $f14, FA_1_0_OFF2($fp)
+1:
+ # Call ffi_closure_mips_inner_O32 to do the work.
+ la t9, ffi_closure_mips_inner_O32
+ move a0, $8 # Pointer to the ffi_closure
+ addu a1, $fp, V0_OFF2
+ addu a2, $fp, A0_OFF2
+ addu a3, $fp, FA_0_0_OFF2
+ jalr t9
+
+ # Load the return value into the appropriate register.
+ move $8, $2
+ li $9, FFI_TYPE_VOID
+ beq $8, $9, closure_done
+
+ li $13, 1 # FFI_O32
+ bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT
+
+ li $9, FFI_TYPE_FLOAT
+ l.s $f0, V0_OFF2($fp)
+ beq $8, $9, closure_done
+
+ li $9, FFI_TYPE_DOUBLE
+ l.d $f0, V0_OFF2($fp)
+ beq $8, $9, closure_done
+1:
+ REG_L $3, V1_OFF2($fp)
+ REG_L $2, V0_OFF2($fp)
+
+closure_done:
+ # Epilogue
+ move $sp, $fp
+ REG_L $16, S0_OFF2($sp) # Restore s0
+ REG_L $fp, FP_OFF2($sp) # Restore frame pointer
+ REG_L ra, RA_OFF2($sp) # Restore return address
+ ADDU $sp, SIZEOF_FRAME2
+ j ra
+$LFE1:
+ .end ffi_closure_O32
+
+/* DWARF-2 unwind info. */
+
+ .section .eh_frame,"a",@progbits
+$Lframe0:
+ .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry
+$LSCIE0:
+ .4byte 0x0 # CIE Identifier Tag
+ .byte 0x1 # CIE Version
+ .ascii "zR\0" # CIE Augmentation
+ .uleb128 0x1 # CIE Code Alignment Factor
+ .sleb128 4 # CIE Data Alignment Factor
+ .byte 0x1f # CIE RA Column
+ .uleb128 0x1 # Augmentation size
+ .byte 0x00 # FDE Encoding (absptr)
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1d
+ .uleb128 0x0
+ .align 2
+$LECIE0:
+$LSFDE0:
+ .4byte $LEFDE0-$LASFDE0 # FDE Length
+$LASFDE0:
+ .4byte $LASFDE0-$Lframe0 # FDE CIE offset
+ .4byte $LFB0 # FDE initial location
+ .4byte $LFE0-$LFB0 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI0-$LFB0
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x18
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI2-$LCFI0
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI3-$LCFI2
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 0x18
+ .align 2
+$LEFDE0:
+$LSFDE1:
+ .4byte $LEFDE1-$LASFDE1 # FDE Length
+$LASFDE1:
+ .4byte $LASFDE1-$Lframe0 # FDE CIE offset
+ .4byte $LFB1 # FDE initial location
+ .4byte $LFE1-$LFB1 # FDE address range
+ .uleb128 0x0 # Augmentation size
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI4-$LFB1
+ .byte 0xe # DW_CFA_def_cfa_offset
+ .uleb128 0x38
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI6-$LCFI4
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x10 # $16
+ .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1e # $fp
+ .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp)
+ .byte 0x11 # DW_CFA_offset_extended_sf
+ .uleb128 0x1f # $ra
+ .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp)
+ .byte 0x4 # DW_CFA_advance_loc4
+ .4byte $LCFI7-$LCFI6
+ .byte 0xc # DW_CFA_def_cfa
+ .uleb128 0x1e
+ .uleb128 0x38
+ .align 2
+$LEFDE1:
+
+#endif