PageRenderTime 811ms CodeModel.GetById 510ms app.highlight 176ms RepoModel.GetById 120ms app.codeStats 0ms

/Modules/_ctypes/libffi/src/sh64/ffi.c

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