OSDN Git Service

Add ARM VFP ABI support to libffi.
[pf3gnuchains/gcc-fork.git] / libffi / src / arm / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1998, 2008  Red Hat, Inc.
3    
4    ARM 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,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24    DEALINGS IN THE SOFTWARE.
25    ----------------------------------------------------------------------- */
26
27 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31
32 /* Forward declares. */
33 static int vfp_type_p (ffi_type *);
34 static void layout_vfp_args (ffi_cif *);
35
36 /* ffi_prep_args is called by the assembly routine once stack space
37    has been allocated for the function's arguments
38    
39    The vfp_space parameter is the load area for VFP regs, the return
40    value is cif->vfp_used (word bitset of VFP regs used for passing
41    arguments). These are only used for the VFP hard-float ABI.
42 */
43 int ffi_prep_args(char *stack, extended_cif *ecif, float *vfp_space)
44 {
45   register unsigned int i, vi = 0;
46   register void **p_argv;
47   register char *argp;
48   register ffi_type **p_arg;
49
50   argp = stack;
51
52   if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
53     *(void **) argp = ecif->rvalue;
54     argp += 4;
55   }
56
57   p_argv = ecif->avalue;
58
59   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
60        (i != 0);
61        i--, p_arg++)
62     {
63       size_t z;
64
65       /* Allocated in VFP registers. */
66       if (ecif->cif->abi == FFI_VFP
67           && vi < ecif->cif->vfp_nargs && vfp_type_p (*p_arg))
68         {
69           float* vfp_slot = vfp_space + ecif->cif->vfp_args[vi++];
70           if ((*p_arg)->type == FFI_TYPE_FLOAT)
71             *((float*)vfp_slot) = *((float*)*p_argv);
72           else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
73             *((double*)vfp_slot) = *((double*)*p_argv);
74           else
75             memcpy(vfp_slot, *p_argv, (*p_arg)->size);
76           p_argv++;
77           continue;
78         }
79
80       /* Align if necessary */
81       if (((*p_arg)->alignment - 1) & (unsigned) argp) {
82         argp = (char *) ALIGN(argp, (*p_arg)->alignment);
83       }
84
85       if ((*p_arg)->type == FFI_TYPE_STRUCT)
86         argp = (char *) ALIGN(argp, 4);
87
88           z = (*p_arg)->size;
89           if (z < sizeof(int))
90             {
91               z = sizeof(int);
92               switch ((*p_arg)->type)
93                 {
94                 case FFI_TYPE_SINT8:
95                   *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
96                   break;
97                   
98                 case FFI_TYPE_UINT8:
99                   *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
100                   break;
101                   
102                 case FFI_TYPE_SINT16:
103                   *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
104                   break;
105                   
106                 case FFI_TYPE_UINT16:
107                   *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
108                   break;
109                   
110                 case FFI_TYPE_STRUCT:
111                   memcpy(argp, *p_argv, (*p_arg)->size);
112                   break;
113
114                 default:
115                   FFI_ASSERT(0);
116                 }
117             }
118           else if (z == sizeof(int))
119             {
120               *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
121             }
122           else
123             {
124               memcpy(argp, *p_argv, z);
125             }
126           p_argv++;
127           argp += z;
128     }
129
130   /* Indicate the VFP registers used. */
131   return ecif->cif->vfp_used;
132 }
133
134 /* Perform machine dependent cif processing */
135 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
136 {
137   int type_code;
138   /* Round the stack up to a multiple of 8 bytes.  This isn't needed 
139      everywhere, but it is on some platforms, and it doesn't harm anything
140      when it isn't needed.  */
141   cif->bytes = (cif->bytes + 7) & ~7;
142
143   /* Set the return type flag */
144   switch (cif->rtype->type)
145     {
146     case FFI_TYPE_VOID:
147     case FFI_TYPE_FLOAT:
148     case FFI_TYPE_DOUBLE:
149       cif->flags = (unsigned) cif->rtype->type;
150       break;
151
152     case FFI_TYPE_SINT64:
153     case FFI_TYPE_UINT64:
154       cif->flags = (unsigned) FFI_TYPE_SINT64;
155       break;
156
157     case FFI_TYPE_STRUCT:
158       if (cif->abi == FFI_VFP
159           && (type_code = vfp_type_p (cif->rtype)) != 0)
160         {
161           /* A Composite Type passed in VFP registers, either
162              FFI_TYPE_STRUCT_VFP_FLOAT or FFI_TYPE_STRUCT_VFP_DOUBLE. */
163           cif->flags = (unsigned) type_code;
164         }
165       else if (cif->rtype->size <= 4)
166         /* A Composite Type not larger than 4 bytes is returned in r0.  */
167         cif->flags = (unsigned)FFI_TYPE_INT;
168       else
169         /* A Composite Type larger than 4 bytes, or whose size cannot
170            be determined statically ... is stored in memory at an
171            address passed [in r0].  */
172         cif->flags = (unsigned)FFI_TYPE_STRUCT;
173       break;
174
175     default:
176       cif->flags = FFI_TYPE_INT;
177       break;
178     }
179
180   /* Map out the register placements of VFP register args.
181      The VFP hard-float calling conventions are slightly more sophisticated than
182      the base calling conventions, so we do it here instead of in ffi_prep_args(). */
183   if (cif->abi == FFI_VFP)
184     layout_vfp_args (cif);
185
186   return FFI_OK;
187 }
188
189 /* Prototypes for assembly functions, in sysv.S */
190 extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
191 extern void ffi_call_VFP (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
192
193 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
194 {
195   extended_cif ecif;
196
197   int small_struct = (cif->flags == FFI_TYPE_INT 
198                       && cif->rtype->type == FFI_TYPE_STRUCT);
199   int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT
200                     || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE);
201
202   ecif.cif = cif;
203   ecif.avalue = avalue;
204
205   unsigned int temp;
206   
207   /* If the return value is a struct and we don't have a return */
208   /* value address then we need to make one                     */
209
210   if ((rvalue == NULL) && 
211       (cif->flags == FFI_TYPE_STRUCT))
212     {
213       ecif.rvalue = alloca(cif->rtype->size);
214     }
215   else if (small_struct)
216     ecif.rvalue = &temp;
217   else if (vfp_struct)
218     {
219       /* Largest case is double x 4. */
220       ecif.rvalue = alloca(32);
221     }
222   else
223     ecif.rvalue = rvalue;
224
225   switch (cif->abi) 
226     {
227     case FFI_SYSV:
228       ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
229       break;
230
231     case FFI_VFP:
232       ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
233       break;
234
235     default:
236       FFI_ASSERT(0);
237       break;
238     }
239   if (small_struct)
240     memcpy (rvalue, &temp, cif->rtype->size);
241   else if (vfp_struct)
242     memcpy (rvalue, ecif.rvalue, cif->rtype->size);
243 }
244
245 /** private members **/
246
247 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
248                                          void** args, ffi_cif* cif, float *vfp_stack);
249
250 void ffi_closure_SYSV (ffi_closure *);
251
252 void ffi_closure_VFP (ffi_closure *);
253
254 /* This function is jumped to by the trampoline */
255
256 unsigned int
257 ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
258      ffi_closure *closure;
259      void **respp;
260      void *args;
261      void *vfp_args;
262 {
263   // our various things...
264   ffi_cif       *cif;
265   void         **arg_area;
266
267   cif         = closure->cif;
268   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
269
270   /* this call will initialize ARG_AREA, such that each
271    * element in that array points to the corresponding 
272    * value on the stack; and if the function returns
273    * a structure, it will re-set RESP to point to the
274    * structure return address.  */
275
276   ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
277
278   (closure->fun) (cif, *respp, arg_area, closure->user_data);
279
280   return cif->flags;
281 }
282
283 /*@-exportheader@*/
284 static void 
285 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
286                             void **avalue, ffi_cif *cif,
287                             /* Used only under VFP hard-float ABI. */
288                             float *vfp_stack)
289 /*@=exportheader@*/
290 {
291   register unsigned int i, vi = 0;
292   register void **p_argv;
293   register char *argp;
294   register ffi_type **p_arg;
295
296   argp = stack;
297
298   if ( cif->flags == FFI_TYPE_STRUCT ) {
299     *rvalue = *(void **) argp;
300     argp += 4;
301   }
302
303   p_argv = avalue;
304
305   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
306     {
307       size_t z;
308       size_t alignment;
309   
310       if (cif->abi == FFI_VFP
311           && vi < cif->vfp_nargs && vfp_type_p (*p_arg))
312         {
313           *p_argv++ = (void*)(vfp_stack + cif->vfp_args[vi++]);
314           continue;
315         }
316
317       alignment = (*p_arg)->alignment;
318       if (alignment < 4)
319         alignment = 4;
320       /* Align if necessary */
321       if ((alignment - 1) & (unsigned) argp) {
322         argp = (char *) ALIGN(argp, alignment);
323       }
324
325       z = (*p_arg)->size;
326
327       /* because we're little endian, this is what it turns into.   */
328
329       *p_argv = (void*) argp;
330
331       p_argv++;
332       argp += z;
333     }
334   
335   return;
336 }
337
338 /* How to make a trampoline.  */
339
340 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
341 ({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
342    unsigned int  __fun = (unsigned int)(FUN);                           \
343    unsigned int  __ctx = (unsigned int)(CTX);                           \
344    *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */  \
345    *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */        \
346    *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */        \
347    *(unsigned int*) &__tramp[12] = __ctx;                               \
348    *(unsigned int*) &__tramp[16] = __fun;                               \
349    __clear_cache((&__tramp[0]), (&__tramp[19]));                        \
350  })
351
352
353 /* the cif must already be prep'ed */
354
355 ffi_status
356 ffi_prep_closure_loc (ffi_closure* closure,
357                       ffi_cif* cif,
358                       void (*fun)(ffi_cif*,void*,void**,void*),
359                       void *user_data,
360                       void *codeloc)
361 {
362   void (*closure_func)(ffi_closure*) = NULL;
363
364   if (cif->abi == FFI_SYSV)
365     closure_func = &ffi_closure_SYSV;
366   else if (cif->abi == FFI_VFP)
367     closure_func = &ffi_closure_VFP;
368   else
369     FFI_ASSERT (0);
370     
371   FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
372                        closure_func,  \
373                        codeloc);
374     
375   closure->cif  = cif;
376   closure->user_data = user_data;
377   closure->fun  = fun;
378
379   return FFI_OK;
380 }
381
382 /* Below are routines for VFP hard-float support. */
383
384 static int rec_vfp_type_p (ffi_type *t, int *elt, int *elnum)
385 {
386   switch (t->type)
387     {
388     case FFI_TYPE_FLOAT:
389     case FFI_TYPE_DOUBLE:
390       *elt = (int) t->type;
391       *elnum = 1;
392       return 1;
393
394     case FFI_TYPE_STRUCT_VFP_FLOAT:
395       *elt = FFI_TYPE_FLOAT;
396       *elnum = t->size / sizeof (float);
397       return 1;
398
399     case FFI_TYPE_STRUCT_VFP_DOUBLE:
400       *elt = FFI_TYPE_DOUBLE;
401       *elnum = t->size / sizeof (double);
402       return 1;
403
404     case FFI_TYPE_STRUCT:;
405       {
406         int base_elt = 0, total_elnum = 0;
407         ffi_type **el = t->elements;
408         while (*el)
409           {
410             int el_elt = 0, el_elnum = 0;
411             if (! rec_vfp_type_p (*el, &el_elt, &el_elnum)
412                 || (base_elt && base_elt != el_elt)
413                 || total_elnum + el_elnum > 4)
414               return 0;
415             base_elt = el_elt;
416             total_elnum += el_elnum;
417             el++;
418           }
419         *elnum = total_elnum;
420         *elt = base_elt;
421         return 1;
422       }
423     default: ;
424     }
425   return 0;
426 }
427
428 static int vfp_type_p (ffi_type *t)
429 {
430   int elt, elnum;
431   if (rec_vfp_type_p (t, &elt, &elnum))
432     {
433       if (t->type == FFI_TYPE_STRUCT)
434         {
435           if (elnum == 1)
436             t->type = elt;
437           else
438             t->type = (elt == FFI_TYPE_FLOAT
439                        ? FFI_TYPE_STRUCT_VFP_FLOAT
440                        : FFI_TYPE_STRUCT_VFP_DOUBLE);
441         }
442       return (int) t->type;
443     }
444   return 0;
445 }
446
447 static void place_vfp_arg (ffi_cif *cif, ffi_type *t)
448 {
449   int reg = cif->vfp_reg_free;
450   int nregs = t->size / sizeof (float);
451   int align = ((t->type == FFI_TYPE_STRUCT_VFP_FLOAT
452                 || t->type == FFI_TYPE_FLOAT) ? 1 : 2);
453   /* Align register number. */
454   if ((reg & 1) && align == 2)
455     reg++;
456   while (reg + nregs <= 16)
457     {
458       int s, new_used = 0;
459       for (s = reg; s < reg + nregs; s++)
460         {
461           new_used |= (1 << s);
462           if (cif->vfp_used & (1 << s))
463             {
464               reg += align;
465               goto next_reg;
466             }
467         }
468       /* Found regs to allocate. */
469       cif->vfp_used |= new_used;
470       cif->vfp_args[cif->vfp_nargs++] = reg;
471
472       /* Update vfp_reg_free. */
473       if (cif->vfp_used & (1 << cif->vfp_reg_free))
474         {
475           reg += nregs;
476           while (cif->vfp_used & (1 << reg))
477             reg += 1;
478           cif->vfp_reg_free = reg;
479         }
480       return;
481     next_reg: ;
482     }
483 }
484
485 static void layout_vfp_args (ffi_cif *cif)
486 {
487   int i;
488   /* Init VFP fields */
489   cif->vfp_used = 0;
490   cif->vfp_nargs = 0;
491   cif->vfp_reg_free = 0;
492   memset (cif->vfp_args, -1, 16); /* Init to -1. */
493
494   for (i = 0; i < cif->nargs; i++)
495     {
496       ffi_type *t = cif->arg_types[i];
497       if (vfp_type_p (t))
498         place_vfp_arg (cif, t);
499     }
500 }