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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2013  Synopsys, Inc. (www.synopsys.com)
     3     
     4     ARC 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, EXPRESS
    18     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    20     IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
    21     OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    22     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    23     OTHER DEALINGS IN THE SOFTWARE.
    24     ----------------------------------------------------------------------- */
    25  
    26  #include <ffi.h>
    27  #include <ffi_common.h>
    28  
    29  #include <stdlib.h>
    30  #include <stdint.h>
    31  
    32  #include <sys/cachectl.h>
    33  
    34  /* for little endian ARC, the code is in fact stored as mixed endian for
    35     performance reasons */
    36  #if __BIG_ENDIAN__
    37  #define CODE_ENDIAN(x) (x)
    38  #else
    39  #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
    40  #endif
    41  
    42  /* ffi_prep_args is called by the assembly routine once stack
    43     space has been allocated for the function's arguments.  */
    44  
    45  void
    46  ffi_prep_args (char *stack, extended_cif * ecif)
    47  {
    48    unsigned int i;
    49    int tmp;
    50    void **p_argv;
    51    char *argp;
    52    ffi_type **p_arg;
    53  
    54    tmp = 0;
    55    argp = stack;
    56  
    57    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
    58      {
    59        *(void **) argp = ecif->rvalue;
    60        argp += 4;
    61      }
    62  
    63    p_argv = ecif->avalue;
    64  
    65    for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
    66         (i != 0); i--, p_arg++)
    67      {
    68        size_t z;
    69        int alignment;
    70  
    71        /* align alignment to 4 */
    72        alignment = (((*p_arg)->alignment - 1) | 3) + 1;
    73  
    74        /* Align if necessary.  */
    75        if ((alignment - 1) & (unsigned) argp)
    76  	argp = (char *) ALIGN (argp, alignment);
    77  
    78        z = (*p_arg)->size;
    79        if (z < sizeof (int))
    80  	{
    81  	  z = sizeof (int);
    82  
    83  	  switch ((*p_arg)->type)
    84  	    {
    85  	    case FFI_TYPE_SINT8:
    86  	      *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
    87  	      break;
    88  
    89  	    case FFI_TYPE_UINT8:
    90  	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv);
    91  	      break;
    92  
    93  	    case FFI_TYPE_SINT16:
    94  	      *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
    95  	      break;
    96  
    97  	    case FFI_TYPE_UINT16:
    98  	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv);
    99  	      break;
   100  
   101  	    case FFI_TYPE_STRUCT:
   102  	      memcpy (argp, *p_argv, (*p_arg)->size);
   103  	      break;
   104  
   105  	    default:
   106  	      FFI_ASSERT (0);
   107  	    }
   108  	}
   109        else if (z == sizeof (int))
   110  	{
   111  	  *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
   112  	}
   113        else
   114  	{
   115  	  if ((*p_arg)->type == FFI_TYPE_STRUCT)
   116  	    {
   117  	      memcpy (argp, *p_argv, z);
   118  	    }
   119  	  else
   120  	    {
   121  	      /* Double or long long 64bit.  */
   122  	      memcpy (argp, *p_argv, z);
   123  	    }
   124  	}
   125        p_argv++;
   126        argp += z;
   127      }
   128  
   129    return;
   130  }
   131  
   132  /* Perform machine dependent cif processing.  */
   133  ffi_status
   134  ffi_prep_cif_machdep (ffi_cif * cif)
   135  {
   136    /* Set the return type flag.  */
   137    switch (cif->rtype->type)
   138      {
   139      case FFI_TYPE_VOID:
   140        cif->flags = (unsigned) cif->rtype->type;
   141        break;
   142  
   143      case FFI_TYPE_STRUCT:
   144        cif->flags = (unsigned) cif->rtype->type;
   145        break;
   146  
   147      case FFI_TYPE_SINT64:
   148      case FFI_TYPE_UINT64:
   149      case FFI_TYPE_DOUBLE:
   150        cif->flags = FFI_TYPE_DOUBLE;
   151        break;
   152  
   153      case FFI_TYPE_FLOAT:
   154      default:
   155        cif->flags = FFI_TYPE_INT;
   156        break;
   157      }
   158  
   159    return FFI_OK;
   160  }
   161  
   162  extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
   163  				extended_cif *, unsigned, unsigned,
   164  				unsigned *, void (*fn) (void));
   165  
   166  void
   167  ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
   168  {
   169    extended_cif ecif;
   170  
   171    ecif.cif = cif;
   172    ecif.avalue = avalue;
   173  
   174    /* If the return value is a struct and we don't have
   175       a return value address then we need to make one.  */
   176    if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
   177      {
   178        ecif.rvalue = alloca (cif->rtype->size);
   179      }
   180    else
   181      ecif.rvalue = rvalue;
   182  
   183    switch (cif->abi)
   184      {
   185      case FFI_ARCOMPACT:
   186        ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
   187  			  cif->flags, ecif.rvalue, fn);
   188        break;
   189  
   190      default:
   191        FFI_ASSERT (0);
   192        break;
   193      }
   194  }
   195  
   196  int
   197  ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
   198  			     ffi_arg * args)
   199  {
   200    void **arg_area, **p_argv;
   201    ffi_cif *cif = closure->cif;
   202    char *argp = (char *) args;
   203    ffi_type **p_argt;
   204    int i;
   205  
   206    arg_area = (void **) alloca (cif->nargs * sizeof (void *));
   207  
   208    /* handle hidden argument */
   209    if (cif->flags == FFI_TYPE_STRUCT)
   210      {
   211        rvalue = *(void **) argp;
   212        argp += 4;
   213      }
   214  
   215    p_argv = arg_area;
   216  
   217    for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
   218         i++, p_argt++, p_argv++)
   219      {
   220        size_t z;
   221        int alignment;
   222  
   223        /* align alignment to 4 */
   224        alignment = (((*p_argt)->alignment - 1) | 3) + 1;
   225  
   226        /* Align if necessary.  */
   227        if ((alignment - 1) & (unsigned) argp)
   228  	argp = (char *) ALIGN (argp, alignment);
   229  
   230        z = (*p_argt)->size;
   231        *p_argv = (void *) argp;
   232        argp += z;
   233      }
   234  
   235    (closure->fun) (cif, rvalue, arg_area, closure->user_data);
   236  
   237    return cif->flags;
   238  }
   239  
   240  extern void ffi_closure_ARCompact (void);
   241  
   242  ffi_status
   243  ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
   244  		      void (*fun) (ffi_cif *, void *, void **, void *),
   245  		      void *user_data, void *codeloc)
   246  {
   247    uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
   248  
   249    switch (cif->abi)
   250      {
   251      case FFI_ARCOMPACT:
   252        FFI_ASSERT (tramp == codeloc);
   253        tramp[0] = CODE_ENDIAN (0x200a1fc0);	/* mov r8, pcl  */
   254        tramp[1] = CODE_ENDIAN (0x20200f80);	/* j [long imm] */
   255        tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
   256        break;
   257  
   258      default:
   259        return FFI_BAD_ABI;
   260      }
   261  
   262    closure->cif = cif;
   263    closure->fun = fun;
   264    closure->user_data = user_data;
   265    cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
   266  
   267    return FFI_OK;
   268  }