github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/tile/ffi.c (about)

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2012 Tilera Corp.
     3  
     4     TILE Foreign Function Interface
     5  
     6     Permission is hereby granted, free of charge, to any person obtaining
     7     a copy of this software and associated documentation files (the
     8     ``Software''), to deal in the Software without restriction, including
     9     without limitation the rights to use, copy, modify, merge, publish,
    10     distribute, sublicense, and/or sell copies of the Software, and to
    11     permit persons to whom the Software is furnished to do so, subject to
    12     the following conditions:
    13  
    14     The above copyright notice and this permission notice shall be included
    15     in all copies or substantial portions of the Software.
    16  
    17     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
    18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    24     DEALINGS IN THE SOFTWARE.
    25     ----------------------------------------------------------------------- */
    26  
    27  #include <ffi.h>
    28  #include <ffi_common.h>
    29  #include <stdlib.h>
    30  #include <stdint.h>
    31  #include <unistd.h>
    32  #include <arch/abi.h>
    33  #include <arch/icache.h>
    34  #include <arch/opcode.h>
    35  
    36  
    37  /* The first 10 registers are used to pass arguments and return values. */
    38  #define NUM_ARG_REGS 10
    39  
    40  /* Performs a raw function call with the given NUM_ARG_REGS register arguments
    41     and the specified additional stack arguments (if any). */
    42  extern void ffi_call_tile(ffi_sarg reg_args[NUM_ARG_REGS],
    43                            const ffi_sarg *stack_args,
    44                            size_t stack_args_bytes,
    45                            void (*fnaddr)(void))
    46    FFI_HIDDEN;
    47  
    48  /* This handles the raw call from the closure stub, cleaning up the
    49     parameters and delegating to ffi_closure_tile_inner. */
    50  extern void ffi_closure_tile(void) FFI_HIDDEN;
    51  
    52  
    53  ffi_status
    54  ffi_prep_cif_machdep(ffi_cif *cif)
    55  {
    56    /* We always allocate room for all registers. Even if we don't
    57       use them as parameters, they get returned in the same array
    58       as struct return values so we need to make room. */
    59    if (cif->bytes < NUM_ARG_REGS * FFI_SIZEOF_ARG)
    60      cif->bytes = NUM_ARG_REGS * FFI_SIZEOF_ARG;
    61  
    62    if (cif->rtype->size > NUM_ARG_REGS * FFI_SIZEOF_ARG)
    63      cif->flags = FFI_TYPE_STRUCT;
    64    else
    65      cif->flags = FFI_TYPE_INT;
    66  
    67    /* Nothing to do. */
    68    return FFI_OK;
    69  }
    70  
    71  
    72  static long
    73  assign_to_ffi_arg(ffi_sarg *out, void *in, const ffi_type *type,
    74                    int write_to_reg)
    75  {
    76    switch (type->type)
    77      {
    78      case FFI_TYPE_SINT8:
    79        *out = *(SINT8 *)in;
    80        return 1;
    81  
    82      case FFI_TYPE_UINT8:
    83        *out = *(UINT8 *)in;
    84        return 1;
    85  
    86      case FFI_TYPE_SINT16:
    87        *out = *(SINT16 *)in;
    88        return 1;
    89  
    90      case FFI_TYPE_UINT16:
    91        *out = *(UINT16 *)in;
    92        return 1;
    93  
    94      case FFI_TYPE_SINT32:
    95      case FFI_TYPE_UINT32:
    96  #ifndef __LP64__
    97      case FFI_TYPE_POINTER:
    98  #endif
    99        /* Note that even unsigned 32-bit quantities are sign extended
   100           on tilegx when stored in a register.  */
   101        *out = *(SINT32 *)in;
   102        return 1;
   103  
   104      case FFI_TYPE_FLOAT:
   105  #ifdef __tilegx__
   106        if (write_to_reg)
   107          {
   108            /* Properly sign extend the value.  */
   109            union { float f; SINT32 s32; } val;
   110            val.f = *(float *)in;
   111            *out = val.s32;
   112          }
   113        else
   114  #endif
   115          {
   116            *(float *)out = *(float *)in;
   117          }
   118        return 1;
   119  
   120      case FFI_TYPE_SINT64:
   121      case FFI_TYPE_UINT64:
   122      case FFI_TYPE_DOUBLE:
   123  #ifdef __LP64__
   124      case FFI_TYPE_POINTER:
   125  #endif
   126        *(UINT64 *)out = *(UINT64 *)in;
   127        return sizeof(UINT64) / FFI_SIZEOF_ARG;
   128  
   129      case FFI_TYPE_STRUCT:
   130        memcpy(out, in, type->size);
   131        return (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
   132  
   133      case FFI_TYPE_VOID:
   134        /* Must be a return type. Nothing to do. */
   135        return 0;
   136  
   137      default:
   138        FFI_ASSERT(0);
   139        return -1;
   140      }
   141  }
   142  
   143  
   144  void
   145  ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   146  {
   147    ffi_sarg * const arg_mem = alloca(cif->bytes);
   148    ffi_sarg * const reg_args = arg_mem;
   149    ffi_sarg * const stack_args = &reg_args[NUM_ARG_REGS];
   150    ffi_sarg *argp = arg_mem;
   151    ffi_type ** const arg_types = cif->arg_types;
   152    const long num_args = cif->nargs;
   153    long i;
   154  
   155    if (cif->flags == FFI_TYPE_STRUCT)
   156      {
   157        /* Pass a hidden pointer to the return value. We make sure there
   158           is scratch space for the callee to store the return value even if
   159           our caller doesn't care about it. */
   160        *argp++ = (intptr_t)(rvalue ? rvalue : alloca(cif->rtype->size));
   161  
   162        /* No more work needed to return anything. */
   163        rvalue = NULL;
   164      }
   165  
   166    for (i = 0; i < num_args; i++)
   167      {
   168        ffi_type *type = arg_types[i];
   169        void * const arg_in = avalue[i];
   170        ptrdiff_t arg_word = argp - arg_mem;
   171  
   172  #ifndef __tilegx__
   173        /* Doubleword-aligned values are always in an even-number register
   174           pair, or doubleword-aligned stack slot if out of registers. */
   175        long align = arg_word & (type->alignment > FFI_SIZEOF_ARG);
   176        argp += align;
   177        arg_word += align;
   178  #endif
   179  
   180        if (type->type == FFI_TYPE_STRUCT)
   181          {
   182            const size_t arg_size_in_words =
   183              (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
   184  
   185            if (arg_word < NUM_ARG_REGS &&
   186                arg_word + arg_size_in_words > NUM_ARG_REGS)
   187              {
   188                /* Args are not allowed to span registers and the stack. */
   189                argp = stack_args;
   190              }
   191  
   192            memcpy(argp, arg_in, type->size);
   193            argp += arg_size_in_words;
   194          }
   195        else
   196          {
   197            argp += assign_to_ffi_arg(argp, arg_in, arg_types[i], 1);
   198          }
   199      }
   200  
   201    /* Actually do the call. */
   202    ffi_call_tile(reg_args, stack_args,
   203                  cif->bytes - (NUM_ARG_REGS * FFI_SIZEOF_ARG), fn);
   204  
   205    if (rvalue != NULL)
   206      assign_to_ffi_arg(rvalue, reg_args, cif->rtype, 0);
   207  }
   208  
   209  
   210  /* Template code for closure. */
   211  extern const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN;
   212  
   213  
   214  ffi_status
   215  ffi_prep_closure_loc (ffi_closure *closure,
   216                        ffi_cif *cif,
   217                        void (*fun)(ffi_cif*, void*, void**, void*),
   218                        void *user_data,
   219                        void *codeloc)
   220  {
   221  #ifdef __tilegx__
   222    /* TILE-Gx */
   223    SINT64 c;
   224    SINT64 h;
   225    int s;
   226    UINT64 *out;
   227  
   228    if (cif->abi != FFI_UNIX)
   229      return FFI_BAD_ABI;
   230  
   231    out = (UINT64 *)closure->tramp;
   232  
   233    c = (intptr_t)closure;
   234    h = (intptr_t)ffi_closure_tile;
   235    s = 0;
   236  
   237    /* Find the smallest shift count that doesn't lose information
   238       (i.e. no need to explicitly insert high bits of the address that
   239       are just the sign extension of the low bits). */
   240    while ((c >> s) != (SINT16)(c >> s) || (h >> s) != (SINT16)(h >> s))
   241      s += 16;
   242  
   243  #define OPS(a, b, shift) \
   244    (create_Imm16_X0((a) >> (shift)) | create_Imm16_X1((b) >> (shift)))
   245  
   246    /* Emit the moveli. */
   247    *out++ = ffi_template_tramp_tile[0] | OPS(c, h, s);
   248    for (s -= 16; s >= 0; s -= 16)
   249      *out++ = ffi_template_tramp_tile[1] | OPS(c, h, s);
   250  
   251  #undef OPS
   252  
   253    *out++ = ffi_template_tramp_tile[2];
   254  
   255  #else
   256    /* TILEPro */
   257    UINT64 *out;
   258    intptr_t delta;
   259  
   260    if (cif->abi != FFI_UNIX)
   261      return FFI_BAD_ABI;
   262  
   263    out = (UINT64 *)closure->tramp;
   264    delta = (intptr_t)ffi_closure_tile - (intptr_t)codeloc;
   265  
   266    *out++ = ffi_template_tramp_tile[0] | create_JOffLong_X1(delta >> 3);
   267  #endif
   268  
   269    closure->cif = cif;
   270    closure->fun = fun;
   271    closure->user_data = user_data;
   272  
   273    invalidate_icache(closure->tramp, (char *)out - closure->tramp,
   274                      getpagesize());
   275  
   276    return FFI_OK;
   277  }
   278  
   279  
   280  /* This is called by the assembly wrapper for closures. This does
   281     all of the work. On entry reg_args[0] holds the values the registers
   282     had when the closure was invoked. On return reg_args[1] holds the register
   283     values to be returned to the caller (many of which may be garbage). */
   284  void FFI_HIDDEN
   285  ffi_closure_tile_inner(ffi_closure *closure,
   286                         ffi_sarg reg_args[2][NUM_ARG_REGS],
   287                         ffi_sarg *stack_args)
   288  {
   289    ffi_cif * const cif = closure->cif;
   290    void ** const avalue = alloca(cif->nargs * sizeof(void *));
   291    void *rvalue;
   292    ffi_type ** const arg_types = cif->arg_types;
   293    ffi_sarg * const reg_args_in = reg_args[0];
   294    ffi_sarg * const reg_args_out = reg_args[1];
   295    ffi_sarg * argp;
   296    long i, arg_word, nargs = cif->nargs;
   297    /* Use a union to guarantee proper alignment for double. */
   298    union { ffi_sarg arg[NUM_ARG_REGS]; double d; UINT64 u64; } closure_ret;
   299  
   300    /* Start out reading register arguments. */
   301    argp = reg_args_in;
   302  
   303    /* Copy the caller's structure return address to that the closure
   304       returns the data directly to the caller.  */
   305    if (cif->flags == FFI_TYPE_STRUCT)
   306      {
   307        /* Return by reference via hidden pointer. */
   308        rvalue = (void *)(intptr_t)*argp++;
   309        arg_word = 1;
   310      }
   311    else
   312      {
   313        /* Return the value in registers. */
   314        rvalue = &closure_ret;
   315        arg_word = 0;
   316      }
   317  
   318    /* Grab the addresses of the arguments. */
   319    for (i = 0; i < nargs; i++)
   320      {
   321        ffi_type * const type = arg_types[i];
   322        const size_t arg_size_in_words =
   323          (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
   324  
   325  #ifndef __tilegx__
   326        /* Doubleword-aligned values are always in an even-number register
   327           pair, or doubleword-aligned stack slot if out of registers. */
   328        long align = arg_word & (type->alignment > FFI_SIZEOF_ARG);
   329        argp += align;
   330        arg_word += align;
   331  #endif
   332  
   333        if (arg_word == NUM_ARG_REGS ||
   334            (arg_word < NUM_ARG_REGS &&
   335             arg_word + arg_size_in_words > NUM_ARG_REGS))
   336          {
   337            /* Switch to reading arguments from the stack. */
   338            argp = stack_args;
   339            arg_word = NUM_ARG_REGS;
   340          }
   341  
   342        avalue[i] = argp;
   343        argp += arg_size_in_words;
   344        arg_word += arg_size_in_words;
   345      }
   346  
   347    /* Invoke the closure.  */
   348    closure->fun(cif, rvalue, avalue, closure->user_data);
   349  
   350    if (cif->flags != FFI_TYPE_STRUCT)
   351      {
   352        /* Canonicalize for register representation. */
   353        assign_to_ffi_arg(reg_args_out, &closure_ret, cif->rtype, 1);
   354      }
   355  }