(root)/
gcc-13.2.0/
libffi/
src/
tile/
ffi.c
       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  }