1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3 Copyright (c) 2000 Hewlett Packard Company
4 Copyright (c) 2011 Anthony Green
6 IA64 Foreign Function Interface
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 ``Software''), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice shall be included
17 in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 ----------------------------------------------------------------------- */
30 #include <ffi_common.h>
36 #include "ia64_flags.h"
38 /* A 64-bit pointer value. In LP64 mode, this is effectively a plain
39 pointer. In ILP32 mode, it's a pointer that's been extended to
40 64 bits by "addp4". */
41 typedef void *PTR64
__attribute__((mode(DI
)));
43 /* Memory image of fp register contents. This is the implementation
44 specific format used by ldf.fill/stf.spill. All we care about is
45 that it wants a 16 byte aligned slot. */
48 UINT64 x
[2] __attribute__((aligned(16)));
52 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
56 fpreg fp_regs
[8]; /* Contents of 8 fp arg registers. */
57 UINT64 gp_regs
[8]; /* Contents of 8 gp arg registers. */
58 UINT64 other_args
[]; /* Arguments passed on stack, variable size. */
62 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
65 endian_adjust (void *addr
, size_t len
)
68 return addr
+ (8 - len
);
74 /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
75 This is a macro instead of a function, so that it works for all 3 floating
76 point types without type conversions. Type conversion to long double breaks
77 the denorm support. */
79 #define stf_spill(addr, value) \
80 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
82 /* Load a value from ADDR, which is in the current cpu implementation's
83 fp spill format. As above, this must also be a macro. */
85 #define ldf_fill(result, addr) \
86 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
88 /* Return the size of the C type associated with with TYPE. Which will
89 be one of the FFI_IA64_TYPE_HFA_* values. */
92 hfa_type_size (int type
)
96 case FFI_IA64_TYPE_HFA_FLOAT
:
98 case FFI_IA64_TYPE_HFA_DOUBLE
:
99 return sizeof(double);
100 case FFI_IA64_TYPE_HFA_LDOUBLE
:
101 return sizeof(__float80
);
107 /* Load from ADDR a value indicated by TYPE. Which will be one of
108 the FFI_IA64_TYPE_HFA_* values. */
111 hfa_type_load (fpreg
*fpaddr
, int type
, void *addr
)
115 case FFI_IA64_TYPE_HFA_FLOAT
:
116 stf_spill (fpaddr
, *(float *) addr
);
118 case FFI_IA64_TYPE_HFA_DOUBLE
:
119 stf_spill (fpaddr
, *(double *) addr
);
121 case FFI_IA64_TYPE_HFA_LDOUBLE
:
122 stf_spill (fpaddr
, *(__float80
*) addr
);
129 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of
130 the FFI_IA64_TYPE_HFA_* values. */
133 hfa_type_store (int type
, void *addr
, fpreg
*fpaddr
)
137 case FFI_IA64_TYPE_HFA_FLOAT
:
140 ldf_fill (result
, fpaddr
);
141 *(float *) addr
= result
;
144 case FFI_IA64_TYPE_HFA_DOUBLE
:
147 ldf_fill (result
, fpaddr
);
148 *(double *) addr
= result
;
151 case FFI_IA64_TYPE_HFA_LDOUBLE
:
154 ldf_fill (result
, fpaddr
);
155 *(__float80
*) addr
= result
;
163 /* Is TYPE a struct containing floats, doubles, or extended doubles,
164 all of the same fp type? If so, return the element type. Return
165 FFI_TYPE_VOID if not. */
168 hfa_element_type (ffi_type
*type
, int nested
)
170 int element
= FFI_TYPE_VOID
;
175 /* We want to return VOID for raw floating-point types, but the
176 synthetic HFA type if we're nested within an aggregate. */
178 element
= FFI_IA64_TYPE_HFA_FLOAT
;
181 case FFI_TYPE_DOUBLE
:
184 element
= FFI_IA64_TYPE_HFA_DOUBLE
;
187 case FFI_TYPE_LONGDOUBLE
:
188 /* Similarly, except that that HFA is true for double extended,
189 but not quad precision. Both have sizeof == 16, so tell the
190 difference based on the precision. */
191 if (LDBL_MANT_DIG
== 64 && nested
)
192 element
= FFI_IA64_TYPE_HFA_LDOUBLE
;
195 case FFI_TYPE_STRUCT
:
197 ffi_type
**ptr
= &type
->elements
[0];
199 for (ptr
= &type
->elements
[0]; *ptr
; ptr
++)
201 int sub_element
= hfa_element_type (*ptr
, 1);
202 if (sub_element
== FFI_TYPE_VOID
)
203 return FFI_TYPE_VOID
;
205 if (element
== FFI_TYPE_VOID
)
206 element
= sub_element
;
207 else if (element
!= sub_element
)
208 return FFI_TYPE_VOID
;
214 return FFI_TYPE_VOID
;
221 /* Perform machine dependent cif processing. */
224 ffi_prep_cif_machdep(ffi_cif
*cif
)
228 /* Adjust cif->bytes to include space for the bits of the ia64_args frame
229 that precedes the integer register portion. The estimate that the
230 generic bits did for the argument space required is good enough for the
231 integer component. */
232 cif
->bytes
+= offsetof(struct ia64_args
, gp_regs
[0]);
233 if (cif
->bytes
< sizeof(struct ia64_args
))
234 cif
->bytes
= sizeof(struct ia64_args
);
236 /* Set the return type flag. */
237 flags
= cif
->rtype
->type
;
238 switch (cif
->rtype
->type
)
240 case FFI_TYPE_LONGDOUBLE
:
241 /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
242 and encode quad precision as a two-word integer structure. */
243 if (LDBL_MANT_DIG
!= 64)
244 flags
= FFI_IA64_TYPE_SMALL_STRUCT
| (16 << 8);
247 case FFI_TYPE_STRUCT
:
249 size_t size
= cif
->rtype
->size
;
250 int hfa_type
= hfa_element_type (cif
->rtype
, 0);
252 if (hfa_type
!= FFI_TYPE_VOID
)
254 size_t nelts
= size
/ hfa_type_size (hfa_type
);
256 flags
= hfa_type
| (size
<< 8);
261 flags
= FFI_IA64_TYPE_SMALL_STRUCT
| (size
<< 8);
274 extern int ffi_call_unix (struct ia64_args
*, PTR64
, void (*)(void), UINT64
);
277 ffi_call(ffi_cif
*cif
, void (*fn
)(void), void *rvalue
, void **avalue
)
279 struct ia64_args
*stack
;
280 long i
, avn
, gpcount
, fpcount
;
283 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
285 /* If we have no spot for a return value, make one. */
286 if (rvalue
== NULL
&& cif
->rtype
->type
!= FFI_TYPE_VOID
)
287 rvalue
= alloca (cif
->rtype
->size
);
289 /* Allocate the stack frame. */
290 stack
= alloca (cif
->bytes
);
292 gpcount
= fpcount
= 0;
294 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
296 switch ((*p_arg
)->type
)
299 stack
->gp_regs
[gpcount
++] = *(SINT8
*)avalue
[i
];
302 stack
->gp_regs
[gpcount
++] = *(UINT8
*)avalue
[i
];
304 case FFI_TYPE_SINT16
:
305 stack
->gp_regs
[gpcount
++] = *(SINT16
*)avalue
[i
];
307 case FFI_TYPE_UINT16
:
308 stack
->gp_regs
[gpcount
++] = *(UINT16
*)avalue
[i
];
310 case FFI_TYPE_SINT32
:
311 stack
->gp_regs
[gpcount
++] = *(SINT32
*)avalue
[i
];
313 case FFI_TYPE_UINT32
:
314 stack
->gp_regs
[gpcount
++] = *(UINT32
*)avalue
[i
];
316 case FFI_TYPE_SINT64
:
317 case FFI_TYPE_UINT64
:
318 stack
->gp_regs
[gpcount
++] = *(UINT64
*)avalue
[i
];
321 case FFI_TYPE_POINTER
:
322 stack
->gp_regs
[gpcount
++] = (UINT64
)(PTR64
) *(void **)avalue
[i
];
326 if (gpcount
< 8 && fpcount
< 8)
327 stf_spill (&stack
->fp_regs
[fpcount
++], *(float *)avalue
[i
]);
330 memcpy (&tmp
, avalue
[i
], sizeof (UINT32
));
331 stack
->gp_regs
[gpcount
++] = tmp
;
335 case FFI_TYPE_DOUBLE
:
336 if (gpcount
< 8 && fpcount
< 8)
337 stf_spill (&stack
->fp_regs
[fpcount
++], *(double *)avalue
[i
]);
338 memcpy (&stack
->gp_regs
[gpcount
++], avalue
[i
], sizeof (UINT64
));
341 case FFI_TYPE_LONGDOUBLE
:
344 if (LDBL_MANT_DIG
== 64 && gpcount
< 8 && fpcount
< 8)
345 stf_spill (&stack
->fp_regs
[fpcount
++], *(__float80
*)avalue
[i
]);
346 memcpy (&stack
->gp_regs
[gpcount
], avalue
[i
], 16);
350 case FFI_TYPE_STRUCT
:
352 size_t size
= (*p_arg
)->size
;
353 size_t align
= (*p_arg
)->alignment
;
354 int hfa_type
= hfa_element_type (*p_arg
, 0);
356 FFI_ASSERT (align
<= 16);
357 if (align
== 16 && (gpcount
& 1))
360 if (hfa_type
!= FFI_TYPE_VOID
)
362 size_t hfa_size
= hfa_type_size (hfa_type
);
364 size_t gp_offset
= gpcount
* 8;
368 && gp_offset
< 8 * 8)
370 hfa_type_load (&stack
->fp_regs
[fpcount
], hfa_type
,
373 gp_offset
+= hfa_size
;
378 memcpy (&stack
->gp_regs
[gpcount
], avalue
[i
], size
);
379 gpcount
+= (size
+ 7) / 8;
388 ffi_call_unix (stack
, rvalue
, fn
, cif
->flags
);
391 /* Closures represent a pair consisting of a function pointer, and
392 some user data. A closure is invoked by reinterpreting the closure
393 as a function pointer, and branching to it. Thus we can make an
394 interpreted function callable as a C function: We turn the
395 interpreter itself, together with a pointer specifying the
396 interpreted procedure, into a closure.
398 For IA64, function pointer are already pairs consisting of a code
399 pointer, and a gp pointer. The latter is needed to access global
400 variables. Here we set up such a pair as the first two words of
401 the closure (in the "trampoline" area), but we replace the gp
402 pointer with a pointer to the closure itself. We also add the real
403 gp pointer to the closure. This allows the function entry code to
404 both retrieve the user data, and to restore the correct gp pointer. */
406 extern void ffi_closure_unix ();
409 ffi_prep_closure_loc (ffi_closure
* closure
,
411 void (*fun
)(ffi_cif
*,void*,void**,void*),
415 /* The layout of a function descriptor. A C function pointer really
416 points to one of these. */
423 struct ffi_ia64_trampoline_struct
425 UINT64 code_pointer
; /* Pointer to ffi_closure_unix. */
426 UINT64 fake_gp
; /* Pointer to closure, installed as gp. */
427 UINT64 real_gp
; /* Real gp value. */
430 struct ffi_ia64_trampoline_struct
*tramp
;
433 if (cif
->abi
!= FFI_UNIX
)
436 tramp
= (struct ffi_ia64_trampoline_struct
*)closure
->tramp
;
437 fd
= (struct ia64_fd
*)(void *)ffi_closure_unix
;
439 tramp
->code_pointer
= fd
->code_pointer
;
440 tramp
->real_gp
= fd
->gp
;
441 tramp
->fake_gp
= (UINT64
)(PTR64
)codeloc
;
443 closure
->user_data
= user_data
;
451 ffi_closure_unix_inner (ffi_closure
*closure
, struct ia64_args
*stack
,
452 void *rvalue
, void *r8
)
457 long i
, avn
, gpcount
, fpcount
;
461 avalue
= alloca (avn
* sizeof (void *));
463 /* If the structure return value is passed in memory get that location
464 from r8 so as to pass the value directly back to the caller. */
465 if (cif
->flags
== FFI_TYPE_STRUCT
)
468 gpcount
= fpcount
= 0;
469 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
471 switch ((*p_arg
)->type
)
475 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 1);
477 case FFI_TYPE_SINT16
:
478 case FFI_TYPE_UINT16
:
479 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 2);
481 case FFI_TYPE_SINT32
:
482 case FFI_TYPE_UINT32
:
483 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 4);
485 case FFI_TYPE_SINT64
:
486 case FFI_TYPE_UINT64
:
487 avalue
[i
] = &stack
->gp_regs
[gpcount
++];
489 case FFI_TYPE_POINTER
:
490 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], sizeof(void*));
494 if (gpcount
< 8 && fpcount
< 8)
496 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
499 ldf_fill (result
, addr
);
500 *(float *)addr
= result
;
503 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
], 4);
507 case FFI_TYPE_DOUBLE
:
508 if (gpcount
< 8 && fpcount
< 8)
510 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
513 ldf_fill (result
, addr
);
514 *(double *)addr
= result
;
517 avalue
[i
] = &stack
->gp_regs
[gpcount
];
521 case FFI_TYPE_LONGDOUBLE
:
524 if (LDBL_MANT_DIG
== 64 && gpcount
< 8 && fpcount
< 8)
526 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
529 ldf_fill (result
, addr
);
530 *(__float80
*)addr
= result
;
533 avalue
[i
] = &stack
->gp_regs
[gpcount
];
537 case FFI_TYPE_STRUCT
:
539 size_t size
= (*p_arg
)->size
;
540 size_t align
= (*p_arg
)->alignment
;
541 int hfa_type
= hfa_element_type (*p_arg
, 0);
543 FFI_ASSERT (align
<= 16);
544 if (align
== 16 && (gpcount
& 1))
547 if (hfa_type
!= FFI_TYPE_VOID
)
549 size_t hfa_size
= hfa_type_size (hfa_type
);
551 size_t gp_offset
= gpcount
* 8;
552 void *addr
= alloca (size
);
558 && gp_offset
< 8 * 8)
560 hfa_type_store (hfa_type
, addr
+ offset
,
561 &stack
->fp_regs
[fpcount
]);
563 gp_offset
+= hfa_size
;
568 memcpy (addr
+ offset
, (char *)stack
->gp_regs
+ gp_offset
,
572 avalue
[i
] = &stack
->gp_regs
[gpcount
];
574 gpcount
+= (size
+ 7) / 8;
583 closure
->fun (cif
, rvalue
, avalue
, closure
->user_data
);