github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/frv/ffi.c (about)

     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 : 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 = 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  }