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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2012  Anthony Green
     3  	   Copyright (c) 1998, 2001, 2007, 2008  Red Hat, Inc.
     4  
     5     Alpha 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  /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
    34     all further uses in this file will refer to the 128-bit type.  */
    35  #if defined(__LONG_DOUBLE_128__)
    36  # if FFI_TYPE_LONGDOUBLE != 4
    37  #  error FFI_TYPE_LONGDOUBLE out of date
    38  # endif
    39  #else
    40  # undef FFI_TYPE_LONGDOUBLE
    41  # define FFI_TYPE_LONGDOUBLE 4
    42  #endif
    43  
    44  extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
    45  			 void *raddr, void (*fn)(void), void *closure)
    46  	FFI_HIDDEN;
    47  extern void ffi_closure_osf(void) FFI_HIDDEN;
    48  extern void ffi_go_closure_osf(void) FFI_HIDDEN;
    49  
    50  /* Promote a float value to its in-register double representation.
    51     Unlike actually casting to double, this does not trap on NaN.  */
    52  static inline UINT64 lds(void *ptr)
    53  {
    54    UINT64 ret;
    55    asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
    56    return ret;
    57  }
    58  
    59  /* And the reverse.  */
    60  static inline void sts(void *ptr, UINT64 val)
    61  {
    62    asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
    63  }
    64  
    65  ffi_status FFI_HIDDEN
    66  ffi_prep_cif_machdep(ffi_cif *cif)
    67  {
    68    size_t bytes = 0;
    69    int flags, i, avn;
    70    ffi_type *rtype, *itype;
    71  
    72    if (cif->abi != FFI_OSF)
    73      return FFI_BAD_ABI;
    74  
    75    /* Compute the size of the argument area.  */
    76    for (i = 0, avn = cif->nargs; i < avn; i++)
    77      {
    78        itype = cif->arg_types[i];
    79        switch (itype->type)
    80  	{
    81  	case FFI_TYPE_INT:
    82  	case FFI_TYPE_SINT8:
    83  	case FFI_TYPE_UINT8:
    84  	case FFI_TYPE_SINT16:
    85  	case FFI_TYPE_UINT16:
    86  	case FFI_TYPE_SINT32:
    87  	case FFI_TYPE_UINT32:
    88  	case FFI_TYPE_SINT64:
    89  	case FFI_TYPE_UINT64:
    90  	case FFI_TYPE_POINTER:
    91  	case FFI_TYPE_FLOAT:
    92  	case FFI_TYPE_DOUBLE:
    93  	case FFI_TYPE_LONGDOUBLE:
    94  	  /* All take one 8 byte slot.  */
    95  	  bytes += 8;
    96  	  break;
    97  
    98  	case FFI_TYPE_VOID:
    99  	case FFI_TYPE_STRUCT:
   100  	  /* Passed by value in N slots.  */
   101  	  bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
   102  	  break;
   103  
   104  	case FFI_TYPE_COMPLEX:
   105  	  /* _Complex long double passed by reference; others in 2 slots.  */
   106  	  if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
   107  	    bytes += 8;
   108  	  else
   109  	    bytes += 16;
   110  	  break;
   111  
   112  	default:
   113  	  abort();
   114  	}
   115      }
   116  
   117    /* Set the return type flag */
   118    rtype = cif->rtype;
   119    switch (rtype->type)
   120      {
   121      case FFI_TYPE_VOID:
   122        flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
   123        break;
   124      case FFI_TYPE_INT:
   125      case FFI_TYPE_UINT32:
   126      case FFI_TYPE_SINT32:
   127        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
   128        break;
   129      case FFI_TYPE_FLOAT:
   130        flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
   131        break;
   132      case FFI_TYPE_DOUBLE:
   133        flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
   134        break;
   135      case FFI_TYPE_UINT8:
   136        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
   137        break;
   138      case FFI_TYPE_SINT8:
   139        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
   140        break;
   141      case FFI_TYPE_UINT16:
   142        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
   143        break;
   144      case FFI_TYPE_SINT16:
   145        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
   146        break;
   147      case FFI_TYPE_UINT64:
   148      case FFI_TYPE_SINT64:
   149      case FFI_TYPE_POINTER:
   150        flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
   151        break;
   152      case FFI_TYPE_LONGDOUBLE:
   153      case FFI_TYPE_STRUCT:
   154        /* Passed in memory, with a hidden pointer.  */
   155        flags = ALPHA_RET_IN_MEM;
   156        break;
   157      case FFI_TYPE_COMPLEX:
   158        itype = rtype->elements[0];
   159        switch (itype->type)
   160  	{
   161  	case FFI_TYPE_FLOAT:
   162  	  flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
   163  	  break;
   164  	case FFI_TYPE_DOUBLE:
   165  	  flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
   166  	  break;
   167  	default:
   168  	  if (rtype->size <= 8)
   169  	    flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
   170  	  else
   171  	    flags = ALPHA_RET_IN_MEM;
   172  	  break;
   173  	}
   174        break;
   175      default:
   176        abort();
   177      }
   178    cif->flags = flags;
   179  
   180    /* Include the hidden structure pointer in args requirement.  */
   181    if (flags == ALPHA_RET_IN_MEM)
   182      bytes += 8;
   183    /* Minimum size is 6 slots, so that ffi_call_osf can pop them.  */
   184    if (bytes < 6*8)
   185      bytes = 6*8;
   186    cif->bytes = bytes;
   187  
   188    return FFI_OK;
   189  }
   190  
   191  static unsigned long
   192  extend_basic_type(void *valp, int type, int argn)
   193  {
   194    switch (type)
   195      {
   196      case FFI_TYPE_SINT8:
   197        return *(SINT8 *)valp;
   198      case FFI_TYPE_UINT8:
   199        return *(UINT8 *)valp;
   200      case FFI_TYPE_SINT16:
   201        return *(SINT16 *)valp;
   202      case FFI_TYPE_UINT16:
   203        return *(UINT16 *)valp;
   204  
   205      case FFI_TYPE_FLOAT:
   206        if (argn < 6)
   207  	return lds(valp);
   208        /* FALLTHRU */
   209  
   210      case FFI_TYPE_INT:
   211      case FFI_TYPE_SINT32:
   212      case FFI_TYPE_UINT32:
   213        /* Note that unsigned 32-bit quantities are sign extended.  */
   214        return *(SINT32 *)valp;
   215  
   216      case FFI_TYPE_SINT64:
   217      case FFI_TYPE_UINT64:
   218      case FFI_TYPE_POINTER:
   219      case FFI_TYPE_DOUBLE:
   220        return *(UINT64 *)valp;
   221  
   222      default:
   223        abort();
   224      }
   225  }
   226  
   227  static void
   228  ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
   229  	      void **avalue, void *closure)
   230  {
   231    unsigned long *argp;
   232    long i, avn, argn, flags = cif->flags;
   233    ffi_type **arg_types;
   234    void *frame;
   235  
   236    /* If the return value is a struct and we don't have a return
   237       value address then we need to make one.  */
   238    if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
   239      rvalue = alloca(cif->rtype->size);
   240  
   241    /* Allocate the space for the arguments, plus 4 words of temp
   242       space for ffi_call_osf.  */
   243    argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
   244    frame += cif->bytes;
   245  
   246    argn = 0;
   247    if (flags == ALPHA_RET_IN_MEM)
   248      argp[argn++] = (unsigned long)rvalue;
   249  
   250    avn = cif->nargs;
   251    arg_types = cif->arg_types;
   252  
   253    for (i = 0, avn = cif->nargs; i < avn; i++)
   254      {
   255        ffi_type *ty = arg_types[i];
   256        void *valp = avalue[i];
   257        int type = ty->type;
   258        size_t size;
   259  
   260        switch (type)
   261  	{
   262  	case FFI_TYPE_INT:
   263  	case FFI_TYPE_SINT8:
   264  	case FFI_TYPE_UINT8:
   265  	case FFI_TYPE_SINT16:
   266  	case FFI_TYPE_UINT16:
   267  	case FFI_TYPE_SINT32:
   268  	case FFI_TYPE_UINT32:
   269  	case FFI_TYPE_SINT64:
   270  	case FFI_TYPE_UINT64:
   271  	case FFI_TYPE_POINTER:
   272  	case FFI_TYPE_FLOAT:
   273  	case FFI_TYPE_DOUBLE:
   274  	  argp[argn] = extend_basic_type(valp, type, argn);
   275  	  argn++;
   276  	  break;
   277  
   278  	case FFI_TYPE_LONGDOUBLE:
   279  	by_reference:
   280  	  /* Note that 128-bit long double is passed by reference.  */
   281  	  argp[argn++] = (unsigned long)valp;
   282  	  break;
   283  
   284  	case FFI_TYPE_VOID:
   285  	case FFI_TYPE_STRUCT:
   286  	  size = ty->size;
   287  	  memcpy(argp + argn, valp, size);
   288  	  argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
   289  	  break;
   290  
   291  	case FFI_TYPE_COMPLEX:
   292  	  type = ty->elements[0]->type;
   293  	  if (type == FFI_TYPE_LONGDOUBLE)
   294  	    goto by_reference;
   295  
   296  	  /* Most complex types passed as two separate arguments.  */
   297  	  size = ty->elements[0]->size;
   298  	  argp[argn] = extend_basic_type(valp, type, argn);
   299  	  argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
   300  	  argn += 2;
   301  	  break;
   302  
   303  	default:
   304  	  abort();
   305  	}
   306      }
   307  
   308    flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
   309    ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
   310  }
   311  
   312  void
   313  ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   314  {
   315    ffi_call_int(cif, fn, rvalue, avalue, NULL);
   316  }
   317  
   318  void
   319  ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
   320  	     void **avalue, void *closure)
   321  {
   322    ffi_call_int(cif, fn, rvalue, avalue, closure);
   323  }
   324  
   325  ffi_status
   326  ffi_prep_closure_loc (ffi_closure* closure,
   327  		      ffi_cif* cif,
   328  		      void (*fun)(ffi_cif*, void*, void**, void*),
   329  		      void *user_data,
   330  		      void *codeloc)
   331  {
   332    unsigned int *tramp;
   333  
   334    if (cif->abi != FFI_OSF)
   335      return FFI_BAD_ABI;
   336  
   337    tramp = (unsigned int *) &closure->tramp[0];
   338    tramp[0] = 0x47fb0401;	/* mov $27,$1		*/
   339    tramp[1] = 0xa77b0010;	/* ldq $27,16($27)	*/
   340    tramp[2] = 0x6bfb0000;	/* jmp $31,($27),0	*/
   341    tramp[3] = 0x47ff041f;	/* nop			*/
   342    *(void **) &tramp[4] = ffi_closure_osf;
   343  
   344    closure->cif = cif;
   345    closure->fun = fun;
   346    closure->user_data = user_data;
   347  
   348    /* Flush the Icache.
   349  
   350       Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
   351       instead, since both Compaq as and gas can handle it.
   352  
   353       0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>.  */
   354    asm volatile ("call_pal 0x86" : : : "memory");
   355  
   356    return FFI_OK;
   357  }
   358  
   359  ffi_status
   360  ffi_prep_go_closure (ffi_go_closure* closure,
   361  		     ffi_cif* cif,
   362  		     void (*fun)(ffi_cif*, void*, void**, void*))
   363  {
   364    if (cif->abi != FFI_OSF)
   365      return FFI_BAD_ABI;
   366  
   367    closure->tramp = (void *)ffi_go_closure_osf;
   368    closure->cif = cif;
   369    closure->fun = fun;
   370  
   371    return FFI_OK;
   372  }
   373  
   374  long FFI_HIDDEN
   375  ffi_closure_osf_inner (ffi_cif *cif,
   376  		       void (*fun)(ffi_cif*, void*, void**, void*),
   377  		       void *user_data,
   378  		       void *rvalue, unsigned long *argp)
   379  {
   380    void **avalue;
   381    ffi_type **arg_types;
   382    long i, avn, argn, flags;
   383  
   384    avalue = alloca(cif->nargs * sizeof(void *));
   385    flags = cif->flags;
   386    argn = 0;
   387  
   388    /* Copy the caller's structure return address to that the closure
   389       returns the data directly to the caller.  */
   390    if (flags == ALPHA_RET_IN_MEM)
   391      {
   392        rvalue = (void *) argp[0];
   393        argn = 1;
   394      }
   395  
   396    arg_types = cif->arg_types;
   397  
   398    /* Grab the addresses of the arguments from the stack frame.  */
   399    for (i = 0, avn = cif->nargs; i < avn; i++)
   400      {
   401        ffi_type *ty = arg_types[i];
   402        int type = ty->type;
   403        void *valp = &argp[argn];
   404        size_t size;
   405  
   406        switch (type)
   407  	{
   408  	case FFI_TYPE_INT:
   409  	case FFI_TYPE_SINT8:
   410  	case FFI_TYPE_UINT8:
   411  	case FFI_TYPE_SINT16:
   412  	case FFI_TYPE_UINT16:
   413  	case FFI_TYPE_SINT32:
   414  	case FFI_TYPE_UINT32:
   415  	case FFI_TYPE_SINT64:
   416  	case FFI_TYPE_UINT64:
   417  	case FFI_TYPE_POINTER:
   418  	  argn += 1;
   419  	  break;
   420  
   421  	case FFI_TYPE_VOID:
   422  	case FFI_TYPE_STRUCT:
   423  	  size = ty->size;
   424  	  argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
   425  	  break;
   426  
   427  	case FFI_TYPE_FLOAT:
   428  	  /* Floats coming from registers need conversion from double
   429  	     back to float format.  */
   430  	  if (argn < 6)
   431  	    {
   432  	      valp = &argp[argn - 6];
   433  	      sts(valp, argp[argn - 6]);
   434  	    }
   435  	  argn += 1;
   436  	  break;
   437  
   438  	case FFI_TYPE_DOUBLE:
   439  	  if (argn < 6)
   440  	    valp = &argp[argn - 6];
   441  	  argn += 1;
   442  	  break;
   443  
   444  	case FFI_TYPE_LONGDOUBLE:
   445  	by_reference:
   446  	  /* 128-bit long double is passed by reference.  */
   447  	  valp = (void *)argp[argn];
   448  	  argn += 1;
   449  	  break;
   450  
   451  	case FFI_TYPE_COMPLEX:
   452  	  type = ty->elements[0]->type;
   453  	  switch (type)
   454  	    {
   455  	    case FFI_TYPE_SINT64:
   456  	    case FFI_TYPE_UINT64:
   457  	      /* Passed as separate arguments, but they wind up sequential.  */
   458  	      break;
   459  
   460  	    case FFI_TYPE_INT:
   461  	    case FFI_TYPE_SINT8:
   462  	    case FFI_TYPE_UINT8:
   463  	    case FFI_TYPE_SINT16:
   464  	    case FFI_TYPE_UINT16:
   465  	    case FFI_TYPE_SINT32:
   466  	    case FFI_TYPE_UINT32:
   467  	      /* Passed as separate arguments.  Disjoint, but there's room
   468  		 enough in one slot to hold the pair.  */
   469  	      size = ty->elements[0]->size;
   470  	      memcpy(valp + size, valp + 8, size);
   471  	      break;
   472  
   473  	    case FFI_TYPE_FLOAT:
   474  	      /* Passed as separate arguments.  Disjoint, and each piece
   475  		 may need conversion back to float.  */
   476  	      if (argn < 6)
   477  		{
   478  		  valp = &argp[argn - 6];
   479  		  sts(valp, argp[argn - 6]);
   480  		}
   481  	      if (argn + 1 < 6)
   482  		sts(valp + 4, argp[argn + 1 - 6]);
   483  	      else
   484  		*(UINT32 *)(valp + 4) = argp[argn + 1];
   485  	      break;
   486  
   487  	    case FFI_TYPE_DOUBLE:
   488  	      /* Passed as separate arguments.  Only disjoint if one part
   489  		 is in fp regs and the other is on the stack.  */
   490  	      if (argn < 5)
   491  		valp = &argp[argn - 6];
   492  	      else if (argn == 5)
   493  		{
   494  		  valp = alloca(16);
   495  		  ((UINT64 *)valp)[0] = argp[5 - 6];
   496  		  ((UINT64 *)valp)[1] = argp[6];
   497  		}
   498  	      break;
   499  
   500  	    case FFI_TYPE_LONGDOUBLE:
   501  	      goto by_reference;
   502  
   503  	    default:
   504  	      abort();
   505  	    }
   506  	  argn += 2;
   507  	  break;
   508  
   509  	default:
   510  	  abort ();
   511  	}
   512  
   513        avalue[i] = valp;
   514      }
   515  
   516    /* Invoke the closure.  */
   517    fun (cif, rvalue, avalue, user_data);
   518  
   519    /* Tell ffi_closure_osf how to perform return type promotions.  */
   520    return (flags >> ALPHA_LD_SHIFT) & 0xff;
   521  }