OSDN Git Service

2908081a12ba649ffb33024745bc8b190346f121
[pf3gnuchains/gcc-fork.git] / libffi / src / ia64 / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1998 Red Hat, Inc.
3            Copyright (c) 2000 Hewlett Packard Company
4    
5    IA64 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, EXPRESS
19    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24    OTHER DEALINGS IN THE SOFTWARE.
25    ----------------------------------------------------------------------- */
26
27 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31 #include <stdbool.h>
32
33 #include "ia64_flags.h"
34
35 /* Memory image of fp register contents.  Should eventually be an fp    */
36 /* type long enough to hold an entire register.  For now we use double. */
37 typedef double float80;
38
39 /* The stack layout at call to ffi_prep_args.  Other_args will remain   */
40 /* on the stack for the actual call.  Everything else we be transferred */
41 /* to registers and popped by the assembly code.                        */
42
43 struct ia64_args {
44     long scratch[2];    /* Two scratch words at top of stack.           */
45                         /* Allows sp to be passed as arg pointer.       */
46     void * r8_contents; /* Value to be passed in r8                     */
47     long spare;         /* Not used.                                    */
48     float80 fp_regs[8]; /* Contents of 8 floating point argument        */
49                         /* registers.                                   */
50     long out_regs[8];   /* Contents of the 8 out registers used         */
51                         /* for integer parameters.                      */
52     long other_args[0]; /* Arguments passed on stack, variable size     */
53                         /* Treated as continuation of out_regs.         */
54 };
55
56 static size_t float_type_size(unsigned short tp)
57 {
58   switch(tp) {
59     case FFI_TYPE_FLOAT:
60       return sizeof(float);
61     case FFI_TYPE_DOUBLE:
62       return sizeof(double);
63 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
64     case FFI_TYPE_LONGDOUBLE:
65       return sizeof(long double);
66 #endif
67     default:
68       FFI_ASSERT(0);
69   }
70 }
71
72 /*
73  * Is type a struct containing at most n floats, doubles, or extended
74  * doubles, all of the same fp type?
75  * If so, set *element_type to the fp type.
76  */
77 static bool is_homogeneous_fp_aggregate(ffi_type * type, int n,
78                                         unsigned short * element_type)
79 {
80   ffi_type **ptr; 
81   unsigned short element, struct_element;
82
83   int type_set = 0;
84
85   FFI_ASSERT(type != NULL);
86
87   FFI_ASSERT(type->elements != NULL);
88
89   ptr = &(type->elements[0]);
90
91   while ((*ptr) != NULL)
92     {
93       switch((*ptr) -> type) {
94         case FFI_TYPE_FLOAT:
95           if (type_set && element != FFI_TYPE_FLOAT) return 0;
96           if (--n < 0) return FALSE;
97           type_set = 1;
98           element = FFI_TYPE_FLOAT;
99           break;
100         case FFI_TYPE_DOUBLE:
101           if (type_set && element != FFI_TYPE_DOUBLE) return 0;
102           if (--n < 0) return FALSE;
103           type_set = 1;
104           element = FFI_TYPE_DOUBLE;
105           break;
106         case FFI_TYPE_STRUCT:
107           if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
108               return FALSE;
109           if (type_set && struct_element != element) return FALSE;
110           n -= (type -> size)/float_type_size(element);
111           element = struct_element;
112           if (n < 0) return FALSE;
113           break;
114         /* case FFI_TYPE_LONGDOUBLE:
115           Not yet implemented.  */
116         default:
117           return FALSE;
118       }
119       ptr++;
120     }
121   *element_type = element;
122   return TRUE;
123    
124
125
126 /* ffi_prep_args is called by the assembly routine once stack space
127    has been allocated for the function's arguments.  It fills in
128    the arguments in the structure referenced by stack. Returns nonzero
129    if fp registers are used for arguments. */
130
131 static bool
132 ffi_prep_args(struct ia64_args *stack, extended_cif *ecif, int bytes)
133 {
134   register long i, avn;
135   register void **p_argv;
136   register long *argp = stack -> out_regs;
137   register float80 *fp_argp = stack -> fp_regs;
138   register ffi_type **p_arg;
139
140   /* For big return structs, r8 needs to contain the target address.    */
141   /* Since r8 is otherwise dead, we set it unconditionally.             */
142   stack -> r8_contents = ecif -> rvalue;
143   i = 0;
144   avn = ecif->cif->nargs;
145   p_arg = ecif->cif->arg_types;
146   p_argv = ecif->avalue;
147   while (i < avn)
148     {
149       size_t z; /* z is in units of arg slots or words, not bytes.      */
150
151       switch ((*p_arg)->type)
152         {
153         case FFI_TYPE_SINT8:
154           z = 1;
155           *(SINT64 *) argp = *(SINT8 *)(* p_argv);
156           break;
157                   
158         case FFI_TYPE_UINT8:
159           z = 1;
160           *(UINT64 *) argp = *(UINT8 *)(* p_argv);
161           break;
162                   
163         case FFI_TYPE_SINT16:
164           z = 1;
165           *(SINT64 *) argp = *(SINT16 *)(* p_argv);
166           break;
167                   
168         case FFI_TYPE_UINT16:
169           z = 1;
170           *(UINT64 *) argp = *(UINT16 *)(* p_argv);
171           break;
172                   
173         case FFI_TYPE_SINT32:
174           z = 1;
175           *(SINT64 *) argp = *(SINT32 *)(* p_argv);
176           break;
177                   
178         case FFI_TYPE_UINT32:
179           z = 1;
180           *(UINT64 *) argp = *(UINT32 *)(* p_argv);
181           break;
182
183         case FFI_TYPE_SINT64:
184         case FFI_TYPE_UINT64:
185         case FFI_TYPE_POINTER:
186           z = 1;
187           *(UINT64 *) argp = *(UINT64 *)(* p_argv);
188           break;
189
190         case FFI_TYPE_FLOAT:
191           z = 1;
192           if (fp_argp - stack->fp_regs < 8)
193             {
194               /* Note the conversion -- all the fp regs are loaded as
195                  doubles.  */
196               *fp_argp++ = *(float *)(* p_argv);
197             }
198           /* Also put it into the integer registers or memory: */
199             *(UINT64 *) argp = *(UINT32 *)(* p_argv);
200           break;
201
202         case FFI_TYPE_DOUBLE:
203           z = 1;
204           if (fp_argp - stack->fp_regs < 8)
205             *fp_argp++ = *(double *)(* p_argv);
206           /* Also put it into the integer registers or memory: */
207             *(double *) argp = *(double *)(* p_argv);
208           break;
209
210         case FFI_TYPE_STRUCT:
211           {
212               size_t sz = (*p_arg)->size;
213               unsigned short element_type;
214               z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
215               if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
216                 int i;
217                 int nelements = sz/float_type_size(element_type);
218                 for (i = 0; i < nelements; ++i) {
219                   switch (element_type) {
220                     case FFI_TYPE_FLOAT:
221                       if (fp_argp - stack->fp_regs < 8)
222                         *fp_argp++ = ((float *)(* p_argv))[i];
223                       break;
224                     case FFI_TYPE_DOUBLE:
225                       if (fp_argp - stack->fp_regs < 8)
226                         *fp_argp++ = ((double *)(* p_argv))[i];
227                       break;
228                     default:
229                         /* Extended precision not yet implemented. */
230                         abort();
231                   }
232                 }
233               }
234               /* And pass it in integer registers as a struct, with     */
235               /* its actual field sizes packed into registers.          */
236               memcpy(argp, *p_argv, (*p_arg)->size);
237           }
238           break;
239
240         default:
241           FFI_ASSERT(0);
242         }
243
244       argp += z;
245       i++, p_arg++, p_argv++;
246     }
247   return (fp_argp != stack -> fp_regs);
248 }
249
250 /* Perform machine dependent cif processing */
251 ffi_status
252 ffi_prep_cif_machdep(ffi_cif *cif)
253 {
254   long i, avn;
255   bool is_simple = TRUE;
256   long simple_flag = FFI_SIMPLE_V;
257   /* Adjust cif->bytes to include space for the 2 scratch words,
258      r8 register contents, spare word,
259      the 8 fp register contents, and all 8 integer register contents.
260      This will be removed before the call, though 2 scratch words must
261      remain.  */
262
263   cif->bytes += 4*sizeof(long) + 8 *sizeof(float80);
264   if (cif->bytes < sizeof(struct ia64_args))
265     cif->bytes = sizeof(struct ia64_args);
266
267   /* The stack must be double word aligned, so round bytes up
268      appropriately. */
269
270   cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
271
272   avn = cif->nargs;
273   if (avn <= 2) {
274     for (i = 0; i < avn; ++i) {
275       switch(cif -> arg_types[i] -> type) {
276         case FFI_TYPE_SINT32:
277           simple_flag = FFI_ADD_INT_ARG(simple_flag);
278           break;
279         case FFI_TYPE_SINT64:
280         case FFI_TYPE_UINT64:
281         case FFI_TYPE_POINTER:
282           simple_flag = FFI_ADD_LONG_ARG(simple_flag);
283           break;
284         default:
285           is_simple = FALSE;
286       }
287     }
288   } else {
289     is_simple = FALSE;
290   }
291
292   /* Set the return type flag */
293   switch (cif->rtype->type)
294     {
295     case FFI_TYPE_VOID:
296       cif->flags = FFI_TYPE_VOID;
297       break;
298
299     case FFI_TYPE_STRUCT:
300       {
301         size_t sz = cif -> rtype -> size;
302         unsigned short element_type;
303
304         is_simple = FALSE;
305         if (is_homogeneous_fp_aggregate(cif -> rtype, 8, &element_type)) {
306           int nelements = sz/float_type_size(element_type);
307           if (nelements <= 1) {
308             if (0 == nelements) {
309               cif -> flags = FFI_TYPE_VOID;
310             } else {
311               cif -> flags = element_type;
312             }
313           } else {
314             switch(element_type) {
315               case FFI_TYPE_FLOAT:
316                 cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
317                 break;
318               case FFI_TYPE_DOUBLE:
319                 cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
320                 break;
321               default:
322                 /* long double NYI */
323                 abort();
324             }
325           }
326           break;
327         }
328         if (sz <= 32) {
329           if (sz <= 8) {
330               cif->flags = FFI_TYPE_INT;
331           } else if (sz <= 16) {
332               cif->flags = FFI_IS_SMALL_STRUCT2;
333           } else if (sz <= 24) {
334               cif->flags = FFI_IS_SMALL_STRUCT3;
335           } else {
336               cif->flags = FFI_IS_SMALL_STRUCT4;
337           }
338         } else {
339           cif->flags = FFI_TYPE_STRUCT;
340         }
341       }
342       break;
343
344     case FFI_TYPE_FLOAT:
345       is_simple = FALSE;
346       cif->flags = FFI_TYPE_FLOAT;
347       break;
348
349     case FFI_TYPE_DOUBLE:
350       is_simple = FALSE;
351       cif->flags = FFI_TYPE_DOUBLE;
352       break;
353
354     default:
355       cif->flags = FFI_TYPE_INT;
356       /* This seems to depend on little endian mode, and the fact that  */
357       /* the return pointer always points to at least 8 bytes.  But     */
358       /* that also seems to be true for other platforms.                */
359       break;
360     }
361   
362   if (is_simple) cif -> flags |= simple_flag;
363   return FFI_OK;
364 }
365
366 extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int), 
367                          extended_cif *, unsigned, 
368                          unsigned, unsigned *, void (*)());
369
370 void
371 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
372 {
373   extended_cif ecif;
374   long simple = cif -> flags & FFI_SIMPLE;
375
376   /* Should this also check for Unix ABI? */
377   /* This is almost, but not quite, machine independent.  Note that     */
378   /* we can get away with not caring about length of the result because */
379   /* we assume we are little endian, and the result buffer is large     */
380   /* enough.                                                            */
381   /* This needs work for HP/UX.                                         */
382   if (simple) {
383     long (*lfn)() = (long (*)())fn;
384     long result;
385     switch(simple) {
386       case FFI_SIMPLE_V:
387         result = lfn();
388         break;
389       case FFI_SIMPLE_I:
390         result = lfn(*(int *)avalue[0]);
391         break;
392       case FFI_SIMPLE_L:
393         result = lfn(*(long *)avalue[0]);
394         break;
395       case FFI_SIMPLE_II:
396         result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
397         break;
398       case FFI_SIMPLE_IL:
399         result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
400         break;
401       case FFI_SIMPLE_LI:
402         result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
403         break;
404       case FFI_SIMPLE_LL:
405         result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
406         break;
407     }
408     if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
409       * (long *)rvalue = result;
410     }
411     return;
412   }
413   ecif.cif = cif;
414   ecif.avalue = avalue;
415   
416   /* If the return value is a struct and we don't have a return
417      value address then we need to make one.  */
418   
419   if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT)
420     ecif.rvalue = alloca(cif->rtype->size);
421   else
422     ecif.rvalue = rvalue;
423     
424   switch (cif->abi) 
425     {
426     case FFI_UNIX:
427       ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
428                     cif->flags, rvalue, fn);
429       break;
430
431     default:
432       FFI_ASSERT(0);
433       break;
434     }
435 }
436
437 /*
438  * Closures represent a pair consisting of a function pointer, and
439  * some user data.  A closure is invoked by reinterpreting the closure
440  * as a function pointer, and branching to it.  Thus we can make an
441  * interpreted function callable as a C function:  We turn the interpreter
442  * itself, together with a pointer specifying the interpreted procedure,
443  * into a closure.
444  * On X86, the first few words of the closure structure actually contain code,
445  * which will do the right thing.  On most other architectures, this
446  * would raise some Icache/Dcache coherence issues (which can be solved, but
447  * often not cheaply).
448  * For IA64, function pointer are already pairs consisting of a code
449  * pointer, and a gp pointer.  The latter is needed to access global variables.
450  * Here we set up such a pair as the first two words of the closure (in
451  * the "trampoline" area), but we replace the gp pointer with a pointer
452  * to the closure itself.  We also add the real gp pointer to the
453  * closure.  This allows the function entry code to both retrieve the
454  * user data, and to restire the correct gp pointer.
455  */
456
457 static void 
458 ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
459                             void **avalue, ffi_cif *cif);
460
461 /* This function is entered with the doctored gp (r1) value.
462  * This code is extremely gcc specific.  There is some argument that
463  * it should really be written in assembly code, since it depends on
464  * gcc properties that might change over time.
465  */
466
467 /* ffi_closure_UNIX is an assembly routine, which copies the register   */
468 /* state into a struct ia64_args, and then invokes                      */
469 /* ffi_closure_UNIX_inner.  It also recovers the closure pointer        */
470 /* from its fake gp pointer.                                            */
471 void ffi_closure_UNIX();
472
473 #ifndef __GNUC__
474 #   error This requires gcc
475 #endif
476 void
477 ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
478 /* Hopefully declaring this as a varargs function will force all args   */
479 /* to memory.                                                           */
480 {
481   // this is our return value storage
482   long double    res;
483
484   // our various things...
485   ffi_cif       *cif;
486   unsigned short rtype;
487   void          *resp;
488   void          **arg_area;
489
490   resp = (void*)&res;
491   cif         = closure->cif;
492   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
493
494   /* this call will initialize ARG_AREA, such that each
495    * element in that array points to the corresponding 
496    * value on the stack; and if the function returns
497    * a structure, it will re-set RESP to point to the
498    * structure return address.  */
499
500   ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
501   
502   (closure->fun) (cif, resp, arg_area, closure->user_data);
503
504   rtype = cif->flags;
505
506   /* now, do a generic return based on the value of rtype */
507   if (rtype == FFI_TYPE_INT)
508     {
509       asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
510     }
511   else if (rtype == FFI_TYPE_FLOAT)
512     {
513       asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
514     }
515   else if (rtype == FFI_TYPE_DOUBLE)
516     {
517       asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
518     }
519   else if (rtype == FFI_IS_SMALL_STRUCT2)
520     {
521       asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
522                     : : "r" (resp), "r" (resp+8) : "r8","r9");
523     }
524   else if (rtype == FFI_IS_SMALL_STRUCT3)
525     {
526       asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
527                     : : "r" (resp), "r" (resp+8), "r" (resp+16)
528                     : "r8","r9","r10");
529     }
530   else if (rtype == FFI_IS_SMALL_STRUCT4)
531     {
532       asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
533                     : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
534                     : "r8","r9","r10","r11");
535     }
536   else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
537     {
538       /* Can only happen for homogeneous FP aggregates? */
539       abort();
540     }
541 }
542
543 static void 
544 ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
545                             void **avalue, ffi_cif *cif)
546 {
547   register unsigned int i;
548   register unsigned int avn;
549   register void **p_argv;
550   register unsigned long *argp = args -> out_regs;
551   unsigned fp_reg_num = 0;
552   register ffi_type **p_arg;
553
554   avn = cif->nargs;
555   p_argv = avalue;
556
557   for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
558     {
559       size_t z; /* In units of words or argument slots. */
560
561       switch ((*p_arg)->type)
562         {
563         case FFI_TYPE_SINT8:
564         case FFI_TYPE_UINT8:
565         case FFI_TYPE_SINT16:
566         case FFI_TYPE_UINT16:
567         case FFI_TYPE_SINT32:
568         case FFI_TYPE_UINT32:
569         case FFI_TYPE_SINT64:
570         case FFI_TYPE_UINT64:
571         case FFI_TYPE_POINTER:
572           z = 1;
573           *p_argv = (void *)argp;
574           break;
575                   
576         case FFI_TYPE_FLOAT:
577           z = 1;
578           /* Convert argument back to float in place from the saved value */
579           if (fp_reg_num < 8) {
580               *(float *)argp = args -> fp_regs[fp_reg_num++];
581           } else {
582               *(float *)argp = *(double *)argp;
583           }
584           *p_argv = (void *)argp;
585           break;
586
587         case FFI_TYPE_DOUBLE:
588           z = 1;
589           if (fp_reg_num < 8) {
590               *p_argv = args -> fp_regs + fp_reg_num++;
591           } else {
592               *p_argv = (void *)argp;
593           }
594           break;
595
596         case FFI_TYPE_STRUCT:
597           {
598               size_t sz = (*p_arg)->size;
599               unsigned short element_type;
600               z = ((*p_arg)->size + FFI_SIZEOF_ARG - 1)/FFI_SIZEOF_ARG;
601               if (is_homogeneous_fp_aggregate(*p_arg, 8, &element_type)) {
602                 int nelements = sz/float_type_size(element_type);
603                 if (nelements + fp_reg_num >= 8) {
604                   /* hard case NYI.     */
605                   abort();
606                 }
607                 if (element_type == FFI_TYPE_DOUBLE) {
608                   *p_argv = args -> fp_regs + fp_reg_num;
609                   fp_reg_num += nelements;
610                   break;
611                 }
612                 if (element_type == FFI_TYPE_FLOAT) {
613                   int j;
614                   for (j = 0; j < nelements; ++ j) {
615                      ((float *)argp)[j] = args -> fp_regs[fp_reg_num + j];
616                   }
617                   *p_argv = (void *)argp;
618                   fp_reg_num += nelements;
619                   break;
620                 }
621                 abort();  /* Other fp types NYI */
622               }
623           }
624           break;
625
626         default:
627           FFI_ASSERT(0);
628         }
629
630       argp += z;
631       p_argv++;
632
633     }
634   
635   return;
636 }
637
638
639 /* Fill in a closure to refer to the specified fun and user_data.       */
640 /* cif specifies the argument and result types for fun.                 */
641 /* the cif must already be prep'ed */
642
643 /* The layout of a function descriptor.  A C function pointer really    */
644 /* points to one of these.                                              */
645 typedef struct ia64_fd_struct {
646     void *code_pointer;
647     void *gp;
648 } ia64_fd;
649
650 ffi_status
651 ffi_prep_closure (ffi_closure* closure,
652                   ffi_cif* cif,
653                   void (*fun)(ffi_cif*,void*,void**,void*),
654                   void *user_data)
655 {
656   struct ffi_ia64_trampoline_struct *tramp =
657     (struct ffi_ia64_trampoline_struct *) (closure -> tramp);
658   ia64_fd *fd = (ia64_fd *)(void *)ffi_closure_UNIX;
659
660   FFI_ASSERT (cif->abi == FFI_UNIX);
661
662   tramp -> code_pointer = fd -> code_pointer;
663   tramp -> real_gp = fd -> gp;
664   tramp -> fake_gp = closure;
665   closure->cif  = cif;
666   closure->user_data = user_data;
667   closure->fun  = fun;
668
669   return FFI_OK;
670 }
671
672