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 = &reg_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