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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima
     3             Copyright (c) 2008 Anthony Green
     4     
     5     SuperH SHmedia Foreign Function Interface 
     6  
     7     Permission is hereby granted, free of charge, to any person obtaining
     8     a copy of this software and associated documentation files (the
     9     ``Software''), to deal in the Software without restriction, including
    10     without limitation the rights to use, copy, modify, merge, publish,
    11     distribute, sublicense, and/or sell copies of the Software, and to
    12     permit persons to whom the Software is furnished to do so, subject to
    13     the following conditions:
    14  
    15     The above copyright notice and this permission notice shall be included
    16     in all copies or substantial portions of the Software.
    17  
    18     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
    19     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    20     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    21     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    22     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    23     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    24     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    25     DEALINGS IN THE SOFTWARE.
    26     ----------------------------------------------------------------------- */
    27  
    28  #include <ffi.h>
    29  #include <ffi_common.h>
    30  
    31  #include <stdlib.h>
    32  
    33  #define NGREGARG 8
    34  #define NFREGARG 12
    35  
    36  static int
    37  return_type (ffi_type *arg)
    38  {
    39  
    40    if (arg->type != FFI_TYPE_STRUCT)
    41      return arg->type;
    42  
    43    /* gcc uses r2 if the result can be packed in on register.  */
    44    if (arg->size <= sizeof (UINT8))
    45      return FFI_TYPE_UINT8;
    46    else if (arg->size <= sizeof (UINT16))
    47      return FFI_TYPE_UINT16;
    48    else if (arg->size <= sizeof (UINT32))
    49      return FFI_TYPE_UINT32;
    50    else if (arg->size <= sizeof (UINT64))
    51      return FFI_TYPE_UINT64;
    52  
    53    return FFI_TYPE_STRUCT;
    54  }
    55  
    56  /* ffi_prep_args is called by the assembly routine once stack space
    57     has been allocated for the function's arguments */
    58  
    59  void ffi_prep_args(char *stack, extended_cif *ecif)
    60  {
    61    register unsigned int i;
    62    register unsigned int avn;
    63    register void **p_argv;
    64    register char *argp;
    65    register ffi_type **p_arg;
    66  
    67    argp = stack;
    68  
    69    if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
    70      {
    71        *(void **) argp = ecif->rvalue;
    72        argp += sizeof (UINT64);
    73      }
    74  
    75    avn = ecif->cif->nargs;
    76    p_argv = ecif->avalue;
    77  
    78    for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
    79      {
    80        size_t z;
    81        int align;
    82  
    83        z = (*p_arg)->size;
    84        align = (*p_arg)->alignment;
    85        if (z < sizeof (UINT32))
    86  	{
    87  	  switch ((*p_arg)->type)
    88  	    {
    89  	    case FFI_TYPE_SINT8:
    90  	      *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
    91  	      break;
    92    
    93  	    case FFI_TYPE_UINT8:
    94  	      *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
    95  	      break;
    96    
    97  	    case FFI_TYPE_SINT16:
    98  	      *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
    99  	      break;
   100    
   101  	    case FFI_TYPE_UINT16:
   102  	      *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
   103  	      break;
   104    
   105  	    case FFI_TYPE_STRUCT:
   106  	      memcpy (argp, *p_argv, z);
   107  	      break;
   108  
   109  	    default:
   110  	      FFI_ASSERT(0);
   111  	    }
   112  	  argp += sizeof (UINT64);
   113  	}
   114        else if (z == sizeof (UINT32) && align == sizeof (UINT32))
   115  	{
   116  	  switch ((*p_arg)->type)
   117  	    {
   118  	    case FFI_TYPE_INT:
   119  	    case FFI_TYPE_SINT32:
   120  	      *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
   121  	      break;
   122  
   123  	    case FFI_TYPE_FLOAT:
   124  	    case FFI_TYPE_POINTER:
   125  	    case FFI_TYPE_UINT32:
   126  	    case FFI_TYPE_STRUCT:
   127  	      *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
   128  	      break;
   129  
   130  	    default:
   131  	      FFI_ASSERT(0);
   132  	      break;
   133  	    }
   134  	  argp += sizeof (UINT64);
   135  	}
   136        else if (z == sizeof (UINT64)
   137  	       && align == sizeof (UINT64)
   138  	       && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
   139  	{
   140  	  *(UINT64 *) argp = *(UINT64 *) (*p_argv);
   141  	  argp += sizeof (UINT64);
   142  	}
   143        else
   144  	{
   145  	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
   146  
   147  	  memcpy (argp, *p_argv, z);
   148  	  argp += n * sizeof (UINT64);
   149  	}
   150      }
   151  
   152    return;
   153  }
   154  
   155  /* Perform machine dependent cif processing */
   156  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   157  {
   158    int i, j;
   159    int size, type;
   160    int n, m;
   161    int greg;
   162    int freg;
   163    int fpair = -1;
   164  
   165    greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
   166    freg = 0;
   167    cif->flags2 = 0;
   168  
   169    for (i = j = 0; i < cif->nargs; i++)
   170      {
   171        type = (cif->arg_types)[i]->type;
   172        switch (type)
   173  	{
   174  	case FFI_TYPE_FLOAT:
   175  	  greg++;
   176  	  cif->bytes += sizeof (UINT64) - sizeof (float);
   177  	  if (freg >= NFREGARG - 1)
   178  	    continue;
   179  	  if (fpair < 0)
   180  	    {
   181  	      fpair = freg;
   182  	      freg += 2;
   183  	    }
   184  	  else
   185  	    fpair = -1;
   186  	  cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
   187  	  break;
   188  
   189  	case FFI_TYPE_DOUBLE:
   190  	  if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
   191  	    continue;
   192  	  if ((freg + 1) < NFREGARG)
   193  	    {
   194  	      freg += 2;
   195  	      cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
   196  	    }
   197  	  else
   198  	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
   199  	  break;
   200  	      
   201  	default:
   202  	  size = (cif->arg_types)[i]->size;
   203  	  if (size < sizeof (UINT64))
   204  	    cif->bytes += sizeof (UINT64) - size;
   205  	  n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
   206  	  if (greg >= NGREGARG)
   207  	    continue;
   208  	  else if (greg + n - 1 >= NGREGARG)
   209  	    greg = NGREGARG;
   210  	  else
   211  	    greg += n;
   212  	  for (m = 0; m < n; m++)
   213  	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
   214  	  break;
   215  	}
   216      }
   217  
   218    /* Set the return type flag */
   219    switch (cif->rtype->type)
   220      {
   221      case FFI_TYPE_STRUCT:
   222        cif->flags = return_type (cif->rtype);
   223        break;
   224  
   225      case FFI_TYPE_VOID:
   226      case FFI_TYPE_FLOAT:
   227      case FFI_TYPE_DOUBLE:
   228      case FFI_TYPE_SINT64:
   229      case FFI_TYPE_UINT64:
   230        cif->flags = cif->rtype->type;
   231        break;
   232  
   233      default:
   234        cif->flags = FFI_TYPE_INT;
   235        break;
   236      }
   237  
   238    return FFI_OK;
   239  }
   240  
   241  /*@-declundef@*/
   242  /*@-exportheader@*/
   243  extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
   244  			  /*@out@*/ extended_cif *, 
   245  			  unsigned, unsigned, long long,
   246  			  /*@out@*/ unsigned *, 
   247  			  void (*fn)(void));
   248  /*@=declundef@*/
   249  /*@=exportheader@*/
   250  
   251  void ffi_call(/*@dependent@*/ ffi_cif *cif, 
   252  	      void (*fn)(void), 
   253  	      /*@out@*/ void *rvalue, 
   254  	      /*@dependent@*/ void **avalue)
   255  {
   256    extended_cif ecif;
   257    UINT64 trvalue;
   258  
   259    ecif.cif = cif;
   260    ecif.avalue = avalue;
   261    
   262    /* If the return value is a struct and we don't have a return	*/
   263    /* value address then we need to make one		        */
   264  
   265    if (cif->rtype->type == FFI_TYPE_STRUCT
   266        && return_type (cif->rtype) != FFI_TYPE_STRUCT)
   267      ecif.rvalue = &trvalue;
   268    else if ((rvalue == NULL) && 
   269        (cif->rtype->type == FFI_TYPE_STRUCT))
   270      {
   271        ecif.rvalue = alloca(cif->rtype->size);
   272      }
   273    else
   274      ecif.rvalue = rvalue;
   275  
   276    switch (cif->abi) 
   277      {
   278      case FFI_SYSV:
   279        ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
   280  		    ecif.rvalue, fn);
   281        break;
   282      default:
   283        FFI_ASSERT(0);
   284        break;
   285      }
   286  
   287    if (rvalue
   288        && cif->rtype->type == FFI_TYPE_STRUCT
   289        && return_type (cif->rtype) != FFI_TYPE_STRUCT)
   290      memcpy (rvalue, &trvalue, cif->rtype->size);
   291  }
   292  
   293  extern void ffi_closure_SYSV (void);
   294  extern void __ic_invalidate (void *line);
   295  
   296  ffi_status
   297  ffi_prep_closure_loc (ffi_closure *closure,
   298  		      ffi_cif *cif,
   299  		      void (*fun)(ffi_cif*, void*, void**, void*),
   300  		      void *user_data,
   301  		      void *codeloc)
   302  {
   303    unsigned int *tramp;
   304  
   305    if (cif->abi != FFI_SYSV)
   306      return FFI_BAD_ABI;
   307  
   308    tramp = (unsigned int *) &closure->tramp[0];
   309    /* Since ffi_closure is an aligned object, the ffi trampoline is
   310       called as an SHcompact code.  Sigh.
   311       SHcompact part:
   312       mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
   313       SHmedia part:
   314       movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
   315       movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
   316  #ifdef __LITTLE_ENDIAN__
   317    tramp[0] = 0x7001c701;
   318    tramp[1] = 0x0009402b;
   319  #else
   320    tramp[0] = 0xc7017001;
   321    tramp[1] = 0x402b0009;
   322  #endif
   323    tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
   324    tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
   325    tramp[4] = 0x6bf10600;
   326    tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
   327    tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
   328    tramp[7] = 0x4401fff0;
   329  
   330    closure->cif = cif;
   331    closure->fun = fun;
   332    closure->user_data = user_data;
   333  
   334    /* Flush the icache.  */
   335    asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
   336  		"r"(codeloc));
   337  
   338    return FFI_OK;
   339  }
   340  
   341  /* Basically the trampoline invokes ffi_closure_SYSV, and on 
   342   * entry, r3 holds the address of the closure.
   343   * After storing the registers that could possibly contain
   344   * parameters to be passed into the stack frame and setting
   345   * up space for a return value, ffi_closure_SYSV invokes the 
   346   * following helper function to do most of the work.
   347   */
   348  
   349  int
   350  ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, 
   351  			 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
   352  {
   353    void **avalue;
   354    ffi_type **p_arg;
   355    int i, avn;
   356    int greg, freg;
   357    ffi_cif *cif;
   358    int fpair = -1;
   359  
   360    cif = closure->cif;
   361    avalue = alloca (cif->nargs * sizeof (void *));
   362  
   363    /* Copy the caller's structure return value address so that the closure
   364       returns the data directly to the caller.  */
   365    if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
   366      {
   367        rvalue = (UINT64 *) *pgr;
   368        greg = 1;
   369      }
   370    else
   371      greg = 0;
   372  
   373    freg = 0;
   374    cif = closure->cif;
   375    avn = cif->nargs;
   376  
   377    /* Grab the addresses of the arguments from the stack frame.  */
   378    for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
   379      {
   380        size_t z;
   381        void *p;
   382  
   383        z = (*p_arg)->size;
   384        if (z < sizeof (UINT32))
   385  	{
   386  	  p = pgr + greg++;
   387  
   388  	  switch ((*p_arg)->type)
   389  	    {
   390  	    case FFI_TYPE_SINT8:
   391  	    case FFI_TYPE_UINT8:
   392  	    case FFI_TYPE_SINT16:
   393  	    case FFI_TYPE_UINT16:
   394  	    case FFI_TYPE_STRUCT:
   395  #ifdef __LITTLE_ENDIAN__
   396  	      avalue[i] = p;
   397  #else
   398  	      avalue[i] = ((char *) p) + sizeof (UINT32) - z;
   399  #endif
   400  	      break;
   401  
   402  	    default:
   403  	      FFI_ASSERT(0);
   404  	    }
   405  	}
   406        else if (z == sizeof (UINT32))
   407  	{
   408  	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
   409  	    {
   410  	      if (freg < NFREGARG - 1)
   411  		{
   412  		  if (fpair >= 0)
   413  		    {
   414  		      avalue[i] = (UINT32 *) pfr + fpair;
   415  		      fpair = -1;
   416  		    }
   417  		  else
   418  		    {
   419  #ifdef __LITTLE_ENDIAN__
   420  		      fpair = freg;
   421  		      avalue[i] = (UINT32 *) pfr + (1 ^ freg);
   422  #else
   423  		      fpair = 1 ^ freg;
   424  		      avalue[i] = (UINT32 *) pfr + freg;
   425  #endif
   426  		      freg += 2;
   427  		    }
   428  		}
   429  	      else
   430  #ifdef __LITTLE_ENDIAN__
   431  		avalue[i] = pgr + greg;
   432  #else
   433  		avalue[i] = (UINT32 *) (pgr + greg) + 1;
   434  #endif
   435  	    }
   436  	  else
   437  #ifdef __LITTLE_ENDIAN__
   438  	    avalue[i] = pgr + greg;
   439  #else
   440  	    avalue[i] = (UINT32 *) (pgr + greg) + 1;
   441  #endif
   442  	  greg++;
   443  	}
   444        else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
   445  	{
   446  	  if (freg + 1 >= NFREGARG)
   447  	    avalue[i] = pgr + greg;
   448  	  else
   449  	    {
   450  	      avalue[i] = pfr + (freg >> 1);
   451  	      freg += 2;
   452  	    }
   453  	  greg++;
   454  	}
   455        else
   456  	{
   457  	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
   458  
   459  	  avalue[i] = pgr + greg;
   460  	  greg += n;
   461  	}
   462      }
   463  
   464    (closure->fun) (cif, rvalue, avalue, closure->user_data);
   465  
   466    /* Tell ffi_closure_SYSV how to perform return type promotions.  */
   467    return return_type (cif->rtype);
   468  }
   469