(root)/
gcc-13.2.0/
libffi/
src/
frv/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (C) 2004  Anthony Green
       3     Copyright (C) 2007  Free Software Foundation, Inc.
       4  	   Copyright (C) 2008  Red Hat, Inc.
       5     
       6     FR-V Foreign Function Interface 
       7  
       8     Permission is hereby granted, free of charge, to any person obtaining
       9     a copy of this software and associated documentation files (the
      10     ``Software''), to deal in the Software without restriction, including
      11     without limitation the rights to use, copy, modify, merge, publish,
      12     distribute, sublicense, and/or sell copies of the Software, and to
      13     permit persons to whom the Software is furnished to do so, subject to
      14     the following conditions:
      15  
      16     The above copyright notice and this permission notice shall be included
      17     in all copies or substantial portions of the Software.
      18  
      19     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      20     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      21     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      22     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      23     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      24     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      25     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26     DEALINGS IN THE SOFTWARE.
      27     ----------------------------------------------------------------------- */
      28  
      29  #include <ffi.h>
      30  #include <ffi_common.h>
      31  
      32  #include <stdlib.h>
      33  
      34  /* ffi_prep_args is called by the assembly routine once stack space
      35     has been allocated for the function's arguments */
      36  
      37  void *ffi_prep_args(char *stack, extended_cif *ecif)
      38  {
      39    register unsigned int i;
      40    register void **p_argv;
      41    register char *argp;
      42    register ffi_type **p_arg;
      43    register int count = 0;
      44  
      45    p_argv = ecif->avalue;
      46    argp = stack;
      47  
      48    for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
      49         (i != 0);
      50         i--, p_arg++)
      51      {
      52        size_t z;
      53        
      54        z = (*p_arg)->size;
      55  
      56        if ((*p_arg)->type == FFI_TYPE_STRUCT)
      57  	{
      58  	  z = sizeof(void*);
      59  	  *(void **) argp = *p_argv;
      60  	} 
      61        /*      if ((*p_arg)->type == FFI_TYPE_FLOAT)
      62  	{
      63  	  if (count > 24)
      64  	    {
      65  	      // This is going on the stack.  Turn it into a double.  
      66  	      *(double *) argp = (double) *(float*)(* p_argv);
      67  	      z = sizeof(double);
      68  	    }
      69  	  else
      70  	    *(void **) argp = *(void **)(* p_argv);
      71  	}  */
      72        else if (z < sizeof(int))
      73  	{
      74  	  z = sizeof(int);
      75  	  switch ((*p_arg)->type)
      76  	    {
      77  	    case FFI_TYPE_SINT8:
      78  	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
      79  	      break;
      80  	      
      81  	    case FFI_TYPE_UINT8:
      82  	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
      83  	      break;
      84  	      
      85  	    case FFI_TYPE_SINT16:
      86  	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
      87  	      break;
      88  		  
      89  	    case FFI_TYPE_UINT16:
      90  	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
      91  	      break;
      92  		  
      93  	    default:
      94  	      FFI_ASSERT(0);
      95  	    }
      96  	}
      97        else if (z == sizeof(int))
      98  	{
      99  	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
     100  	}
     101        else
     102  	{
     103  	  memcpy(argp, *p_argv, z);
     104  	}
     105        p_argv++;
     106        argp += z;
     107        count += z;
     108      }
     109  
     110    return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
     111  }
     112  
     113  /* Perform machine dependent cif processing */
     114  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     115  {
     116    if (cif->rtype->type == FFI_TYPE_STRUCT)
     117      cif->flags = -1;
     118    else
     119      cif->flags = cif->rtype->size;
     120  
     121    cif->bytes = FFI_ALIGN (cif->bytes, 8);
     122  
     123    return FFI_OK;
     124  }
     125  
     126  extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
     127  			  extended_cif *, 
     128  			  unsigned, unsigned, 
     129  			  unsigned *, 
     130  			  void (*fn)(void));
     131  
     132  void ffi_call(ffi_cif *cif, 
     133  	      void (*fn)(void), 
     134  	      void *rvalue, 
     135  	      void **avalue)
     136  {
     137    extended_cif ecif;
     138  
     139    ecif.cif = cif;
     140    ecif.avalue = avalue;
     141    
     142    /* If the return value is a struct and we don't have a return	*/
     143    /* value address then we need to make one		        */
     144  
     145    if ((rvalue == NULL) && 
     146        (cif->rtype->type == FFI_TYPE_STRUCT))
     147      {
     148        ecif.rvalue = alloca(cif->rtype->size);
     149      }
     150    else
     151      ecif.rvalue = rvalue;
     152      
     153    
     154    switch (cif->abi) 
     155      {
     156      case FFI_EABI:
     157        ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
     158  		    cif->flags, ecif.rvalue, fn);
     159        break;
     160      default:
     161        FFI_ASSERT(0);
     162        break;
     163      }
     164  }
     165  
     166  void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
     167  		       unsigned arg4, unsigned arg5, unsigned arg6)
     168  {
     169    /* This function is called by a trampoline.  The trampoline stows a
     170       pointer to the ffi_closure object in gr7.  We must save this
     171       pointer in a place that will persist while we do our work.  */
     172    register ffi_closure *creg __asm__ ("gr7");
     173    ffi_closure *closure = creg;
     174  
     175    /* Arguments that don't fit in registers are found on the stack
     176       at a fixed offset above the current frame pointer.  */
     177    register char *frame_pointer __asm__ ("fp");
     178    char *stack_args = frame_pointer + 16;
     179  
     180    /* Lay the register arguments down in a continuous chunk of memory.  */
     181    unsigned register_args[6] =
     182      { arg1, arg2, arg3, arg4, arg5, arg6 };
     183  
     184    ffi_cif *cif = closure->cif;
     185    ffi_type **arg_types = cif->arg_types;
     186    void **avalue = alloca (cif->nargs * sizeof(void *));
     187    char *ptr = (char *) register_args;
     188    int i;
     189  
     190    /* Find the address of each argument.  */
     191    for (i = 0; i < cif->nargs; i++)
     192      {
     193        switch (arg_types[i]->type)
     194  	{
     195  	case FFI_TYPE_SINT8:
     196  	case FFI_TYPE_UINT8:
     197  	  avalue[i] = ptr + 3;
     198  	  break;
     199  	case FFI_TYPE_SINT16:
     200  	case FFI_TYPE_UINT16:
     201  	  avalue[i] = ptr + 2;
     202  	  break;
     203  	case FFI_TYPE_SINT32:
     204  	case FFI_TYPE_UINT32:
     205  	case FFI_TYPE_FLOAT:
     206  	  avalue[i] = ptr;
     207  	  break;
     208  	case FFI_TYPE_STRUCT:
     209  	  avalue[i] = *(void**)ptr;
     210  	  break;
     211  	default:
     212  	  /* This is an 8-byte value.  */
     213  	  avalue[i] = ptr;
     214  	  ptr += 4;
     215  	  break;
     216  	}
     217        ptr += 4;
     218  
     219        /* If we've handled more arguments than fit in registers,
     220  	 start looking at the those passed on the stack.  */
     221        if (ptr == ((char *)register_args + (6*4)))
     222  	ptr = stack_args;
     223      }
     224  
     225    /* Invoke the closure.  */
     226    if (cif->rtype->type == FFI_TYPE_STRUCT)
     227      {
     228        /* The caller allocates space for the return structure, and
     229         passes a pointer to this space in gr3.  Use this value directly
     230         as the return value.  */
     231        register void *return_struct_ptr __asm__("gr3");
     232        (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
     233      }
     234    else
     235      {
     236        /* Allocate space for the return value and call the function.  */
     237        long long rvalue;
     238        (closure->fun) (cif, &rvalue, avalue, closure->user_data);
     239  
     240        /* Functions return 4-byte or smaller results in gr8.  8-byte
     241  	 values also use gr9.  We fill the both, even for small return
     242  	 values, just to avoid a branch.  */ 
     243        asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
     244        asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
     245      }
     246  }
     247  
     248  ffi_status
     249  ffi_prep_closure_loc (ffi_closure* closure,
     250  		      ffi_cif* cif,
     251  		      void (*fun)(ffi_cif*, void*, void**, void*),
     252  		      void *user_data,
     253  		      void *codeloc)
     254  {
     255    unsigned int *tramp = (unsigned int *) &closure->tramp[0];
     256    unsigned long fn = (long) ffi_closure_eabi;
     257    unsigned long cls = (long) codeloc;
     258  #ifdef __FRV_FDPIC__
     259    register void *got __asm__("gr15");
     260  #endif
     261    int i;
     262  
     263    fn = (unsigned long) ffi_closure_eabi;
     264  
     265  #ifdef __FRV_FDPIC__
     266    tramp[0] = &((unsigned int *)codeloc)[2];
     267    tramp[1] = got;
     268    tramp[2] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
     269    tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
     270    tramp[4] = 0x8cf80000 + (fn  >> 16);	  /* sethi hi(fn), gr6     */
     271    tramp[5] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
     272    tramp[6] = 0x9cc86000;                  /* ldi @(gr6, #0), gr14  */
     273    tramp[7] = 0x8030e000;                  /* jmpl @(gr14, gr0)     */
     274  #else
     275    tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
     276    tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
     277    tramp[2] = 0x8cf80000 + (fn  >> 16);	  /* sethi hi(fn), gr6     */
     278    tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
     279    tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
     280  #endif
     281  
     282    closure->cif = cif;
     283    closure->fun = fun;
     284    closure->user_data = user_data;
     285  
     286    /* Cache flushing.  */
     287    for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
     288      __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
     289  		      "r" (codeloc));
     290  
     291    return FFI_OK;
     292  }