(root)/
gcc-13.2.0/
libffi/
src/
metag/
ffi.c
       1  /* ----------------------------------------------------------------------
       2    ffi.c - Copyright (c) 2013 Imagination Technologies
       3  
       4    Meta Foreign Function Interface
       5    Permission is hereby granted, free of charge, to any person obtaining
       6    a copy of this software and associated documentation files (the
       7    `Software''), to deal in the Software without restriction, including
       8    without limitation the rights to use, copy, modify, merge, publish,
       9    distribute, sublicense, and/or sell copies of the Software, and to
      10    permit persons to whom the Software is furnished to do so, subject to
      11    the following conditions:
      12  
      13    The above copyright notice and this permission notice shall be included
      14    in all copies or substantial portions of the Software.
      15  
      16    THE SOFTWARE IS PROVIDED `AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
      17    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      18    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      19    IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
      20    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      21    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      22    OTHER DEALINGS IN THE SOFTWARE.
      23  ----------------------------------------------------------------------- */
      24  
      25  #include <ffi.h>
      26  #include <ffi_common.h>
      27  
      28  #include <stdlib.h>
      29  
      30  #define MIN(a,b) (((a) < (b)) ? (a) : (b))
      31  
      32  /*
      33   * ffi_prep_args is called by the assembly routine once stack space has been
      34   * allocated for the function's arguments
      35   */
      36  
      37  unsigned int 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  
      44  	argp = stack;
      45  
      46  	/* Store return value */
      47  	if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
      48  		argp -= 4;
      49  		*(void **) argp = ecif->rvalue;
      50  	}
      51  
      52  	p_argv = ecif->avalue;
      53  
      54  	/* point to next location */
      55  	for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
      56  	{
      57  		size_t z;
      58  
      59  		/* Move argp to address of argument */
      60  		z = (*p_arg)->size;
      61  		argp -= z;
      62  
      63  		/* Align if necessary */
      64  		argp = (char *) FFI_ALIGN_DOWN(FFI_ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
      65  
      66  		if (z < sizeof(int)) {
      67  			z = sizeof(int);
      68  			switch ((*p_arg)->type)
      69  			{
      70  			case FFI_TYPE_SINT8:
      71  				*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
      72  				break;
      73  			case FFI_TYPE_UINT8:
      74  				*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
      75  				break;
      76  			case FFI_TYPE_SINT16:
      77  				*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
      78  				break;
      79  			case FFI_TYPE_UINT16:
      80  				*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
      81  			case FFI_TYPE_STRUCT:
      82  				memcpy(argp, *p_argv, (*p_arg)->size);
      83  				break;
      84  			default:
      85  				FFI_ASSERT(0);
      86  			}
      87  		} else if ( z == sizeof(int)) {
      88  			*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
      89  		} else {
      90  			memcpy(argp, *p_argv, z);
      91  		}
      92  	}
      93  
      94  	/* return the size of the arguments to be passed in registers,
      95  	   padded to an 8 byte boundary to preserve stack alignment */
      96  	return FFI_ALIGN(MIN(stack - argp, 6*4), 8);
      97  }
      98  
      99  /* Perform machine dependent cif processing */
     100  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     101  {
     102  	ffi_type **ptr;
     103  	unsigned i, bytes = 0;
     104  
     105  	for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
     106  		if ((*ptr)->size == 0)
     107  			return FFI_BAD_TYPEDEF;
     108  
     109  		/* Perform a sanity check on the argument type, do this
     110  		   check after the initialization.  */
     111  		FFI_ASSERT_VALID_TYPE(*ptr);
     112  
     113  		/* Add any padding if necessary */
     114  		if (((*ptr)->alignment - 1) & bytes)
     115  			bytes = FFI_ALIGN(bytes, (*ptr)->alignment);
     116  
     117  		bytes += FFI_ALIGN((*ptr)->size, 4);
     118  	}
     119  
     120  	/* Ensure arg space is aligned to an 8-byte boundary */
     121  	bytes = FFI_ALIGN(bytes, 8);
     122  
     123  	/* Make space for the return structure pointer */
     124  	if (cif->rtype->type == FFI_TYPE_STRUCT) {
     125  		bytes += sizeof(void*);
     126  
     127  		/* Ensure stack is aligned to an 8-byte boundary */
     128  		bytes = FFI_ALIGN(bytes, 8);
     129  	}
     130  
     131  	cif->bytes = bytes;
     132  
     133  	/* Set the return type flag */
     134  	switch (cif->rtype->type) {
     135  	case FFI_TYPE_VOID:
     136  	case FFI_TYPE_FLOAT:
     137  	case FFI_TYPE_DOUBLE:
     138  		cif->flags = (unsigned) cif->rtype->type;
     139  		break;
     140  	case FFI_TYPE_SINT64:
     141  	case FFI_TYPE_UINT64:
     142  		cif->flags = (unsigned) FFI_TYPE_SINT64;
     143  		break;
     144  	case FFI_TYPE_STRUCT:
     145  		/* Meta can store return values which are <= 64 bits */
     146  		if (cif->rtype->size <= 4)
     147  			/* Returned to D0Re0 as 32-bit value */
     148  			cif->flags = (unsigned)FFI_TYPE_INT;
     149  		else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
     150  			/* Returned valued is stored to D1Re0|R0Re0 */
     151  			cif->flags = (unsigned)FFI_TYPE_DOUBLE;
     152  		else
     153  			/* value stored in memory */
     154  			cif->flags = (unsigned)FFI_TYPE_STRUCT;
     155  		break;
     156  	default:
     157  		cif->flags = (unsigned)FFI_TYPE_INT;
     158  		break;
     159  	}
     160  	return FFI_OK;
     161  }
     162  
     163  extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
     164  
     165  /*
     166   * Exported in API. Entry point
     167   * cif -> ffi_cif object
     168   * fn -> function pointer
     169   * rvalue -> pointer to return value
     170   * avalue -> vector of void * pointers pointing to memory locations holding the
     171   * arguments
     172   */
     173  void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     174  {
     175  	extended_cif ecif;
     176  
     177  	int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
     178  	ecif.cif = cif;
     179  	ecif.avalue = avalue;
     180  
     181  	double temp;
     182  
     183  	/*
     184  	 * If the return value is a struct and we don't have a return value address
     185  	 * then we need to make one
     186  	 */
     187  
     188  	if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
     189  		ecif.rvalue = alloca(cif->rtype->size);
     190  	else if (small_struct)
     191  		ecif.rvalue = &temp;
     192  	else
     193  		ecif.rvalue = rvalue;
     194  
     195  	switch (cif->abi) {
     196  	case FFI_SYSV:
     197  		ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
     198  		break;
     199  	default:
     200  		FFI_ASSERT(0);
     201  		break;
     202  	}
     203  
     204  	if (small_struct)
     205  		memcpy (rvalue, &temp, cif->rtype->size);
     206  }
     207  
     208  /* private members */
     209  
     210  static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
     211  	ffi_cif*, float *);
     212  
     213  void ffi_closure_SYSV (ffi_closure *);
     214  
     215  /* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
     216  extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
     217  
     218  /* end of private members */
     219  
     220  /*
     221   * __tramp: trampoline memory location
     222   * __fun: assembly routine
     223   * __ctx: memory location for wrapper
     224   *
     225   * At this point, tramp[0] == __ctx !
     226   */
     227  void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
     228  	memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
     229  	*(unsigned int*) &__tramp[40] = __ctx;
     230  	*(unsigned int*) &__tramp[44] = __fun;
     231  	/* This will flush the instruction cache */
     232  	__builtin_meta2_cachewd(&__tramp[0], 1);
     233  	__builtin_meta2_cachewd(&__tramp[47], 1);
     234  }
     235  
     236  
     237  
     238  /* the cif must already be prepared */
     239  
     240  ffi_status
     241  ffi_prep_closure_loc (ffi_closure *closure,
     242  	ffi_cif* cif,
     243  	void (*fun)(ffi_cif*,void*,void**,void*),
     244  	void *user_data,
     245  	void *codeloc)
     246  {
     247  	void (*closure_func)(ffi_closure*) = NULL;
     248  
     249  	if (cif->abi == FFI_SYSV)
     250  		closure_func = &ffi_closure_SYSV;
     251  	else
     252  		return FFI_BAD_ABI;
     253  
     254  	ffi_init_trampoline(
     255  		(unsigned char*)&closure->tramp[0],
     256  		(unsigned int)closure_func,
     257  		(unsigned int)codeloc);
     258  
     259  	closure->cif = cif;
     260  	closure->user_data = user_data;
     261  	closure->fun = fun;
     262  
     263  	return FFI_OK;
     264  }
     265  
     266  
     267  /* This function is jumped to by the trampoline */
     268  unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
     269  	ffi_closure *closure;
     270  	void **respp;
     271  	void *args;
     272  	void *vfp_args;
     273  {
     274  	ffi_cif *cif;
     275  	void **arg_area;
     276  
     277  	cif = closure->cif;
     278  	arg_area = (void**) alloca (cif->nargs * sizeof (void*));
     279  
     280  	/*
     281  	 * This call will initialize ARG_AREA, such that each
     282  	 * element in that array points to the corresponding
     283  	 * value on the stack; and if the function returns
     284  	 * a structure, it will re-set RESP to point to the
     285  	 * structure return address.
     286  	 */
     287  	ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
     288  
     289  	(closure->fun) ( cif, *respp, arg_area, closure->user_data);
     290  
     291  	return cif->flags;
     292  }
     293  
     294  static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
     295  	void **avalue, ffi_cif *cif,
     296  	float *vfp_stack)
     297  {
     298  	register unsigned int i;
     299  	register void **p_argv;
     300  	register char *argp;
     301  	register ffi_type **p_arg;
     302  
     303  	/* stack points to original arguments */
     304  	argp = stack;
     305  
     306  	/* Store return value */
     307  	if ( cif->flags == FFI_TYPE_STRUCT ) {
     308  		argp -= 4;
     309  		*rvalue = *(void **) argp;
     310  	}
     311  
     312  	p_argv = avalue;
     313  
     314  	for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
     315  		size_t z;
     316  		size_t alignment;
     317  
     318  		alignment = (*p_arg)->alignment;
     319  		if (alignment < 4)
     320  			alignment = 4;
     321  		if ((alignment - 1) & (unsigned)argp)
     322  			argp = (char *) FFI_ALIGN(argp, alignment);
     323  
     324  		z = (*p_arg)->size;
     325  		*p_argv = (void*) argp;
     326  		p_argv++;
     327  		argp -= z;
     328  	}
     329  	return;
     330  }