1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 Cygnus Solutions
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>
32 #include "ia64_flags.h"
34 /* Memory image of fp register contents. Should eventually be an fp */
35 /* type long enough to hold an entire register. For now we use double. */
36 typedef double float80
;
38 /* The stack layout at call to ffi_prep_args. Other_args will remain */
39 /* on the stack for the actual call. Everything else we be transferred */
40 /* to registers and popped by the assembly code. */
43 long scratch
[2]; /* Two scratch words at top of stack. */
44 /* Allows sp to be passed as arg pointer. */
45 void * r8_contents
; /* Value to be passed in r8 */
46 long spare
; /* Not used. */
47 float80 fp_regs
[8]; /* Contents of 8 floating point argument */
49 long out_regs
[8]; /* Contents of the 8 out registers used */
50 /* for integer parameters. */
51 long other_args
[0]; /* Arguments passed on stack, variable size */
52 /* Treated as continuation of out_regs. */
55 static size_t float_type_size(unsigned short tp
)
61 return sizeof(double);
62 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
63 case FFI_TYPE_LONGDOUBLE
:
64 return sizeof(long double);
72 * Is type a struct containing at most n floats, doubles, or extended
73 * doubles, all of the same fp type?
74 * If so, set *element_type to the fp type.
76 static bool is_homogeneous_fp_aggregate(ffi_type
* type
, int n
,
77 unsigned short * element_type
)
80 unsigned short element
, struct_element
;
84 FFI_ASSERT(type
!= NULL
);
86 FFI_ASSERT(type
->elements
!= NULL
);
88 ptr
= &(type
->elements
[0]);
90 while ((*ptr
) != NULL
)
92 switch((*ptr
) -> type
) {
94 if (type_set
&& element
!= FFI_TYPE_FLOAT
) return 0;
95 if (--n
< 0) return FALSE
;
97 element
= FFI_TYPE_FLOAT
;
100 if (type_set
&& element
!= FFI_TYPE_DOUBLE
) return 0;
101 if (--n
< 0) return FALSE
;
103 element
= FFI_TYPE_DOUBLE
;
105 case FFI_TYPE_STRUCT
:
106 if (!is_homogeneous_fp_aggregate(type
, n
, &struct_element
))
108 if (type_set
&& struct_element
!= element
) return FALSE
;
109 n
-= (type
-> size
)/float_type_size(element
);
110 element
= struct_element
;
111 if (n
< 0) return FALSE
;
113 /* case FFI_TYPE_LONGDOUBLE:
114 Not yet implemented. */
120 *element_type
= element
;
125 /* ffi_prep_args is called by the assembly routine once stack space
126 has been allocated for the function's arguments. It fills in
127 the arguments in the structure referenced by stack. Returns nonzero
128 if fp registers are used for arguments. */
131 ffi_prep_args(struct ia64_args
*stack
, extended_cif
*ecif
, int bytes
)
133 register long i
, avn
;
134 register void **p_argv
;
135 register long *argp
= stack
-> out_regs
;
136 register float80
*fp_argp
= stack
-> fp_regs
;
137 register ffi_type
**p_arg
;
139 /* For big return structs, r8 needs to contain the target address. */
140 /* Since r8 is otherwise dead, we set it unconditionally. */
141 stack
-> r8_contents
= ecif
-> rvalue
;
143 avn
= ecif
->cif
->nargs
;
144 p_arg
= ecif
->cif
->arg_types
;
145 p_argv
= ecif
->avalue
;
148 size_t z
; /* z is in units of arg slots or words, not bytes. */
150 switch ((*p_arg
)->type
)
154 *(SINT64
*) argp
= *(SINT8
*)(* p_argv
);
159 *(UINT64
*) argp
= *(UINT8
*)(* p_argv
);
162 case FFI_TYPE_SINT16
:
164 *(SINT64
*) argp
= *(SINT16
*)(* p_argv
);
167 case FFI_TYPE_UINT16
:
169 *(UINT64
*) argp
= *(UINT16
*)(* p_argv
);
172 case FFI_TYPE_SINT32
:
174 *(SINT64
*) argp
= *(SINT32
*)(* p_argv
);
177 case FFI_TYPE_UINT32
:
179 *(UINT64
*) argp
= *(UINT32
*)(* p_argv
);
182 case FFI_TYPE_SINT64
:
183 case FFI_TYPE_UINT64
:
184 case FFI_TYPE_POINTER
:
186 *(UINT64
*) argp
= *(UINT64
*)(* p_argv
);
191 if (fp_argp
- stack
->fp_regs
< 8)
193 /* Note the conversion -- all the fp regs are loaded as
195 *fp_argp
++ = *(float *)(* p_argv
);
197 /* Also put it into the integer registers or memory: */
198 *(UINT64
*) argp
= *(UINT32
*)(* p_argv
);
201 case FFI_TYPE_DOUBLE
:
203 if (fp_argp
- stack
->fp_regs
< 8)
204 *fp_argp
++ = *(double *)(* p_argv
);
205 /* Also put it into the integer registers or memory: */
206 *(double *) argp
= *(double *)(* p_argv
);
209 case FFI_TYPE_STRUCT
:
211 size_t sz
= (*p_arg
)->size
;
212 unsigned short element_type
;
213 z
= ((*p_arg
)->size
+ SIZEOF_ARG
- 1)/SIZEOF_ARG
;
214 if (is_homogeneous_fp_aggregate(*p_arg
, 8, &element_type
)) {
216 int nelements
= sz
/float_type_size(element_type
);
217 for (i
= 0; i
< nelements
; ++i
) {
218 switch (element_type
) {
220 if (fp_argp
- stack
->fp_regs
< 8)
221 *fp_argp
++ = ((float *)(* p_argv
))[i
];
223 case FFI_TYPE_DOUBLE
:
224 if (fp_argp
- stack
->fp_regs
< 8)
225 *fp_argp
++ = ((double *)(* p_argv
))[i
];
228 /* Extended precision not yet implemented. */
233 /* And pass it in integer registers as a struct, with */
234 /* its actual field sizes packed into registers. */
235 memcpy(argp
, *p_argv
, (*p_arg
)->size
);
244 i
++, p_arg
++, p_argv
++;
246 return (fp_argp
!= stack
-> fp_regs
);
249 /* Perform machine dependent cif processing */
251 ffi_prep_cif_machdep(ffi_cif
*cif
)
254 bool is_simple
= TRUE
;
255 long simple_flag
= FFI_SIMPLE_V
;
256 /* Adjust cif->bytes to include space for the 2 scratch words,
257 r8 register contents, spare word,
258 the 8 fp register contents, and all 8 integer register contents.
259 This will be removed before the call, though 2 scratch words must
262 cif
->bytes
+= 4*sizeof(long) + 8 *sizeof(float80
);
263 if (cif
->bytes
< sizeof(struct ia64_args
))
264 cif
->bytes
= sizeof(struct ia64_args
);
266 /* The stack must be double word aligned, so round bytes up
269 cif
->bytes
= ALIGN(cif
->bytes
, 2*sizeof(void*));
273 for (i
= 0; i
< avn
; ++i
) {
274 switch(cif
-> arg_types
[i
] -> type
) {
275 case FFI_TYPE_SINT32
:
276 simple_flag
= FFI_ADD_INT_ARG(simple_flag
);
278 case FFI_TYPE_SINT64
:
279 case FFI_TYPE_UINT64
:
280 case FFI_TYPE_POINTER
:
281 simple_flag
= FFI_ADD_LONG_ARG(simple_flag
);
291 /* Set the return type flag */
292 switch (cif
->rtype
->type
)
295 cif
->flags
= FFI_TYPE_VOID
;
298 case FFI_TYPE_STRUCT
:
300 size_t sz
= cif
-> rtype
-> size
;
301 unsigned short element_type
;
304 if (is_homogeneous_fp_aggregate(cif
-> rtype
, 8, &element_type
)) {
305 int nelements
= sz
/float_type_size(element_type
);
306 if (nelements
<= 1) {
307 if (0 == nelements
) {
308 cif
-> flags
= FFI_TYPE_VOID
;
310 cif
-> flags
= element_type
;
313 switch(element_type
) {
315 cif
-> flags
= FFI_IS_FLOAT_FP_AGGREGATE
| nelements
;
317 case FFI_TYPE_DOUBLE
:
318 cif
-> flags
= FFI_IS_DOUBLE_FP_AGGREGATE
| nelements
;
321 /* long double NYI */
329 cif
->flags
= FFI_TYPE_INT
;
330 } else if (sz
<= 16) {
331 cif
->flags
= FFI_IS_SMALL_STRUCT2
;
332 } else if (sz
<= 24) {
333 cif
->flags
= FFI_IS_SMALL_STRUCT3
;
335 cif
->flags
= FFI_IS_SMALL_STRUCT4
;
338 cif
->flags
= FFI_TYPE_STRUCT
;
345 cif
->flags
= FFI_TYPE_FLOAT
;
348 case FFI_TYPE_DOUBLE
:
350 cif
->flags
= FFI_TYPE_DOUBLE
;
354 cif
->flags
= FFI_TYPE_INT
;
355 /* This seems to depend on little endian mode, and the fact that */
356 /* the return pointer always points to at least 8 bytes. But */
357 /* that also seems to be true for other platforms. */
361 if (is_simple
) cif
-> flags
|= simple_flag
;
365 extern int ffi_call_unix(bool (*)(struct ia64_args
*, extended_cif
*, int),
366 extended_cif
*, unsigned,
367 unsigned, unsigned *, void (*)());
370 ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
373 long simple
= cif
-> flags
& FFI_SIMPLE
;
375 /* Should this also check for Unix ABI? */
376 /* This is almost, but not quite, machine independent. Note that */
377 /* we can get away with not caring about length of the result because */
378 /* we assume we are little endian, and the result buffer is large */
380 /* This needs work for HP/UX. */
382 long (*lfn
)() = (long (*)())fn
;
389 result
= lfn(*(int *)avalue
[0]);
392 result
= lfn(*(long *)avalue
[0]);
395 result
= lfn(*(int *)avalue
[0], *(int *)avalue
[1]);
398 result
= lfn(*(int *)avalue
[0], *(long *)avalue
[1]);
401 result
= lfn(*(long *)avalue
[0], *(int *)avalue
[1]);
404 result
= lfn(*(long *)avalue
[0], *(long *)avalue
[1]);
407 if ((cif
->flags
& ~FFI_SIMPLE
) != FFI_TYPE_VOID
&& 0 != rvalue
) {
408 * (long *)rvalue
= result
;
413 ecif
.avalue
= avalue
;
415 /* If the return value is a struct and we don't have a return
416 value address then we need to make one. */
418 if (rvalue
== NULL
&& cif
->rtype
->type
== FFI_TYPE_STRUCT
)
419 ecif
.rvalue
= alloca(cif
->rtype
->size
);
421 ecif
.rvalue
= rvalue
;
426 ffi_call_unix(ffi_prep_args
, &ecif
, cif
->bytes
,
427 cif
->flags
, rvalue
, fn
);
437 * Closures represent a pair consisting of a function pointer, and
438 * some user data. A closure is invoked by reinterpreting the closure
439 * as a function pointer, and branching to it. Thus we can make an
440 * interpreted function callable as a C function: We turn the interpreter
441 * itself, together with a pointer specifying the interpreted procedure,
443 * On X86, the first few words of the closure structure actually contain code,
444 * which will do the right thing. On most other architectures, this
445 * would raise some Icache/Dcache coherence issues (which can be solved, but
446 * often not cheaply).
447 * For IA64, function pointer are already pairs consisting of a code
448 * pointer, and a gp pointer. The latter is needed to access global variables.
449 * Here we set up such a pair as the first two words of the closure (in
450 * the "trampoline" area), but we replace the gp pointer with a pointer
451 * to the closure itself. We also add the real gp pointer to the
452 * closure. This allows the function entry code to both retrieve the
453 * user data, and to restire the correct gp pointer.
457 ffi_prep_incoming_args_UNIX(struct ia64_args
*args
, void **rvalue
,
458 void **avalue
, ffi_cif
*cif
);
460 /* This function is entered with the doctored gp (r1) value.
461 * This code is extremely gcc specific. There is some argument that
462 * it should really be written in assembly code, since it depends on
463 * gcc properties that might change over time.
466 /* ffi_closure_UNIX is an assembly routine, which copies the register */
467 /* state into a struct ia64_args, and then invokes */
468 /* ffi_closure_UNIX_inner. It also recovers the closure pointer */
469 /* from its fake gp pointer. */
470 void ffi_closure_UNIX();
473 # error This requires gcc
476 ffi_closure_UNIX_inner (ffi_closure
*closure
, struct ia64_args
* args
)
477 /* Hopefully declaring this as a varargs function will force all args */
480 // this is our return value storage
483 // our various things...
485 unsigned short rtype
;
491 arg_area
= (void**) alloca (cif
->nargs
* sizeof (void*));
493 /* this call will initialize ARG_AREA, such that each
494 * element in that array points to the corresponding
495 * value on the stack; and if the function returns
496 * a structure, it will re-set RESP to point to the
497 * structure return address. */
499 ffi_prep_incoming_args_UNIX(args
, (void**)&resp
, arg_area
, cif
);
501 (closure
->fun
) (cif
, resp
, arg_area
, closure
->user_data
);
505 /* now, do a generic return based on the value of rtype */
506 if (rtype
== FFI_TYPE_INT
)
508 asm volatile ("ld8 r8=[%0]" : : "r" (resp
) : "r8");
510 else if (rtype
== FFI_TYPE_FLOAT
)
512 asm volatile ("ldfs f8=[%0]" : : "r" (resp
) : "f8");
514 else if (rtype
== FFI_TYPE_DOUBLE
)
516 asm volatile ("ldfd f8=[%0]" : : "r" (resp
) : "f8");
518 else if (rtype
== FFI_IS_SMALL_STRUCT2
)
520 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
521 : : "r" (resp
), "r" (resp
+8) : "r8","r9");
523 else if (rtype
== FFI_IS_SMALL_STRUCT3
)
525 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
526 : : "r" (resp
), "r" (resp
+8), "r" (resp
+16)
529 else if (rtype
== FFI_IS_SMALL_STRUCT4
)
531 asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
532 : : "r" (resp
), "r" (resp
+8), "r" (resp
+16), "r" (resp
+24)
533 : "r8","r9","r10","r11");
535 else if (rtype
!= FFI_TYPE_VOID
&& rtype
!= FFI_TYPE_STRUCT
)
537 /* Can only happen for homogeneous FP aggregates? */
543 ffi_prep_incoming_args_UNIX(struct ia64_args
*args
, void **rvalue
,
544 void **avalue
, ffi_cif
*cif
)
546 register unsigned int i
;
547 register unsigned int avn
;
548 register void **p_argv
;
549 register unsigned long *argp
= args
-> out_regs
;
550 unsigned fp_reg_num
= 0;
551 register ffi_type
**p_arg
;
556 for (i
= cif
->nargs
, p_arg
= cif
->arg_types
; i
!= 0; i
--, p_arg
++)
558 size_t z
; /* In units of words or argument slots. */
560 switch ((*p_arg
)->type
)
564 case FFI_TYPE_SINT16
:
565 case FFI_TYPE_UINT16
:
566 case FFI_TYPE_SINT32
:
567 case FFI_TYPE_UINT32
:
568 case FFI_TYPE_SINT64
:
569 case FFI_TYPE_UINT64
:
570 case FFI_TYPE_POINTER
:
572 *p_argv
= (void *)argp
;
577 /* Convert argument back to float in place from the saved value */
578 if (fp_reg_num
< 8) {
579 *(float *)argp
= args
-> fp_regs
[fp_reg_num
++];
581 *(float *)argp
= *(double *)argp
;
583 *p_argv
= (void *)argp
;
586 case FFI_TYPE_DOUBLE
:
588 if (fp_reg_num
< 8) {
589 *p_argv
= args
-> fp_regs
+ fp_reg_num
++;
591 *p_argv
= (void *)argp
;
595 case FFI_TYPE_STRUCT
:
597 size_t sz
= (*p_arg
)->size
;
598 unsigned short element_type
;
599 z
= ((*p_arg
)->size
+ SIZEOF_ARG
- 1)/SIZEOF_ARG
;
600 if (is_homogeneous_fp_aggregate(*p_arg
, 8, &element_type
)) {
601 int nelements
= sz
/float_type_size(element_type
);
602 if (nelements
+ fp_reg_num
>= 8) {
606 if (element_type
== FFI_TYPE_DOUBLE
) {
607 *p_argv
= args
-> fp_regs
+ fp_reg_num
;
608 fp_reg_num
+= nelements
;
611 if (element_type
== FFI_TYPE_FLOAT
) {
613 for (j
= 0; j
< nelements
; ++ j
) {
614 ((float *)argp
)[j
] = args
-> fp_regs
[fp_reg_num
+ j
];
616 *p_argv
= (void *)argp
;
617 fp_reg_num
+= nelements
;
620 abort(); /* Other fp types NYI */
638 /* Fill in a closure to refer to the specified fun and user_data. */
639 /* cif specifies the argument and result types for fun. */
640 /* the cif must already be prep'ed */
642 /* The layout of a function descriptor. A C function pointer really */
643 /* points to one of these. */
644 typedef struct ia64_fd_struct
{
650 ffi_prep_closure (ffi_closure
* closure
,
652 void (*fun
)(ffi_cif
*,void*,void**,void*),
655 struct ffi_ia64_trampoline_struct
*tramp
=
656 (struct ffi_ia64_trampoline_struct
*) (closure
-> tramp
);
657 ia64_fd
*fd
= (ia64_fd
*)(void *)ffi_closure_UNIX
;
659 FFI_ASSERT (cif
->abi
== FFI_UNIX
);
661 tramp
-> code_pointer
= fd
-> code_pointer
;
662 tramp
-> real_gp
= fd
-> gp
;
663 tramp
-> fake_gp
= closure
;
665 closure
->user_data
= user_data
;