1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 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, 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 ----------------------------------------------------------------------- */
28 #include <ffi_common.h>
34 #include "ia64_flags.h"
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
)));
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. */
46 UINT64 x
[2] __attribute__((aligned(16)));
50 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */
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. */
60 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */
63 endian_adjust (void *addr
, size_t len
)
66 return addr
+ (8 - len
);
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. */
77 #define stf_spill(addr, value) \
78 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
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. */
83 #define ldf_fill(result, addr) \
84 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
86 /* Return the size of the C type associated with with TYPE. Which will
87 be one of the FFI_IA64_TYPE_HFA_* values. */
90 hfa_type_size (int type
)
94 case FFI_IA64_TYPE_HFA_FLOAT
:
96 case FFI_IA64_TYPE_HFA_DOUBLE
:
97 return sizeof(double);
98 case FFI_IA64_TYPE_HFA_LDOUBLE
:
99 return sizeof(__float80
);
105 /* Load from ADDR a value indicated by TYPE. Which will be one of
106 the FFI_IA64_TYPE_HFA_* values. */
109 hfa_type_load (fpreg
*fpaddr
, int type
, void *addr
)
113 case FFI_IA64_TYPE_HFA_FLOAT
:
114 stf_spill (fpaddr
, *(float *) addr
);
116 case FFI_IA64_TYPE_HFA_DOUBLE
:
117 stf_spill (fpaddr
, *(double *) addr
);
119 case FFI_IA64_TYPE_HFA_LDOUBLE
:
120 stf_spill (fpaddr
, *(__float80
*) addr
);
127 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of
128 the FFI_IA64_TYPE_HFA_* values. */
131 hfa_type_store (int type
, void *addr
, fpreg
*fpaddr
)
135 case FFI_IA64_TYPE_HFA_FLOAT
:
138 ldf_fill (result
, fpaddr
);
139 *(float *) addr
= result
;
142 case FFI_IA64_TYPE_HFA_DOUBLE
:
145 ldf_fill (result
, fpaddr
);
146 *(double *) addr
= result
;
149 case FFI_IA64_TYPE_HFA_LDOUBLE
:
152 ldf_fill (result
, fpaddr
);
153 *(__float80
*) addr
= result
;
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. */
166 hfa_element_type (ffi_type
*type
, int nested
)
168 int element
= FFI_TYPE_VOID
;
173 /* We want to return VOID for raw floating-point types, but the
174 synthetic HFA type if we're nested within an aggregate. */
176 element
= FFI_IA64_TYPE_HFA_FLOAT
;
179 case FFI_TYPE_DOUBLE
:
182 element
= FFI_IA64_TYPE_HFA_DOUBLE
;
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
;
193 case FFI_TYPE_STRUCT
:
195 ffi_type
**ptr
= &type
->elements
[0];
197 for (ptr
= &type
->elements
[0]; *ptr
; ptr
++)
199 int sub_element
= hfa_element_type (*ptr
, 1);
200 if (sub_element
== FFI_TYPE_VOID
)
201 return FFI_TYPE_VOID
;
203 if (element
== FFI_TYPE_VOID
)
204 element
= sub_element
;
205 else if (element
!= sub_element
)
206 return FFI_TYPE_VOID
;
212 return FFI_TYPE_VOID
;
219 /* Perform machine dependent cif processing. */
222 ffi_prep_cif_machdep(ffi_cif
*cif
)
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
);
234 /* Set the return type flag. */
235 flags
= cif
->rtype
->type
;
236 switch (cif
->rtype
->type
)
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);
245 case FFI_TYPE_STRUCT
:
247 size_t size
= cif
->rtype
->size
;
248 int hfa_type
= hfa_element_type (cif
->rtype
, 0);
250 if (hfa_type
!= FFI_TYPE_VOID
)
252 size_t nelts
= size
/ hfa_type_size (hfa_type
);
254 flags
= hfa_type
| (size
<< 8);
259 flags
= FFI_IA64_TYPE_SMALL_STRUCT
| (size
<< 8);
272 extern int ffi_call_unix (struct ia64_args
*, PTR64
, void (*)(), UINT64
);
275 ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
277 struct ia64_args
*stack
;
278 long i
, avn
, gpcount
, fpcount
;
281 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
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
);
287 /* Allocate the stack frame. */
288 stack
= alloca (cif
->bytes
);
290 gpcount
= fpcount
= 0;
292 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
294 switch ((*p_arg
)->type
)
297 stack
->gp_regs
[gpcount
++] = *(SINT8
*)avalue
[i
];
300 stack
->gp_regs
[gpcount
++] = *(UINT8
*)avalue
[i
];
302 case FFI_TYPE_SINT16
:
303 stack
->gp_regs
[gpcount
++] = *(SINT16
*)avalue
[i
];
305 case FFI_TYPE_UINT16
:
306 stack
->gp_regs
[gpcount
++] = *(UINT16
*)avalue
[i
];
308 case FFI_TYPE_SINT32
:
309 stack
->gp_regs
[gpcount
++] = *(SINT32
*)avalue
[i
];
311 case FFI_TYPE_UINT32
:
312 stack
->gp_regs
[gpcount
++] = *(UINT32
*)avalue
[i
];
314 case FFI_TYPE_SINT64
:
315 case FFI_TYPE_UINT64
:
316 stack
->gp_regs
[gpcount
++] = *(UINT64
*)avalue
[i
];
319 case FFI_TYPE_POINTER
:
320 stack
->gp_regs
[gpcount
++] = (UINT64
)(PTR64
) *(void **)avalue
[i
];
324 if (gpcount
< 8 && fpcount
< 8)
325 stf_spill (&stack
->fp_regs
[fpcount
++], *(float *)avalue
[i
]);
326 stack
->gp_regs
[gpcount
++] = *(UINT32
*)avalue
[i
];
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
];
335 case FFI_TYPE_LONGDOUBLE
:
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);
344 case FFI_TYPE_STRUCT
:
346 size_t size
= (*p_arg
)->size
;
347 size_t align
= (*p_arg
)->alignment
;
348 int hfa_type
= hfa_element_type (*p_arg
, 0);
350 FFI_ASSERT (align
<= 16);
351 if (align
== 16 && (gpcount
& 1))
354 if (hfa_type
!= FFI_TYPE_VOID
)
356 size_t hfa_size
= hfa_type_size (hfa_type
);
358 size_t gp_offset
= gpcount
* 8;
362 && gp_offset
< 8 * 8)
364 hfa_type_load (&stack
->fp_regs
[fpcount
], hfa_type
,
367 gp_offset
+= hfa_size
;
372 memcpy (&stack
->gp_regs
[gpcount
], avalue
[i
], size
);
373 gpcount
+= (size
+ 7) / 8;
382 ffi_call_unix (stack
, rvalue
, fn
, cif
->flags
);
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.
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. */
400 extern void ffi_closure_unix ();
403 ffi_prep_closure (ffi_closure
* closure
,
405 void (*fun
)(ffi_cif
*,void*,void**,void*),
408 /* The layout of a function descriptor. A C function pointer really
409 points to one of these. */
416 struct ffi_ia64_trampoline_struct
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. */
423 struct ffi_ia64_trampoline_struct
*tramp
;
426 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
428 tramp
= (struct ffi_ia64_trampoline_struct
*)closure
->tramp
;
429 fd
= (struct ia64_fd
*)(void *)ffi_closure_unix
;
431 tramp
->code_pointer
= fd
->code_pointer
;
432 tramp
->real_gp
= fd
->gp
;
433 tramp
->fake_gp
= (UINT64
)(PTR64
)closure
;
435 closure
->user_data
= user_data
;
443 ffi_closure_unix_inner (ffi_closure
*closure
, struct ia64_args
*stack
,
444 void *rvalue
, void *r8
)
449 long i
, avn
, gpcount
, fpcount
;
453 avalue
= alloca (avn
* sizeof (void *));
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
)
460 gpcount
= fpcount
= 0;
461 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
463 switch ((*p_arg
)->type
)
467 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 1);
469 case FFI_TYPE_SINT16
:
470 case FFI_TYPE_UINT16
:
471 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 2);
473 case FFI_TYPE_SINT32
:
474 case FFI_TYPE_UINT32
:
475 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], 4);
477 case FFI_TYPE_SINT64
:
478 case FFI_TYPE_UINT64
:
479 avalue
[i
] = &stack
->gp_regs
[gpcount
++];
481 case FFI_TYPE_POINTER
:
482 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
++], sizeof(void*));
486 if (gpcount
< 8 && fpcount
< 8)
488 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
491 ldf_fill (result
, addr
);
492 *(float *)addr
= result
;
495 avalue
[i
] = endian_adjust(&stack
->gp_regs
[gpcount
], 4);
499 case FFI_TYPE_DOUBLE
:
500 if (gpcount
< 8 && fpcount
< 8)
502 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
505 ldf_fill (result
, addr
);
506 *(double *)addr
= result
;
509 avalue
[i
] = &stack
->gp_regs
[gpcount
];
513 case FFI_TYPE_LONGDOUBLE
:
516 if (LDBL_MANT_DIG
== 64 && gpcount
< 8 && fpcount
< 8)
518 fpreg
*addr
= &stack
->fp_regs
[fpcount
++];
521 ldf_fill (result
, addr
);
522 *(__float80
*)addr
= result
;
525 avalue
[i
] = &stack
->gp_regs
[gpcount
];
529 case FFI_TYPE_STRUCT
:
531 size_t size
= (*p_arg
)->size
;
532 size_t align
= (*p_arg
)->alignment
;
533 int hfa_type
= hfa_element_type (*p_arg
, 0);
535 FFI_ASSERT (align
<= 16);
536 if (align
== 16 && (gpcount
& 1))
539 if (hfa_type
!= FFI_TYPE_VOID
)
541 size_t hfa_size
= hfa_type_size (hfa_type
);
543 size_t gp_offset
= gpcount
* 8;
544 void *addr
= alloca (size
);
550 && gp_offset
< 8 * 8)
552 hfa_type_store (hfa_type
, addr
+ offset
,
553 &stack
->fp_regs
[fpcount
]);
555 gp_offset
+= hfa_size
;
560 memcpy (addr
+ offset
, (char *)stack
->gp_regs
+ gp_offset
,
564 avalue
[i
] = &stack
->gp_regs
[gpcount
];
566 gpcount
+= (size
+ 7) / 8;
575 closure
->fun (cif
, rvalue
, avalue
, closure
->user_data
);