* Makefile.am (check-gccgo, check-gcc): Add options to pick up
[official-gcc.git] / libffi / src / alpha / ffi.c
blobefae4cc3d671a549852130ae57515e94f043bb00
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 ----------------------------------------------------------------------- */
28 #include <ffi.h>
29 #include <ffi_common.h>
30 #include <stdlib.h>
31 #include "internal.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
38 # endif
39 #else
40 # undef FFI_TYPE_LONGDOUBLE
41 # define FFI_TYPE_LONGDOUBLE 4
42 #endif
44 extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
45 void *raddr, void (*fn)(void), void *closure)
46 FFI_HIDDEN;
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)
54 UINT64 ret;
55 asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
56 return ret;
59 /* And the reverse. */
60 static inline void sts(void *ptr, UINT64 val)
62 asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
65 ffi_status FFI_HIDDEN
66 ffi_prep_cif_machdep(ffi_cif *cif)
68 size_t bytes = 0;
69 int flags, i, avn;
70 ffi_type *rtype, *itype;
72 if (cif->abi != FFI_OSF)
73 return FFI_BAD_ABI;
75 /* Compute the size of the argument area. */
76 for (i = 0, avn = cif->nargs; i < avn; i++)
78 itype = cif->arg_types[i];
79 switch (itype->type)
81 case FFI_TYPE_INT:
82 case FFI_TYPE_SINT8:
83 case FFI_TYPE_UINT8:
84 case FFI_TYPE_SINT16:
85 case FFI_TYPE_UINT16:
86 case FFI_TYPE_SINT32:
87 case FFI_TYPE_UINT32:
88 case FFI_TYPE_SINT64:
89 case FFI_TYPE_UINT64:
90 case FFI_TYPE_POINTER:
91 case FFI_TYPE_FLOAT:
92 case FFI_TYPE_DOUBLE:
93 case FFI_TYPE_LONGDOUBLE:
94 /* All take one 8 byte slot. */
95 bytes += 8;
96 break;
98 case FFI_TYPE_VOID:
99 case FFI_TYPE_STRUCT:
100 /* Passed by value in N slots. */
101 bytes += ALIGN(itype->size, FFI_SIZEOF_ARG);
102 break;
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)
107 bytes += 8;
108 else
109 bytes += 16;
110 break;
112 default:
113 abort();
117 /* Set the return type flag */
118 rtype = cif->rtype;
119 switch (rtype->type)
121 case FFI_TYPE_VOID:
122 flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
123 break;
124 case FFI_TYPE_INT:
125 case FFI_TYPE_UINT32:
126 case FFI_TYPE_SINT32:
127 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
128 break;
129 case FFI_TYPE_FLOAT:
130 flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
131 break;
132 case FFI_TYPE_DOUBLE:
133 flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
134 break;
135 case FFI_TYPE_UINT8:
136 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
137 break;
138 case FFI_TYPE_SINT8:
139 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
140 break;
141 case FFI_TYPE_UINT16:
142 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
143 break;
144 case FFI_TYPE_SINT16:
145 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
146 break;
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);
151 break;
152 case FFI_TYPE_LONGDOUBLE:
153 case FFI_TYPE_STRUCT:
154 /* Passed in memory, with a hidden pointer. */
155 flags = ALPHA_RET_IN_MEM;
156 break;
157 case FFI_TYPE_COMPLEX:
158 itype = rtype->elements[0];
159 switch (itype->type)
161 case FFI_TYPE_FLOAT:
162 flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
163 break;
164 case FFI_TYPE_DOUBLE:
165 flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
166 break;
167 default:
168 if (rtype->size <= 8)
169 flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
170 else
171 flags = ALPHA_RET_IN_MEM;
172 break;
174 break;
175 default:
176 abort();
178 cif->flags = flags;
180 /* Include the hidden structure pointer in args requirement. */
181 if (flags == ALPHA_RET_IN_MEM)
182 bytes += 8;
183 /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
184 if (bytes < 6*8)
185 bytes = 6*8;
186 cif->bytes = bytes;
188 return FFI_OK;
191 static unsigned long
192 extend_basic_type(void *valp, int type, int argn)
194 switch (type)
196 case FFI_TYPE_SINT8:
197 return *(SINT8 *)valp;
198 case FFI_TYPE_UINT8:
199 return *(UINT8 *)valp;
200 case FFI_TYPE_SINT16:
201 return *(SINT16 *)valp;
202 case FFI_TYPE_UINT16:
203 return *(UINT16 *)valp;
205 case FFI_TYPE_FLOAT:
206 if (argn < 6)
207 return lds(valp);
208 /* FALLTHRU */
210 case FFI_TYPE_INT:
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;
222 default:
223 abort();
227 static void
228 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
229 void **avalue, void *closure)
231 unsigned long *argp;
232 long i, avn, argn, flags = cif->flags;
233 ffi_type **arg_types;
234 void *frame;
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);
244 frame += cif->bytes;
246 argn = 0;
247 if (flags == ALPHA_RET_IN_MEM)
248 argp[argn++] = (unsigned long)rvalue;
250 avn = cif->nargs;
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];
257 int type = ty->type;
258 size_t size;
260 switch (type)
262 case FFI_TYPE_INT:
263 case FFI_TYPE_SINT8:
264 case FFI_TYPE_UINT8:
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:
272 case FFI_TYPE_FLOAT:
273 case FFI_TYPE_DOUBLE:
274 argp[argn] = extend_basic_type(valp, type, argn);
275 argn++;
276 break;
278 case FFI_TYPE_LONGDOUBLE:
279 by_reference:
280 /* Note that 128-bit long double is passed by reference. */
281 argp[argn++] = (unsigned long)valp;
282 break;
284 case FFI_TYPE_VOID:
285 case FFI_TYPE_STRUCT:
286 size = ty->size;
287 memcpy(argp + argn, valp, size);
288 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
289 break;
291 case FFI_TYPE_COMPLEX:
292 type = ty->elements[0]->type;
293 if (type == FFI_TYPE_LONGDOUBLE)
294 goto by_reference;
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);
300 argn += 2;
301 break;
303 default:
304 abort();
308 flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
309 ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
312 void
313 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
315 ffi_call_int(cif, fn, rvalue, avalue, NULL);
318 void
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);
325 ffi_status
326 ffi_prep_closure_loc (ffi_closure* closure,
327 ffi_cif* cif,
328 void (*fun)(ffi_cif*, void*, void**, void*),
329 void *user_data,
330 void *codeloc)
332 unsigned int *tramp;
334 if (cif->abi != FFI_OSF)
335 return FFI_BAD_ABI;
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;
344 closure->cif = cif;
345 closure->fun = fun;
346 closure->user_data = user_data;
348 /* Flush the Icache.
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");
356 return FFI_OK;
359 ffi_status
360 ffi_prep_go_closure (ffi_go_closure* closure,
361 ffi_cif* cif,
362 void (*fun)(ffi_cif*, void*, void**, void*))
364 if (cif->abi != FFI_OSF)
365 return FFI_BAD_ABI;
367 closure->tramp = (void *)ffi_go_closure_osf;
368 closure->cif = cif;
369 closure->fun = fun;
371 return FFI_OK;
374 long FFI_HIDDEN
375 ffi_closure_osf_inner (ffi_cif *cif,
376 void (*fun)(ffi_cif*, void*, void**, void*),
377 void *user_data,
378 void *rvalue, unsigned long *argp)
380 void **avalue;
381 ffi_type **arg_types;
382 long i, avn, argn, flags;
384 avalue = alloca(cif->nargs * sizeof(void *));
385 flags = cif->flags;
386 argn = 0;
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];
393 argn = 1;
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];
402 int type = ty->type;
403 void *valp = &argp[argn];
404 size_t size;
406 switch (type)
408 case FFI_TYPE_INT:
409 case FFI_TYPE_SINT8:
410 case FFI_TYPE_UINT8:
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:
418 argn += 1;
419 break;
421 case FFI_TYPE_VOID:
422 case FFI_TYPE_STRUCT:
423 size = ty->size;
424 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
425 break;
427 case FFI_TYPE_FLOAT:
428 /* Floats coming from registers need conversion from double
429 back to float format. */
430 if (argn < 6)
432 valp = &argp[argn - 6];
433 sts(valp, argp[argn - 6]);
435 argn += 1;
436 break;
438 case FFI_TYPE_DOUBLE:
439 if (argn < 6)
440 valp = &argp[argn - 6];
441 argn += 1;
442 break;
444 case FFI_TYPE_LONGDOUBLE:
445 by_reference:
446 /* 128-bit long double is passed by reference. */
447 valp = (void *)argp[argn];
448 argn += 1;
449 break;
451 case FFI_TYPE_COMPLEX:
452 type = ty->elements[0]->type;
453 switch (type)
455 case FFI_TYPE_SINT64:
456 case FFI_TYPE_UINT64:
457 /* Passed as separate arguments, but they wind up sequential. */
458 break;
460 case FFI_TYPE_INT:
461 case FFI_TYPE_SINT8:
462 case FFI_TYPE_UINT8:
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);
471 break;
473 case FFI_TYPE_FLOAT:
474 /* Passed as separate arguments. Disjoint, and each piece
475 may need conversion back to float. */
476 if (argn < 6)
478 valp = &argp[argn - 6];
479 sts(valp, argp[argn - 6]);
481 if (argn + 1 < 6)
482 sts(valp + 4, argp[argn + 1 - 6]);
483 else
484 *(UINT32 *)(valp + 4) = argp[argn + 1];
485 break;
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. */
490 if (argn < 5)
491 valp = &argp[argn - 6];
492 else if (argn == 5)
494 valp = alloca(16);
495 ((UINT64 *)valp)[0] = argp[5 - 6];
496 ((UINT64 *)valp)[1] = argp[6];
498 break;
500 case FFI_TYPE_LONGDOUBLE:
501 goto by_reference;
503 default:
504 abort();
506 argn += 2;
507 break;
509 default:
510 abort ();
513 avalue[i] = valp;
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;