OSDN Git Service

Initial Contribution
[android-x86/external-libffi.git] / 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 #include <float.h>
33
34 #include "ia64_flags.h"
35
36 /* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
37    pointer.  In ILP32 mode, it's a pointer that's been extended to 
38    64 bits by "addp4".  */
39 typedef void *PTR64 __attribute__((mode(DI)));
40
41 /* Memory image of fp register contents.  This is the implementation
42    specific format used by ldf.fill/stf.spill.  All we care about is
43    that it wants a 16 byte aligned slot.  */
44 typedef struct
45 {
46   UINT64 x[2] __attribute__((aligned(16)));
47 } fpreg;
48
49
50 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner.  */
51
52 struct ia64_args
53 {
54   fpreg fp_regs[8];     /* Contents of 8 fp arg registers.  */
55   UINT64 gp_regs[8];    /* Contents of 8 gp arg registers.  */
56   UINT64 other_args[];  /* Arguments passed on stack, variable size.  */
57 };
58
59
60 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes.  */
61
62 static inline void *
63 endian_adjust (void *addr, size_t len)
64 {
65 #ifdef __BIG_ENDIAN__
66   return addr + (8 - len);
67 #else
68   return addr;
69 #endif
70 }
71
72 /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
73    This is a macro instead of a function, so that it works for all 3 floating
74    point types without type conversions.  Type conversion to long double breaks
75    the denorm support.  */
76
77 #define stf_spill(addr, value)  \
78   asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
79
80 /* Load a value from ADDR, which is in the current cpu implementation's
81    fp spill format.  As above, this must also be a macro.  */
82
83 #define ldf_fill(result, addr)  \
84   asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
85
86 /* Return the size of the C type associated with with TYPE.  Which will
87    be one of the FFI_IA64_TYPE_HFA_* values.  */
88
89 static size_t
90 hfa_type_size (int type)
91 {
92   switch (type)
93     {
94     case FFI_IA64_TYPE_HFA_FLOAT:
95       return sizeof(float);
96     case FFI_IA64_TYPE_HFA_DOUBLE:
97       return sizeof(double);
98     case FFI_IA64_TYPE_HFA_LDOUBLE:
99       return sizeof(__float80);
100     default:
101       abort ();
102     }
103 }
104
105 /* Load from ADDR a value indicated by TYPE.  Which will be one of
106    the FFI_IA64_TYPE_HFA_* values.  */
107
108 static void
109 hfa_type_load (fpreg *fpaddr, int type, void *addr)
110 {
111   switch (type)
112     {
113     case FFI_IA64_TYPE_HFA_FLOAT:
114       stf_spill (fpaddr, *(float *) addr);
115       return;
116     case FFI_IA64_TYPE_HFA_DOUBLE:
117       stf_spill (fpaddr, *(double *) addr);
118       return;
119     case FFI_IA64_TYPE_HFA_LDOUBLE:
120       stf_spill (fpaddr, *(__float80 *) addr);
121       return;
122     default:
123       abort ();
124     }
125 }
126
127 /* Load VALUE into ADDR as indicated by TYPE.  Which will be one of
128    the FFI_IA64_TYPE_HFA_* values.  */
129
130 static void
131 hfa_type_store (int type, void *addr, fpreg *fpaddr)
132 {
133   switch (type)
134     {
135     case FFI_IA64_TYPE_HFA_FLOAT:
136       {
137         float result;
138         ldf_fill (result, fpaddr);
139         *(float *) addr = result;
140         break;
141       }
142     case FFI_IA64_TYPE_HFA_DOUBLE:
143       {
144         double result;
145         ldf_fill (result, fpaddr);
146         *(double *) addr = result;
147         break;
148       }
149     case FFI_IA64_TYPE_HFA_LDOUBLE:
150       {
151         __float80 result;
152         ldf_fill (result, fpaddr);
153         *(__float80 *) addr = result;
154         break;
155       }
156     default:
157       abort ();
158     }
159 }
160
161 /* Is TYPE a struct containing floats, doubles, or extended doubles,
162    all of the same fp type?  If so, return the element type.  Return
163    FFI_TYPE_VOID if not.  */
164
165 static int
166 hfa_element_type (ffi_type *type, int nested)
167 {
168   int element = FFI_TYPE_VOID;
169
170   switch (type->type)
171     {
172     case FFI_TYPE_FLOAT:
173       /* We want to return VOID for raw floating-point types, but the
174          synthetic HFA type if we're nested within an aggregate.  */
175       if (nested)
176         element = FFI_IA64_TYPE_HFA_FLOAT;
177       break;
178
179     case FFI_TYPE_DOUBLE:
180       /* Similarly.  */
181       if (nested)
182         element = FFI_IA64_TYPE_HFA_DOUBLE;
183       break;
184
185     case FFI_TYPE_LONGDOUBLE:
186       /* Similarly, except that that HFA is true for double extended,
187          but not quad precision.  Both have sizeof == 16, so tell the
188          difference based on the precision.  */
189       if (LDBL_MANT_DIG == 64 && nested)
190         element = FFI_IA64_TYPE_HFA_LDOUBLE;
191       break;
192
193     case FFI_TYPE_STRUCT:
194       {
195         ffi_type **ptr = &type->elements[0];
196
197         for (ptr = &type->elements[0]; *ptr ; ptr++)
198           {
199             int sub_element = hfa_element_type (*ptr, 1);
200             if (sub_element == FFI_TYPE_VOID)
201               return FFI_TYPE_VOID;
202
203             if (element == FFI_TYPE_VOID)
204               element = sub_element;
205             else if (element != sub_element)
206               return FFI_TYPE_VOID;
207           }
208       }
209       break;
210
211     default:
212       return FFI_TYPE_VOID;
213     }
214
215   return element;
216 }
217
218
219 /* Perform machine dependent cif processing. */
220
221 ffi_status
222 ffi_prep_cif_machdep(ffi_cif *cif)
223 {
224   int flags;
225
226   /* Adjust cif->bytes to include space for the bits of the ia64_args frame
227      that preceeds the integer register portion.  The estimate that the 
228      generic bits did for the argument space required is good enough for the
229      integer component.  */
230   cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
231   if (cif->bytes < sizeof(struct ia64_args))
232     cif->bytes = sizeof(struct ia64_args);
233
234   /* Set the return type flag. */
235   flags = cif->rtype->type;
236   switch (cif->rtype->type)
237     {
238     case FFI_TYPE_LONGDOUBLE:
239       /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
240          and encode quad precision as a two-word integer structure.  */
241       if (LDBL_MANT_DIG != 64)
242         flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
243       break;
244
245     case FFI_TYPE_STRUCT:
246       {
247         size_t size = cif->rtype->size;
248         int hfa_type = hfa_element_type (cif->rtype, 0);
249
250         if (hfa_type != FFI_TYPE_VOID)
251           {
252             size_t nelts = size / hfa_type_size (hfa_type);
253             if (nelts <= 8)
254               flags = hfa_type | (size << 8);
255           }
256         else
257           {
258             if (size <= 32)
259               flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
260           }
261       }
262       break;
263
264     default:
265       break;
266     }
267   cif->flags = flags;
268
269   return FFI_OK;
270 }
271
272 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64);
273
274 void
275 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
276 {
277   struct ia64_args *stack;
278   long i, avn, gpcount, fpcount;
279   ffi_type **p_arg;
280
281   FFI_ASSERT (cif->abi == FFI_UNIX);
282
283   /* If we have no spot for a return value, make one.  */
284   if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
285     rvalue = alloca (cif->rtype->size);
286     
287   /* Allocate the stack frame.  */
288   stack = alloca (cif->bytes);
289
290   gpcount = fpcount = 0;
291   avn = cif->nargs;
292   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
293     {
294       switch ((*p_arg)->type)
295         {
296         case FFI_TYPE_SINT8:
297           stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
298           break;
299         case FFI_TYPE_UINT8:
300           stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
301           break;
302         case FFI_TYPE_SINT16:
303           stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
304           break;
305         case FFI_TYPE_UINT16:
306           stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
307           break;
308         case FFI_TYPE_SINT32:
309           stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
310           break;
311         case FFI_TYPE_UINT32:
312           stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
313           break;
314         case FFI_TYPE_SINT64:
315         case FFI_TYPE_UINT64:
316           stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
317           break;
318
319         case FFI_TYPE_POINTER:
320           stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
321           break;
322
323         case FFI_TYPE_FLOAT:
324           if (gpcount < 8 && fpcount < 8)
325             stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
326           stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
327           break;
328
329         case FFI_TYPE_DOUBLE:
330           if (gpcount < 8 && fpcount < 8)
331             stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
332           stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
333           break;
334
335         case FFI_TYPE_LONGDOUBLE:
336           if (gpcount & 1)
337             gpcount++;
338           if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
339             stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
340           memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
341           gpcount += 2;
342           break;
343
344         case FFI_TYPE_STRUCT:
345           {
346             size_t size = (*p_arg)->size;
347             size_t align = (*p_arg)->alignment;
348             int hfa_type = hfa_element_type (*p_arg, 0);
349
350             FFI_ASSERT (align <= 16);
351             if (align == 16 && (gpcount & 1))
352               gpcount++;
353
354             if (hfa_type != FFI_TYPE_VOID)
355               {
356                 size_t hfa_size = hfa_type_size (hfa_type);
357                 size_t offset = 0;
358                 size_t gp_offset = gpcount * 8;
359
360                 while (fpcount < 8
361                        && offset < size
362                        && gp_offset < 8 * 8)
363                   {
364                     hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
365                                    avalue[i] + offset);
366                     offset += hfa_size;
367                     gp_offset += hfa_size;
368                     fpcount += 1;
369                   }
370               }
371
372             memcpy (&stack->gp_regs[gpcount], avalue[i], size);
373             gpcount += (size + 7) / 8;
374           }
375           break;
376
377         default:
378           abort ();
379         }
380     }
381
382   ffi_call_unix (stack, rvalue, fn, cif->flags);
383 }
384
385 /* Closures represent a pair consisting of a function pointer, and
386    some user data.  A closure is invoked by reinterpreting the closure
387    as a function pointer, and branching to it.  Thus we can make an
388    interpreted function callable as a C function: We turn the
389    interpreter itself, together with a pointer specifying the
390    interpreted procedure, into a closure.
391
392    For IA64, function pointer are already pairs consisting of a code
393    pointer, and a gp pointer.  The latter is needed to access global
394    variables.  Here we set up such a pair as the first two words of
395    the closure (in the "trampoline" area), but we replace the gp
396    pointer with a pointer to the closure itself.  We also add the real
397    gp pointer to the closure.  This allows the function entry code to
398    both retrieve the user data, and to restire the correct gp pointer.  */
399
400 extern void ffi_closure_unix ();
401
402 ffi_status
403 ffi_prep_closure (ffi_closure* closure,
404                   ffi_cif* cif,
405                   void (*fun)(ffi_cif*,void*,void**,void*),
406                   void *user_data)
407 {
408   /* The layout of a function descriptor.  A C function pointer really 
409      points to one of these.  */
410   struct ia64_fd
411   {
412     UINT64 code_pointer;
413     UINT64 gp;
414   };
415
416   struct ffi_ia64_trampoline_struct
417   {
418     UINT64 code_pointer;        /* Pointer to ffi_closure_unix.  */
419     UINT64 fake_gp;             /* Pointer to closure, installed as gp.  */
420     UINT64 real_gp;             /* Real gp value.  */
421   };
422
423   struct ffi_ia64_trampoline_struct *tramp;
424   struct ia64_fd *fd;
425
426   FFI_ASSERT (cif->abi == FFI_UNIX);
427
428   tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
429   fd = (struct ia64_fd *)(void *)ffi_closure_unix;
430
431   tramp->code_pointer = fd->code_pointer;
432   tramp->real_gp = fd->gp;
433   tramp->fake_gp = (UINT64)(PTR64)closure;
434   closure->cif = cif;
435   closure->user_data = user_data;
436   closure->fun = fun;
437
438   return FFI_OK;
439 }
440
441
442 UINT64
443 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
444                         void *rvalue, void *r8)
445 {
446   ffi_cif *cif;
447   void **avalue;
448   ffi_type **p_arg;
449   long i, avn, gpcount, fpcount;
450
451   cif = closure->cif;
452   avn = cif->nargs;
453   avalue = alloca (avn * sizeof (void *));
454
455   /* If the structure return value is passed in memory get that location
456      from r8 so as to pass the value directly back to the caller.  */
457   if (cif->flags == FFI_TYPE_STRUCT)
458     rvalue = r8;
459
460   gpcount = fpcount = 0;
461   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
462     {
463       switch ((*p_arg)->type)
464         {
465         case FFI_TYPE_SINT8:
466         case FFI_TYPE_UINT8:
467           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
468           break;
469         case FFI_TYPE_SINT16:
470         case FFI_TYPE_UINT16:
471           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
472           break;
473         case FFI_TYPE_SINT32:
474         case FFI_TYPE_UINT32:
475           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
476           break;
477         case FFI_TYPE_SINT64:
478         case FFI_TYPE_UINT64:
479           avalue[i] = &stack->gp_regs[gpcount++];
480           break;
481         case FFI_TYPE_POINTER:
482           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
483           break;
484
485         case FFI_TYPE_FLOAT:
486           if (gpcount < 8 && fpcount < 8)
487             {
488               fpreg *addr = &stack->fp_regs[fpcount++];
489               float result;
490               avalue[i] = addr;
491               ldf_fill (result, addr);
492               *(float *)addr = result;
493             }
494           else
495             avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
496           gpcount++;
497           break;
498
499         case FFI_TYPE_DOUBLE:
500           if (gpcount < 8 && fpcount < 8)
501             {
502               fpreg *addr = &stack->fp_regs[fpcount++];
503               double result;
504               avalue[i] = addr;
505               ldf_fill (result, addr);
506               *(double *)addr = result;
507             }
508           else
509             avalue[i] = &stack->gp_regs[gpcount];
510           gpcount++;
511           break;
512
513         case FFI_TYPE_LONGDOUBLE:
514           if (gpcount & 1)
515             gpcount++;
516           if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
517             {
518               fpreg *addr = &stack->fp_regs[fpcount++];
519               __float80 result;
520               avalue[i] = addr;
521               ldf_fill (result, addr);
522               *(__float80 *)addr = result;
523             }
524           else
525             avalue[i] = &stack->gp_regs[gpcount];
526           gpcount += 2;
527           break;
528
529         case FFI_TYPE_STRUCT:
530           {
531             size_t size = (*p_arg)->size;
532             size_t align = (*p_arg)->alignment;
533             int hfa_type = hfa_element_type (*p_arg, 0);
534
535             FFI_ASSERT (align <= 16);
536             if (align == 16 && (gpcount & 1))
537               gpcount++;
538
539             if (hfa_type != FFI_TYPE_VOID)
540               {
541                 size_t hfa_size = hfa_type_size (hfa_type);
542                 size_t offset = 0;
543                 size_t gp_offset = gpcount * 8;
544                 void *addr = alloca (size);
545
546                 avalue[i] = addr;
547
548                 while (fpcount < 8
549                        && offset < size
550                        && gp_offset < 8 * 8)
551                   {
552                     hfa_type_store (hfa_type, addr + offset,
553                                     &stack->fp_regs[fpcount]);
554                     offset += hfa_size;
555                     gp_offset += hfa_size;
556                     fpcount += 1;
557                   }
558
559                 if (offset < size)
560                   memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
561                           size - offset);
562               }
563             else
564               avalue[i] = &stack->gp_regs[gpcount];
565
566             gpcount += (size + 7) / 8;
567           }
568           break;
569
570         default:
571           abort ();
572         }
573     }
574
575   closure->fun (cif, rvalue, avalue, closure->user_data);
576
577   return cif->flags;
578 }