OSDN Git Service

libffi/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libffi / src / ia64 / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1998, 2007 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_loc (ffi_closure* closure,
404                       ffi_cif* cif,
405                       void (*fun)(ffi_cif*,void*,void**,void*),
406                       void *user_data,
407                       void *codeloc)
408 {
409   /* The layout of a function descriptor.  A C function pointer really 
410      points to one of these.  */
411   struct ia64_fd
412   {
413     UINT64 code_pointer;
414     UINT64 gp;
415   };
416
417   struct ffi_ia64_trampoline_struct
418   {
419     UINT64 code_pointer;        /* Pointer to ffi_closure_unix.  */
420     UINT64 fake_gp;             /* Pointer to closure, installed as gp.  */
421     UINT64 real_gp;             /* Real gp value.  */
422   };
423
424   struct ffi_ia64_trampoline_struct *tramp;
425   struct ia64_fd *fd;
426
427   FFI_ASSERT (cif->abi == FFI_UNIX);
428
429   tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
430   fd = (struct ia64_fd *)(void *)ffi_closure_unix;
431
432   tramp->code_pointer = fd->code_pointer;
433   tramp->real_gp = fd->gp;
434   tramp->fake_gp = (UINT64)(PTR64)codeloc;
435   closure->cif = cif;
436   closure->user_data = user_data;
437   closure->fun = fun;
438
439   return FFI_OK;
440 }
441
442
443 UINT64
444 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
445                         void *rvalue, void *r8)
446 {
447   ffi_cif *cif;
448   void **avalue;
449   ffi_type **p_arg;
450   long i, avn, gpcount, fpcount;
451
452   cif = closure->cif;
453   avn = cif->nargs;
454   avalue = alloca (avn * sizeof (void *));
455
456   /* If the structure return value is passed in memory get that location
457      from r8 so as to pass the value directly back to the caller.  */
458   if (cif->flags == FFI_TYPE_STRUCT)
459     rvalue = r8;
460
461   gpcount = fpcount = 0;
462   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
463     {
464       switch ((*p_arg)->type)
465         {
466         case FFI_TYPE_SINT8:
467         case FFI_TYPE_UINT8:
468           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
469           break;
470         case FFI_TYPE_SINT16:
471         case FFI_TYPE_UINT16:
472           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
473           break;
474         case FFI_TYPE_SINT32:
475         case FFI_TYPE_UINT32:
476           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
477           break;
478         case FFI_TYPE_SINT64:
479         case FFI_TYPE_UINT64:
480           avalue[i] = &stack->gp_regs[gpcount++];
481           break;
482         case FFI_TYPE_POINTER:
483           avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
484           break;
485
486         case FFI_TYPE_FLOAT:
487           if (gpcount < 8 && fpcount < 8)
488             {
489               fpreg *addr = &stack->fp_regs[fpcount++];
490               float result;
491               avalue[i] = addr;
492               ldf_fill (result, addr);
493               *(float *)addr = result;
494             }
495           else
496             avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
497           gpcount++;
498           break;
499
500         case FFI_TYPE_DOUBLE:
501           if (gpcount < 8 && fpcount < 8)
502             {
503               fpreg *addr = &stack->fp_regs[fpcount++];
504               double result;
505               avalue[i] = addr;
506               ldf_fill (result, addr);
507               *(double *)addr = result;
508             }
509           else
510             avalue[i] = &stack->gp_regs[gpcount];
511           gpcount++;
512           break;
513
514         case FFI_TYPE_LONGDOUBLE:
515           if (gpcount & 1)
516             gpcount++;
517           if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
518             {
519               fpreg *addr = &stack->fp_regs[fpcount++];
520               __float80 result;
521               avalue[i] = addr;
522               ldf_fill (result, addr);
523               *(__float80 *)addr = result;
524             }
525           else
526             avalue[i] = &stack->gp_regs[gpcount];
527           gpcount += 2;
528           break;
529
530         case FFI_TYPE_STRUCT:
531           {
532             size_t size = (*p_arg)->size;
533             size_t align = (*p_arg)->alignment;
534             int hfa_type = hfa_element_type (*p_arg, 0);
535
536             FFI_ASSERT (align <= 16);
537             if (align == 16 && (gpcount & 1))
538               gpcount++;
539
540             if (hfa_type != FFI_TYPE_VOID)
541               {
542                 size_t hfa_size = hfa_type_size (hfa_type);
543                 size_t offset = 0;
544                 size_t gp_offset = gpcount * 8;
545                 void *addr = alloca (size);
546
547                 avalue[i] = addr;
548
549                 while (fpcount < 8
550                        && offset < size
551                        && gp_offset < 8 * 8)
552                   {
553                     hfa_type_store (hfa_type, addr + offset,
554                                     &stack->fp_regs[fpcount]);
555                     offset += hfa_size;
556                     gp_offset += hfa_size;
557                     fpcount += 1;
558                   }
559
560                 if (offset < size)
561                   memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
562                           size - offset);
563               }
564             else
565               avalue[i] = &stack->gp_regs[gpcount];
566
567             gpcount += (size + 7) / 8;
568           }
569           break;
570
571         default:
572           abort ();
573         }
574     }
575
576   closure->fun (cif, rvalue, avalue, closure->user_data);
577
578   return cif->flags;
579 }