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>
33 #include "ia64_flags.h"
35 /* Memory image of fp register contents. Should eventually be an fp */
36 /* type long enough to hold an entire register. For now we use double. */
37 typedef double float80
;
39 /* The stack layout at call to ffi_prep_args. Other_args will remain */
40 /* on the stack for the actual call. Everything else we be transferred */
41 /* to registers and popped by the assembly code. */
44 long scratch
[2]; /* Two scratch words at top of stack. */
45 /* Allows sp to be passed as arg pointer. */
46 void * r8_contents
; /* Value to be passed in r8 */
47 long spare
; /* Not used. */
48 float80 fp_regs
[8]; /* Contents of 8 floating point argument */
50 long out_regs
[8]; /* Contents of the 8 out registers used */
51 /* for integer parameters. */
52 long other_args
[0]; /* Arguments passed on stack, variable size */
53 /* Treated as continuation of out_regs. */
56 static size_t float_type_size(unsigned short tp
)
62 return sizeof(double);
63 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
64 case FFI_TYPE_LONGDOUBLE
:
65 return sizeof(long double);
73 * Is type a struct containing at most n floats, doubles, or extended
74 * doubles, all of the same fp type?
75 * If so, set *element_type to the fp type.
77 static bool is_homogeneous_fp_aggregate(ffi_type
* type
, int n
,
78 unsigned short * element_type
)
81 unsigned short element
, struct_element
;
85 FFI_ASSERT(type
!= NULL
);
87 FFI_ASSERT(type
->elements
!= NULL
);
89 ptr
= &(type
->elements
[0]);
91 while ((*ptr
) != NULL
)
93 switch((*ptr
) -> type
) {
95 if (type_set
&& element
!= FFI_TYPE_FLOAT
) return 0;
96 if (--n
< 0) return false;
98 element
= FFI_TYPE_FLOAT
;
100 case FFI_TYPE_DOUBLE
:
101 if (type_set
&& element
!= FFI_TYPE_DOUBLE
) return 0;
102 if (--n
< 0) return false;
104 element
= FFI_TYPE_DOUBLE
;
106 case FFI_TYPE_STRUCT
:
107 if (!is_homogeneous_fp_aggregate(type
, n
, &struct_element
))
109 if (type_set
&& struct_element
!= element
) return false;
110 n
-= (type
-> size
)/float_type_size(element
);
111 element
= struct_element
;
112 if (n
< 0) return false;
114 /* case FFI_TYPE_LONGDOUBLE:
115 Not yet implemented. */
121 *element_type
= element
;
126 /* ffi_prep_args is called by the assembly routine once stack space
127 has been allocated for the function's arguments. It fills in
128 the arguments in the structure referenced by stack. Returns nonzero
129 if fp registers are used for arguments. */
132 ffi_prep_args(struct ia64_args
*stack
, extended_cif
*ecif
, int bytes
)
134 register long i
, avn
;
135 register void **p_argv
;
136 register long *argp
= stack
-> out_regs
;
137 register float80
*fp_argp
= stack
-> fp_regs
;
138 register ffi_type
**p_arg
;
140 /* For big return structs, r8 needs to contain the target address. */
141 /* Since r8 is otherwise dead, we set it unconditionally. */
142 stack
-> r8_contents
= ecif
-> rvalue
;
144 avn
= ecif
->cif
->nargs
;
145 p_arg
= ecif
->cif
->arg_types
;
146 p_argv
= ecif
->avalue
;
149 size_t z
; /* z is in units of arg slots or words, not bytes. */
151 switch ((*p_arg
)->type
)
155 *(SINT64
*) argp
= *(SINT8
*)(* p_argv
);
160 *(UINT64
*) argp
= *(UINT8
*)(* p_argv
);
163 case FFI_TYPE_SINT16
:
165 *(SINT64
*) argp
= *(SINT16
*)(* p_argv
);
168 case FFI_TYPE_UINT16
:
170 *(UINT64
*) argp
= *(UINT16
*)(* p_argv
);
173 case FFI_TYPE_SINT32
:
175 *(SINT64
*) argp
= *(SINT32
*)(* p_argv
);
178 case FFI_TYPE_UINT32
:
180 *(UINT64
*) argp
= *(UINT32
*)(* p_argv
);
183 case FFI_TYPE_SINT64
:
184 case FFI_TYPE_UINT64
:
185 case FFI_TYPE_POINTER
:
187 *(UINT64
*) argp
= *(UINT64
*)(* p_argv
);
192 if (fp_argp
- stack
->fp_regs
< 8)
194 /* Note the conversion -- all the fp regs are loaded as
196 *fp_argp
++ = *(float *)(* p_argv
);
198 /* Also put it into the integer registers or memory: */
199 *(UINT64
*) argp
= *(UINT32
*)(* p_argv
);
202 case FFI_TYPE_DOUBLE
:
204 if (fp_argp
- stack
->fp_regs
< 8)
205 *fp_argp
++ = *(double *)(* p_argv
);
206 /* Also put it into the integer registers or memory: */
207 *(double *) argp
= *(double *)(* p_argv
);
210 case FFI_TYPE_STRUCT
:
212 size_t sz
= (*p_arg
)->size
;
213 unsigned short element_type
;
214 z
= ((*p_arg
)->size
+ FFI_SIZEOF_ARG
- 1)/FFI_SIZEOF_ARG
;
215 if (is_homogeneous_fp_aggregate(*p_arg
, 8, &element_type
)) {
217 int nelements
= sz
/float_type_size(element_type
);
218 for (i
= 0; i
< nelements
; ++i
) {
219 switch (element_type
) {
221 if (fp_argp
- stack
->fp_regs
< 8)
222 *fp_argp
++ = ((float *)(* p_argv
))[i
];
224 case FFI_TYPE_DOUBLE
:
225 if (fp_argp
- stack
->fp_regs
< 8)
226 *fp_argp
++ = ((double *)(* p_argv
))[i
];
229 /* Extended precision not yet implemented. */
234 /* And pass it in integer registers as a struct, with */
235 /* its actual field sizes packed into registers. */
236 memcpy(argp
, *p_argv
, (*p_arg
)->size
);
245 i
++, p_arg
++, p_argv
++;
247 return (fp_argp
!= stack
-> fp_regs
);
250 /* Perform machine dependent cif processing */
252 ffi_prep_cif_machdep(ffi_cif
*cif
)
255 bool is_simple
= true;
256 long simple_flag
= FFI_SIMPLE_V
;
257 /* Adjust cif->bytes to include space for the 2 scratch words,
258 r8 register contents, spare word,
259 the 8 fp register contents, and all 8 integer register contents.
260 This will be removed before the call, though 2 scratch words must
263 cif
->bytes
+= 4*sizeof(long) + 8 *sizeof(float80
);
264 if (cif
->bytes
< sizeof(struct ia64_args
))
265 cif
->bytes
= sizeof(struct ia64_args
);
267 /* The stack must be double word aligned, so round bytes up
270 cif
->bytes
= ALIGN(cif
->bytes
, 2*sizeof(void*));
274 for (i
= 0; i
< avn
; ++i
) {
275 switch(cif
-> arg_types
[i
] -> type
) {
276 case FFI_TYPE_SINT32
:
277 simple_flag
= FFI_ADD_INT_ARG(simple_flag
);
279 case FFI_TYPE_SINT64
:
280 case FFI_TYPE_UINT64
:
281 case FFI_TYPE_POINTER
:
282 simple_flag
= FFI_ADD_LONG_ARG(simple_flag
);
292 /* Set the return type flag */
293 switch (cif
->rtype
->type
)
296 cif
->flags
= FFI_TYPE_VOID
;
299 case FFI_TYPE_STRUCT
:
301 size_t sz
= cif
-> rtype
-> size
;
302 unsigned short element_type
;
305 if (is_homogeneous_fp_aggregate(cif
-> rtype
, 8, &element_type
)) {
306 int nelements
= sz
/float_type_size(element_type
);
307 if (nelements
<= 1) {
308 if (0 == nelements
) {
309 cif
-> flags
= FFI_TYPE_VOID
;
311 cif
-> flags
= element_type
;
314 switch(element_type
) {
316 cif
-> flags
= FFI_IS_FLOAT_FP_AGGREGATE
| nelements
;
318 case FFI_TYPE_DOUBLE
:
319 cif
-> flags
= FFI_IS_DOUBLE_FP_AGGREGATE
| nelements
;
322 /* long double NYI */
330 cif
->flags
= FFI_TYPE_INT
;
331 } else if (sz
<= 16) {
332 cif
->flags
= FFI_IS_SMALL_STRUCT2
;
333 } else if (sz
<= 24) {
334 cif
->flags
= FFI_IS_SMALL_STRUCT3
;
336 cif
->flags
= FFI_IS_SMALL_STRUCT4
;
339 cif
->flags
= FFI_TYPE_STRUCT
;
346 cif
->flags
= FFI_TYPE_FLOAT
;
349 case FFI_TYPE_DOUBLE
:
351 cif
->flags
= FFI_TYPE_DOUBLE
;
355 cif
->flags
= FFI_TYPE_INT
;
356 /* This seems to depend on little endian mode, and the fact that */
357 /* the return pointer always points to at least 8 bytes. But */
358 /* that also seems to be true for other platforms. */
362 if (is_simple
) cif
-> flags
|= simple_flag
;
366 extern int ffi_call_unix(bool (*)(struct ia64_args
*, extended_cif
*, int),
367 extended_cif
*, unsigned,
368 unsigned, unsigned *, void (*)());
371 ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
374 long simple
= cif
-> flags
& FFI_SIMPLE
;
376 /* Should this also check for Unix ABI? */
377 /* This is almost, but not quite, machine independent. Note that */
378 /* we can get away with not caring about length of the result because */
379 /* we assume we are little endian, and the result buffer is large */
381 /* This needs work for HP/UX. */
383 long (*lfn
)() = (long (*)())fn
;
390 result
= lfn(*(int *)avalue
[0]);
393 result
= lfn(*(long *)avalue
[0]);
396 result
= lfn(*(int *)avalue
[0], *(int *)avalue
[1]);
399 result
= lfn(*(int *)avalue
[0], *(long *)avalue
[1]);
402 result
= lfn(*(long *)avalue
[0], *(int *)avalue
[1]);
405 result
= lfn(*(long *)avalue
[0], *(long *)avalue
[1]);
408 if ((cif
->flags
& ~FFI_SIMPLE
) != FFI_TYPE_VOID
&& 0 != rvalue
) {
409 * (long *)rvalue
= result
;
414 ecif
.avalue
= avalue
;
416 /* If the return value is a struct and we don't have a return
417 value address then we need to make one. */
419 if (rvalue
== NULL
&& cif
->rtype
->type
== FFI_TYPE_STRUCT
)
420 ecif
.rvalue
= alloca(cif
->rtype
->size
);
422 ecif
.rvalue
= rvalue
;
427 ffi_call_unix(ffi_prep_args
, &ecif
, cif
->bytes
,
428 cif
->flags
, rvalue
, fn
);
438 * Closures represent a pair consisting of a function pointer, and
439 * some user data. A closure is invoked by reinterpreting the closure
440 * as a function pointer, and branching to it. Thus we can make an
441 * interpreted function callable as a C function: We turn the interpreter
442 * itself, together with a pointer specifying the interpreted procedure,
444 * On X86, the first few words of the closure structure actually contain code,
445 * which will do the right thing. On most other architectures, this
446 * would raise some Icache/Dcache coherence issues (which can be solved, but
447 * often not cheaply).
448 * For IA64, function pointer are already pairs consisting of a code
449 * pointer, and a gp pointer. The latter is needed to access global variables.
450 * Here we set up such a pair as the first two words of the closure (in
451 * the "trampoline" area), but we replace the gp pointer with a pointer
452 * to the closure itself. We also add the real gp pointer to the
453 * closure. This allows the function entry code to both retrieve the
454 * user data, and to restire the correct gp pointer.
458 ffi_prep_incoming_args_UNIX(struct ia64_args
*args
, void **rvalue
,
459 void **avalue
, ffi_cif
*cif
);
461 /* This function is entered with the doctored gp (r1) value.
462 * This code is extremely gcc specific. There is some argument that
463 * it should really be written in assembly code, since it depends on
464 * gcc properties that might change over time.
467 /* ffi_closure_UNIX is an assembly routine, which copies the register */
468 /* state into a struct ia64_args, and then invokes */
469 /* ffi_closure_UNIX_inner. It also recovers the closure pointer */
470 /* from its fake gp pointer. */
471 void ffi_closure_UNIX();
474 # error This requires gcc
477 ffi_closure_UNIX_inner (ffi_closure
*closure
, struct ia64_args
* args
)
478 /* Hopefully declaring this as a varargs function will force all args */
481 // this is our return value storage
484 // our various things...
486 unsigned short rtype
;
492 arg_area
= (void**) alloca (cif
->nargs
* sizeof (void*));
494 /* this call will initialize ARG_AREA, such that each
495 * element in that array points to the corresponding
496 * value on the stack; and if the function returns
497 * a structure, it will re-set RESP to point to the
498 * structure return address. */
500 ffi_prep_incoming_args_UNIX(args
, (void**)&resp
, arg_area
, cif
);
502 (closure
->fun
) (cif
, resp
, arg_area
, closure
->user_data
);
506 /* now, do a generic return based on the value of rtype */
507 if (rtype
== FFI_TYPE_INT
)
509 asm volatile ("ld8 r8=[%0]" : : "r" (resp
) : "r8");
511 else if (rtype
== FFI_TYPE_FLOAT
)
513 asm volatile ("ldfs f8=[%0]" : : "r" (resp
) : "f8");
515 else if (rtype
== FFI_TYPE_DOUBLE
)
517 asm volatile ("ldfd f8=[%0]" : : "r" (resp
) : "f8");
519 else if (rtype
== FFI_IS_SMALL_STRUCT2
)
521 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
522 : : "r" (resp
), "r" (resp
+8) : "r8","r9");
524 else if (rtype
== FFI_IS_SMALL_STRUCT3
)
526 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
527 : : "r" (resp
), "r" (resp
+8), "r" (resp
+16)
530 else if (rtype
== FFI_IS_SMALL_STRUCT4
)
532 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
533 : : "r" (resp
), "r" (resp
+8), "r" (resp
+16), "r" (resp
+24)
534 : "r8","r9","r10","r11");
536 else if (rtype
!= FFI_TYPE_VOID
&& rtype
!= FFI_TYPE_STRUCT
)
538 /* Can only happen for homogeneous FP aggregates? */
544 ffi_prep_incoming_args_UNIX(struct ia64_args
*args
, void **rvalue
,
545 void **avalue
, ffi_cif
*cif
)
547 register unsigned int i
;
548 register unsigned int avn
;
549 register void **p_argv
;
550 register unsigned long *argp
= args
-> out_regs
;
551 unsigned fp_reg_num
= 0;
552 register ffi_type
**p_arg
;
557 for (i
= cif
->nargs
, p_arg
= cif
->arg_types
; i
!= 0; i
--, p_arg
++)
559 size_t z
; /* In units of words or argument slots. */
561 switch ((*p_arg
)->type
)
565 case FFI_TYPE_SINT16
:
566 case FFI_TYPE_UINT16
:
567 case FFI_TYPE_SINT32
:
568 case FFI_TYPE_UINT32
:
569 case FFI_TYPE_SINT64
:
570 case FFI_TYPE_UINT64
:
571 case FFI_TYPE_POINTER
:
573 *p_argv
= (void *)argp
;
578 /* Convert argument back to float in place from the saved value */
579 if (fp_reg_num
< 8) {
580 *(float *)argp
= args
-> fp_regs
[fp_reg_num
++];
582 *(float *)argp
= *(double *)argp
;
584 *p_argv
= (void *)argp
;
587 case FFI_TYPE_DOUBLE
:
589 if (fp_reg_num
< 8) {
590 *p_argv
= args
-> fp_regs
+ fp_reg_num
++;
592 *p_argv
= (void *)argp
;
596 case FFI_TYPE_STRUCT
:
598 size_t sz
= (*p_arg
)->size
;
599 unsigned short element_type
;
600 z
= ((*p_arg
)->size
+ FFI_SIZEOF_ARG
- 1)/FFI_SIZEOF_ARG
;
601 if (is_homogeneous_fp_aggregate(*p_arg
, 8, &element_type
)) {
602 int nelements
= sz
/float_type_size(element_type
);
603 if (nelements
+ fp_reg_num
>= 8) {
607 if (element_type
== FFI_TYPE_DOUBLE
) {
608 *p_argv
= args
-> fp_regs
+ fp_reg_num
;
609 fp_reg_num
+= nelements
;
612 if (element_type
== FFI_TYPE_FLOAT
) {
614 for (j
= 0; j
< nelements
; ++ j
) {
615 ((float *)argp
)[j
] = args
-> fp_regs
[fp_reg_num
+ j
];
617 *p_argv
= (void *)argp
;
618 fp_reg_num
+= nelements
;
621 abort(); /* Other fp types NYI */
639 /* Fill in a closure to refer to the specified fun and user_data. */
640 /* cif specifies the argument and result types for fun. */
641 /* the cif must already be prep'ed */
643 /* The layout of a function descriptor. A C function pointer really */
644 /* points to one of these. */
645 typedef struct ia64_fd_struct
{
651 ffi_prep_closure (ffi_closure
* closure
,
653 void (*fun
)(ffi_cif
*,void*,void**,void*),
656 struct ffi_ia64_trampoline_struct
*tramp
=
657 (struct ffi_ia64_trampoline_struct
*) (closure
-> tramp
);
658 ia64_fd
*fd
= (ia64_fd
*)(void *)ffi_closure_UNIX
;
660 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
662 tramp
-> code_pointer
= fd
-> code_pointer
;
663 tramp
-> real_gp
= fd
-> gp
;
664 tramp
-> fake_gp
= closure
;
666 closure
->user_data
= user_data
;