fixed more binutils issues (newer gcc/libc)
[zpugcc/jano.git] / toolchain / gcc / libffi / src / ia64 / ffi.c
blobc846f6e1338913ac3057d1698157a425624166ac
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 ----------------------------------------------------------------------- */
27 #include <ffi.h>
28 #include <ffi_common.h>
30 #include <stdlib.h>
31 #include <stdbool.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. */
43 struct ia64_args {
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 */
49 /* registers. */
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)
58 switch(tp) {
59 case FFI_TYPE_FLOAT:
60 return sizeof(float);
61 case FFI_TYPE_DOUBLE:
62 return sizeof(double);
63 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
64 case FFI_TYPE_LONGDOUBLE:
65 return sizeof(long double);
66 #endif
67 default:
68 FFI_ASSERT(0);
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)
80 ffi_type **ptr;
81 unsigned short element, struct_element;
83 int type_set = 0;
85 FFI_ASSERT(type != NULL);
87 FFI_ASSERT(type->elements != NULL);
89 ptr = &(type->elements[0]);
91 while ((*ptr) != NULL)
93 switch((*ptr) -> type) {
94 case FFI_TYPE_FLOAT:
95 if (type_set && element != FFI_TYPE_FLOAT) return 0;
96 if (--n < 0) return false;
97 type_set = 1;
98 element = FFI_TYPE_FLOAT;
99 break;
100 case FFI_TYPE_DOUBLE:
101 if (type_set && element != FFI_TYPE_DOUBLE) return 0;
102 if (--n < 0) return false;
103 type_set = 1;
104 element = FFI_TYPE_DOUBLE;
105 break;
106 case FFI_TYPE_STRUCT:
107 if (!is_homogeneous_fp_aggregate(type, n, &struct_element))
108 return false;
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;
113 break;
114 /* case FFI_TYPE_LONGDOUBLE:
115 Not yet implemented. */
116 default:
117 return false;
119 ptr++;
121 *element_type = element;
122 return true;
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. */
131 static bool
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;
143 i = 0;
144 avn = ecif->cif->nargs;
145 p_arg = ecif->cif->arg_types;
146 p_argv = ecif->avalue;
147 while (i < avn)
149 size_t z; /* z is in units of arg slots or words, not bytes. */
151 switch ((*p_arg)->type)
153 case FFI_TYPE_SINT8:
154 z = 1;
155 *(SINT64 *) argp = *(SINT8 *)(* p_argv);
156 break;
158 case FFI_TYPE_UINT8:
159 z = 1;
160 *(UINT64 *) argp = *(UINT8 *)(* p_argv);
161 break;
163 case FFI_TYPE_SINT16:
164 z = 1;
165 *(SINT64 *) argp = *(SINT16 *)(* p_argv);
166 break;
168 case FFI_TYPE_UINT16:
169 z = 1;
170 *(UINT64 *) argp = *(UINT16 *)(* p_argv);
171 break;
173 case FFI_TYPE_SINT32:
174 z = 1;
175 *(SINT64 *) argp = *(SINT32 *)(* p_argv);
176 break;
178 case FFI_TYPE_UINT32:
179 z = 1;
180 *(UINT64 *) argp = *(UINT32 *)(* p_argv);
181 break;
183 case FFI_TYPE_SINT64:
184 case FFI_TYPE_UINT64:
185 case FFI_TYPE_POINTER:
186 z = 1;
187 *(UINT64 *) argp = *(UINT64 *)(* p_argv);
188 break;
190 case FFI_TYPE_FLOAT:
191 z = 1;
192 if (fp_argp - stack->fp_regs < 8)
194 /* Note the conversion -- all the fp regs are loaded as
195 doubles. */
196 *fp_argp++ = *(float *)(* p_argv);
198 /* Also put it into the integer registers or memory: */
199 *(UINT64 *) argp = *(UINT32 *)(* p_argv);
200 break;
202 case FFI_TYPE_DOUBLE:
203 z = 1;
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);
208 break;
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)) {
216 int i;
217 int nelements = sz/float_type_size(element_type);
218 for (i = 0; i < nelements; ++i) {
219 switch (element_type) {
220 case FFI_TYPE_FLOAT:
221 if (fp_argp - stack->fp_regs < 8)
222 *fp_argp++ = ((float *)(* p_argv))[i];
223 break;
224 case FFI_TYPE_DOUBLE:
225 if (fp_argp - stack->fp_regs < 8)
226 *fp_argp++ = ((double *)(* p_argv))[i];
227 break;
228 default:
229 /* Extended precision not yet implemented. */
230 abort();
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);
238 break;
240 default:
241 FFI_ASSERT(0);
244 argp += z;
245 i++, p_arg++, p_argv++;
247 return (fp_argp != stack -> fp_regs);
250 /* Perform machine dependent cif processing */
251 ffi_status
252 ffi_prep_cif_machdep(ffi_cif *cif)
254 long i, avn;
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
261 remain. */
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
268 appropriately. */
270 cif->bytes = ALIGN(cif->bytes, 2*sizeof(void*));
272 avn = cif->nargs;
273 if (avn <= 2) {
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);
278 break;
279 case FFI_TYPE_SINT64:
280 case FFI_TYPE_UINT64:
281 case FFI_TYPE_POINTER:
282 simple_flag = FFI_ADD_LONG_ARG(simple_flag);
283 break;
284 default:
285 is_simple = false;
288 } else {
289 is_simple = false;
292 /* Set the return type flag */
293 switch (cif->rtype->type)
295 case FFI_TYPE_VOID:
296 cif->flags = FFI_TYPE_VOID;
297 break;
299 case FFI_TYPE_STRUCT:
301 size_t sz = cif -> rtype -> size;
302 unsigned short element_type;
304 is_simple = false;
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;
310 } else {
311 cif -> flags = element_type;
313 } else {
314 switch(element_type) {
315 case FFI_TYPE_FLOAT:
316 cif -> flags = FFI_IS_FLOAT_FP_AGGREGATE | nelements;
317 break;
318 case FFI_TYPE_DOUBLE:
319 cif -> flags = FFI_IS_DOUBLE_FP_AGGREGATE | nelements;
320 break;
321 default:
322 /* long double NYI */
323 abort();
326 break;
328 if (sz <= 32) {
329 if (sz <= 8) {
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;
335 } else {
336 cif->flags = FFI_IS_SMALL_STRUCT4;
338 } else {
339 cif->flags = FFI_TYPE_STRUCT;
342 break;
344 case FFI_TYPE_FLOAT:
345 is_simple = false;
346 cif->flags = FFI_TYPE_FLOAT;
347 break;
349 case FFI_TYPE_DOUBLE:
350 is_simple = false;
351 cif->flags = FFI_TYPE_DOUBLE;
352 break;
354 default:
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. */
359 break;
362 if (is_simple) cif -> flags |= simple_flag;
363 return FFI_OK;
366 extern int ffi_call_unix(bool (*)(struct ia64_args *, extended_cif *, int),
367 extended_cif *, unsigned,
368 unsigned, unsigned *, void (*)());
370 void
371 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
373 extended_cif ecif;
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 */
380 /* enough. */
381 /* This needs work for HP/UX. */
382 if (simple) {
383 long (*lfn)() = (long (*)())fn;
384 long result;
385 switch(simple) {
386 case FFI_SIMPLE_V:
387 result = lfn();
388 break;
389 case FFI_SIMPLE_I:
390 result = lfn(*(int *)avalue[0]);
391 break;
392 case FFI_SIMPLE_L:
393 result = lfn(*(long *)avalue[0]);
394 break;
395 case FFI_SIMPLE_II:
396 result = lfn(*(int *)avalue[0], *(int *)avalue[1]);
397 break;
398 case FFI_SIMPLE_IL:
399 result = lfn(*(int *)avalue[0], *(long *)avalue[1]);
400 break;
401 case FFI_SIMPLE_LI:
402 result = lfn(*(long *)avalue[0], *(int *)avalue[1]);
403 break;
404 case FFI_SIMPLE_LL:
405 result = lfn(*(long *)avalue[0], *(long *)avalue[1]);
406 break;
408 if ((cif->flags & ~FFI_SIMPLE) != FFI_TYPE_VOID && 0 != rvalue) {
409 * (long *)rvalue = result;
411 return;
413 ecif.cif = cif;
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);
421 else
422 ecif.rvalue = rvalue;
424 switch (cif->abi)
426 case FFI_UNIX:
427 ffi_call_unix(ffi_prep_args, &ecif, cif->bytes,
428 cif->flags, rvalue, fn);
429 break;
431 default:
432 FFI_ASSERT(0);
433 break;
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,
443 * into a closure.
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.
457 static void
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();
473 #ifndef __GNUC__
474 # error This requires gcc
475 #endif
476 void
477 ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
478 /* Hopefully declaring this as a varargs function will force all args */
479 /* to memory. */
481 // this is our return value storage
482 long double res;
484 // our various things...
485 ffi_cif *cif;
486 unsigned short rtype;
487 void *resp;
488 void **arg_area;
490 resp = (void*)&res;
491 cif = closure->cif;
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);
504 rtype = cif->flags;
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)
528 : "r8","r9","r10");
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? */
539 abort();
543 static void
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;
554 avn = cif->nargs;
555 p_argv = avalue;
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)
563 case FFI_TYPE_SINT8:
564 case FFI_TYPE_UINT8:
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:
572 z = 1;
573 *p_argv = (void *)argp;
574 break;
576 case FFI_TYPE_FLOAT:
577 z = 1;
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++];
581 } else {
582 *(float *)argp = *(double *)argp;
584 *p_argv = (void *)argp;
585 break;
587 case FFI_TYPE_DOUBLE:
588 z = 1;
589 if (fp_reg_num < 8) {
590 *p_argv = args -> fp_regs + fp_reg_num++;
591 } else {
592 *p_argv = (void *)argp;
594 break;
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) {
604 /* hard case NYI. */
605 abort();
607 if (element_type == FFI_TYPE_DOUBLE) {
608 *p_argv = args -> fp_regs + fp_reg_num;
609 fp_reg_num += nelements;
610 break;
612 if (element_type == FFI_TYPE_FLOAT) {
613 int j;
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;
619 break;
621 abort(); /* Other fp types NYI */
624 break;
626 default:
627 FFI_ASSERT(0);
630 argp += z;
631 p_argv++;
635 return;
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 {
646 void *code_pointer;
647 void *gp;
648 } ia64_fd;
650 ffi_status
651 ffi_prep_closure (ffi_closure* closure,
652 ffi_cif* cif,
653 void (*fun)(ffi_cif*,void*,void**,void*),
654 void *user_data)
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;
665 closure->cif = cif;
666 closure->user_data = user_data;
667 closure->fun = fun;
669 return FFI_OK;