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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2011, 2013 Anthony Green
     3             Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
     4     
     5     SPARC 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  #include <stdlib.h>
    31  #include "internal.h"
    32  
    33  #ifndef SPARC64
    34  
    35  /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
    36     all further uses in this file will refer to the 128-bit type.  */
    37  #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
    38  # if FFI_TYPE_LONGDOUBLE != 4
    39  #  error FFI_TYPE_LONGDOUBLE out of date
    40  # endif
    41  #else
    42  # undef FFI_TYPE_LONGDOUBLE
    43  # define FFI_TYPE_LONGDOUBLE 4
    44  #endif
    45  
    46  /* Perform machine dependent cif processing */
    47  ffi_status FFI_HIDDEN
    48  ffi_prep_cif_machdep(ffi_cif *cif)
    49  {
    50    ffi_type *rtype = cif->rtype;
    51    int rtt = rtype->type;
    52    size_t bytes;
    53    int i, n, flags;
    54  
    55    /* Set the return type flag */
    56    switch (rtt)
    57      {
    58      case FFI_TYPE_VOID:
    59        flags = SPARC_RET_VOID;
    60        break;
    61      case FFI_TYPE_FLOAT:
    62        flags = SPARC_RET_F_1;
    63        break;
    64      case FFI_TYPE_DOUBLE:
    65        flags = SPARC_RET_F_2;
    66        break;
    67      case FFI_TYPE_LONGDOUBLE:
    68      case FFI_TYPE_STRUCT:
    69        flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
    70        flags |= SPARC_RET_STRUCT;
    71        break;
    72      case FFI_TYPE_SINT8:
    73        flags = SPARC_RET_SINT8;
    74        break;
    75      case FFI_TYPE_UINT8:
    76        flags = SPARC_RET_UINT8;
    77        break;
    78      case FFI_TYPE_SINT16:
    79        flags = SPARC_RET_SINT16;
    80        break;
    81      case FFI_TYPE_UINT16:
    82        flags = SPARC_RET_UINT16;
    83        break;
    84      case FFI_TYPE_INT:
    85      case FFI_TYPE_SINT32:
    86      case FFI_TYPE_UINT32:
    87      case FFI_TYPE_POINTER:
    88        flags = SPARC_RET_UINT32;
    89        break;
    90      case FFI_TYPE_SINT64:
    91      case FFI_TYPE_UINT64:
    92        flags = SPARC_RET_INT64;
    93        break;
    94      case FFI_TYPE_COMPLEX:
    95        rtt = rtype->elements[0]->type;
    96        switch (rtt)
    97  	{
    98  	case FFI_TYPE_FLOAT:
    99  	  flags = SPARC_RET_F_2;
   100  	  break;
   101  	case FFI_TYPE_DOUBLE:
   102  	  flags = SPARC_RET_F_4;
   103  	  break;
   104  	case FFI_TYPE_LONGDOUBLE:
   105  	  flags = SPARC_RET_F_8;
   106  	  break;
   107  	case FFI_TYPE_SINT64:
   108  	case FFI_TYPE_UINT64:
   109  	  flags = SPARC_RET_INT128;
   110  	  break;
   111  	case FFI_TYPE_INT:
   112  	case FFI_TYPE_SINT32:
   113  	case FFI_TYPE_UINT32:
   114  	  flags = SPARC_RET_INT64;
   115  	  break;
   116  	case FFI_TYPE_SINT16:
   117  	case FFI_TYPE_UINT16:
   118  	  flags = SP_V8_RET_CPLX16;
   119  	  break;
   120  	case FFI_TYPE_SINT8:
   121  	case FFI_TYPE_UINT8:
   122  	  flags = SP_V8_RET_CPLX8;
   123  	  break;
   124  	default:
   125  	  abort();
   126  	}
   127        break;
   128      default:
   129        abort();
   130      }
   131    cif->flags = flags;
   132  
   133    bytes = 0;
   134    for (i = 0, n = cif->nargs; i < n; ++i)
   135      {
   136        ffi_type *ty = cif->arg_types[i];
   137        size_t z = ty->size;
   138        int tt = ty->type;
   139  
   140        switch (tt)
   141  	{
   142  	case FFI_TYPE_STRUCT:
   143  	case FFI_TYPE_LONGDOUBLE:
   144  	by_reference:
   145  	  /* Passed by reference.  */
   146  	  z = 4;
   147  	  break;
   148  
   149  	case FFI_TYPE_COMPLEX:
   150  	  tt = ty->elements[0]->type;
   151  	  if (tt == FFI_TYPE_FLOAT || z > 8)
   152  	    goto by_reference;
   153  	  /* FALLTHRU */
   154  
   155  	default:
   156  	  z = ALIGN(z, 4);
   157  	}
   158        bytes += z;
   159      }
   160  
   161    /* Sparc call frames require that space is allocated for 6 args,
   162       even if they aren't used. Make that space if necessary.  */
   163    if (bytes < 6 * 4)
   164      bytes = 6 * 4;
   165  
   166    /* The ABI always requires space for the struct return pointer.  */
   167    bytes += 4;
   168  
   169    /* The stack must be 2 word aligned, so round bytes up appropriately. */
   170    bytes = ALIGN(bytes, 2 * 4);
   171  
   172    /* Include the call frame to prep_args.  */
   173    bytes += 4*16 + 4*8;
   174    cif->bytes = bytes;
   175  
   176    return FFI_OK;
   177  }
   178  
   179  extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
   180  			void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
   181  
   182  int FFI_HIDDEN
   183  ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
   184  {
   185    ffi_type **p_arg;
   186    int flags = cif->flags;
   187    int i, nargs;
   188  
   189    if (rvalue == NULL)
   190      {
   191        if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
   192  	{
   193  	  /* Since we pass the pointer to the callee, we need a value.
   194  	     We allowed for this space in ffi_call, before ffi_call_v8
   195  	     alloca'd the space.  */
   196  	  rvalue = (char *)argp + cif->bytes;
   197  	}
   198        else
   199  	{
   200  	  /* Otherwise, we can ignore the return value.  */
   201  	  flags = SPARC_RET_VOID;
   202  	}
   203      }
   204  
   205    /* This could only really be done when we are returning a structure.
   206       However, the space is reserved so we can do it unconditionally.  */
   207    *argp++ = (unsigned long)rvalue;
   208  
   209  #ifdef USING_PURIFY
   210    /* Purify will probably complain in our assembly routine,
   211       unless we zero out this memory. */
   212    memset(argp, 0, 6*4);
   213  #endif
   214  
   215    p_arg = cif->arg_types;
   216    for (i = 0, nargs = cif->nargs; i < nargs; i++)
   217      {
   218        ffi_type *ty = p_arg[i];
   219        void *a = avalue[i];
   220        int tt = ty->type;
   221        size_t z;
   222  
   223        switch (tt)
   224  	{
   225  	case FFI_TYPE_STRUCT:
   226  	case FFI_TYPE_LONGDOUBLE:
   227  	by_reference:
   228  	  *argp++ = (unsigned long)a;
   229  	  break;
   230  
   231  	case FFI_TYPE_DOUBLE:
   232  	case FFI_TYPE_UINT64:
   233  	case FFI_TYPE_SINT64:
   234  	  memcpy(argp, a, 8);
   235  	  argp += 2;
   236  	  break;
   237  
   238  	case FFI_TYPE_INT:
   239  	case FFI_TYPE_FLOAT:
   240  	case FFI_TYPE_UINT32:
   241  	case FFI_TYPE_SINT32:
   242  	case FFI_TYPE_POINTER:
   243  	  *argp++ = *(unsigned *)a;
   244  	  break;
   245  
   246  	case FFI_TYPE_UINT8:
   247  	  *argp++ = *(UINT8 *)a;
   248  	  break;
   249  	case FFI_TYPE_SINT8:
   250  	  *argp++ = *(SINT8 *)a;
   251  	  break;
   252  	case FFI_TYPE_UINT16:
   253  	  *argp++ = *(UINT16 *)a;
   254  	  break;
   255  	case FFI_TYPE_SINT16:
   256  	  *argp++ = *(SINT16 *)a;
   257  	  break;
   258  
   259          case FFI_TYPE_COMPLEX:
   260  	  tt = ty->elements[0]->type;
   261  	  z = ty->size;
   262  	  if (tt == FFI_TYPE_FLOAT || z > 8)
   263  	    goto by_reference;
   264  	  if (z < 4)
   265  	    {
   266  	      memcpy((char *)argp + 4 - z, a, z);
   267  	      argp++;
   268  	    }
   269  	  else
   270  	    {
   271  	      memcpy(argp, a, z);
   272  	      argp += z / 4;
   273  	    }
   274  	  break;
   275  
   276  	default:
   277  	  abort();
   278  	}
   279      }
   280  
   281    return flags;
   282  }
   283  
   284  static void
   285  ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   286  	      void **avalue, void *closure)
   287  {
   288    size_t bytes = cif->bytes;
   289  
   290    FFI_ASSERT (cif->abi == FFI_V8);
   291  
   292    /* If we've not got a return value, we need to create one if we've
   293       got to pass the return value to the callee.  Otherwise ignore it.  */
   294    if (rvalue == NULL
   295        && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
   296      bytes += ALIGN (cif->rtype->size, 8);
   297  
   298    ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
   299  }
   300  
   301  void
   302  ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   303  {
   304    ffi_call_int (cif, fn, rvalue, avalue, NULL);
   305  }
   306  
   307  void
   308  ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
   309  	     void **avalue, void *closure)
   310  {
   311    ffi_call_int (cif, fn, rvalue, avalue, closure);
   312  }
   313  
   314  #ifdef __GNUC__
   315  static inline void
   316  ffi_flush_icache (void *p)
   317  {
   318    /* SPARC v8 requires 5 instructions for flush to be visible */
   319    asm volatile ("iflush	%0; iflush %0+8; nop; nop; nop; nop; nop"
   320  		: : "r" (p) : "memory");
   321  }
   322  #else
   323  extern void ffi_flush_icache (void *) FFI_HIDDEN;
   324  #endif
   325  
   326  extern void ffi_closure_v8(void) FFI_HIDDEN;
   327  extern void ffi_go_closure_v8(void) FFI_HIDDEN;
   328  
   329  ffi_status
   330  ffi_prep_closure_loc (ffi_closure *closure,
   331  		      ffi_cif *cif,
   332  		      void (*fun)(ffi_cif*, void*, void**, void*),
   333  		      void *user_data,
   334  		      void *codeloc)
   335  {
   336    unsigned int *tramp = (unsigned int *) &closure->tramp[0];
   337    unsigned long ctx = (unsigned long) closure;
   338    unsigned long fn = (unsigned long) ffi_closure_v8;
   339  
   340    if (cif->abi != FFI_V8)
   341      return FFI_BAD_ABI;
   342  
   343    tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
   344    tramp[1] = 0x05000000 | ctx >> 10;	/* sethi %hi(ctx), %g2	*/
   345    tramp[2] = 0x81c06000 | (fn & 0x3ff);	/* jmp   %g1+%lo(fn)	*/
   346    tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)	*/
   347  
   348    closure->cif = cif;
   349    closure->fun = fun;
   350    closure->user_data = user_data;
   351  
   352    ffi_flush_icache (closure);
   353  
   354    return FFI_OK;
   355  }
   356  
   357  ffi_status
   358  ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
   359  		     void (*fun)(ffi_cif*, void*, void**, void*))
   360  {
   361    if (cif->abi != FFI_V8)
   362      return FFI_BAD_ABI;
   363  
   364    closure->tramp = ffi_go_closure_v8;
   365    closure->cif = cif;
   366    closure->fun = fun;
   367  
   368    return FFI_OK;
   369  }
   370  
   371  int FFI_HIDDEN
   372  ffi_closure_sparc_inner_v8(ffi_cif *cif, 
   373  			   void (*fun)(ffi_cif*, void*, void**, void*),
   374  			   void *user_data, void *rvalue,
   375  			   unsigned long *argp)
   376  {
   377    ffi_type **arg_types;
   378    void **avalue;
   379    int i, nargs, flags;
   380  
   381    arg_types = cif->arg_types;
   382    nargs = cif->nargs;
   383    flags = cif->flags;
   384    avalue = alloca(nargs * sizeof(void *));
   385  
   386    /* Copy the caller's structure return address so that the closure
   387       returns the data directly to the caller.  Also install it so we
   388       can return the address in %o0.  */
   389    if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
   390      {
   391        void *new_rvalue = (void *)*argp;
   392        *(void **)rvalue = new_rvalue;
   393        rvalue = new_rvalue;
   394      }
   395  
   396    /* Always skip the structure return address.  */
   397    argp++;
   398  
   399    /* Grab the addresses of the arguments from the stack frame.  */
   400    for (i = 0; i < nargs; i++)
   401      {
   402        ffi_type *ty = arg_types[i];
   403        int tt = ty->type;
   404        void *a = argp;
   405        size_t z;
   406  
   407        switch (tt)
   408  	{
   409  	case FFI_TYPE_STRUCT:
   410  	case FFI_TYPE_LONGDOUBLE:
   411  	by_reference:
   412  	  /* Straight copy of invisible reference.  */
   413  	  a = (void *)*argp;
   414  	  break;
   415  
   416  	case FFI_TYPE_DOUBLE:
   417  	case FFI_TYPE_SINT64:
   418  	case FFI_TYPE_UINT64:
   419  	  if ((unsigned long)a & 7)
   420  	    {
   421  	      /* Align on a 8-byte boundary.  */
   422  	      UINT64 *tmp = alloca(8);
   423  	      *tmp = ((UINT64)argp[0] << 32) | argp[1];
   424  	      a = tmp;
   425  	    }
   426  	  argp++;
   427  	  break;
   428  
   429  	case FFI_TYPE_INT:
   430  	case FFI_TYPE_FLOAT:
   431  	case FFI_TYPE_UINT32:
   432  	case FFI_TYPE_SINT32:
   433  	case FFI_TYPE_POINTER:
   434  	  break;
   435          case FFI_TYPE_UINT16:
   436          case FFI_TYPE_SINT16:
   437  	  a += 2;
   438  	  break;
   439          case FFI_TYPE_UINT8:
   440          case FFI_TYPE_SINT8:
   441  	  a += 3;
   442  	  break;
   443  
   444          case FFI_TYPE_COMPLEX:
   445  	  tt = ty->elements[0]->type;
   446  	  z = ty->size;
   447  	  if (tt == FFI_TYPE_FLOAT || z > 8)
   448  	    goto by_reference;
   449  	  if (z < 4)
   450  	    a += 4 - z;
   451  	  else if (z > 4)
   452  	    argp++;
   453  	  break;
   454  
   455  	default:
   456  	  abort();
   457  	}
   458        argp++;
   459        avalue[i] = a;
   460      }
   461  
   462    /* Invoke the closure.  */
   463    fun (cif, rvalue, avalue, user_data);
   464  
   465    /* Tell ffi_closure_sparc how to perform return type promotions.  */
   466    return flags;
   467  }
   468  #endif /* !SPARC64 */