09021def3a44716fa6c9cd3cab31d242459ede46
[libffi.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 }