(root)/
gcc-13.2.0/
libffi/
src/
sparc/
ffi64.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  /* 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 = FFI_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 = FFI_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 = FFI_ALIGN(bytes, a);
     288        bytes += FFI_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 = FFI_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 += FFI_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 += FFI_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 + FFI_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 = FFI_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 */