146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* ----------------------------------------------------------------------- 246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi.c - Copyright (c) 2012 Tilera Corp. 346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith TILE Foreign Function Interface 546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith Permission is hereby granted, free of charge, to any person obtaining 746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith a copy of this software and associated documentation files (the 846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ``Software''), to deal in the Software without restriction, including 946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith without limitation the rights to use, copy, modify, merge, publish, 1046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith distribute, sublicense, and/or sell copies of the Software, and to 1146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith permit persons to whom the Software is furnished to do so, subject to 1246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith the following conditions: 1346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 1446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith The above copyright notice and this permission notice shall be included 1546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith in all copies or substantial portions of the Software. 1646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 1746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 1846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 2146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith DEALINGS IN THE SOFTWARE. 2546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ----------------------------------------------------------------------- */ 2646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 2746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <ffi.h> 2846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <ffi_common.h> 2946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <stdlib.h> 3046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <stdint.h> 3146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <unistd.h> 3246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <arch/abi.h> 3346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <arch/icache.h> 3446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#include <arch/opcode.h> 3546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 3646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 3746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* The first 10 registers are used to pass arguments and return values. */ 3846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#define NUM_ARG_REGS 10 3946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 4046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* Performs a raw function call with the given NUM_ARG_REGS register arguments 4146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith and the specified additional stack arguments (if any). */ 4246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithextern void ffi_call_tile(ffi_sarg reg_args[NUM_ARG_REGS], 4346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith const ffi_sarg *stack_args, 4446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith size_t stack_args_bytes, 4546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void (*fnaddr)(void)) 4646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith FFI_HIDDEN; 4746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 4846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* This handles the raw call from the closure stub, cleaning up the 4946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith parameters and delegating to ffi_closure_tile_inner. */ 5046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithextern void ffi_closure_tile(void) FFI_HIDDEN; 5146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 5246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 5346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_status 5446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_prep_cif_machdep(ffi_cif *cif) 5546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith{ 5646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* We always allocate room for all registers. Even if we don't 5746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith use them as parameters, they get returned in the same array 5846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith as struct return values so we need to make room. */ 5946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->bytes < NUM_ARG_REGS * FFI_SIZEOF_ARG) 6046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith cif->bytes = NUM_ARG_REGS * FFI_SIZEOF_ARG; 6146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 6246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->rtype->size > NUM_ARG_REGS * FFI_SIZEOF_ARG) 6346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith cif->flags = FFI_TYPE_STRUCT; 6446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith else 6546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith cif->flags = FFI_TYPE_INT; 6646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 6746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Nothing to do. */ 6846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return FFI_OK; 6946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith} 7046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 7146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 7246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithstatic long 7346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithassign_to_ffi_arg(ffi_sarg *out, void *in, const ffi_type *type, 7446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith int write_to_reg) 7546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith{ 7646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith switch (type->type) 7746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 7846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_SINT8: 7946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = *(SINT8 *)in; 8046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 8146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 8246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_UINT8: 8346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = *(UINT8 *)in; 8446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 8546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 8646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_SINT16: 8746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = *(SINT16 *)in; 8846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 8946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 9046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_UINT16: 9146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = *(UINT16 *)in; 9246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 9346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 9446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_SINT32: 9546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_UINT32: 9646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifndef __LP64__ 9746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_POINTER: 9846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 9946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Note that even unsigned 32-bit quantities are sign extended 10046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith on tilegx when stored in a register. */ 10146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = *(SINT32 *)in; 10246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 10346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 10446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_FLOAT: 10546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifdef __tilegx__ 10646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (write_to_reg) 10746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 10846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Properly sign extend the value. */ 10946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith union { float f; SINT32 s32; } val; 11046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith val.f = *(float *)in; 11146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out = val.s32; 11246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 11346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith else 11446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 11546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 11646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *(float *)out = *(float *)in; 11746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 11846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 1; 11946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 12046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_SINT64: 12146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_UINT64: 12246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_DOUBLE: 12346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifdef __LP64__ 12446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_POINTER: 12546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 12646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *(UINT64 *)out = *(UINT64 *)in; 12746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return sizeof(UINT64) / FFI_SIZEOF_ARG; 12846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 12946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_STRUCT: 13046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith memcpy(out, in, type->size); 13146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG; 13246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 13346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith case FFI_TYPE_VOID: 13446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Must be a return type. Nothing to do. */ 13546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return 0; 13646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 13746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith default: 13846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith FFI_ASSERT(0); 13946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return -1; 14046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 14146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith} 14246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 14346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 14446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithvoid 14546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 14646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith{ 14746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * const arg_mem = alloca(cif->bytes); 14846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * const reg_args = arg_mem; 14946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * const stack_args = ®_args[NUM_ARG_REGS]; 15046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg *argp = arg_mem; 15146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_type ** const arg_types = cif->arg_types; 15246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith const long num_args = cif->nargs; 15346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith long i; 15446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 15546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->flags == FFI_TYPE_STRUCT) 15646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 15746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Pass a hidden pointer to the return value. We make sure there 15846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith is scratch space for the callee to store the return value even if 15946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith our caller doesn't care about it. */ 16046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *argp++ = (intptr_t)(rvalue ? rvalue : alloca(cif->rtype->size)); 16146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 16246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* No more work needed to return anything. */ 16346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith rvalue = NULL; 16446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 16546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 16646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith for (i = 0; i < num_args; i++) 16746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 16846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_type *type = arg_types[i]; 16946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void * const arg_in = avalue[i]; 17046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ptrdiff_t arg_word = argp - arg_mem; 17146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 17246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifndef __tilegx__ 17346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Doubleword-aligned values are always in an even-number register 17446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith pair, or doubleword-aligned stack slot if out of registers. */ 17546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith long align = arg_word & (type->alignment > FFI_SIZEOF_ARG); 17646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp += align; 17746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word += align; 17846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 17946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 18046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (type->type == FFI_TYPE_STRUCT) 18146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 18246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith const size_t arg_size_in_words = 18346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG; 18446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 18546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (arg_word < NUM_ARG_REGS && 18646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word + arg_size_in_words > NUM_ARG_REGS) 18746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 18846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Args are not allowed to span registers and the stack. */ 18946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp = stack_args; 19046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 19146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 19246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith memcpy(argp, arg_in, type->size); 19346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp += arg_size_in_words; 19446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 19546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith else 19646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 19746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp += assign_to_ffi_arg(argp, arg_in, arg_types[i], 1); 19846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 19946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 20046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 20146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Actually do the call. */ 20246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_call_tile(reg_args, stack_args, 20346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith cif->bytes - (NUM_ARG_REGS * FFI_SIZEOF_ARG), fn); 20446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 20546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (rvalue != NULL) 20646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith assign_to_ffi_arg(rvalue, reg_args, cif->rtype, 0); 20746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith} 20846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 20946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 21046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* Template code for closure. */ 21146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithextern const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN; 21246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 21346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 21446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_status 21546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_prep_closure_loc (ffi_closure *closure, 21646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_cif *cif, 21746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void (*fun)(ffi_cif*, void*, void**, void*), 21846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void *user_data, 21946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void *codeloc) 22046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith{ 22146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifdef __tilegx__ 22246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* TILE-Gx */ 22346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith SINT64 c; 22446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith SINT64 h; 22546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith int s; 22646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith UINT64 *out; 22746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 22846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->abi != FFI_UNIX) 22946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return FFI_BAD_ABI; 23046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 23146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith out = (UINT64 *)closure->tramp; 23246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 23346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith c = (intptr_t)closure; 23446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith h = (intptr_t)ffi_closure_tile; 23546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith s = 0; 23646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 23746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Find the smallest shift count that doesn't lose information 23846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith (i.e. no need to explicitly insert high bits of the address that 23946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith are just the sign extension of the low bits). */ 24046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith while ((c >> s) != (SINT16)(c >> s) || (h >> s) != (SINT16)(h >> s)) 24146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith s += 16; 24246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 24346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#define OPS(a, b, shift) \ 24446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith (create_Imm16_X0((a) >> (shift)) | create_Imm16_X1((b) >> (shift))) 24546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 24646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Emit the moveli. */ 24746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out++ = ffi_template_tramp_tile[0] | OPS(c, h, s); 24846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith for (s -= 16; s >= 0; s -= 16) 24946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out++ = ffi_template_tramp_tile[1] | OPS(c, h, s); 25046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 25146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#undef OPS 25246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 25346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out++ = ffi_template_tramp_tile[2]; 25446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 25546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#else 25646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* TILEPro */ 25746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith UINT64 *out; 25846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith intptr_t delta; 25946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 26046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->abi != FFI_UNIX) 26146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return FFI_BAD_ABI; 26246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 26346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith out = (UINT64 *)closure->tramp; 26446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith delta = (intptr_t)ffi_closure_tile - (intptr_t)codeloc; 26546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 26646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith *out++ = ffi_template_tramp_tile[0] | create_JOffLong_X1(delta >> 3); 26746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 26846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 26946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith closure->cif = cif; 27046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith closure->fun = fun; 27146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith closure->user_data = user_data; 27246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 27346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith invalidate_icache(closure->tramp, (char *)out - closure->tramp, 27446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith getpagesize()); 27546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 27646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith return FFI_OK; 27746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith} 27846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 27946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 28046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith/* This is called by the assembly wrapper for closures. This does 28146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith all of the work. On entry reg_args[0] holds the values the registers 28246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith had when the closure was invoked. On return reg_args[1] holds the register 28346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith values to be returned to the caller (many of which may be garbage). */ 28446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithvoid FFI_HIDDEN 28546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smithffi_closure_tile_inner(ffi_closure *closure, 28646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg reg_args[2][NUM_ARG_REGS], 28746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg *stack_args) 28846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith{ 28946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_cif * const cif = closure->cif; 29046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void ** const avalue = alloca(cif->nargs * sizeof(void *)); 29146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith void *rvalue; 29246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_type ** const arg_types = cif->arg_types; 29346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * const reg_args_in = reg_args[0]; 29446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * const reg_args_out = reg_args[1]; 29546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_sarg * argp; 29646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith long i, arg_word, nargs = cif->nargs; 29746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Use a union to guarantee proper alignment for double. */ 29846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith union { ffi_sarg arg[NUM_ARG_REGS]; double d; UINT64 u64; } closure_ret; 29946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 30046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Start out reading register arguments. */ 30146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp = reg_args_in; 30246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 30346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Copy the caller's structure return address to that the closure 30446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith returns the data directly to the caller. */ 30546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->flags == FFI_TYPE_STRUCT) 30646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 30746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Return by reference via hidden pointer. */ 30846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith rvalue = (void *)(intptr_t)*argp++; 30946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word = 1; 31046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 31146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith else 31246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 31346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Return the value in registers. */ 31446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith rvalue = &closure_ret; 31546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word = 0; 31646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 31746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 31846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Grab the addresses of the arguments. */ 31946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith for (i = 0; i < nargs; i++) 32046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 32146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith ffi_type * const type = arg_types[i]; 32246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith const size_t arg_size_in_words = 32346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG; 32446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 32546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#ifndef __tilegx__ 32646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Doubleword-aligned values are always in an even-number register 32746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith pair, or doubleword-aligned stack slot if out of registers. */ 32846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith long align = arg_word & (type->alignment > FFI_SIZEOF_ARG); 32946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp += align; 33046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word += align; 33146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith#endif 33246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 33346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (arg_word == NUM_ARG_REGS || 33446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith (arg_word < NUM_ARG_REGS && 33546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word + arg_size_in_words > NUM_ARG_REGS)) 33646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 33746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Switch to reading arguments from the stack. */ 33846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp = stack_args; 33946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word = NUM_ARG_REGS; 34046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 34146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 34246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith avalue[i] = argp; 34346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith argp += arg_size_in_words; 34446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith arg_word += arg_size_in_words; 34546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 34646ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 34746ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Invoke the closure. */ 34846ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith closure->fun(cif, rvalue, avalue, closure->user_data); 34946ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith 35046ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith if (cif->flags != FFI_TYPE_STRUCT) 35146ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith { 35246ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith /* Canonicalize for register representation. */ 35346ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith assign_to_ffi_arg(reg_args_out, &closure_ret, cif->rtype, 1); 35446ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith } 35546ce27ab1e22ca98957e0900c6a2415b86578b2eGregory P. Smith} 356