(root)/
gcc-13.2.0/
libffi/
src/
sh64/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima
       3             Copyright (c) 2008 Anthony Green
       4     
       5     SuperH SHmedia 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  
      31  #include <stdlib.h>
      32  
      33  #define NGREGARG 8
      34  #define NFREGARG 12
      35  
      36  static int
      37  return_type (ffi_type *arg)
      38  {
      39  
      40    if (arg->type != FFI_TYPE_STRUCT)
      41      return arg->type;
      42  
      43    /* gcc uses r2 if the result can be packed in on register.  */
      44    if (arg->size <= sizeof (UINT8))
      45      return FFI_TYPE_UINT8;
      46    else if (arg->size <= sizeof (UINT16))
      47      return FFI_TYPE_UINT16;
      48    else if (arg->size <= sizeof (UINT32))
      49      return FFI_TYPE_UINT32;
      50    else if (arg->size <= sizeof (UINT64))
      51      return FFI_TYPE_UINT64;
      52  
      53    return FFI_TYPE_STRUCT;
      54  }
      55  
      56  /* ffi_prep_args is called by the assembly routine once stack space
      57     has been allocated for the function's arguments */
      58  
      59  void ffi_prep_args(char *stack, extended_cif *ecif)
      60  {
      61    register unsigned int i;
      62    register unsigned int avn;
      63    register void **p_argv;
      64    register char *argp;
      65    register ffi_type **p_arg;
      66  
      67    argp = stack;
      68  
      69    if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
      70      {
      71        *(void **) argp = ecif->rvalue;
      72        argp += sizeof (UINT64);
      73      }
      74  
      75    avn = ecif->cif->nargs;
      76    p_argv = ecif->avalue;
      77  
      78    for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
      79      {
      80        size_t z;
      81        int align;
      82  
      83        z = (*p_arg)->size;
      84        align = (*p_arg)->alignment;
      85        if (z < sizeof (UINT32))
      86  	{
      87  	  switch ((*p_arg)->type)
      88  	    {
      89  	    case FFI_TYPE_SINT8:
      90  	      *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
      91  	      break;
      92    
      93  	    case FFI_TYPE_UINT8:
      94  	      *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
      95  	      break;
      96    
      97  	    case FFI_TYPE_SINT16:
      98  	      *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
      99  	      break;
     100    
     101  	    case FFI_TYPE_UINT16:
     102  	      *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
     103  	      break;
     104    
     105  	    case FFI_TYPE_STRUCT:
     106  	      memcpy (argp, *p_argv, z);
     107  	      break;
     108  
     109  	    default:
     110  	      FFI_ASSERT(0);
     111  	    }
     112  	  argp += sizeof (UINT64);
     113  	}
     114        else if (z == sizeof (UINT32) && align == sizeof (UINT32))
     115  	{
     116  	  switch ((*p_arg)->type)
     117  	    {
     118  	    case FFI_TYPE_INT:
     119  	    case FFI_TYPE_SINT32:
     120  	      *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
     121  	      break;
     122  
     123  	    case FFI_TYPE_FLOAT:
     124  	    case FFI_TYPE_POINTER:
     125  	    case FFI_TYPE_UINT32:
     126  	    case FFI_TYPE_STRUCT:
     127  	      *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
     128  	      break;
     129  
     130  	    default:
     131  	      FFI_ASSERT(0);
     132  	      break;
     133  	    }
     134  	  argp += sizeof (UINT64);
     135  	}
     136        else if (z == sizeof (UINT64)
     137  	       && align == sizeof (UINT64)
     138  	       && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
     139  	{
     140  	  *(UINT64 *) argp = *(UINT64 *) (*p_argv);
     141  	  argp += sizeof (UINT64);
     142  	}
     143        else
     144  	{
     145  	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
     146  
     147  	  memcpy (argp, *p_argv, z);
     148  	  argp += n * sizeof (UINT64);
     149  	}
     150      }
     151  
     152    return;
     153  }
     154  
     155  /* Perform machine dependent cif processing */
     156  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     157  {
     158    int i, j;
     159    int size, type;
     160    int n, m;
     161    int greg;
     162    int freg;
     163    int fpair = -1;
     164  
     165    greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
     166    freg = 0;
     167    cif->flags2 = 0;
     168  
     169    for (i = j = 0; i < cif->nargs; i++)
     170      {
     171        type = (cif->arg_types)[i]->type;
     172        switch (type)
     173  	{
     174  	case FFI_TYPE_FLOAT:
     175  	  greg++;
     176  	  cif->bytes += sizeof (UINT64) - sizeof (float);
     177  	  if (freg >= NFREGARG - 1)
     178  	    continue;
     179  	  if (fpair < 0)
     180  	    {
     181  	      fpair = freg;
     182  	      freg += 2;
     183  	    }
     184  	  else
     185  	    fpair = -1;
     186  	  cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
     187  	  break;
     188  
     189  	case FFI_TYPE_DOUBLE:
     190  	  if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
     191  	    continue;
     192  	  if ((freg + 1) < NFREGARG)
     193  	    {
     194  	      freg += 2;
     195  	      cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
     196  	    }
     197  	  else
     198  	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
     199  	  break;
     200  	      
     201  	default:
     202  	  size = (cif->arg_types)[i]->size;
     203  	  if (size < sizeof (UINT64))
     204  	    cif->bytes += sizeof (UINT64) - size;
     205  	  n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
     206  	  if (greg >= NGREGARG)
     207  	    continue;
     208  	  else if (greg + n - 1 >= NGREGARG)
     209  	    greg = NGREGARG;
     210  	  else
     211  	    greg += n;
     212  	  for (m = 0; m < n; m++)
     213  	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
     214  	  break;
     215  	}
     216      }
     217  
     218    /* Set the return type flag */
     219    switch (cif->rtype->type)
     220      {
     221      case FFI_TYPE_STRUCT:
     222        cif->flags = return_type (cif->rtype);
     223        break;
     224  
     225      case FFI_TYPE_VOID:
     226      case FFI_TYPE_FLOAT:
     227      case FFI_TYPE_DOUBLE:
     228      case FFI_TYPE_SINT64:
     229      case FFI_TYPE_UINT64:
     230        cif->flags = cif->rtype->type;
     231        break;
     232  
     233      default:
     234        cif->flags = FFI_TYPE_INT;
     235        break;
     236      }
     237  
     238    return FFI_OK;
     239  }
     240  
     241  /*@-declundef@*/
     242  /*@-exportheader@*/
     243  extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
     244  			  /*@out@*/ extended_cif *, 
     245  			  unsigned, unsigned, long long,
     246  			  /*@out@*/ unsigned *, 
     247  			  void (*fn)(void));
     248  /*@=declundef@*/
     249  /*@=exportheader@*/
     250  
     251  void ffi_call(/*@dependent@*/ ffi_cif *cif, 
     252  	      void (*fn)(void), 
     253  	      /*@out@*/ void *rvalue, 
     254  	      /*@dependent@*/ void **avalue)
     255  {
     256    extended_cif ecif;
     257    UINT64 trvalue;
     258  
     259    ecif.cif = cif;
     260    ecif.avalue = avalue;
     261    
     262    /* If the return value is a struct and we don't have a return	*/
     263    /* value address then we need to make one		        */
     264  
     265    if (cif->rtype->type == FFI_TYPE_STRUCT
     266        && return_type (cif->rtype) != FFI_TYPE_STRUCT)
     267      ecif.rvalue = &trvalue;
     268    else if ((rvalue == NULL) && 
     269        (cif->rtype->type == FFI_TYPE_STRUCT))
     270      {
     271        ecif.rvalue = alloca(cif->rtype->size);
     272      }
     273    else
     274      ecif.rvalue = rvalue;
     275  
     276    switch (cif->abi) 
     277      {
     278      case FFI_SYSV:
     279        ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
     280  		    ecif.rvalue, fn);
     281        break;
     282      default:
     283        FFI_ASSERT(0);
     284        break;
     285      }
     286  
     287    if (rvalue
     288        && cif->rtype->type == FFI_TYPE_STRUCT
     289        && return_type (cif->rtype) != FFI_TYPE_STRUCT)
     290      memcpy (rvalue, &trvalue, cif->rtype->size);
     291  }
     292  
     293  extern void ffi_closure_SYSV (void);
     294  extern void __ic_invalidate (void *line);
     295  
     296  ffi_status
     297  ffi_prep_closure_loc (ffi_closure *closure,
     298  		      ffi_cif *cif,
     299  		      void (*fun)(ffi_cif*, void*, void**, void*),
     300  		      void *user_data,
     301  		      void *codeloc)
     302  {
     303    unsigned int *tramp;
     304  
     305    if (cif->abi != FFI_SYSV)
     306      return FFI_BAD_ABI;
     307  
     308    tramp = (unsigned int *) &closure->tramp[0];
     309    /* Since ffi_closure is an aligned object, the ffi trampoline is
     310       called as an SHcompact code.  Sigh.
     311       SHcompact part:
     312       mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
     313       SHmedia part:
     314       movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
     315       movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
     316  #ifdef __LITTLE_ENDIAN__
     317    tramp[0] = 0x7001c701;
     318    tramp[1] = 0x0009402b;
     319  #else
     320    tramp[0] = 0xc7017001;
     321    tramp[1] = 0x402b0009;
     322  #endif
     323    tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
     324    tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
     325    tramp[4] = 0x6bf10600;
     326    tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
     327    tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
     328    tramp[7] = 0x4401fff0;
     329  
     330    closure->cif = cif;
     331    closure->fun = fun;
     332    closure->user_data = user_data;
     333  
     334    /* Flush the icache.  */
     335    asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
     336  		"r"(codeloc));
     337  
     338    return FFI_OK;
     339  }
     340  
     341  /* Basically the trampoline invokes ffi_closure_SYSV, and on 
     342   * entry, r3 holds the address of the closure.
     343   * After storing the registers that could possibly contain
     344   * parameters to be passed into the stack frame and setting
     345   * up space for a return value, ffi_closure_SYSV invokes the 
     346   * following helper function to do most of the work.
     347   */
     348  
     349  int
     350  ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, 
     351  			 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
     352  {
     353    void **avalue;
     354    ffi_type **p_arg;
     355    int i, avn;
     356    int greg, freg;
     357    ffi_cif *cif;
     358    int fpair = -1;
     359  
     360    cif = closure->cif;
     361    avalue = alloca (cif->nargs * sizeof (void *));
     362  
     363    /* Copy the caller's structure return value address so that the closure
     364       returns the data directly to the caller.  */
     365    if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
     366      {
     367        rvalue = (UINT64 *) *pgr;
     368        greg = 1;
     369      }
     370    else
     371      greg = 0;
     372  
     373    freg = 0;
     374    cif = closure->cif;
     375    avn = cif->nargs;
     376  
     377    /* Grab the addresses of the arguments from the stack frame.  */
     378    for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
     379      {
     380        size_t z;
     381        void *p;
     382  
     383        z = (*p_arg)->size;
     384        if (z < sizeof (UINT32))
     385  	{
     386  	  p = pgr + greg++;
     387  
     388  	  switch ((*p_arg)->type)
     389  	    {
     390  	    case FFI_TYPE_SINT8:
     391  	    case FFI_TYPE_UINT8:
     392  	    case FFI_TYPE_SINT16:
     393  	    case FFI_TYPE_UINT16:
     394  	    case FFI_TYPE_STRUCT:
     395  #ifdef __LITTLE_ENDIAN__
     396  	      avalue[i] = p;
     397  #else
     398  	      avalue[i] = ((char *) p) + sizeof (UINT32) - z;
     399  #endif
     400  	      break;
     401  
     402  	    default:
     403  	      FFI_ASSERT(0);
     404  	    }
     405  	}
     406        else if (z == sizeof (UINT32))
     407  	{
     408  	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
     409  	    {
     410  	      if (freg < NFREGARG - 1)
     411  		{
     412  		  if (fpair >= 0)
     413  		    {
     414  		      avalue[i] = (UINT32 *) pfr + fpair;
     415  		      fpair = -1;
     416  		    }
     417  		  else
     418  		    {
     419  #ifdef __LITTLE_ENDIAN__
     420  		      fpair = freg;
     421  		      avalue[i] = (UINT32 *) pfr + (1 ^ freg);
     422  #else
     423  		      fpair = 1 ^ freg;
     424  		      avalue[i] = (UINT32 *) pfr + freg;
     425  #endif
     426  		      freg += 2;
     427  		    }
     428  		}
     429  	      else
     430  #ifdef __LITTLE_ENDIAN__
     431  		avalue[i] = pgr + greg;
     432  #else
     433  		avalue[i] = (UINT32 *) (pgr + greg) + 1;
     434  #endif
     435  	    }
     436  	  else
     437  #ifdef __LITTLE_ENDIAN__
     438  	    avalue[i] = pgr + greg;
     439  #else
     440  	    avalue[i] = (UINT32 *) (pgr + greg) + 1;
     441  #endif
     442  	  greg++;
     443  	}
     444        else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
     445  	{
     446  	  if (freg + 1 >= NFREGARG)
     447  	    avalue[i] = pgr + greg;
     448  	  else
     449  	    {
     450  	      avalue[i] = pfr + (freg >> 1);
     451  	      freg += 2;
     452  	    }
     453  	  greg++;
     454  	}
     455        else
     456  	{
     457  	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
     458  
     459  	  avalue[i] = pgr + greg;
     460  	  greg += n;
     461  	}
     462      }
     463  
     464    (closure->fun) (cif, rvalue, avalue, closure->user_data);
     465  
     466    /* Tell ffi_closure_SYSV how to perform return type promotions.  */
     467    return return_type (cif->rtype);
     468  }
     469