1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998, 2007 Red Hat, Inc.
3 Copyright (c) 2000 Hewlett Packard Company
5 IA64 Foreign Function Interface
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:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
29 #include <ffi_common.h>
35 #include "ia64_flags.h"
37 /* A 64-bit pointer value. In LP64 mode, this is effectively a plain
38 pointer. In ILP32 mode, it's a pointer that's been extended to
39 64 bits by "addp4". */
40 typedef void *PTR64
__attribute__((mode(DI
)));
42 /* Memory image of fp register contents. This is the implementation
43 specific format used by ldf.fill/stf.spill. All we care about is
44 that it wants a 16 byte aligned slot. */
47 UINT64 x
[2] __attribute__((aligned(16)));
51 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
55 fpreg fp_regs
[8]; /* Contents of 8 fp arg registers. */
56 UINT64 gp_regs
[8]; /* Contents of 8 gp arg registers. */
57 UINT64 other_args
[]; /* Arguments passed on stack, variable size. */
61 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
64 endian_adjust (void *addr
, size_t len
)
67 return addr
+ (8 - len
);
73 /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
74 This is a macro instead of a function, so that it works for all 3 floating
75 point types without type conversions. Type conversion to long double breaks
76 the denorm support. */
78 #define stf_spill(addr, value) \
79 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
81 /* Load a value from ADDR, which is in the current cpu implementation's
82 fp spill format. As above, this must also be a macro. */
84 #define ldf_fill(result, addr) \
85 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87 /* Return the size of the C type associated with with TYPE. Which will
88 be one of the FFI_IA64_TYPE_HFA_* values. */
91 hfa_type_size (int type
)
95 case FFI_IA64_TYPE_HFA_FLOAT
:
97 case FFI_IA64_TYPE_HFA_DOUBLE
:
98 return sizeof(double);
99 case FFI_IA64_TYPE_HFA_LDOUBLE
:
100 return sizeof(__float80
);
106 /* Load from ADDR a value indicated by TYPE. Which will be one of
107 the FFI_IA64_TYPE_HFA_* values. */
110 hfa_type_load (fpreg
*fpaddr
, int type
, void *addr
)
114 case FFI_IA64_TYPE_HFA_FLOAT
:
115 stf_spill (fpaddr
, *(float *) addr
);
117 case FFI_IA64_TYPE_HFA_DOUBLE
:
118 stf_spill (fpaddr
, *(double *) addr
);
120 case FFI_IA64_TYPE_HFA_LDOUBLE
:
121 stf_spill (fpaddr
, *(__float80
*) addr
);
128 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of
129 the FFI_IA64_TYPE_HFA_* values. */
132 hfa_type_store (int type
, void *addr
, fpreg
*fpaddr
)
136 case FFI_IA64_TYPE_HFA_FLOAT
:
139 ldf_fill (result
, fpaddr
);
140 *(float *) addr
= result
;
143 case FFI_IA64_TYPE_HFA_DOUBLE
:
146 ldf_fill (result
, fpaddr
);
147 *(double *) addr
= result
;
150 case FFI_IA64_TYPE_HFA_LDOUBLE
:
153 ldf_fill (result
, fpaddr
);
154 *(__float80
*) addr
= result
;
162 /* Is TYPE a struct containing floats, doubles, or extended doubles,
163 all of the same fp type? If so, return the element type. Return
164 FFI_TYPE_VOID if not. */
167 hfa_element_type (ffi_type
*type
, int nested
)
169 int element
= FFI_TYPE_VOID
;
174 /* We want to return VOID for raw floating-point types, but the
175 synthetic HFA type if we're nested within an aggregate. */
177 element
= FFI_IA64_TYPE_HFA_FLOAT
;
180 case FFI_TYPE_DOUBLE
:
183 element
= FFI_IA64_TYPE_HFA_DOUBLE
;
186 case FFI_TYPE_LONGDOUBLE
:
187 /* Similarly, except that that HFA is true for double extended,
188 but not quad precision. Both have sizeof == 16, so tell the
189 difference based on the precision. */
190 if (LDBL_MANT_DIG
== 64 && nested
)
191 element
= FFI_IA64_TYPE_HFA_LDOUBLE
;
194 case FFI_TYPE_STRUCT
:
196 ffi_type
**ptr
= &type
->elements
[0];
198 for (ptr
= &type
->elements
[0]; *ptr
; ptr
++)
200 int sub_element
= hfa_element_type (*ptr
, 1);
201 if (sub_element
== FFI_TYPE_VOID
)
202 return FFI_TYPE_VOID
;
204 if (element
== FFI_TYPE_VOID
)
205 element
= sub_element
;
206 else if (element
!= sub_element
)
207 return FFI_TYPE_VOID
;
213 return FFI_TYPE_VOID
;
220 /* Perform machine dependent cif processing. */
223 ffi_prep_cif_machdep(ffi_cif
*cif
)
227 /* Adjust cif->bytes to include space for the bits of the ia64_args frame
228 that preceeds the integer register portion. The estimate that the
229 generic bits did for the argument space required is good enough for the
230 integer component. */
231 cif
->bytes
+= offsetof(struct ia64_args
, gp_regs
[0]);
232 if (cif
->bytes
< sizeof(struct ia64_args
))
233 cif
->bytes
= sizeof(struct ia64_args
);
235 /* Set the return type flag. */
236 flags
= cif
->rtype
->type
;
237 switch (cif
->rtype
->type
)
239 case FFI_TYPE_LONGDOUBLE
:
240 /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
241 and encode quad precision as a two-word integer structure. */
242 if (LDBL_MANT_DIG
!= 64)
243 flags
= FFI_IA64_TYPE_SMALL_STRUCT
| (16 << 8);
246 case FFI_TYPE_STRUCT
:
248 size_t size
= cif
->rtype
->size
;
249 int hfa_type
= hfa_element_type (cif
->rtype
, 0);
251 if (hfa_type
!= FFI_TYPE_VOID
)
253 size_t nelts
= size
/ hfa_type_size (hfa_type
);
255 flags
= hfa_type
| (size
<< 8);
260 flags
= FFI_IA64_TYPE_SMALL_STRUCT
| (size
<< 8);
273 extern int ffi_call_unix (struct ia64_args
*, PTR64
, void (*)(), UINT64
);
276 ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
278 struct ia64_args
*stack
;
279 long i
, avn
, gpcount
, fpcount
;
282 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
284 /* If we have no spot for a return value, make one. */
285 if (rvalue
== NULL
&& cif
->rtype
->type
!= FFI_TYPE_VOID
)
286 rvalue
= alloca (cif
->rtype
->size
);
288 /* Allocate the stack frame. */
289 stack
= alloca (cif
->bytes
);
291 gpcount
= fpcount
= 0;
293 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
295 switch ((*p_arg
)->type
)
298 stack
->gp_regs
[gpcount
++] = *(SINT8
*)avalue
[i
];
301 stack
->gp_regs
[gpcount
++] = *(UINT8
*)avalue
[i
];
303 case FFI_TYPE_SINT16
:
304 stack
->gp_regs
[gpcount
++] = *(SINT16
*)avalue
[i
];
306 case FFI_TYPE_UINT16
:
307 stack
->gp_regs
[gpcount
++] = *(UINT16
*)avalue
[i
];
309 case FFI_TYPE_SINT32
:
310 stack
->gp_regs
[gpcount
++] = *(SINT32
*)avalue
[i
];
312 case FFI_TYPE_UINT32
:
313 stack
->gp_regs
[gpcount
++] = *(UINT32
*)avalue
[i
];
315 case FFI_TYPE_SINT64
:
316 case FFI_TYPE_UINT64
:
317 stack
->gp_regs
[gpcount
++] = *(UINT64
*)avalue
[i
];
320 case FFI_TYPE_POINTER
:
321 stack
->gp_regs
[gpcount
++] = (UINT64
)(PTR64
) *(void **)avalue
[i
];
325 if (gpcount
< 8 && fpcount
< 8)
326 stf_spill (&stack
->fp_regs
[fpcount
++], *(float *)avalue
[i
]);
327 stack
->gp_regs
[gpcount
++] = *(UINT32
*)avalue
[i
];
330 case FFI_TYPE_DOUBLE
:
331 if (gpcount
< 8 && fpcount
< 8)
332 stf_spill (&stack
->fp_regs
[fpcount
++], *(double *)avalue
[i
]);
333 stack
->gp_regs
[gpcount
++] = *(UINT64
*)avalue
[i
];
336 case FFI_TYPE_LONGDOUBLE
:
339 if (LDBL_MANT_DIG
== 64 && gpcount
< 8 && fpcount
< 8)
340 stf_spill (&stack
->fp_regs
[fpcount
++], *(__float80
*)avalue
[i
]);
341 memcpy (&stack
->gp_regs
[gpcount
], avalue
[i
], 16);
345 case FFI_TYPE_STRUCT
:
347 size_t size
= (*p_arg
)->size
;
348 size_t align
= (*p_arg
)->alignment
;
349 int hfa_type
= hfa_element_type (*p_arg
, 0);
351 FFI_ASSERT (align
<= 16);
352 if (align
== 16 && (gpcount
& 1))
355 if (hfa_type
!= FFI_TYPE_VOID
)
357 size_t hfa_size
= hfa_type_size (hfa_type
);
359 size_t gp_offset
= gpcount
* 8;
363 && gp_offset
< 8 * 8)
365 hfa_type_load (&stack
->fp_regs
[fpcount
], hfa_type
,
368 gp_offset
+= hfa_size
;
373 memcpy (&stack
->gp_regs
[gpcount
], avalue
[i
], size
);
374 gpcount
+= (size
+ 7) / 8;
383 ffi_call_unix (stack
, rvalue
, fn
, cif
->flags
);
386 /* Closures represent a pair consisting of a function pointer, and
387 some user data. A closure is invoked by reinterpreting the closure
388 as a function pointer, and branching to it. Thus we can make an
389 interpreted function callable as a C function: We turn the
390 interpreter itself, together with a pointer specifying the
391 interpreted procedure, into a closure.
393 For IA64, function pointer are already pairs consisting of a code
394 pointer, and a gp pointer. The latter is needed to access global
395 variables. Here we set up such a pair as the first two words of
396 the closure (in the "trampoline" area), but we replace the gp
397 pointer with a pointer to the closure itself. We also add the real
398 gp pointer to the closure. This allows the function entry code to
399 both retrieve the user data, and to restire the correct gp pointer. */
401 extern void ffi_closure_unix ();
404 ffi_prep_closure_loc (ffi_closure
* closure
,
406 void (*fun
)(ffi_cif
*,void*,void**,void*),
410 /* The layout of a function descriptor. A C function pointer really
411 points to one of these. */
418 struct ffi_ia64_trampoline_struct
420 UINT64 code_pointer
; /* Pointer to ffi_closure_unix. */
421 UINT64 fake_gp
; /* Pointer to closure, installed as gp. */
422 UINT64 real_gp
; /* Real gp value. */
425 struct ffi_ia64_trampoline_struct
*tramp
;
428 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
430 tramp
= (struct ffi_ia64_trampoline_struct
*)closure
->tramp
;
431 fd
= (struct ia64_fd
*)(void *)ffi_closure_unix
;
433 tramp
->code_pointer
= fd
->code_pointer
;
434 tramp
->real_gp
= fd
->gp
;
435 tramp
->fake_gp
= (UINT64
)(PTR64
)codeloc
;
437 closure
->user_data
= user_data
;
445 ffi_closure_unix_inner (ffi_closure
*closure
, struct ia64_args
*stack
,
446 void *rvalue
, void *r8
)
451 long i
, avn
, gpcount
, fpcount
;
455 avalue
= alloca (avn
* sizeof (void *));
457 /* If the structure return value is passed in memory get that location
458 from r8 so as to pass the value directly back to the caller. */
459 if (cif
->flags
== FFI_TYPE_STRUCT
)
462 gpcount
= fpcount
= 0;
463 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
465 switch ((*p_arg
)->type
)
469 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 1);
471 case FFI_TYPE_SINT16
:
472 case FFI_TYPE_UINT16
:
473 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 2);
475 case FFI_TYPE_SINT32
:
476 case FFI_TYPE_UINT32
:
477 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 4);
479 case FFI_TYPE_SINT64
:
480 case FFI_TYPE_UINT64
:
481 avalue
[i
] = &stack
->gp_regs
[gpcount
++];
483 case FFI_TYPE_POINTER
:
484 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], sizeof(void*));
488 if (gpcount
< 8 && fpcount
< 8)
490 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
493 ldf_fill (result
, addr
);
494 *(float *)addr
= result
;
497 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
], 4);
501 case FFI_TYPE_DOUBLE
:
502 if (gpcount
< 8 && fpcount
< 8)
504 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
507 ldf_fill (result
, addr
);
508 *(double *)addr
= result
;
511 avalue
[i
] = &stack
->gp_regs
[gpcount
];
515 case FFI_TYPE_LONGDOUBLE
:
518 if (LDBL_MANT_DIG
== 64 && gpcount
< 8 && fpcount
< 8)
520 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
523 ldf_fill (result
, addr
);
524 *(__float80
*)addr
= result
;
527 avalue
[i
] = &stack
->gp_regs
[gpcount
];
531 case FFI_TYPE_STRUCT
:
533 size_t size
= (*p_arg
)->size
;
534 size_t align
= (*p_arg
)->alignment
;
535 int hfa_type
= hfa_element_type (*p_arg
, 0);
537 FFI_ASSERT (align
<= 16);
538 if (align
== 16 && (gpcount
& 1))
541 if (hfa_type
!= FFI_TYPE_VOID
)
543 size_t hfa_size
= hfa_type_size (hfa_type
);
545 size_t gp_offset
= gpcount
* 8;
546 void *addr
= alloca (size
);
552 && gp_offset
< 8 * 8)
554 hfa_type_store (hfa_type
, addr
+ offset
,
555 &stack
->fp_regs
[fpcount
]);
557 gp_offset
+= hfa_size
;
562 memcpy (addr
+ offset
, (char *)stack
->gp_regs
+ gp_offset
,
566 avalue
[i
] = &stack
->gp_regs
[gpcount
];
568 gpcount
+= (size
+ 7) / 8;
577 closure
->fun (cif
, rvalue
, avalue
, closure
->user_data
);