github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/sparc/ffi64.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  /* 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 FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
    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  #ifdef SPARC64
    45  
    46  /* Flatten the contents of a structure to the parts that are passed in
    47     floating point registers.  The return is a bit mask wherein bit N
    48     set means bytes [4*n, 4*n+3] are passed in %fN.
    49  
    50     We encode both the (running) size (maximum 32) and mask (maxumum 255)
    51     into one integer.  The size is placed in the low byte, so that align
    52     and addition work correctly.  The mask is placed in the second byte.  */
    53  
    54  static int
    55  ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
    56  {
    57    ffi_type **elts;
    58    ffi_type *t;
    59  
    60    if (outer_type->type == FFI_TYPE_COMPLEX)
    61      {
    62        int m = 0, tt = outer_type->elements[0]->type;
    63        size_t z = outer_type->size;
    64  
    65        if (tt == FFI_TYPE_FLOAT
    66  	  || tt == FFI_TYPE_DOUBLE
    67  	  || tt == FFI_TYPE_LONGDOUBLE)
    68          m = (1 << (z / 4)) - 1;
    69        return (m << 8) | z;
    70      }
    71    FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
    72  
    73    for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
    74      {
    75        size_t z = t->size;
    76        int o, m, tt;
    77  
    78        size_mask = ALIGN(size_mask, t->alignment);
    79        switch (t->type)
    80  	{
    81  	case FFI_TYPE_STRUCT:
    82  	  size_mask = ffi_struct_float_mask (t, size_mask);
    83  	  continue;
    84  	case FFI_TYPE_COMPLEX:
    85  	  tt = t->elements[0]->type;
    86  	  if (tt != FFI_TYPE_FLOAT
    87  	      && tt != FFI_TYPE_DOUBLE
    88  	      && tt != FFI_TYPE_LONGDOUBLE)
    89  	    break;
    90  	  /* FALLTHRU */
    91  	case FFI_TYPE_FLOAT:
    92  	case FFI_TYPE_DOUBLE:
    93  	case FFI_TYPE_LONGDOUBLE:
    94  	  m = (1 << (z / 4)) - 1;	/* compute mask for type */
    95  	  o = (size_mask >> 2) & 0x3f;	/* extract word offset */
    96  	  size_mask |= m << (o + 8);	/* insert mask into place */
    97  	  break;
    98  	}
    99        size_mask += z;
   100      }
   101  
   102    size_mask = ALIGN(size_mask, outer_type->alignment);
   103    FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
   104  
   105    return size_mask;
   106  }
   107  
   108  /* Merge floating point data into integer data.  If the structure is
   109     entirely floating point, simply return a pointer to the fp data.  */
   110  
   111  static void *
   112  ffi_struct_float_merge (int size_mask, void *vi, void *vf)
   113  {
   114    int size = size_mask & 0xff;
   115    int mask = size_mask >> 8;
   116    int n = size >> 2;
   117  
   118    if (mask == 0)
   119      return vi;
   120    else if (mask == (1 << n) - 1)
   121      return vf;
   122    else
   123      {
   124        unsigned int *wi = vi, *wf = vf;
   125        int i;
   126  
   127        for (i = 0; i < n; ++i)
   128  	if ((mask >> i) & 1)
   129  	  wi[i] = wf[i];
   130  
   131        return vi;
   132      }
   133  }
   134  
   135  /* Similar, but place the data into VD in the end.  */
   136  
   137  void FFI_HIDDEN
   138  ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
   139  {
   140    int size = size_mask & 0xff;
   141    int mask = size_mask >> 8;
   142    int n = size >> 2;
   143  
   144    if (mask == 0)
   145      ;
   146    else if (mask == (1 << n) - 1)
   147      vi = vf;
   148    else
   149      {
   150        unsigned int *wd = vd, *wi = vi, *wf = vf;
   151        int i;
   152  
   153        for (i = 0; i < n; ++i)
   154  	wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
   155        return;
   156      }
   157    memcpy (vd, vi, size);
   158  }
   159  
   160  /* Perform machine dependent cif processing */
   161  
   162  static ffi_status
   163  ffi_prep_cif_machdep_core(ffi_cif *cif)
   164  {
   165    ffi_type *rtype = cif->rtype;
   166    int rtt = rtype->type;
   167    size_t bytes = 0;
   168    int i, n, flags;
   169  
   170    /* Set the return type flag */
   171    switch (rtt)
   172      {
   173      case FFI_TYPE_VOID:
   174        flags = SPARC_RET_VOID;
   175        break;
   176      case FFI_TYPE_FLOAT:
   177        flags = SPARC_RET_F_1;
   178        break;
   179      case FFI_TYPE_DOUBLE:
   180        flags = SPARC_RET_F_2;
   181        break;
   182      case FFI_TYPE_LONGDOUBLE:
   183        flags = SPARC_RET_F_4;
   184        break;
   185  
   186      case FFI_TYPE_COMPLEX:
   187      case FFI_TYPE_STRUCT:
   188        if (rtype->size > 32)
   189  	{
   190  	  flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
   191  	  bytes = 8;
   192  	}
   193        else
   194  	{
   195  	  int size_mask = ffi_struct_float_mask (rtype, 0);
   196  	  int word_size = (size_mask >> 2) & 0x3f;
   197  	  int all_mask = (1 << word_size) - 1;
   198  	  int fp_mask = size_mask >> 8;
   199  
   200  	  flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
   201  
   202  	  /* For special cases of all-int or all-fp, we can return
   203  	     the value directly without popping through a struct copy.  */
   204  	  if (fp_mask == 0)
   205  	    {
   206  	      if (rtype->alignment >= 8)
   207  		{
   208  		  if (rtype->size == 8)
   209  		    flags = SPARC_RET_INT64;
   210  		  else if (rtype->size == 16)
   211  		    flags = SPARC_RET_INT128;
   212  		}
   213  	    }
   214  	  else if (fp_mask == all_mask)
   215  	    switch (word_size)
   216  	      {
   217  	      case 1: flags = SPARC_RET_F_1; break;
   218  	      case 2: flags = SPARC_RET_F_2; break;
   219  	      case 3: flags = SP_V9_RET_F_3; break;
   220  	      case 4: flags = SPARC_RET_F_4; break;
   221  	      /* 5 word structures skipped; handled via RET_STRUCT.  */
   222  	      case 6: flags = SPARC_RET_F_6; break;
   223  	      /* 7 word structures skipped; handled via RET_STRUCT.  */
   224  	      case 8: flags = SPARC_RET_F_8; break;
   225  	      }
   226  	}
   227        break;
   228  
   229      case FFI_TYPE_SINT8:
   230        flags = SPARC_RET_SINT8;
   231        break;
   232      case FFI_TYPE_UINT8:
   233        flags = SPARC_RET_UINT8;
   234        break;
   235      case FFI_TYPE_SINT16:
   236        flags = SPARC_RET_SINT16;
   237        break;
   238      case FFI_TYPE_UINT16:
   239        flags = SPARC_RET_UINT16;
   240        break;
   241      case FFI_TYPE_INT:
   242      case FFI_TYPE_SINT32:
   243        flags = SP_V9_RET_SINT32;
   244        break;
   245      case FFI_TYPE_UINT32:
   246        flags = SPARC_RET_UINT32;
   247        break;
   248      case FFI_TYPE_SINT64:
   249      case FFI_TYPE_UINT64:
   250      case FFI_TYPE_POINTER:
   251        flags = SPARC_RET_INT64;
   252        break;
   253  
   254      default:
   255        abort();
   256      }
   257  
   258    bytes = 0;
   259    for (i = 0, n = cif->nargs; i < n; ++i)
   260      {
   261        ffi_type *ty = cif->arg_types[i];
   262        size_t z = ty->size;
   263        size_t a = ty->alignment;
   264  
   265        switch (ty->type)
   266  	{
   267  	case FFI_TYPE_COMPLEX:
   268  	case FFI_TYPE_STRUCT:
   269  	  /* Large structs passed by reference.  */
   270  	  if (z > 16)
   271  	    {
   272  	      a = z = 8;
   273  	      break;
   274  	    }
   275  	  /* Small structs may be passed in integer or fp regs or both.  */
   276  	  if (bytes >= 16*8)
   277  	    break;
   278  	  if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
   279  	    break;
   280  	  /* FALLTHRU */
   281  	case FFI_TYPE_FLOAT:
   282  	case FFI_TYPE_DOUBLE:
   283  	case FFI_TYPE_LONGDOUBLE:
   284  	  flags |= SPARC_FLAG_FP_ARGS;
   285  	  break;
   286  	}
   287        bytes = ALIGN(bytes, a);
   288        bytes += ALIGN(z, 8);
   289      }
   290  
   291    /* Sparc call frames require that space is allocated for 6 args,
   292       even if they aren't used. Make that space if necessary. */
   293    if (bytes < 6 * 8)
   294      bytes = 6 * 8;
   295  
   296    /* The stack must be 2 word aligned, so round bytes up appropriately. */
   297    bytes = ALIGN(bytes, 16);
   298  
   299    /* Include the call frame to prep_args.  */
   300    bytes += 8*16 + 8*8;
   301  
   302    cif->bytes = bytes;
   303    cif->flags = flags;
   304    return FFI_OK;
   305  }
   306  
   307  ffi_status FFI_HIDDEN
   308  ffi_prep_cif_machdep(ffi_cif *cif)
   309  {
   310    cif->nfixedargs = cif->nargs;
   311    return ffi_prep_cif_machdep_core(cif);
   312  }
   313  
   314  ffi_status FFI_HIDDEN
   315  ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
   316  {
   317    cif->nfixedargs = nfixedargs;
   318    return ffi_prep_cif_machdep_core(cif);
   319  }
   320  
   321  extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
   322  			void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
   323  
   324  /* ffi_prep_args is called by the assembly routine once stack space
   325     has been allocated for the function's arguments */
   326  
   327  int FFI_HIDDEN
   328  ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
   329  {
   330    ffi_type **p_arg;
   331    int flags = cif->flags;
   332    int i, nargs;
   333  
   334    if (rvalue == NULL)
   335      {
   336        if (flags & SPARC_FLAG_RET_IN_MEM)
   337  	{
   338  	  /* Since we pass the pointer to the callee, we need a value.
   339  	     We allowed for this space in ffi_call, before ffi_call_v8
   340  	     alloca'd the space.  */
   341  	  rvalue = (char *)argp + cif->bytes;
   342  	}
   343        else
   344  	{
   345  	  /* Otherwise, we can ignore the return value.  */
   346  	  flags = SPARC_RET_VOID;
   347  	}
   348      }
   349  
   350  #ifdef USING_PURIFY
   351    /* Purify will probably complain in our assembly routine,
   352       unless we zero out this memory. */
   353    memset(argp, 0, 6*8);
   354  #endif
   355  
   356    if (flags & SPARC_FLAG_RET_IN_MEM)
   357      *argp++ = (unsigned long)rvalue;
   358  
   359    p_arg = cif->arg_types;
   360    for (i = 0, nargs = cif->nargs; i < nargs; i++)
   361      {
   362        ffi_type *ty = p_arg[i];
   363        void *a = avalue[i];
   364        size_t z;
   365  
   366        switch (ty->type)
   367  	{
   368  	case FFI_TYPE_SINT8:
   369  	  *argp++ = *(SINT8 *)a;
   370  	  break;
   371  	case FFI_TYPE_UINT8:
   372  	  *argp++ = *(UINT8 *)a;
   373  	  break;
   374  	case FFI_TYPE_SINT16:
   375  	  *argp++ = *(SINT16 *)a;
   376  	  break;
   377  	case FFI_TYPE_UINT16:
   378  	  *argp++ = *(UINT16 *)a;
   379  	  break;
   380  	case FFI_TYPE_INT:
   381  	case FFI_TYPE_SINT32:
   382  	  *argp++ = *(SINT32 *)a;
   383  	  break;
   384  	case FFI_TYPE_UINT32:
   385  	case FFI_TYPE_FLOAT:
   386  	  *argp++ = *(UINT32 *)a;
   387  	  break;
   388  	case FFI_TYPE_SINT64:
   389  	case FFI_TYPE_UINT64:
   390  	case FFI_TYPE_POINTER:
   391  	case FFI_TYPE_DOUBLE:
   392  	  *argp++ = *(UINT64 *)a;
   393  	  break;
   394  
   395  	case FFI_TYPE_LONGDOUBLE:
   396  	case FFI_TYPE_COMPLEX:
   397  	case FFI_TYPE_STRUCT:
   398  	  z = ty->size;
   399  	  if (z > 16)
   400  	    {
   401  	      /* For structures larger than 16 bytes we pass reference.  */
   402  	      *argp++ = (unsigned long)a;
   403  	      break;
   404  	    }
   405  	  if (((unsigned long)argp & 15) && ty->alignment > 8)
   406  	    argp++;
   407  	  memcpy(argp, a, z);
   408  	  argp += ALIGN(z, 8) / 8;
   409  	  break;
   410  
   411  	default:
   412  	  abort();
   413  	}
   414      }
   415  
   416    return flags;
   417  }
   418  
   419  static void
   420  ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
   421  	     void **avalue, void *closure)
   422  {
   423    size_t bytes = cif->bytes;
   424  
   425    FFI_ASSERT (cif->abi == FFI_V9);
   426  
   427    if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
   428      bytes += ALIGN (cif->rtype->size, 16);
   429  
   430    ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
   431  }
   432  
   433  void
   434  ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   435  {
   436    ffi_call_int(cif, fn, rvalue, avalue, NULL);
   437  }
   438  
   439  void
   440  ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue,
   441  	    void **avalue, void *closure)
   442  {
   443    ffi_call_int(cif, fn, rvalue, avalue, closure);
   444  }
   445  
   446  #ifdef __GNUC__
   447  static inline void
   448  ffi_flush_icache (void *p)
   449  {
   450    asm volatile ("flush	%0; flush %0+8" : : "r" (p) : "memory");
   451  }
   452  #else
   453  extern void ffi_flush_icache (void *) FFI_HIDDEN;
   454  #endif
   455  
   456  extern void ffi_closure_v9(void) FFI_HIDDEN;
   457  extern void ffi_go_closure_v9(void) FFI_HIDDEN;
   458  
   459  ffi_status
   460  ffi_prep_closure_loc (ffi_closure* closure,
   461  		      ffi_cif* cif,
   462  		      void (*fun)(ffi_cif*, void*, void**, void*),
   463  		      void *user_data,
   464  		      void *codeloc)
   465  {
   466    unsigned int *tramp = (unsigned int *) &closure->tramp[0];
   467    unsigned long fn;
   468  
   469    if (cif->abi != FFI_V9)
   470      return FFI_BAD_ABI;
   471  
   472    /* Trampoline address is equal to the closure address.  We take advantage
   473       of that to reduce the trampoline size by 8 bytes. */
   474    fn = (unsigned long) ffi_closure_v9;
   475    tramp[0] = 0x83414000;	/* rd	%pc, %g1	*/
   476    tramp[1] = 0xca586010;	/* ldx	[%g1+16], %g5	*/
   477    tramp[2] = 0x81c14000;	/* jmp	%g5		*/
   478    tramp[3] = 0x01000000;	/* nop			*/
   479    *((unsigned long *) &tramp[4]) = fn;
   480  
   481    closure->cif = cif;
   482    closure->fun = fun;
   483    closure->user_data = user_data;
   484  
   485    ffi_flush_icache (closure);
   486  
   487    return FFI_OK;
   488  }
   489  
   490  ffi_status
   491  ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
   492  		     void (*fun)(ffi_cif*, void*, void**, void*))
   493  {
   494    if (cif->abi != FFI_V9)
   495      return FFI_BAD_ABI;
   496  
   497    closure->tramp = ffi_go_closure_v9;
   498    closure->cif = cif;
   499    closure->fun = fun;
   500  
   501    return FFI_OK;
   502  }
   503  
   504  int FFI_HIDDEN
   505  ffi_closure_sparc_inner_v9(ffi_cif *cif,
   506  			   void (*fun)(ffi_cif*, void*, void**, void*),
   507  			   void *user_data, void *rvalue,
   508  			   unsigned long *gpr, unsigned long *fpr)
   509  {
   510    ffi_type **arg_types;
   511    void **avalue;
   512    int i, argn, argx, nargs, flags, nfixedargs;
   513  
   514    arg_types = cif->arg_types;
   515    nargs = cif->nargs;
   516    flags = cif->flags;
   517    nfixedargs = cif->nfixedargs;
   518  
   519    avalue = alloca(nargs * sizeof(void *));
   520  
   521    /* Copy the caller's structure return address so that the closure
   522       returns the data directly to the caller.  */
   523    if (flags & SPARC_FLAG_RET_IN_MEM)
   524      {
   525        rvalue = (void *) gpr[0];
   526        /* Skip the structure return address.  */
   527        argn = 1;
   528      }
   529    else
   530      argn = 0;
   531  
   532    /* Grab the addresses of the arguments from the stack frame.  */
   533    for (i = 0; i < nargs; i++, argn = argx)
   534      {
   535        int named = i < nfixedargs;
   536        ffi_type *ty = arg_types[i];
   537        void *a = &gpr[argn];
   538        size_t z;
   539  
   540        argx = argn + 1;
   541        switch (ty->type)
   542  	{
   543  	case FFI_TYPE_COMPLEX:
   544  	case FFI_TYPE_STRUCT:
   545  	  z = ty->size;
   546  	  if (z > 16)
   547  	    a = *(void **)a;
   548  	  else
   549  	    {
   550  	      argx = argn + ALIGN (z, 8) / 8;
   551  	      if (named && argn < 16)
   552  		{
   553  		  int size_mask = ffi_struct_float_mask (ty, 0);
   554  		  int argn_mask = (0xffff00 >> argn) & 0xff00;
   555  
   556  		  /* Eliminate fp registers off the end.  */
   557  		  size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
   558  		  a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
   559  		}
   560  	    }
   561  	  break;
   562  
   563  	case FFI_TYPE_LONGDOUBLE:
   564  	  argn = ALIGN (argn, 2);
   565  	  a = (named && argn < 16 ? fpr : gpr) + argn;
   566  	  argx = argn + 2;
   567  	  break;
   568  	case FFI_TYPE_DOUBLE:
   569  	  if (named && argn < 16)
   570  	    a = fpr + argn;
   571  	  break;
   572  	case FFI_TYPE_FLOAT:
   573  	  if (named && argn < 16)
   574  	    a = fpr + argn;
   575  	  a += 4;
   576  	  break;
   577  
   578  	case FFI_TYPE_UINT64:
   579  	case FFI_TYPE_SINT64:
   580  	case FFI_TYPE_POINTER:
   581  	  break;
   582  	case FFI_TYPE_INT:
   583  	case FFI_TYPE_UINT32:
   584  	case FFI_TYPE_SINT32:
   585  	  a += 4;
   586  	  break;
   587          case FFI_TYPE_UINT16:
   588          case FFI_TYPE_SINT16:
   589  	  a += 6;
   590  	  break;
   591          case FFI_TYPE_UINT8:
   592          case FFI_TYPE_SINT8:
   593  	  a += 7;
   594  	  break;
   595  
   596  	default:
   597  	  abort();
   598  	}
   599        avalue[i] = a;
   600      }
   601  
   602    /* Invoke the closure.  */
   603    fun (cif, rvalue, avalue, user_data);
   604  
   605    /* Tell ffi_closure_sparc how to perform return type promotions.  */
   606    return flags;
   607  }
   608  #endif /* SPARC64 */