Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libffi / src / s390 / ffi.c
blob399fa2a91d9daebbe62355840013739d39ce3fcd
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2000 Software AG
4 S390 Foreign Function Interface
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
25 /*====================================================================*/
26 /* Includes */
27 /* -------- */
28 /*====================================================================*/
30 #include <ffi.h>
31 #include <ffi_common.h>
33 #include <stdlib.h>
34 #include <stdio.h>
36 /*====================== End of Includes =============================*/
38 /*====================================================================*/
39 /* Defines */
40 /* ------- */
41 /*====================================================================*/
43 /* Maximum number of GPRs available for argument passing. */
44 #define MAX_GPRARGS 5
46 /* Maximum number of FPRs available for argument passing. */
47 #ifdef __s390x__
48 #define MAX_FPRARGS 4
49 #else
50 #define MAX_FPRARGS 2
51 #endif
53 /* Round to multiple of 16. */
54 #define ROUND_SIZE(size) (((size) + 15) & ~15)
56 /* If these values change, sysv.S must be adapted! */
57 #define FFI390_RET_VOID 0
58 #define FFI390_RET_STRUCT 1
59 #define FFI390_RET_FLOAT 2
60 #define FFI390_RET_DOUBLE 3
61 #define FFI390_RET_INT32 4
62 #define FFI390_RET_INT64 5
64 /*===================== End of Defines ===============================*/
66 /*====================================================================*/
67 /* Prototypes */
68 /* ---------- */
69 /*====================================================================*/
71 static void ffi_prep_args (unsigned char *, extended_cif *);
72 void
73 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
74 __attribute__ ((visibility ("hidden")))
75 #endif
76 ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
77 unsigned long long *, unsigned long *);
79 /*====================== End of Prototypes ===========================*/
81 /*====================================================================*/
82 /* Externals */
83 /* --------- */
84 /*====================================================================*/
86 extern void ffi_call_SYSV(unsigned,
87 extended_cif *,
88 void (*)(unsigned char *, extended_cif *),
89 unsigned,
90 void *,
91 void (*fn)());
93 extern void ffi_closure_SYSV(void);
95 /*====================== End of Externals ============================*/
97 /*====================================================================*/
98 /* */
99 /* Name - ffi_check_struct_type. */
100 /* */
101 /* Function - Determine if a structure can be passed within a */
102 /* general purpose or floating point register. */
103 /* */
104 /*====================================================================*/
106 static int
107 ffi_check_struct_type (ffi_type *arg)
109 size_t size = arg->size;
111 /* If the struct has just one element, look at that element
112 to find out whether to consider the struct as floating point. */
113 while (arg->type == FFI_TYPE_STRUCT
114 && arg->elements[0] && !arg->elements[1])
115 arg = arg->elements[0];
117 /* Structs of size 1, 2, 4, and 8 are passed in registers,
118 just like the corresponding int/float types. */
119 switch (size)
121 case 1:
122 return FFI_TYPE_UINT8;
124 case 2:
125 return FFI_TYPE_UINT16;
127 case 4:
128 if (arg->type == FFI_TYPE_FLOAT)
129 return FFI_TYPE_FLOAT;
130 else
131 return FFI_TYPE_UINT32;
133 case 8:
134 if (arg->type == FFI_TYPE_DOUBLE)
135 return FFI_TYPE_DOUBLE;
136 else
137 return FFI_TYPE_UINT64;
139 default:
140 break;
143 /* Other structs are passed via a pointer to the data. */
144 return FFI_TYPE_POINTER;
147 /*======================== End of Routine ============================*/
149 /*====================================================================*/
150 /* */
151 /* Name - ffi_prep_args. */
152 /* */
153 /* Function - Prepare parameters for call to function. */
154 /* */
155 /* ffi_prep_args is called by the assembly routine once stack space */
156 /* has been allocated for the function's arguments. */
157 /* */
158 /*====================================================================*/
160 static void
161 ffi_prep_args (unsigned char *stack, extended_cif *ecif)
163 /* The stack space will be filled with those areas:
165 FPR argument register save area (highest addresses)
166 GPR argument register save area
167 temporary struct copies
168 overflow argument area (lowest addresses)
170 We set up the following pointers:
172 p_fpr: bottom of the FPR area (growing upwards)
173 p_gpr: bottom of the GPR area (growing upwards)
174 p_ov: bottom of the overflow area (growing upwards)
175 p_struct: top of the struct copy area (growing downwards)
177 All areas are kept aligned to twice the word size. */
179 int gpr_off = ecif->cif->bytes;
180 int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
182 unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
183 unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
184 unsigned char *p_struct = (unsigned char *)p_gpr;
185 unsigned long *p_ov = (unsigned long *)stack;
187 int n_fpr = 0;
188 int n_gpr = 0;
189 int n_ov = 0;
191 ffi_type **ptr;
192 void **p_argv = ecif->avalue;
193 int i;
195 /* If we returning a structure then we set the first parameter register
196 to the address of where we are returning this structure. */
198 if (ecif->cif->flags == FFI390_RET_STRUCT)
199 p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
201 /* Now for the arguments. */
203 for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
204 i > 0;
205 i--, ptr++, p_argv++)
207 void *arg = *p_argv;
208 int type = (*ptr)->type;
210 /* Check how a structure type is passed. */
211 if (type == FFI_TYPE_STRUCT)
213 type = ffi_check_struct_type (*ptr);
215 /* If we pass the struct via pointer, copy the data. */
216 if (type == FFI_TYPE_POINTER)
218 p_struct -= ROUND_SIZE ((*ptr)->size);
219 memcpy (p_struct, (char *)arg, (*ptr)->size);
220 arg = &p_struct;
224 /* Now handle all primitive int/pointer/float data types. */
225 switch (type)
227 case FFI_TYPE_DOUBLE:
228 if (n_fpr < MAX_FPRARGS)
229 p_fpr[n_fpr++] = *(unsigned long long *) arg;
230 else
231 #ifdef __s390x__
232 p_ov[n_ov++] = *(unsigned long *) arg;
233 #else
234 p_ov[n_ov++] = ((unsigned long *) arg)[0],
235 p_ov[n_ov++] = ((unsigned long *) arg)[1];
236 #endif
237 break;
239 case FFI_TYPE_FLOAT:
240 if (n_fpr < MAX_FPRARGS)
241 p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
242 else
243 p_ov[n_ov++] = *(unsigned int *) arg;
244 break;
246 case FFI_TYPE_POINTER:
247 if (n_gpr < MAX_GPRARGS)
248 p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
249 else
250 p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
251 break;
253 case FFI_TYPE_UINT64:
254 case FFI_TYPE_SINT64:
255 #ifdef __s390x__
256 if (n_gpr < MAX_GPRARGS)
257 p_gpr[n_gpr++] = *(unsigned long *) arg;
258 else
259 p_ov[n_ov++] = *(unsigned long *) arg;
260 #else
261 if (n_gpr == MAX_GPRARGS-1)
262 n_gpr = MAX_GPRARGS;
263 if (n_gpr < MAX_GPRARGS)
264 p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
265 p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
266 else
267 p_ov[n_ov++] = ((unsigned long *) arg)[0],
268 p_ov[n_ov++] = ((unsigned long *) arg)[1];
269 #endif
270 break;
272 case FFI_TYPE_UINT32:
273 if (n_gpr < MAX_GPRARGS)
274 p_gpr[n_gpr++] = *(unsigned int *) arg;
275 else
276 p_ov[n_ov++] = *(unsigned int *) arg;
277 break;
279 case FFI_TYPE_INT:
280 case FFI_TYPE_SINT32:
281 if (n_gpr < MAX_GPRARGS)
282 p_gpr[n_gpr++] = *(signed int *) arg;
283 else
284 p_ov[n_ov++] = *(signed int *) arg;
285 break;
287 case FFI_TYPE_UINT16:
288 if (n_gpr < MAX_GPRARGS)
289 p_gpr[n_gpr++] = *(unsigned short *) arg;
290 else
291 p_ov[n_ov++] = *(unsigned short *) arg;
292 break;
294 case FFI_TYPE_SINT16:
295 if (n_gpr < MAX_GPRARGS)
296 p_gpr[n_gpr++] = *(signed short *) arg;
297 else
298 p_ov[n_ov++] = *(signed short *) arg;
299 break;
301 case FFI_TYPE_UINT8:
302 if (n_gpr < MAX_GPRARGS)
303 p_gpr[n_gpr++] = *(unsigned char *) arg;
304 else
305 p_ov[n_ov++] = *(unsigned char *) arg;
306 break;
308 case FFI_TYPE_SINT8:
309 if (n_gpr < MAX_GPRARGS)
310 p_gpr[n_gpr++] = *(signed char *) arg;
311 else
312 p_ov[n_ov++] = *(signed char *) arg;
313 break;
315 default:
316 FFI_ASSERT (0);
317 break;
322 /*======================== End of Routine ============================*/
324 /*====================================================================*/
325 /* */
326 /* Name - ffi_prep_cif_machdep. */
327 /* */
328 /* Function - Perform machine dependent CIF processing. */
329 /* */
330 /*====================================================================*/
332 ffi_status
333 ffi_prep_cif_machdep(ffi_cif *cif)
335 size_t struct_size = 0;
336 int n_gpr = 0;
337 int n_fpr = 0;
338 int n_ov = 0;
340 ffi_type **ptr;
341 int i;
343 /* Determine return value handling. */
345 switch (cif->rtype->type)
347 /* Void is easy. */
348 case FFI_TYPE_VOID:
349 cif->flags = FFI390_RET_VOID;
350 break;
352 /* Structures are returned via a hidden pointer. */
353 case FFI_TYPE_STRUCT:
354 cif->flags = FFI390_RET_STRUCT;
355 n_gpr++; /* We need one GPR to pass the pointer. */
356 break;
358 /* Floating point values are returned in fpr 0. */
359 case FFI_TYPE_FLOAT:
360 cif->flags = FFI390_RET_FLOAT;
361 break;
363 case FFI_TYPE_DOUBLE:
364 cif->flags = FFI390_RET_DOUBLE;
365 break;
367 /* Integer values are returned in gpr 2 (and gpr 3
368 for 64-bit values on 31-bit machines). */
369 case FFI_TYPE_UINT64:
370 case FFI_TYPE_SINT64:
371 cif->flags = FFI390_RET_INT64;
372 break;
374 case FFI_TYPE_POINTER:
375 case FFI_TYPE_INT:
376 case FFI_TYPE_UINT32:
377 case FFI_TYPE_SINT32:
378 case FFI_TYPE_UINT16:
379 case FFI_TYPE_SINT16:
380 case FFI_TYPE_UINT8:
381 case FFI_TYPE_SINT8:
382 /* These are to be extended to word size. */
383 #ifdef __s390x__
384 cif->flags = FFI390_RET_INT64;
385 #else
386 cif->flags = FFI390_RET_INT32;
387 #endif
388 break;
390 default:
391 FFI_ASSERT (0);
392 break;
395 /* Now for the arguments. */
397 for (ptr = cif->arg_types, i = cif->nargs;
398 i > 0;
399 i--, ptr++)
401 int type = (*ptr)->type;
403 /* Check how a structure type is passed. */
404 if (type == FFI_TYPE_STRUCT)
406 type = ffi_check_struct_type (*ptr);
408 /* If we pass the struct via pointer, we must reserve space
409 to copy its data for proper call-by-value semantics. */
410 if (type == FFI_TYPE_POINTER)
411 struct_size += ROUND_SIZE ((*ptr)->size);
414 /* Now handle all primitive int/float data types. */
415 switch (type)
417 /* The first MAX_FPRARGS floating point arguments
418 go in FPRs, the rest overflow to the stack. */
420 case FFI_TYPE_DOUBLE:
421 if (n_fpr < MAX_FPRARGS)
422 n_fpr++;
423 else
424 n_ov += sizeof (double) / sizeof (long);
425 break;
427 case FFI_TYPE_FLOAT:
428 if (n_fpr < MAX_FPRARGS)
429 n_fpr++;
430 else
431 n_ov++;
432 break;
434 /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
435 if one is still available, or else on the stack. If only one
436 register is free, skip the register (it won't be used for any
437 subsequent argument either). */
439 #ifndef __s390x__
440 case FFI_TYPE_UINT64:
441 case FFI_TYPE_SINT64:
442 if (n_gpr == MAX_GPRARGS-1)
443 n_gpr = MAX_GPRARGS;
444 if (n_gpr < MAX_GPRARGS)
445 n_gpr += 2;
446 else
447 n_ov += 2;
448 break;
449 #endif
451 /* Everything else is passed in GPRs (until MAX_GPRARGS
452 have been used) or overflows to the stack. */
454 default:
455 if (n_gpr < MAX_GPRARGS)
456 n_gpr++;
457 else
458 n_ov++;
459 break;
463 /* Total stack space as required for overflow arguments
464 and temporary structure copies. */
466 cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
468 return FFI_OK;
471 /*======================== End of Routine ============================*/
473 /*====================================================================*/
474 /* */
475 /* Name - ffi_call. */
476 /* */
477 /* Function - Call the FFI routine. */
478 /* */
479 /*====================================================================*/
481 void
482 ffi_call(ffi_cif *cif,
483 void (*fn)(),
484 void *rvalue,
485 void **avalue)
487 int ret_type = cif->flags;
488 extended_cif ecif;
490 ecif.cif = cif;
491 ecif.avalue = avalue;
492 ecif.rvalue = rvalue;
494 /* If we don't have a return value, we need to fake one. */
495 if (rvalue == NULL)
497 if (ret_type == FFI390_RET_STRUCT)
498 ecif.rvalue = alloca (cif->rtype->size);
499 else
500 ret_type = FFI390_RET_VOID;
503 switch (cif->abi)
505 case FFI_SYSV:
506 ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
507 ret_type, ecif.rvalue, fn);
508 break;
510 default:
511 FFI_ASSERT (0);
512 break;
516 /*======================== End of Routine ============================*/
518 /*====================================================================*/
519 /* */
520 /* Name - ffi_closure_helper_SYSV. */
521 /* */
522 /* Function - Call a FFI closure target function. */
523 /* */
524 /*====================================================================*/
526 void
527 ffi_closure_helper_SYSV (ffi_closure *closure,
528 unsigned long *p_gpr,
529 unsigned long long *p_fpr,
530 unsigned long *p_ov)
532 unsigned long long ret_buffer;
534 void *rvalue = &ret_buffer;
535 void **avalue;
536 void **p_arg;
538 int n_gpr = 0;
539 int n_fpr = 0;
540 int n_ov = 0;
542 ffi_type **ptr;
543 int i;
545 /* Allocate buffer for argument list pointers. */
547 p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
549 /* If we returning a structure, pass the structure address
550 directly to the target function. Otherwise, have the target
551 function store the return value to the GPR save area. */
553 if (closure->cif->flags == FFI390_RET_STRUCT)
554 rvalue = (void *) p_gpr[n_gpr++];
556 /* Now for the arguments. */
558 for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
559 i > 0;
560 i--, p_arg++, ptr++)
562 int deref_struct_pointer = 0;
563 int type = (*ptr)->type;
565 /* Check how a structure type is passed. */
566 if (type == FFI_TYPE_STRUCT)
568 type = ffi_check_struct_type (*ptr);
570 /* If we pass the struct via pointer, remember to
571 retrieve the pointer later. */
572 if (type == FFI_TYPE_POINTER)
573 deref_struct_pointer = 1;
576 /* Pointers are passed like UINTs of the same size. */
577 if (type == FFI_TYPE_POINTER)
578 #ifdef __s390x__
579 type = FFI_TYPE_UINT64;
580 #else
581 type = FFI_TYPE_UINT32;
582 #endif
584 /* Now handle all primitive int/float data types. */
585 switch (type)
587 case FFI_TYPE_DOUBLE:
588 if (n_fpr < MAX_FPRARGS)
589 *p_arg = &p_fpr[n_fpr++];
590 else
591 *p_arg = &p_ov[n_ov],
592 n_ov += sizeof (double) / sizeof (long);
593 break;
595 case FFI_TYPE_FLOAT:
596 if (n_fpr < MAX_FPRARGS)
597 *p_arg = &p_fpr[n_fpr++];
598 else
599 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
600 break;
602 case FFI_TYPE_UINT64:
603 case FFI_TYPE_SINT64:
604 #ifdef __s390x__
605 if (n_gpr < MAX_GPRARGS)
606 *p_arg = &p_gpr[n_gpr++];
607 else
608 *p_arg = &p_ov[n_ov++];
609 #else
610 if (n_gpr == MAX_GPRARGS-1)
611 n_gpr = MAX_GPRARGS;
612 if (n_gpr < MAX_GPRARGS)
613 *p_arg = &p_gpr[n_gpr], n_gpr += 2;
614 else
615 *p_arg = &p_ov[n_ov], n_ov += 2;
616 #endif
617 break;
619 case FFI_TYPE_INT:
620 case FFI_TYPE_UINT32:
621 case FFI_TYPE_SINT32:
622 if (n_gpr < MAX_GPRARGS)
623 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
624 else
625 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
626 break;
628 case FFI_TYPE_UINT16:
629 case FFI_TYPE_SINT16:
630 if (n_gpr < MAX_GPRARGS)
631 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
632 else
633 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
634 break;
636 case FFI_TYPE_UINT8:
637 case FFI_TYPE_SINT8:
638 if (n_gpr < MAX_GPRARGS)
639 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
640 else
641 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
642 break;
644 default:
645 FFI_ASSERT (0);
646 break;
649 /* If this is a struct passed via pointer, we need to
650 actually retrieve that pointer. */
651 if (deref_struct_pointer)
652 *p_arg = *(void **)*p_arg;
656 /* Call the target function. */
657 (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
659 /* Convert the return value. */
660 switch (closure->cif->rtype->type)
662 /* Void is easy, and so is struct. */
663 case FFI_TYPE_VOID:
664 case FFI_TYPE_STRUCT:
665 break;
667 /* Floating point values are returned in fpr 0. */
668 case FFI_TYPE_FLOAT:
669 p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
670 break;
672 case FFI_TYPE_DOUBLE:
673 p_fpr[0] = *(unsigned long long *) rvalue;
674 break;
676 /* Integer values are returned in gpr 2 (and gpr 3
677 for 64-bit values on 31-bit machines). */
678 case FFI_TYPE_UINT64:
679 case FFI_TYPE_SINT64:
680 #ifdef __s390x__
681 p_gpr[0] = *(unsigned long *) rvalue;
682 #else
683 p_gpr[0] = ((unsigned long *) rvalue)[0],
684 p_gpr[1] = ((unsigned long *) rvalue)[1];
685 #endif
686 break;
688 case FFI_TYPE_POINTER:
689 case FFI_TYPE_UINT32:
690 case FFI_TYPE_UINT16:
691 case FFI_TYPE_UINT8:
692 p_gpr[0] = *(unsigned long *) rvalue;
693 break;
695 case FFI_TYPE_INT:
696 case FFI_TYPE_SINT32:
697 case FFI_TYPE_SINT16:
698 case FFI_TYPE_SINT8:
699 p_gpr[0] = *(signed long *) rvalue;
700 break;
702 default:
703 FFI_ASSERT (0);
704 break;
708 /*======================== End of Routine ============================*/
710 /*====================================================================*/
711 /* */
712 /* Name - ffi_prep_closure. */
713 /* */
714 /* Function - Prepare a FFI closure. */
715 /* */
716 /*====================================================================*/
718 ffi_status
719 ffi_prep_closure (ffi_closure *closure,
720 ffi_cif *cif,
721 void (*fun) (ffi_cif *, void *, void **, void *),
722 void *user_data)
724 FFI_ASSERT (cif->abi == FFI_SYSV);
726 #ifndef __s390x__
727 *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
728 *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
729 *(short *)&closure->tramp [4] = 0x1006;
730 *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
731 *(long *)&closure->tramp [8] = (long)closure;
732 *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
733 #else
734 *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
735 *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
736 *(short *)&closure->tramp [4] = 0x100e;
737 *(short *)&closure->tramp [6] = 0x0004;
738 *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
739 *(long *)&closure->tramp[16] = (long)closure;
740 *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
741 #endif
743 closure->cif = cif;
744 closure->user_data = user_data;
745 closure->fun = fun;
747 return FFI_OK;
750 /*======================== End of Routine ============================*/