OSDN Git Service

b83d63dedc775d1855e8f9438662a82bafcf9729
[pf3gnuchains/gcc-fork.git] / libffi / src / sparc / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
3    
4    SPARC Foreign Function Interface 
5
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
13
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
16
17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23    OTHER DEALINGS IN THE SOFTWARE.
24    ----------------------------------------------------------------------- */
25
26 #include <ffi.h>
27 #include <ffi_common.h>
28
29 #include <stdlib.h>
30
31
32 /* ffi_prep_args is called by the assembly routine once stack space
33    has been allocated for the function's arguments */
34
35 void ffi_prep_args_v8(char *stack, extended_cif *ecif)
36 {
37   int i;
38   void **p_argv;
39   char *argp;
40   ffi_type **p_arg;
41
42   /* Skip 16 words for the window save area */
43   argp = stack + 16*sizeof(int);
44
45   /* This should only really be done when we are returning a structure,
46      however, it's faster just to do it all the time...
47
48   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
49   *(int *) argp = (long)ecif->rvalue;
50
51   /* And 1 word for the  structure return value. */
52   argp += sizeof(int);
53
54 #ifdef USING_PURIFY
55   /* Purify will probably complain in our assembly routine, unless we
56      zero out this memory. */
57
58   ((int*)argp)[0] = 0;
59   ((int*)argp)[1] = 0;
60   ((int*)argp)[2] = 0;
61   ((int*)argp)[3] = 0;
62   ((int*)argp)[4] = 0;
63   ((int*)argp)[5] = 0;
64 #endif
65
66   p_argv = ecif->avalue;
67
68   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
69     {
70       size_t z;
71
72           if ((*p_arg)->type == FFI_TYPE_STRUCT
73 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
74               || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
75 #endif
76               )
77             {
78               *(unsigned int *) argp = (unsigned long)(* p_argv);
79               z = sizeof(int);
80             }
81           else
82             {
83               z = (*p_arg)->size;
84               if (z < sizeof(int))
85                 {
86                   z = sizeof(int);
87                   switch ((*p_arg)->type)
88                     {
89                     case FFI_TYPE_SINT8:
90                       *(signed int *) argp = *(SINT8 *)(* p_argv);
91                       break;
92                       
93                     case FFI_TYPE_UINT8:
94                       *(unsigned int *) argp = *(UINT8 *)(* p_argv);
95                       break;
96                       
97                     case FFI_TYPE_SINT16:
98                       *(signed int *) argp = *(SINT16 *)(* p_argv);
99                       break;
100                       
101                     case FFI_TYPE_UINT16:
102                       *(unsigned int *) argp = *(UINT16 *)(* p_argv);
103                       break;
104
105                     default:
106                       FFI_ASSERT(0);
107                     }
108                 }
109               else
110                 {
111                   memcpy(argp, *p_argv, z);
112                 }
113             }
114           p_argv++;
115           argp += z;
116     }
117   
118   return;
119 }
120
121 int ffi_prep_args_v9(char *stack, extended_cif *ecif)
122 {
123   int i, ret = 0;
124   int tmp;
125   void **p_argv;
126   char *argp;
127   ffi_type **p_arg;
128
129   tmp = 0;
130
131   /* Skip 16 words for the window save area */
132   argp = stack + 16*sizeof(long long);
133
134 #ifdef USING_PURIFY
135   /* Purify will probably complain in our assembly routine, unless we
136      zero out this memory. */
137
138   ((long long*)argp)[0] = 0;
139   ((long long*)argp)[1] = 0;
140   ((long long*)argp)[2] = 0;
141   ((long long*)argp)[3] = 0;
142   ((long long*)argp)[4] = 0;
143   ((long long*)argp)[5] = 0;
144 #endif
145
146   p_argv = ecif->avalue;
147
148   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
149       ecif->cif->rtype->size > 32)
150     {
151       *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
152       argp += sizeof(long long);
153       tmp = 1;
154     }
155
156   for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
157        i++, p_arg++)
158     {
159       size_t z;
160
161       z = (*p_arg)->size;
162       switch ((*p_arg)->type)
163         {
164         case FFI_TYPE_STRUCT:
165           if (z > 16)
166             {
167               /* For structures larger than 16 bytes we pass reference.  */
168               *(unsigned long long *) argp = (unsigned long)* p_argv;
169               argp += sizeof(long long);
170               tmp++;
171               p_argv++;
172               continue;
173             }
174           /* FALLTHROUGH */
175         case FFI_TYPE_FLOAT:
176         case FFI_TYPE_DOUBLE:
177 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
178         case FFI_TYPE_LONGDOUBLE:
179 #endif
180           ret = 1; /* We should promote into FP regs as well as integer.  */
181           break;
182         }
183       if (z < sizeof(long long))
184         {
185           switch ((*p_arg)->type)
186             {
187             case FFI_TYPE_SINT8:
188               *(signed long long *) argp = *(SINT8 *)(* p_argv);
189               break;
190
191             case FFI_TYPE_UINT8:
192               *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
193               break;
194
195             case FFI_TYPE_SINT16:
196               *(signed long long *) argp = *(SINT16 *)(* p_argv);
197               break;
198
199             case FFI_TYPE_UINT16:
200               *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
201               break;
202
203             case FFI_TYPE_SINT32:
204               *(signed long long *) argp = *(SINT32 *)(* p_argv);
205               break;
206
207             case FFI_TYPE_UINT32:
208               *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
209               break;
210
211             case FFI_TYPE_FLOAT:
212               *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
213               break;
214
215             case FFI_TYPE_STRUCT:
216               memcpy(argp, *p_argv, z);
217               break;
218
219             default:
220               FFI_ASSERT(0);
221             }
222           z = sizeof(long long);
223           tmp++;
224         }
225       else if (z == sizeof(long long))
226         {
227           memcpy(argp, *p_argv, z);
228           z = sizeof(long long);
229           tmp++;
230         }
231       else
232         {
233           if ((tmp & 1) && (*p_arg)->alignment > 8)
234             {
235               tmp++;
236               argp += sizeof(long long);
237             }
238           memcpy(argp, *p_argv, z);
239           z = 2 * sizeof(long long);
240           tmp += 2;
241         }
242       p_argv++;
243       argp += z;
244     }
245
246   return ret;
247 }
248
249 /* Perform machine dependent cif processing */
250 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
251 {
252   int wordsize;
253
254   if (cif->abi != FFI_V9)
255     {
256       wordsize = 4;
257
258       /* If we are returning a struct, this will already have been added.
259          Otherwise we need to add it because it's always got to be there! */
260
261       if (cif->rtype->type != FFI_TYPE_STRUCT)
262         cif->bytes += wordsize;
263
264       /* sparc call frames require that space is allocated for 6 args,
265          even if they aren't used. Make that space if necessary. */
266   
267       if (cif->bytes < 4*6+4)
268         cif->bytes = 4*6+4;
269     }
270   else
271     {
272       wordsize = 8;
273
274       /* sparc call frames require that space is allocated for 6 args,
275          even if they aren't used. Make that space if necessary. */
276   
277       if (cif->bytes < 8*6)
278         cif->bytes = 8*6;
279     }
280
281   /* Adjust cif->bytes. to include 16 words for the window save area,
282      and maybe the struct/union return pointer area, */
283
284   cif->bytes += 16 * wordsize;
285
286   /* The stack must be 2 word aligned, so round bytes up
287      appropriately. */
288
289   cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
290
291   /* Set the return type flag */
292   switch (cif->rtype->type)
293     {
294     case FFI_TYPE_VOID:
295     case FFI_TYPE_FLOAT:
296     case FFI_TYPE_DOUBLE:
297 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
298     case FFI_TYPE_LONGDOUBLE:
299 #endif
300       cif->flags = cif->rtype->type;
301       break;
302
303     case FFI_TYPE_STRUCT:
304       if (cif->abi == FFI_V9 && cif->rtype->size > 32)
305         cif->flags = FFI_TYPE_VOID;
306       else
307         cif->flags = FFI_TYPE_STRUCT;
308       break;
309
310     case FFI_TYPE_SINT64:
311     case FFI_TYPE_UINT64:
312       if (cif->abi != FFI_V9)
313         {
314           cif->flags = FFI_TYPE_SINT64;
315           break;
316         }
317       /* FALLTHROUGH */
318     default:
319       cif->flags = FFI_TYPE_INT;
320       break;
321     }
322   return FFI_OK;
323 }
324
325 int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
326 {
327   ffi_type **ptr = &arg->elements[0];
328
329   while (*ptr != NULL)
330     {
331       if (off & ((*ptr)->alignment - 1))
332         off = ALIGN(off, (*ptr)->alignment);
333
334       switch ((*ptr)->type)
335         {
336         case FFI_TYPE_STRUCT:
337           off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
338           off = ALIGN(off, FFI_SIZEOF_ARG);
339           break;
340         case FFI_TYPE_FLOAT:
341         case FFI_TYPE_DOUBLE:
342 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
343         case FFI_TYPE_LONGDOUBLE:
344 #endif
345           memmove(ret + off, flt + off, (*ptr)->size);
346           off += (*ptr)->size;
347           break;
348         default:
349           memmove(ret + off, intg + off, (*ptr)->size);
350           off += (*ptr)->size;
351           break;
352         }
353       ptr++;
354     }
355   return off;
356 }
357
358
359 #ifdef SPARC64
360 extern int ffi_call_v9(void *, extended_cif *, unsigned, 
361                        unsigned, unsigned *, void (*fn)());
362 #else
363 extern int ffi_call_v8(void *, extended_cif *, unsigned, 
364                        unsigned, unsigned *, void (*fn)());
365 #endif
366
367 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
368 {
369   extended_cif ecif;
370   void *rval = rvalue;
371
372   ecif.cif = cif;
373   ecif.avalue = avalue;
374
375   /* If the return value is a struct and we don't have a return */
376   /* value address then we need to make one                     */
377
378   ecif.rvalue = rvalue;
379   if (cif->rtype->type == FFI_TYPE_STRUCT)
380     {
381       if (cif->rtype->size <= 32)
382         rval = alloca(64);
383       else
384         {
385           rval = NULL;
386           if (rvalue == NULL)
387             ecif.rvalue = alloca(cif->rtype->size);
388         }
389     }
390
391   switch (cif->abi) 
392     {
393     case FFI_V8:
394 #ifdef SPARC64
395       /* We don't yet support calling 32bit code from 64bit */
396       FFI_ASSERT(0);
397 #else
398       ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, 
399                   cif->flags, rvalue, fn);
400 #endif
401       break;
402     case FFI_V9:
403 #ifdef SPARC64
404       ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
405                   cif->flags, rval, fn);
406       if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
407         ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
408 #else
409       /* And vice versa */
410       FFI_ASSERT(0);
411 #endif
412       break;
413     default:
414       FFI_ASSERT(0);
415       break;
416     }
417
418 }
419
420
421 #ifdef SPARC64
422 extern void ffi_closure_v9(void);
423 #else
424 extern void ffi_closure_v8(void);
425 #endif
426
427 ffi_status
428 ffi_prep_closure (ffi_closure* closure,
429                   ffi_cif* cif,
430                   void (*fun)(ffi_cif*, void*, void**, void*),
431                   void *user_data)
432 {
433   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
434   unsigned long fn;
435 #ifdef SPARC64
436   /* Trampoline address is equal to the closure address.  We take advantage
437      of that to reduce the trampoline size by 8 bytes. */
438   FFI_ASSERT (cif->abi == FFI_V9);
439   fn = (unsigned long) ffi_closure_v9;
440   tramp[0] = 0x83414000;        /* rd   %pc, %g1        */
441   tramp[1] = 0xca586010;        /* ldx  [%g1+16], %g5   */
442   tramp[2] = 0x81c14000;        /* jmp  %g5             */
443   tramp[3] = 0x01000000;        /* nop                  */
444   *((unsigned long *) &tramp[4]) = fn;
445 #else
446   unsigned long ctx = (unsigned long) closure;
447   FFI_ASSERT (cif->abi == FFI_V8);
448   fn = (unsigned long) ffi_closure_v8;
449   tramp[0] = 0x03000000 | fn >> 10;     /* sethi %hi(fn), %g1   */
450   tramp[1] = 0x05000000 | ctx >> 10;    /* sethi %hi(ctx), %g2  */
451   tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp   %g1+%lo(fn)    */
452   tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)  */
453 #endif
454
455   closure->cif = cif;
456   closure->fun = fun;
457   closure->user_data = user_data;
458
459   /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
460 #ifdef SPARC64
461   asm volatile ("flush  %0" : : "r" (closure) : "memory");
462   asm volatile ("flush  %0" : : "r" (((char *) closure) + 8) : "memory");
463 #else
464   asm volatile ("iflush %0" : : "r" (closure) : "memory");
465   asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
466 #endif
467
468   return FFI_OK;
469 }
470
471 int
472 ffi_closure_sparc_inner_v8(ffi_closure *closure,
473   void *rvalue, unsigned long *gpr, unsigned long *scratch)
474 {
475   ffi_cif *cif;
476   ffi_type **arg_types;
477   void **avalue;
478   int i, argn;
479
480   cif = closure->cif;
481   arg_types = cif->arg_types;
482   avalue = alloca(cif->nargs * sizeof(void *));
483
484   /* Copy the caller's structure return address so that the closure
485      returns the data directly to the caller.  */
486   if (cif->flags == FFI_TYPE_STRUCT
487 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE  
488       || cif->flags == FFI_TYPE_LONGDOUBLE
489 #endif
490      )
491     rvalue = (void *) gpr[0];
492
493   /* Always skip the structure return address.  */
494   argn = 1;
495
496   /* Grab the addresses of the arguments from the stack frame.  */
497   for (i = 0; i < cif->nargs; i++)
498     {
499       if (arg_types[i]->type == FFI_TYPE_STRUCT
500 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
501           || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
502 #endif
503          )
504         {
505           /* Straight copy of invisible reference.  */
506           avalue[i] = (void *)gpr[argn++];
507         }
508       else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
509                || arg_types[i]->type == FFI_TYPE_SINT64
510                || arg_types[i]->type == FFI_TYPE_UINT64)
511                /* gpr is 8-byte aligned.  */
512                && (argn % 2) != 0)
513         {
514           /* Align on a 8-byte boundary.  */
515           scratch[0] = gpr[argn];
516           scratch[1] = gpr[argn+1];
517           avalue[i] = scratch;
518           scratch -= 2;
519           argn += 2;
520         }
521       else
522         {
523           /* Always right-justify.  */
524           argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
525           avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
526         }
527     }
528
529   /* Invoke the closure.  */
530   (closure->fun) (cif, rvalue, avalue, closure->user_data);
531
532   /* Tell ffi_closure_sparc how to perform return type promotions.  */
533   return cif->rtype->type;
534 }
535
536 int
537 ffi_closure_sparc_inner_v9(ffi_closure *closure,
538   void *rvalue, unsigned long *gpr, double *fpr)
539 {
540   ffi_cif *cif;
541   ffi_type **arg_types;
542   void **avalue;
543   int i, argn, fp_slot_max;
544
545   cif = closure->cif;
546   arg_types = cif->arg_types;
547   avalue = alloca(cif->nargs * sizeof(void *));
548
549   /* Copy the caller's structure return address so that the closure
550      returns the data directly to the caller.  */
551   if (cif->flags == FFI_TYPE_VOID
552       && cif->rtype->type == FFI_TYPE_STRUCT)
553     {
554       rvalue = (void *) gpr[0];
555       /* Skip the structure return address.  */
556       argn = 1;
557     }
558   else
559     argn = 0;
560
561   fp_slot_max = 16 - argn;
562
563   /* Grab the addresses of the arguments from the stack frame.  */
564   for (i = 0; i < cif->nargs; i++)
565     {
566       if (arg_types[i]->type == FFI_TYPE_STRUCT)
567         {
568           if (arg_types[i]->size > 16)
569             {
570               /* Straight copy of invisible reference.  */
571               avalue[i] = (void *)gpr[argn++];
572             }
573           else
574             {
575               /* Left-justify.  */
576               ffi_v9_layout_struct(arg_types[i],
577                                    0,
578                                    (char *) &gpr[argn],
579                                    (char *) &gpr[argn],
580                                    (char *) &fpr[argn]);
581               avalue[i] = &gpr[argn];
582               argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
583             }
584         }
585       else
586         {
587           /* Right-justify.  */
588           argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
589
590           if (i < fp_slot_max
591               && (arg_types[i]->type == FFI_TYPE_FLOAT
592                   || arg_types[i]->type == FFI_TYPE_DOUBLE
593 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
594                   || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
595 #endif
596                   ))
597             avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
598           else
599             avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
600         }
601     }
602
603   /* Invoke the closure.  */
604   (closure->fun) (cif, rvalue, avalue, closure->user_data);
605
606   /* Tell ffi_closure_sparc how to perform return type promotions.  */
607   return cif->rtype->type;
608 }