1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2012 Anthony Green
3 Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
5 Alpha 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>
33 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
34 all further uses in this file will refer to the 128-bit type. */
35 #if defined(__LONG_DOUBLE_128__)
36 # if FFI_TYPE_LONGDOUBLE != 4
37 # error FFI_TYPE_LONGDOUBLE out of date
40 # undef FFI_TYPE_LONGDOUBLE
41 # define FFI_TYPE_LONGDOUBLE 4
44 extern void ffi_call_osf(void *stack
, void *frame
, unsigned flags
,
45 void *raddr
, void (*fn
)(void), void *closure
)
47 extern void ffi_closure_osf(void) FFI_HIDDEN
;
48 extern void ffi_go_closure_osf(void) FFI_HIDDEN
;
50 /* Promote a float value to its in-register double representation.
51 Unlike actually casting to double, this does not trap on NaN. */
52 static inline UINT64
lds(void *ptr
)
55 asm("lds %0,%1" : "=f"(ret
) : "m"(*(UINT32
*)ptr
));
59 /* And the reverse. */
60 static inline void sts(void *ptr
, UINT64 val
)
62 asm("sts %1,%0" : "=m"(*(UINT32
*)ptr
) : "f"(val
));
66 ffi_prep_cif_machdep(ffi_cif
*cif
)
70 ffi_type
*rtype
, *itype
;
72 if (cif
->abi
!= FFI_OSF
)
75 /* Compute the size of the argument area. */
76 for (i
= 0, avn
= cif
->nargs
; i
< avn
; i
++)
78 itype
= cif
->arg_types
[i
];
90 case FFI_TYPE_POINTER
:
93 case FFI_TYPE_LONGDOUBLE
:
94 /* All take one 8 byte slot. */
100 /* Passed by value in N slots. */
101 bytes
+= ALIGN(itype
->size
, FFI_SIZEOF_ARG
);
104 case FFI_TYPE_COMPLEX
:
105 /* _Complex long double passed by reference; others in 2 slots. */
106 if (itype
->elements
[0]->type
== FFI_TYPE_LONGDOUBLE
)
117 /* Set the return type flag */
122 flags
= ALPHA_FLAGS(ALPHA_ST_VOID
, ALPHA_LD_VOID
);
125 case FFI_TYPE_UINT32
:
126 case FFI_TYPE_SINT32
:
127 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_INT32
);
130 flags
= ALPHA_FLAGS(ALPHA_ST_FLOAT
, ALPHA_LD_FLOAT
);
132 case FFI_TYPE_DOUBLE
:
133 flags
= ALPHA_FLAGS(ALPHA_ST_DOUBLE
, ALPHA_LD_DOUBLE
);
136 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_UINT8
);
139 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_SINT8
);
141 case FFI_TYPE_UINT16
:
142 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_UINT16
);
144 case FFI_TYPE_SINT16
:
145 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_SINT16
);
147 case FFI_TYPE_UINT64
:
148 case FFI_TYPE_SINT64
:
149 case FFI_TYPE_POINTER
:
150 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_INT64
);
152 case FFI_TYPE_LONGDOUBLE
:
153 case FFI_TYPE_STRUCT
:
154 /* Passed in memory, with a hidden pointer. */
155 flags
= ALPHA_RET_IN_MEM
;
157 case FFI_TYPE_COMPLEX
:
158 itype
= rtype
->elements
[0];
162 flags
= ALPHA_FLAGS(ALPHA_ST_CPLXF
, ALPHA_LD_CPLXF
);
164 case FFI_TYPE_DOUBLE
:
165 flags
= ALPHA_FLAGS(ALPHA_ST_CPLXD
, ALPHA_LD_CPLXD
);
168 if (rtype
->size
<= 8)
169 flags
= ALPHA_FLAGS(ALPHA_ST_INT
, ALPHA_LD_INT64
);
171 flags
= ALPHA_RET_IN_MEM
;
180 /* Include the hidden structure pointer in args requirement. */
181 if (flags
== ALPHA_RET_IN_MEM
)
183 /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
192 extend_basic_type(void *valp
, int type
, int argn
)
197 return *(SINT8
*)valp
;
199 return *(UINT8
*)valp
;
200 case FFI_TYPE_SINT16
:
201 return *(SINT16
*)valp
;
202 case FFI_TYPE_UINT16
:
203 return *(UINT16
*)valp
;
211 case FFI_TYPE_SINT32
:
212 case FFI_TYPE_UINT32
:
213 /* Note that unsigned 32-bit quantities are sign extended. */
214 return *(SINT32
*)valp
;
216 case FFI_TYPE_SINT64
:
217 case FFI_TYPE_UINT64
:
218 case FFI_TYPE_POINTER
:
219 case FFI_TYPE_DOUBLE
:
220 return *(UINT64
*)valp
;
228 ffi_call_int (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
229 void **avalue
, void *closure
)
232 long i
, avn
, argn
, flags
= cif
->flags
;
233 ffi_type
**arg_types
;
236 /* If the return value is a struct and we don't have a return
237 value address then we need to make one. */
238 if (rvalue
== NULL
&& flags
== ALPHA_RET_IN_MEM
)
239 rvalue
= alloca(cif
->rtype
->size
);
241 /* Allocate the space for the arguments, plus 4 words of temp
242 space for ffi_call_osf. */
243 argp
= frame
= alloca(cif
->bytes
+ 4*FFI_SIZEOF_ARG
);
247 if (flags
== ALPHA_RET_IN_MEM
)
248 argp
[argn
++] = (unsigned long)rvalue
;
251 arg_types
= cif
->arg_types
;
253 for (i
= 0, avn
= cif
->nargs
; i
< avn
; i
++)
255 ffi_type
*ty
= arg_types
[i
];
256 void *valp
= avalue
[i
];
265 case FFI_TYPE_SINT16
:
266 case FFI_TYPE_UINT16
:
267 case FFI_TYPE_SINT32
:
268 case FFI_TYPE_UINT32
:
269 case FFI_TYPE_SINT64
:
270 case FFI_TYPE_UINT64
:
271 case FFI_TYPE_POINTER
:
273 case FFI_TYPE_DOUBLE
:
274 argp
[argn
] = extend_basic_type(valp
, type
, argn
);
278 case FFI_TYPE_LONGDOUBLE
:
280 /* Note that 128-bit long double is passed by reference. */
281 argp
[argn
++] = (unsigned long)valp
;
285 case FFI_TYPE_STRUCT
:
287 memcpy(argp
+ argn
, valp
, size
);
288 argn
+= ALIGN(size
, FFI_SIZEOF_ARG
) / FFI_SIZEOF_ARG
;
291 case FFI_TYPE_COMPLEX
:
292 type
= ty
->elements
[0]->type
;
293 if (type
== FFI_TYPE_LONGDOUBLE
)
296 /* Most complex types passed as two separate arguments. */
297 size
= ty
->elements
[0]->size
;
298 argp
[argn
] = extend_basic_type(valp
, type
, argn
);
299 argp
[argn
+ 1] = extend_basic_type(valp
+ size
, type
, argn
+ 1);
308 flags
= (flags
>> ALPHA_ST_SHIFT
) & 0xff;
309 ffi_call_osf(argp
, frame
, flags
, rvalue
, fn
, closure
);
313 ffi_call (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
, void **avalue
)
315 ffi_call_int(cif
, fn
, rvalue
, avalue
, NULL
);
319 ffi_call_go (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
320 void **avalue
, void *closure
)
322 ffi_call_int(cif
, fn
, rvalue
, avalue
, closure
);
326 ffi_prep_closure_loc (ffi_closure
* closure
,
328 void (*fun
)(ffi_cif
*, void*, void**, void*),
334 if (cif
->abi
!= FFI_OSF
)
337 tramp
= (unsigned int *) &closure
->tramp
[0];
338 tramp
[0] = 0x47fb0401; /* mov $27,$1 */
339 tramp
[1] = 0xa77b0010; /* ldq $27,16($27) */
340 tramp
[2] = 0x6bfb0000; /* jmp $31,($27),0 */
341 tramp
[3] = 0x47ff041f; /* nop */
342 *(void **) &tramp
[4] = ffi_closure_osf
;
346 closure
->user_data
= user_data
;
350 Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
351 instead, since both Compaq as and gas can handle it.
353 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
354 asm volatile ("call_pal 0x86" : : : "memory");
360 ffi_prep_go_closure (ffi_go_closure
* closure
,
362 void (*fun
)(ffi_cif
*, void*, void**, void*))
364 if (cif
->abi
!= FFI_OSF
)
367 closure
->tramp
= (void *)ffi_go_closure_osf
;
375 ffi_closure_osf_inner (ffi_cif
*cif
,
376 void (*fun
)(ffi_cif
*, void*, void**, void*),
378 void *rvalue
, unsigned long *argp
)
381 ffi_type
**arg_types
;
382 long i
, avn
, argn
, flags
;
384 avalue
= alloca(cif
->nargs
* sizeof(void *));
388 /* Copy the caller's structure return address to that the closure
389 returns the data directly to the caller. */
390 if (flags
== ALPHA_RET_IN_MEM
)
392 rvalue
= (void *) argp
[0];
396 arg_types
= cif
->arg_types
;
398 /* Grab the addresses of the arguments from the stack frame. */
399 for (i
= 0, avn
= cif
->nargs
; i
< avn
; i
++)
401 ffi_type
*ty
= arg_types
[i
];
403 void *valp
= &argp
[argn
];
411 case FFI_TYPE_SINT16
:
412 case FFI_TYPE_UINT16
:
413 case FFI_TYPE_SINT32
:
414 case FFI_TYPE_UINT32
:
415 case FFI_TYPE_SINT64
:
416 case FFI_TYPE_UINT64
:
417 case FFI_TYPE_POINTER
:
422 case FFI_TYPE_STRUCT
:
424 argn
+= ALIGN(size
, FFI_SIZEOF_ARG
) / FFI_SIZEOF_ARG
;
428 /* Floats coming from registers need conversion from double
429 back to float format. */
432 valp
= &argp
[argn
- 6];
433 sts(valp
, argp
[argn
- 6]);
438 case FFI_TYPE_DOUBLE
:
440 valp
= &argp
[argn
- 6];
444 case FFI_TYPE_LONGDOUBLE
:
446 /* 128-bit long double is passed by reference. */
447 valp
= (void *)argp
[argn
];
451 case FFI_TYPE_COMPLEX
:
452 type
= ty
->elements
[0]->type
;
455 case FFI_TYPE_SINT64
:
456 case FFI_TYPE_UINT64
:
457 /* Passed as separate arguments, but they wind up sequential. */
463 case FFI_TYPE_SINT16
:
464 case FFI_TYPE_UINT16
:
465 case FFI_TYPE_SINT32
:
466 case FFI_TYPE_UINT32
:
467 /* Passed as separate arguments. Disjoint, but there's room
468 enough in one slot to hold the pair. */
469 size
= ty
->elements
[0]->size
;
470 memcpy(valp
+ size
, valp
+ 8, size
);
474 /* Passed as separate arguments. Disjoint, and each piece
475 may need conversion back to float. */
478 valp
= &argp
[argn
- 6];
479 sts(valp
, argp
[argn
- 6]);
482 sts(valp
+ 4, argp
[argn
+ 1 - 6]);
484 *(UINT32
*)(valp
+ 4) = argp
[argn
+ 1];
487 case FFI_TYPE_DOUBLE
:
488 /* Passed as separate arguments. Only disjoint if one part
489 is in fp regs and the other is on the stack. */
491 valp
= &argp
[argn
- 6];
495 ((UINT64
*)valp
)[0] = argp
[5 - 6];
496 ((UINT64
*)valp
)[1] = argp
[6];
500 case FFI_TYPE_LONGDOUBLE
:
516 /* Invoke the closure. */
517 fun (cif
, rvalue
, avalue
, user_data
);
519 /* Tell ffi_closure_osf how to perform return type promotions. */
520 return (flags
>> ALPHA_LD_SHIFT
) & 0xff;