(root)/
gcc-13.2.0/
libffi/
src/
sparc/
ffi.c
       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 = FFI_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 = FFI_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 += FFI_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 */