summaryrefslogtreecommitdiff
path: root/libffi/src/sh64
diff options
context:
space:
mode:
Diffstat (limited to 'libffi/src/sh64')
-rw-r--r--libffi/src/sh64/ffi.c448
-rw-r--r--libffi/src/sh64/ffitarget.h52
-rw-r--r--libffi/src/sh64/sysv.S484
3 files changed, 984 insertions, 0 deletions
diff --git a/libffi/src/sh64/ffi.c b/libffi/src/sh64/ffi.c
new file mode 100644
index 0000000..7709603
--- /dev/null
+++ b/libffi/src/sh64/ffi.c
@@ -0,0 +1,448 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2003 Kaz Kojima
+
+ SuperH SHmedia 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>
+
+#define NGREGARG 8
+#define NFREGARG 12
+
+/* If the structure has essentialy an unique element, return its type. */
+static int
+simple_type (ffi_type *arg)
+{
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+ else if (arg->elements[1])
+ return FFI_TYPE_STRUCT;
+
+ return simple_type (arg->elements[0]);
+}
+
+static int
+return_type (ffi_type *arg)
+{
+ unsigned short type;
+
+ if (arg->type != FFI_TYPE_STRUCT)
+ return arg->type;
+
+ type = simple_type (arg->elements[0]);
+ if (! arg->elements[1])
+ {
+ switch (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:
+ return FFI_TYPE_UINT64;
+
+ default:
+ return type;
+ }
+ }
+
+ /* gcc uses r2 if the result can be packed in on register. */
+ if (arg->size <= sizeof (UINT64))
+ return FFI_TYPE_UINT64;
+
+ return FFI_TYPE_STRUCT;
+}
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+ register unsigned int i;
+ register unsigned int avn;
+ register void **p_argv;
+ register char *argp;
+ register ffi_type **p_arg;
+
+ argp = stack;
+
+ if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
+ {
+ *(void **) argp = ecif->rvalue;
+ argp += sizeof (UINT64);
+ }
+
+ avn = ecif->cif->nargs;
+ p_argv = ecif->avalue;
+
+ for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
+ {
+ size_t z;
+
+ z = (*p_arg)->size;
+ if (z < sizeof (UINT32))
+ {
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
+ break;
+
+ case FFI_TYPE_STRUCT:
+ *(UINT64 *) argp = (UINT64) *(UINT32 *)(*p_argv);
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ argp += sizeof (UINT64);
+ }
+ else if (z == sizeof (UINT32))
+ {
+ *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
+ argp += sizeof (UINT64);
+ }
+ else if (z == sizeof (UINT64))
+ {
+ *(UINT64 *) argp = *(UINT64 *) (*p_argv);
+ argp += sizeof (UINT64);
+ }
+ else
+ {
+ int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
+
+ memcpy (argp, *p_argv, z);
+ argp += n * sizeof (UINT64);
+ }
+ }
+
+ return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ int i, j;
+ int size, type;
+ int n, m;
+ int greg;
+ int freg;
+
+ greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
+ freg = 0;
+ cif->flags2 = 0;
+
+ for (i = j = 0; i < cif->nargs; i++)
+ {
+ type = (cif->arg_types)[i]->type;
+ switch (type)
+ {
+ case FFI_TYPE_FLOAT:
+ greg++;
+ cif->bytes += sizeof (UINT64) - sizeof (float);
+ if (freg >= NFREGARG - 1)
+ continue;
+ freg++;
+ cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
+ break;
+
+ case FFI_TYPE_DOUBLE:
+ if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
+ continue;
+ if ((freg + 1) < NFREGARG)
+ {
+ freg = (freg + 1) & ~1;
+ freg += 2;
+ cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
+ }
+ else
+ cif->flags2 += FFI_TYPE_INT << (2 * j++);
+ break;
+
+ default:
+ size = (cif->arg_types)[i]->size;
+ if (size < sizeof (UINT64))
+ cif->bytes += sizeof (UINT64) - size;
+ n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
+ if (greg >= NGREGARG)
+ continue;
+ else if (greg + n - 1 >= NGREGARG)
+ greg = NGREGARG;
+ else
+ greg += n;
+ for (m = 0; m < n; m++)
+ cif->flags2 += FFI_TYPE_INT << (2 * j++);
+ break;
+ }
+ }
+
+ /* Set the return type flag */
+ switch (cif->rtype->type)
+ {
+ case FFI_TYPE_STRUCT:
+ cif->flags = return_type (cif->rtype);
+ break;
+
+ case FFI_TYPE_VOID:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ cif->flags = cif->rtype->type;
+ break;
+
+ default:
+ cif->flags = FFI_TYPE_INT;
+ break;
+ }
+
+ return FFI_OK;
+}
+
+/*@-declundef@*/
+/*@-exportheader@*/
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
+ /*@out@*/ extended_cif *,
+ unsigned, unsigned, long long,
+ /*@out@*/ unsigned *,
+ void (*fn)());
+/*@=declundef@*/
+/*@=exportheader@*/
+
+void ffi_call(/*@dependent@*/ ffi_cif *cif,
+ void (*fn)(),
+ /*@out@*/ void *rvalue,
+ /*@dependent@*/ 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))
+ {
+ /*@-sysunrecog@*/
+ ecif.rvalue = alloca(cif->rtype->size);
+ /*@=sysunrecog@*/
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ /*@-usedef@*/
+ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
+ cif->flags, cif->flags2, ecif.rvalue, fn);
+ /*@=usedef@*/
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+extern void ffi_closure_SYSV (void);
+extern void __ic_invalidate (void *line);
+
+ffi_status
+ffi_prep_closure (ffi_closure *closure,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data)
+{
+ unsigned int *tramp;
+
+ FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
+
+ tramp = (unsigned int *) &closure->tramp[0];
+ /* Since ffi_closure is an aligned object, the ffi trampoline is
+ called as an SHcompact code. Sigh.
+ SHcompact part:
+ mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
+ SHmedia part:
+ movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
+ movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
+#ifdef __LITTLE_ENDIAN__
+ tramp[0] = 0x7001c701;
+ tramp[1] = 0x0009402b;
+#else
+ tramp[0] = 0xc7017001;
+ tramp[1] = 0x402b0009;
+#endif
+ tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
+ tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
+ tramp[4] = 0x6bf10600;
+ tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
+ tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
+ tramp[7] = 0x4401fff0;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ /* Flush the icache. */
+ asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
+
+ return FFI_OK;
+}
+
+/* Basically the trampoline invokes ffi_closure_SYSV, and on
+ * entry, r3 holds the address of the closure.
+ * After storing the registers that could possibly contain
+ * parameters to be passed into the stack frame and setting
+ * up space for a return value, ffi_closure_SYSV invokes the
+ * following helper function to do most of the work.
+ */
+
+int
+ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
+ UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
+{
+ void **avalue;
+ ffi_type **p_arg;
+ int i, avn;
+ int greg, freg;
+ ffi_cif *cif;
+
+ cif = closure->cif;
+ avalue = alloca (cif->nargs * sizeof (void *));
+
+ /* Copy the caller's structure return value address so that the closure
+ returns the data directly to the caller. */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ rvalue = *pgr;
+ greg = 1;
+ }
+ else
+ greg = 0;
+
+ freg = 0;
+ cif = closure->cif;
+ avn = cif->nargs;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
+ {
+ size_t z;
+ void *p;
+
+ z = (*p_arg)->size;
+ if (z < sizeof (UINT32))
+ {
+ p = pgr + greg++;
+
+ switch ((*p_arg)->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_STRUCT:
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = p;
+#else
+ avalue[i] = ((char *) p) + sizeof (UINT32) - z;
+#endif
+ break;
+
+ default:
+ FFI_ASSERT(0);
+ }
+ }
+ else if (z == sizeof (UINT32))
+ {
+ if ((*p_arg)->type == FFI_TYPE_FLOAT)
+ {
+ if (freg < NFREGARG - 1)
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
+#else
+ avalue[i] = (UINT32 *) pfr + freg++;
+#endif
+ else
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = pgr + greg;
+#else
+ avalue[i] = (UINT32 *) (pgr + greg) + 1;
+#endif
+ }
+ else
+#ifdef __LITTLE_ENDIAN__
+ avalue[i] = pgr + greg;
+#else
+ avalue[i] = (UINT32 *) (pgr + greg) + 1;
+#endif
+ greg++;
+ }
+ else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
+ {
+ if (freg + 1 >= NFREGARG)
+ avalue[i] = pgr + greg;
+ else
+ {
+ freg = (freg + 1) & ~1;
+ avalue[i] = pfr + (freg >> 1);
+ freg += 2;
+ }
+ greg++;
+ }
+ else
+ {
+ int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
+
+ avalue[i] = pgr + greg;
+ greg += n;
+ }
+ }
+
+ (closure->fun) (cif, rvalue, avalue, closure->user_data);
+
+ /* Tell ffi_closure_SYSV how to perform return type promotions. */
+ return cif->rtype->type;
+}
+
diff --git a/libffi/src/sh64/ffitarget.h b/libffi/src/sh64/ffitarget.h
new file mode 100644
index 0000000..a174d09
--- /dev/null
+++ b/libffi/src/sh64/ffitarget.h
@@ -0,0 +1,52 @@
+/* -----------------------------------------------------------------*-C-*-
+ ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc.
+ Target configuration macros for SuperH - SHmedia.
+
+ 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
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_DEFAULT_ABI = FFI_SYSV,
+ FFI_LAST_ABI = FFI_DEFAULT_ABI + 1
+} ffi_abi;
+
+#define FFI_EXTRA_CIF_FIELDS long long flags2
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 32
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/libffi/src/sh64/sysv.S b/libffi/src/sh64/sysv.S
new file mode 100644
index 0000000..949f69f
--- /dev/null
+++ b/libffi/src/sh64/sysv.S
@@ -0,0 +1,484 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2003 Kaz Kojima
+
+ SuperH SHmedia 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>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+/* XXX these lose for some platforms, I'm sure. */
+#define CNAME(x) x
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
+#endif
+
+#ifdef __LITTLE_ENDIAN__
+#define OFS_FLT 0
+#else
+#define OFS_FLT 4
+#endif
+
+ .section .text..SHmedia32,"ax"
+
+ # r2: ffi_prep_args
+ # r3: &ecif
+ # r4: bytes
+ # r5: flags
+ # r6: flags2
+ # r7: rvalue
+ # r8: fn
+
+ # This assumes we are using gas.
+ .align 5
+ENTRY(ffi_call_SYSV)
+ # Save registers
+.LFB1:
+ addi.l r15, -48, r15
+.LCFI0:
+ st.q r15, 40, r32
+ st.q r15, 32, r31
+ st.q r15, 24, r30
+ st.q r15, 16, r29
+ st.q r15, 8, r28
+ st.l r15, 4, r18
+ st.l r15, 0, r14
+ add.l r15, r63, r14
+.LCFI1:
+# add r4, r63, r28
+ add r5, r63, r29
+ add r6, r63, r30
+ add r7, r63, r31
+ add r8, r63, r32
+
+ addi r4, (64 + 7), r4
+ andi r4, ~7, r4
+ sub.l r15, r4, r15
+
+ ptabs/l r2, tr0
+ add r15, r63, r2
+ blink tr0, r18
+
+ addi r15, 64, r22
+ movi 0, r0
+ movi 0, r1
+
+ pt/l 1f, tr1
+ bnei/l r29, FFI_TYPE_STRUCT, tr1
+ ld.l r15, 0, r19
+ addi r15, 8, r15
+ addi r0, 1, r0
+1:
+
+.L_pass:
+ andi r30, 3, r20
+ shlri r30, 2, r30
+
+ pt/l .L_call_it, tr0
+ pt/l .L_pass_i, tr1
+ pt/l .L_pass_f, tr2
+
+ beqi/l r20, FFI_TYPE_VOID, tr0
+ beqi/l r20, FFI_TYPE_INT, tr1
+ beqi/l r20, FFI_TYPE_FLOAT, tr2
+
+.L_pass_d:
+ addi r0, 1, r0
+ addi r1, 1, r1
+ andi r1, ~1, r1
+
+ pt/l 3f, tr0
+ movi 12, r20
+ bge/l r1, r20, tr0
+
+ pt/l .L_pop_d, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r1, 2, r1
+ blink tr0, r63
+
+.L_pop_d:
+ pt/l .L_pop_d_tbl, tr1
+ gettr tr1, r20
+ shlli r1, 2, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_d_tbl:
+ fld.d r15, 0, dr0
+ blink tr0, r63
+ fld.d r15, 0, dr2
+ blink tr0, r63
+ fld.d r15, 0, dr4
+ blink tr0, r63
+ fld.d r15, 0, dr6
+ blink tr0, r63
+ fld.d r15, 0, dr8
+ blink tr0, r63
+ fld.d r15, 0, dr10
+ blink tr0, r63
+
+.L_pass_f:
+ addi r0, 1, r0
+ pt/l 3f, tr0
+ movi 12, r20
+ bge/l r1, r20, tr0
+
+ pt/l .L_pop_f, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r1, 1, r1
+ blink tr0, r63
+
+.L_pop_f:
+ pt/l .L_pop_f_tbl, tr1
+ gettr tr1, r20
+ shlli r1, 3, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_f_tbl:
+ fld.s r15, OFS_FLT, fr0
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr1
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr2
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr3
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr4
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr5
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr6
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr7
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr8
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr9
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr10
+ blink tr0, r63
+ fld.s r15, OFS_FLT, fr11
+ blink tr0, r63
+
+.L_pass_i:
+ pt/l 3f, tr0
+ movi 8, r20
+ bge/l r0, r20, tr0
+
+ pt/l .L_pop_i, tr1
+ pt/l 2f, tr0
+ blink tr1, r63
+2:
+ addi.l r15, 8, r15
+3:
+ pt/l .L_pass, tr0
+ addi r0, 1, r0
+ blink tr0, r63
+
+.L_pop_i:
+ pt/l .L_pop_i_tbl, tr1
+ gettr tr1, r20
+ shlli r0, 3, r21
+ add r20, r21, r20
+ ptabs/l r20, tr1
+ blink tr1, r63
+
+.L_pop_i_tbl:
+ ld.q r15, 0, r2
+ blink tr0, r63
+ ld.q r15, 0, r3
+ blink tr0, r63
+ ld.q r15, 0, r4
+ blink tr0, r63
+ ld.q r15, 0, r5
+ blink tr0, r63
+ ld.q r15, 0, r6
+ blink tr0, r63
+ ld.q r15, 0, r7
+ blink tr0, r63
+ ld.q r15, 0, r8
+ blink tr0, r63
+ ld.q r15, 0, r9
+ blink tr0, r63
+
+.L_call_it:
+ # call function
+ pt/l 1f, tr1
+ bnei/l r29, FFI_TYPE_STRUCT, tr1
+ add r19, r63, r2
+1:
+ add r22, r63, r15
+ ptabs/l r32, tr0
+ blink tr0, r18
+
+ pt/l .L_ret_i, tr0
+ pt/l .L_ret_ll, tr1
+ pt/l .L_ret_d, tr2
+ pt/l .L_ret_f, tr3
+ pt/l .L_epilogue, tr4
+
+ beqi/l r29, FFI_TYPE_INT, tr0
+ beqi/l r29, FFI_TYPE_SINT64, tr1
+ beqi/l r29, FFI_TYPE_UINT64, tr1
+ beqi/l r29, FFI_TYPE_DOUBLE, tr2
+ beqi/l r29, FFI_TYPE_FLOAT, tr3
+ blink tr4, r63
+
+.L_ret_d:
+ fst.d r31, 0, dr0
+ blink tr4, r63
+
+.L_ret_ll:
+ st.q r31, 0, r2
+ blink tr4, r63
+
+.L_ret_f:
+ fst.s r31, OFS_FLT, fr0
+ blink tr4, r63
+
+.L_ret_i:
+ st.l r31, 0, r2
+ # Fall
+
+.L_epilogue:
+ # Remove the space we pushed for the args
+ add r14, r63, r15
+
+ ld.l r15, 0, r14
+ ld.l r15, 4, r18
+ ld.q r15, 8, r28
+ ld.q r15, 16, r29
+ ld.q r15, 24, r30
+ ld.q r15, 32, r31
+ ld.q r15, 40, r32
+ addi.l r15, 48, r15
+ ptabs r18, tr0
+ blink tr0, r63
+
+.LFE1:
+.ffi_call_SYSV_end:
+ .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+ .align 5
+ENTRY(ffi_closure_SYSV)
+.LFB2:
+ addi.l r15, -136, r15
+.LCFI2:
+ st.l r15, 12, r18
+ st.l r15, 8, r14
+ st.l r15, 4, r12
+ add r15, r63, r14
+.LCFI3:
+ /* Stack layout:
+ ...
+ 64 bytes (register parameters)
+ 48 bytes (floating register parameters)
+ 8 bytes (result)
+ 4 bytes (r18)
+ 4 bytes (r14)
+ 4 bytes (r12)
+ 4 bytes (for align)
+ <- new stack pointer
+ */
+ fst.d r14, 24, dr0
+ fst.d r14, 32, dr2
+ fst.d r14, 40, dr4
+ fst.d r14, 48, dr6
+ fst.d r14, 56, dr8
+ fst.d r14, 64, dr10
+ st.q r14, 72, r2
+ st.q r14, 80, r3
+ st.q r14, 88, r4
+ st.q r14, 96, r5
+ st.q r14, 104, r6
+ st.q r14, 112, r7
+ st.q r14, 120, r8
+ st.q r14, 128, r9
+
+ add r1, r63, r2
+ addi r14, 16, r3
+ addi r14, 72, r4
+ addi r14, 24, r5
+ addi r14, 136, r6
+#ifdef PIC
+ movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12
+ shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12
+.LPCS0: ptrel/u r12, tr0
+ movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1
+ gettr tr0, r12
+ ldx.l r1, r12, r1
+ ptabs r1, tr0
+#else
+ pt/l ffi_closure_helper_SYSV, tr0
+#endif
+ blink tr0, r18
+
+ shlli r2, 1, r1
+ movi (((datalabel .L_table) >> 16) & 65535), r2
+ shori ((datalabel .L_table) & 65535), r2
+ ldx.w r2, r1, r1
+ add r1, r2, r1
+ pt/l .L_case_v, tr1
+ ptabs r1, tr0
+ blink tr0, r63
+
+ .align 2
+.L_table:
+ .word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */
+ .word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */
+ .word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */
+ .word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */
+ .word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */
+ .word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */
+ .word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */
+ .word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */
+ .word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */
+ .word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */
+ .word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */
+ .word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */
+
+ .align 2
+.L_case_d:
+ fld.d r14, 16, dr0
+ blink tr1, r63
+.L_case_f:
+ fld.s r14, 16, fr0
+ blink tr1, r63
+.L_case_ll:
+ ld.q r14, 16, r2
+ blink tr1, r63
+.L_case_i:
+ ld.l r14, 16, r2
+ blink tr1, r63
+.L_case_q:
+ ld.b r14, 16, r2
+ blink tr1, r63
+.L_case_uq:
+ ld.ub r14, 16, r2
+ blink tr1, r63
+.L_case_h:
+ ld.w r14, 16, r2
+ blink tr1, r63
+.L_case_uh:
+ ld.uw r14, 16, r2
+ blink tr1, r63
+.L_case_v:
+ add.l r14, r63, r15
+ ld.l r15, 4, r12
+ ld.l r15, 8, r14
+ ld.l r15, 12, r18
+ addi.l r15, 136, r15
+ ptabs r18, tr0
+ blink tr0, r63
+
+.LFE2:
+.ffi_closure_SYSV_end:
+ .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+ .section ".eh_frame","aw",@progbits
+__FRAME_BEGIN__:
+ .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */
+.LSCIE1:
+ .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 0x12 /* CIE RA Column */
+ .uleb128 0x1 /* Augmentation size */
+ .byte 0x1b /* FDE Encoding (pcrel sdata4) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0xf
+ .uleb128 0x0
+ .align 2
+.LECIE1:
+.LSFDE1:
+ .4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */
+.LASFDE1:
+ .4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__
+ .4byte datalabel .LFB1-. /* FDE initial location */
+ .4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI0-datalabel .LFB1
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 0x30
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI1-datalabel .LCFI0
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .uleb128 0xc
+ .byte 0x92 /* DW_CFA_offset, column 0x12 */
+ .uleb128 0xb
+ .byte 0x9c /* DW_CFA_offset, column 0x1c */
+ .uleb128 0xa
+ .byte 0x9d /* DW_CFA_offset, column 0x1d */
+ .uleb128 0x8
+ .byte 0x9e /* DW_CFA_offset, column 0x1e */
+ .uleb128 0x6
+ .byte 0x9f /* DW_CFA_offset, column 0x1f */
+ .uleb128 0x4
+ .byte 0xa0 /* DW_CFA_offset, column 0x20 */
+ .uleb128 0x2
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0xe
+ .align 2
+.LEFDE1:
+
+.LSFDE3:
+ .4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */
+.LASFDE3:
+ .4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__
+ .4byte datalabel .LFB2-. /* FDE initial location */
+ .4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI2-datalabel .LFB2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .uleb128 0x88
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .4byte datalabel .LCFI3-datalabel .LCFI2
+ .byte 0x8c /* DW_CFA_offset, column 0xc */
+ .uleb128 0x21
+ .byte 0x8e /* DW_CFA_offset, column 0xe */
+ .uleb128 0x20
+ .byte 0x92 /* DW_CFA_offset, column 0x12 */
+ .uleb128 0x1f
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .uleb128 0xe
+ .align 2
+.LEFDE3: