diff options
author | Claudiu Zissulescu <claziss@gmail.com> | 2023-02-18 03:33:47 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-17 20:33:47 -0500 |
commit | c4df19c99f8d8841942e3edaadbf331d30e298c8 (patch) | |
tree | 6e67954cabd2418307491c31f57d00cfc30d065b | |
parent | 237520649730cb21daf4ebff1cf9a0a64f8507f8 (diff) | |
download | libffi-c4df19c99f8d8841942e3edaadbf331d30e298c8.tar.gz |
Update ARC's libffi port (#771)
* Add support for ARC and ARC64
Add support for ARC/ARC32/ARC64
* Implementation of GO Closure for ARC/ARC32/ARC64 Architectures
---------
Co-authored-by: Nuno Cardoso <cardoso@synopsys.com>
Co-authored-by: Luis Silva <luiss@synopsys.com>
-rw-r--r-- | src/arc/arcompact.S | 263 | ||||
-rw-r--r-- | src/arc/ffi.c | 473 | ||||
-rw-r--r-- | src/arc/ffitarget.h | 14 |
3 files changed, 508 insertions, 242 deletions
diff --git a/src/arc/arcompact.S b/src/arc/arcompact.S index 03715fde..1d7f1a1f 100644 --- a/src/arc/arcompact.S +++ b/src/arc/arcompact.S @@ -33,103 +33,178 @@ #define ENTRY(x) .globl CNAME(x)` .type CNAME(x),%function` CNAME(x): #endif +#if __SIZEOF_POINTER__ == 8 +#define PTRS 8 +#define FLTS 8 +#define LARG ldl +#define SARG stl +#define ADDPTR addl +#define MOVPTR movl_s +#else +#define PTRS 4 +#define FLTS 4 +#define LARG ld +#define SARG st +#define ADDPTR add +#define MOVPTR mov_s +#endif + +#define FRAME_LEN (8 * PTRS + 16) + .text - /* R0: ffi_prep_args */ - /* R1: &ecif */ - /* R2: cif->bytes */ - /* R3: fig->flags */ - /* R4: ecif.rvalue */ - /* R5: fn */ -ENTRY(ffi_call_ARCompact) +ENTRY(ffi_call_asm) + .cfi_startproc + /* Save registers. */ - st.a fp, [sp, -4] /* fp + 20, fp */ - push_s blink /* fp + 16, blink */ - st.a r4, [sp, -4] /* fp + 12, ecif.rvalue */ - push_s r3 /* fp + 8, fig->flags */ - st.a r5, [sp, -4] /* fp + 4, fn */ - push_s r2 /* fp + 0, cif->bytes */ - mov fp, sp - - /* Make room for all of the new args. */ - sub sp, sp, r2 - - /* Place all of the ffi_prep_args in position. */ - /* ffi_prep_args(char *stack, extended_cif *ecif) */ - /* R1 already set. */ - - /* And call. */ - jl_s.d [r0] - mov_s r0, sp - - ld.ab r12, [fp, 4] /* cif->bytes */ - ld.ab r11, [fp, 4] /* fn */ - - /* Move first 8 parameters in registers... */ - ld_s r0, [sp] - ld_s r1, [sp, 4] - ld_s r2, [sp, 8] - ld_s r3, [sp, 12] - ld r4, [sp, 16] - ld r5, [sp, 20] - ld r6, [sp, 24] - ld r7, [sp, 28] - - /* ...and adjust the stack. */ - min r12, r12, 32 + .cfi_def_cfa r1, FRAME_LEN + SARG fp, [r1, FRAME_LEN - 2*PTRS] + .cfi_offset fp, -2*PTRS + SARG blink, [r1, FRAME_LEN - 1*PTRS] + .cfi_offset blink, -1*PTRS + ADDPTR fp, r1, FRAME_LEN + MOVPTR sp, r0 + .cfi_def_cfa fp, 0 + + /* Load arguments. */ + MOVPTR r11, r2 /* fn */ + MOVPTR r12, r3 /* closure */ + + /* Save arguments. */ + LARG r0, [fp, -FRAME_LEN+0*PTRS] + LARG r1, [fp, -FRAME_LEN+1*PTRS] + LARG r2, [fp, -FRAME_LEN+2*PTRS] + LARG r3, [fp, -FRAME_LEN+3*PTRS] + LARG r4, [fp, -FRAME_LEN+4*PTRS] + LARG r5, [fp, -FRAME_LEN+5*PTRS] + LARG r6, [fp, -FRAME_LEN+6*PTRS] + LARG r7, [fp, -FRAME_LEN+7*PTRS] /* Call the function. */ - jl.d [r11] - add sp, sp, r12 - - mov sp, fp - pop_s r3 /* fig->flags, return type */ - pop_s r2 /* ecif.rvalue, pointer for return value */ - - /* If the return value pointer is NULL, assume no return value. */ - breq.d r2, 0, epilogue - pop_s blink - - /* Return INT. */ - brne r3, FFI_TYPE_INT, return_double - b.d epilogue - st_s r0, [r2] - -return_double: - brne r3, FFI_TYPE_DOUBLE, epilogue - st_s r0, [r2] - st_s r1, [r2,4] - -epilogue: - j_s.d [blink] - ld.ab fp, [sp, 4] - -ENTRY(ffi_closure_ARCompact) - st.a r0, [sp, -32] - st_s r1, [sp, 4] - st_s r2, [sp, 8] - st_s r3, [sp, 12] - st r4, [sp, 16] - st r5, [sp, 20] - st r6, [sp, 24] - st r7, [sp, 28] - - /* pointer to arguments */ - mov_s r2, sp - - /* return value goes here */ - sub sp, sp, 8 - mov_s r1, sp - - push_s blink + jl [r11] + + /* Save return value (r0/r1) */ + SARG r0, [fp, -FRAME_LEN+0*PTRS] + SARG r1, [fp, -FRAME_LEN+1*PTRS] + + /* Restore and return. */ + add sp, fp, -FRAME_LEN + .cfi_def_cfa sp, FRAME_LEN + LARG blink, [fp, -1*PTRS] + .cfi_restore blink + LARG fp, [fp, -2*PTRS] + .cfi_restore fp + j_s [blink] + .cfi_endproc + .size ffi_call_asm, .-ffi_call_asm + +/* + ffi_closure_asm. Expects address of the passed-in ffi_closure in r8. + void ffi_closure_inner (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + size_t *stackargs, struct call_context *regargs) +*/ + +ENTRY(ffi_closure_asm) + .cfi_startproc + + ADDPTR sp, sp, -FRAME_LEN + .cfi_def_cfa_offset FRAME_LEN + + /* Make a frame. */ + SARG fp, [sp, FRAME_LEN-2*PTRS] + .cfi_offset fp, -2*PTRS + SARG blink, [sp, FRAME_LEN-1*PTRS] + .cfi_offset blink, -1*PTRS + ADDPTR fp, sp, FRAME_LEN + + /* Save arguments. */ + SARG r0, [sp, 0*PTRS] + SARG r1, [sp, 1*PTRS] + SARG r2, [sp, 2*PTRS] + SARG r3, [sp, 3*PTRS] + SARG r4, [sp, 4*PTRS] + SARG r5, [sp, 5*PTRS] + SARG r6, [sp, 6*PTRS] + SARG r7, [sp, 7*PTRS] + + /* Enter C. */ + LARG r0, [r8, FFI_TRAMPOLINE_SIZE+0*PTRS] + LARG r1, [r8, FFI_TRAMPOLINE_SIZE+1*PTRS] + LARG r2, [r8, FFI_TRAMPOLINE_SIZE+2*PTRS] + ADDPTR r3, sp, FRAME_LEN + MOVPTR r4, sp + + /* Call the C code. */ + bl ffi_closure_inner - bl.d ffi_closure_inner_ARCompact - mov_s r0, r8 /* codeloc, set by trampoline */ - - pop_s blink - - /* set return value to r1:r0 */ - pop_s r0 - pop_s r1 - j_s.d [blink] - add_s sp, sp, 32 + /* Return values. */ + LARG r0, [sp, 0*PTRS] + LARG r1, [sp, 1*PTRS] + + /* Restore and return. */ + LARG blink, [sp, FRAME_LEN-1*PTRS] + .cfi_restore blink + LARG fp, [sp, FRAME_LEN-2*PTRS] + .cfi_restore fp + ADDPTR sp, sp, FRAME_LEN + .cfi_def_cfa_offset 0 + j_s [blink] + .cfi_endproc + .size ffi_closure_asm, .-ffi_closure_asm + +/* + ffi_go_closure_asm. Expects address of the passed-in ffi_go_closure in r12. + void ffi_closure_inner (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + size_t *stackargs, struct call_context *regargs) +*/ + +ENTRY(ffi_go_closure_asm) + .cfi_startproc + + ADDPTR sp, sp, -FRAME_LEN + .cfi_def_cfa_offset FRAME_LEN + + /* make a frame */ + SARG fp, [sp, FRAME_LEN-2*PTRS] + .cfi_offset fp, -2*PTRS + SARG blink, [sp, FRAME_LEN-1*PTRS] + .cfi_offset blink, -1*PTRS + ADDPTR fp, sp, FRAME_LEN + + /* save arguments */ + SARG r0, [sp, 0*PTRS] + SARG r1, [sp, 1*PTRS] + SARG r2, [sp, 2*PTRS] + SARG r3, [sp, 3*PTRS] + SARG r4, [sp, 4*PTRS] + SARG r5, [sp, 5*PTRS] + SARG r6, [sp, 6*PTRS] + SARG r7, [sp, 7*PTRS] + + /* enter C */ + LARG r0, [r12, 1*PTRS] + LARG r1, [r12, 2*PTRS] + MOVPTR r2, r12 + ADDPTR r3, sp, FRAME_LEN + MOVPTR r4, sp + + bl ffi_closure_inner + + /* Return values. */ + LARG r0, [sp, 0*PTRS] + LARG r1, [sp, 1*PTRS] + + + LARG blink, [sp, FRAME_LEN-1*PTRS] + .cfi_restore blink + LARG fp, [sp, FRAME_LEN-2*PTRS] + .cfi_restore fp + ADDPTR sp, sp, FRAME_LEN + .cfi_def_cfa_offset 0 + j_s [blink] + .cfi_endproc + .size ffi_go_closure_asm, .-ffi_go_closure_asm diff --git a/src/arc/ffi.c b/src/arc/ffi.c index 4d10b21a..d7292748 100644 --- a/src/arc/ffi.c +++ b/src/arc/ffi.c @@ -31,6 +31,34 @@ #include <sys/cachectl.h> +#define NARGREG 8 +#define STKALIGN 4 +#define MAXCOPYARG (2 * sizeof(double)) + +typedef struct call_context +{ + size_t r[8]; + /* used by the assembly code to in-place construct its own stack frame */ + char frame[16]; +} call_context; + +typedef struct call_builder +{ + call_context *aregs; + int used_integer; + //int used_float; + size_t *used_stack; + void *struct_stack; +} call_builder; + +/* integer (not pointer) less than ABI XLEN */ +/* FFI_TYPE_INT does not appear to be used */ +#if defined(__ARC64_ARCH64__) +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64) +#else +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32) +#endif + /* for little endian ARC, the code is in fact stored as mixed endian for performance reasons */ #if __BIG_ENDIAN__ @@ -39,94 +67,6 @@ #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16)) #endif -/* ffi_prep_args is called by the assembly routine once stack - space has been allocated for the function's arguments. */ - -void -ffi_prep_args (char *stack, extended_cif * ecif) -{ - unsigned int i; - void **p_argv; - char *argp; - ffi_type **p_arg; - - argp = stack; - - if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) - { - *(void **) argp = ecif->rvalue; - argp += 4; - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - (i != 0); i--, p_arg++) - { - size_t z; - int alignment; - - /* align alignment to 4 */ - alignment = (((*p_arg)->alignment - 1) | 3) + 1; - - /* Align if necessary. */ - if ((alignment - 1) & (unsigned) argp) - argp = (char *) FFI_ALIGN (argp, alignment); - - z = (*p_arg)->size; - if (z < sizeof (int)) - { - z = sizeof (int); - - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv); - break; - - case FFI_TYPE_STRUCT: - memcpy (argp, *p_argv, (*p_arg)->size); - break; - - default: - FFI_ASSERT (0); - } - } - else if (z == sizeof (int)) - { - *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); - } - else - { - if ((*p_arg)->type == FFI_TYPE_STRUCT) - { - memcpy (argp, *p_argv, z); - } - else - { - /* Double or long long 64bit. */ - memcpy (argp, *p_argv, z); - } - } - p_argv++; - argp += z; - } - - return; -} - /* Perform machine dependent cif processing. */ ffi_status ffi_prep_cif_machdep (ffi_cif * cif) @@ -157,85 +97,250 @@ ffi_prep_cif_machdep (ffi_cif * cif) return FFI_OK; } -extern void ffi_call_ARCompact (void (*)(char *, extended_cif *), - extended_cif *, unsigned, unsigned, - unsigned *, void (*fn) (void)); - -void -ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) -{ - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; +/* allocates a single register, float register, or XLEN-sized stack slot to a datum */ +static void marshal_atom(call_builder *cb, int type, void *data) { + size_t value = 0; + switch (type) { + case FFI_TYPE_UINT8: value = *(uint8_t *)data; break; + case FFI_TYPE_SINT8: value = *(int8_t *)data; break; + case FFI_TYPE_UINT16: value = *(uint16_t *)data; break; + case FFI_TYPE_SINT16: value = *(int16_t *)data; break; + /* 32-bit quantities are always sign-extended in the ABI */ + case FFI_TYPE_UINT32: value = *(int32_t *)data; break; + case FFI_TYPE_SINT32: value = *(int32_t *)data; break; +#if defined(__ARC64_ARCH64__) + case FFI_TYPE_UINT64: value = *(uint64_t *)data; break; + case FFI_TYPE_SINT64: value = *(int64_t *)data; break; +#endif + case FFI_TYPE_POINTER: value = *(size_t *)data; break; + default: FFI_ASSERT(0); break; + } + + if (cb->used_integer == NARGREG) { + *cb->used_stack++ = value; + } else { + cb->aregs->r[cb->used_integer++] = value; + } +} - /* 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); +/* adds an argument to a call, or a not by reference return value */ +static void marshal(call_builder *cb, ffi_type *type, int var, void *data) { + size_t realign[2]; + +#if (defined(__ARC64_ARCH64__) || defined(__ARC64_ARCH32__)) + if (type->size > 2 * __SIZEOF_POINTER__) { + if (var) { + marshal_atom(cb, FFI_TYPE_POINTER, &data); + } else { + /* copy to stack and pass by reference */ + data = memcpy (cb->struct_stack, data, type->size); + cb->struct_stack = (size_t *) FFI_ALIGN ((char *) cb->struct_stack + type->size, __SIZEOF_POINTER__); + marshal_atom(cb, FFI_TYPE_POINTER, &data); } - else - ecif.rvalue = rvalue; + } +#else + if (type->type == FFI_TYPE_STRUCT) { + if (var) { + if (type->size > 0) + marshal_atom(cb, FFI_TYPE_POINTER, data); + } else { + int i; + + for (i = 0; i < type->size; i += sizeof(size_t)) { + marshal_atom(cb, FFI_TYPE_POINTER, data); + data += sizeof(size_t); + } + } + } +#endif + else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) { + marshal_atom(cb, type->type, data); + } else { + memcpy(realign, data, type->size); + if (type->size > 0) + marshal_atom(cb, FFI_TYPE_POINTER, realign); + if (type->size > __SIZEOF_POINTER__) + marshal_atom(cb, FFI_TYPE_POINTER, realign + 1); + } +} - switch (cif->abi) - { - case FFI_ARCOMPACT: - ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - break; +static void unmarshal_atom(call_builder *cb, int type, void *data) { + size_t value; + + if (cb->used_integer == NARGREG) { + value = *cb->used_stack++; + } else { + value = cb->aregs->r[cb->used_integer++]; + } + + switch (type) { + case FFI_TYPE_UINT8: *(uint8_t *)data = value; break; + case FFI_TYPE_SINT8: *(uint8_t *)data = value; break; + case FFI_TYPE_UINT16: *(uint16_t *)data = value; break; + case FFI_TYPE_SINT16: *(uint16_t *)data = value; break; + case FFI_TYPE_UINT32: *(uint32_t *)data = value; break; + case FFI_TYPE_SINT32: *(uint32_t *)data = value; break; +#if defined(__ARC64_ARCH64__) + case FFI_TYPE_UINT64: *(uint64_t *)data = value; break; + case FFI_TYPE_SINT64: *(uint64_t *)data = value; break; +#endif + case FFI_TYPE_POINTER: *(size_t *)data = value; break; + default: FFI_ASSERT(0); break; + } +} - default: - FFI_ASSERT (0); - break; +/* for arguments passed by reference returns the pointer, otherwise the arg is copied (up to MAXCOPYARG bytes) */ +static void *unmarshal(call_builder *cb, ffi_type *type, int var, void *data) { + size_t realign[2]; + void *pointer; + +#if defined(__ARC64_ARCH64__) + if (type->size > 2 * __SIZEOF_POINTER__) { + /* pass by reference */ + unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer); + return pointer; } +#elif defined(__ARC64_ARCH32__) + if (type->type == FFI_TYPE_STRUCT) { + if (type->size > 2 * __SIZEOF_POINTER__) { + unmarshal_atom(cb, FFI_TYPE_POINTER, &realign[0]); + memcpy(data, (const void*)realign[0], type->size); + return data; + } else { + int i; + void *pdata = data; + + for (i = 0; i < type->size; i += sizeof(size_t)) { + unmarshal_atom(cb, FFI_TYPE_POINTER, pdata); + pdata += sizeof(size_t); + } + return data; + } + } +#else + if (type->type == FFI_TYPE_STRUCT) { + + if (var) { + int i; + void *pdata = data; + + for (i = 0; i < type->size; i += sizeof(size_t)) { + unmarshal_atom(cb, FFI_TYPE_POINTER, pdata); + pdata += sizeof(size_t); + } + return data; + } else { + if (type->size > 0) + unmarshal_atom(cb, FFI_TYPE_POINTER, &realign[0]); + memcpy(data, (const void*)realign[0], type->size); + return data; + } + } +#endif + else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) { + unmarshal_atom(cb, type->type, data); + return data; + } else { + if (type->size > 0) + unmarshal_atom(cb, FFI_TYPE_POINTER, realign); + if (type->size > __SIZEOF_POINTER__) + unmarshal_atom(cb, FFI_TYPE_POINTER, realign + 1); + memcpy(data, realign, type->size); + return data; + } } -int -ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue, - ffi_arg * args) +static int passed_by_ref(ffi_type *type, int var) { + if (type->type == FFI_TYPE_STRUCT) + return 1; + + return type->size > 2 * __SIZEOF_POINTER__; +} + +/* Low level routine for calling functions */ +extern void ffi_call_asm (void *stack, struct call_context *regs, + void (*fn) (void), void *closure) FFI_HIDDEN; + +static void +ffi_call_int (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue, + void *closure) { - void **arg_area, **p_argv; - ffi_cif *cif = closure->cif; - char *argp = (char *) args; - ffi_type **p_argt; - int i; + int return_by_ref = passed_by_ref(cif->rtype, 0); - arg_area = (void **) alloca (cif->nargs * sizeof (void *)); + /* Allocate space for stack arg parameters. */ + size_t arg_bytes = FFI_ALIGN(2 * sizeof(size_t) * cif->nargs, STKALIGN); + /* Allocate space for copies of big structures. */ + size_t struct_bytes = FFI_ALIGN(cif->bytes, STKALIGN); + // size_t rval_bytes = 0; + // if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__) + // rval_bytes = FFI_ALIGN(cif->rtype->size, STKALIGN); + size_t alloc_size = arg_bytes + /*rval_bytes +*/ struct_bytes + sizeof(call_context); + size_t alloc_base = (size_t)alloca(alloc_size); - /* handle hidden argument */ - if (cif->flags == FFI_TYPE_STRUCT) - { - rvalue = *(void **) argp; - argp += 4; - } + // if (rval_bytes) + // rvalue = (void*)(alloc_base + arg_bytes); - p_argv = arg_area; + call_builder cb; + cb.used_integer = 0; + cb.aregs = (call_context*)(alloc_base + arg_bytes /*+ rval_bytes*/ + struct_bytes); + cb.used_stack = (void*)alloc_base; + cb.struct_stack = (void *)(alloc_base + arg_bytes /*+ rval_bytes*/); - for (i = 0, p_argt = cif->arg_types; i < cif->nargs; - i++, p_argt++, p_argv++) - { - size_t z; - int alignment; + // if (cif->rtype->type == FFI_TYPE_STRUCT) + // marshal(&cb, &ffi_type_pointer, 0, &rvalue); + + if (return_by_ref) + marshal(&cb, &ffi_type_pointer, 0, &rvalue); - /* align alignment to 4 */ - alignment = (((*p_argt)->alignment - 1) | 3) + 1; + int i; + for (i = 0; i < cif->nargs; i++) + marshal(&cb, cif->arg_types[i], 0, avalue[i]); - /* Align if necessary. */ - if ((alignment - 1) & (unsigned) argp) - argp = (char *) FFI_ALIGN (argp, alignment); + ffi_call_asm ((void *) alloc_base, cb.aregs, fn, closure); - z = (*p_argt)->size; - *p_argv = (void *) argp; - argp += z; + cb.used_integer = 0; + if (!return_by_ref && rvalue) + { + if (IS_INT(cif->rtype->type) + && cif->rtype->size < sizeof (ffi_arg)) + { + /* Integer types smaller than ffi_arg need to be extended. */ + switch (cif->rtype->type) { + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + unmarshal_atom (&cb, (sizeof (ffi_arg) > 4 + ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32), + rvalue); + break; + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + unmarshal_atom (&cb, (sizeof (ffi_arg) > 4 + ? FFI_TYPE_UINT64 : FFI_TYPE_UINT32), + rvalue); + break; + } + } + else + unmarshal(&cb, cif->rtype, 0, rvalue); } +} - (closure->fun) (cif, rvalue, arg_area, closure->user_data); +void +ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) +{ + ffi_call_int(cif, fn, rvalue, avalue, NULL); +} - return cif->flags; +void +ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, + void **avalue, void *closure) +{ + ffi_call_int(cif, fn, rvalue, avalue, closure); } -extern void ffi_closure_ARCompact (void); +extern void ffi_closure_asm(void) FFI_HIDDEN; ffi_status ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif, @@ -243,15 +348,28 @@ ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif, void *user_data, void *codeloc) { uint32_t *tramp = (uint32_t *) & (closure->tramp[0]); + size_t address_ffi_closure = (size_t) ffi_closure_asm; switch (cif->abi) { +#if defined(__ARC64_ARCH64__) + case FFI_ARC64: + FFI_ASSERT (tramp == codeloc); + tramp[0] = CODE_ENDIAN (0x580a1fc0); /* movl r8, pcl */ + tramp[1] = CODE_ENDIAN (0x5c0b1f80); /* movhl r12, limm */ + tramp[2] = CODE_ENDIAN ((uint32_t)(address_ffi_closure >> 32)); + tramp[3] = CODE_ENDIAN (0x5c051f8c); /* orl r12, r12, limm */ + tramp[4] = CODE_ENDIAN ((uint32_t)(address_ffi_closure & 0xffffffff)); + tramp[5] = CODE_ENDIAN (0x20200300); /* j [r12] */ + break; +#else case FFI_ARCOMPACT: FFI_ASSERT (tramp == codeloc); tramp[0] = CODE_ENDIAN (0x200a1fc0); /* mov r8, pcl */ tramp[1] = CODE_ENDIAN (0x20200f80); /* j [long imm] */ - tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact); + tramp[2] = CODE_ENDIAN (ffi_closure_asm); break; +#endif default: return FFI_BAD_ABI; @@ -264,3 +382,62 @@ ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif, return FFI_OK; } + +extern void ffi_go_closure_asm (void) FFI_HIDDEN; + +ffi_status +ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *)) +{ + if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI) + return FFI_BAD_ABI; + + closure->tramp = (void *) ffi_go_closure_asm; + closure->cif = cif; + closure->fun = fun; + + return FFI_OK; +} + +/* Called by the assembly code with aregs pointing to saved argument registers + and stack pointing to the stacked arguments. Return values passed in + registers will be reloaded from aregs. */ +void FFI_HIDDEN +ffi_closure_inner (ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data, + size_t *stack, call_context *aregs) +{ + void **avalue = alloca(cif->nargs * sizeof(void*)); + /* storage for arguments which will be copied by unmarshal(). We could + theoretically avoid the copies in many cases and use at most 128 bytes + of memory, but allocating disjoint storage for each argument is + simpler. */ + char *astorage = alloca(cif->bytes); + char *ptr = astorage; + void *rvalue; + call_builder cb; + int i; + + cb.aregs = aregs; + cb.used_integer = 0; + cb.used_stack = stack; + + /* handle hidden argument */ + if (cif->flags == FFI_TYPE_STRUCT) + unmarshal(&cb, &ffi_type_pointer, 0, &rvalue); + else + rvalue = alloca(cif->rtype->size); + + for (i = 0; i < cif->nargs; i++) { + avalue[i] = unmarshal(&cb, cif->arg_types[i], 1, ptr); + ptr += cif->arg_types[i]->size; + } + + fun (cif, rvalue, avalue, user_data); + + if (cif->rtype->type != FFI_TYPE_VOID) { + cb.used_integer = 0; + marshal(&cb, cif->rtype, 1, rvalue); + } +} diff --git a/src/arc/ffitarget.h b/src/arc/ffitarget.h index bf8311bc..5b36902e 100644 --- a/src/arc/ffitarget.h +++ b/src/arc/ffitarget.h @@ -40,14 +40,28 @@ typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, +#if __SIZEOF_POINTER__ == 8 + FFI_ARC64, +#else FFI_ARCOMPACT, +#endif FFI_LAST_ABI, +#if __SIZEOF_POINTER__ == 8 + FFI_DEFAULT_ABI = FFI_ARC64 +#else FFI_DEFAULT_ABI = FFI_ARCOMPACT +#endif } ffi_abi; #endif #define FFI_CLOSURES 1 +#define FFI_GO_CLOSURES 1 +#if __SIZEOF_POINTER__ == 8 +#define FFI_TRAMPOLINE_SIZE 24 +#else #define FFI_TRAMPOLINE_SIZE 12 +#endif + #define FFI_NATIVE_RAW_API 0 #endif |