]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/s390/ffi.c
ffi.h.in (ffi_closure_alloc, [...]): New.
[thirdparty/gcc.git] / libffi / src / s390 / ffi.c
CommitLineData
22bcf65c 1/* -----------------------------------------------------------------------
18fa3240 2 ffi.c - Copyright (c) 2000, 2007 Software AG
22bcf65c
GT
3
4 S390 Foreign Function Interface
5
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:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
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/*====================================================================*/
29
30#include <ffi.h>
31#include <ffi_common.h>
32
33#include <stdlib.h>
34#include <stdio.h>
35
36/*====================== End of Includes =============================*/
37
38/*====================================================================*/
39/* Defines */
40/* ------- */
41/*====================================================================*/
c4f17c6f
UW
42
43/* Maximum number of GPRs available for argument passing. */
44#define MAX_GPRARGS 5
45
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
52
53/* Round to multiple of 16. */
54#define ROUND_SIZE(size) (((size) + 15) & ~15)
55
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
63
22bcf65c
GT
64/*===================== End of Defines ===============================*/
65
22bcf65c
GT
66/*====================================================================*/
67/* Prototypes */
68/* ---------- */
69/*====================================================================*/
70
c4f17c6f 71static void ffi_prep_args (unsigned char *, extended_cif *);
0fcc9e55
JJ
72void
73#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
74__attribute__ ((visibility ("hidden")))
75#endif
76ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
77 unsigned long long *, unsigned long *);
78
22bcf65c
GT
79/*====================== End of Prototypes ===========================*/
80
81/*====================================================================*/
82/* Externals */
83/* --------- */
84/*====================================================================*/
85
c4f17c6f 86extern void ffi_call_SYSV(unsigned,
22bcf65c 87 extended_cif *,
c4f17c6f
UW
88 void (*)(unsigned char *, extended_cif *),
89 unsigned,
90 void *,
22bcf65c 91 void (*fn)());
c4f17c6f
UW
92
93extern void ffi_closure_SYSV(void);
22bcf65c
GT
94
95/*====================== End of Externals ============================*/
96
97/*====================================================================*/
98/* */
c4f17c6f 99/* Name - ffi_check_struct_type. */
22bcf65c
GT
100/* */
101/* Function - Determine if a structure can be passed within a */
c4f17c6f 102/* general purpose or floating point register. */
22bcf65c
GT
103/* */
104/*====================================================================*/
105
c4f17c6f
UW
106static int
107ffi_check_struct_type (ffi_type *arg)
22bcf65c 108{
c4f17c6f
UW
109 size_t size = arg->size;
110
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];
116
117 /* Structs of size 1, 2, 4, and 8 are passed in registers,
118 just like the corresponding int/float types. */
119 switch (size)
120 {
121 case 1:
122 return FFI_TYPE_UINT8;
123
124 case 2:
125 return FFI_TYPE_UINT16;
126
127 case 4:
128 if (arg->type == FFI_TYPE_FLOAT)
129 return FFI_TYPE_FLOAT;
130 else
131 return FFI_TYPE_UINT32;
132
133 case 8:
134 if (arg->type == FFI_TYPE_DOUBLE)
135 return FFI_TYPE_DOUBLE;
136 else
137 return FFI_TYPE_UINT64;
138
139 default:
140 break;
141 }
142
143 /* Other structs are passed via a pointer to the data. */
144 return FFI_TYPE_POINTER;
22bcf65c
GT
145}
146
147/*======================== End of Routine ============================*/
148
149/*====================================================================*/
150/* */
c4f17c6f
UW
151/* Name - ffi_prep_args. */
152/* */
153/* Function - Prepare parameters for call to function. */
22bcf65c 154/* */
c4f17c6f
UW
155/* ffi_prep_args is called by the assembly routine once stack space */
156/* has been allocated for the function's arguments. */
22bcf65c
GT
157/* */
158/*====================================================================*/
159
c4f17c6f
UW
160static void
161ffi_prep_args (unsigned char *stack, extended_cif *ecif)
22bcf65c 162{
c4f17c6f
UW
163 /* The stack space will be filled with those areas:
164
165 FPR argument register save area (highest addresses)
166 GPR argument register save area
167 temporary struct copies
168 overflow argument area (lowest addresses)
169
170 We set up the following pointers:
171
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)
176
177 All areas are kept aligned to twice the word size. */
178
179 int gpr_off = ecif->cif->bytes;
180 int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
181
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;
186
187 int n_fpr = 0;
188 int n_gpr = 0;
189 int n_ov = 0;
190
191 ffi_type **ptr;
192 void **p_argv = ecif->avalue;
193 int i;
194
195 /* If we returning a structure then we set the first parameter register
196 to the address of where we are returning this structure. */
197
198 if (ecif->cif->flags == FFI390_RET_STRUCT)
199 p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
200
201 /* Now for the arguments. */
22bcf65c 202
c4f17c6f
UW
203 for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
204 i > 0;
205 i--, ptr++, p_argv++)
206 {
207 void *arg = *p_argv;
208 int type = (*ptr)->type;
209
7a23933b
AK
210#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
211 /* 16-byte long double is passed like a struct. */
212 if (type == FFI_TYPE_LONGDOUBLE)
213 type = FFI_TYPE_STRUCT;
214#endif
215
c4f17c6f
UW
216 /* Check how a structure type is passed. */
217 if (type == FFI_TYPE_STRUCT)
218 {
219 type = ffi_check_struct_type (*ptr);
220
221 /* If we pass the struct via pointer, copy the data. */
222 if (type == FFI_TYPE_POINTER)
223 {
224 p_struct -= ROUND_SIZE ((*ptr)->size);
225 memcpy (p_struct, (char *)arg, (*ptr)->size);
226 arg = &p_struct;
227 }
228 }
229
e5dce82f 230 /* Now handle all primitive int/pointer/float data types. */
c4f17c6f
UW
231 switch (type)
232 {
233 case FFI_TYPE_DOUBLE:
234 if (n_fpr < MAX_FPRARGS)
235 p_fpr[n_fpr++] = *(unsigned long long *) arg;
236 else
237#ifdef __s390x__
238 p_ov[n_ov++] = *(unsigned long *) arg;
239#else
240 p_ov[n_ov++] = ((unsigned long *) arg)[0],
241 p_ov[n_ov++] = ((unsigned long *) arg)[1];
242#endif
243 break;
244
245 case FFI_TYPE_FLOAT:
246 if (n_fpr < MAX_FPRARGS)
247 p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
248 else
249 p_ov[n_ov++] = *(unsigned int *) arg;
250 break;
e5dce82f
UW
251
252 case FFI_TYPE_POINTER:
253 if (n_gpr < MAX_GPRARGS)
254 p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
255 else
256 p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
257 break;
c4f17c6f
UW
258
259 case FFI_TYPE_UINT64:
260 case FFI_TYPE_SINT64:
261#ifdef __s390x__
262 if (n_gpr < MAX_GPRARGS)
263 p_gpr[n_gpr++] = *(unsigned long *) arg;
264 else
265 p_ov[n_ov++] = *(unsigned long *) arg;
266#else
267 if (n_gpr == MAX_GPRARGS-1)
268 n_gpr = MAX_GPRARGS;
269 if (n_gpr < MAX_GPRARGS)
270 p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
271 p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
272 else
273 p_ov[n_ov++] = ((unsigned long *) arg)[0],
274 p_ov[n_ov++] = ((unsigned long *) arg)[1];
275#endif
276 break;
277
278 case FFI_TYPE_UINT32:
279 if (n_gpr < MAX_GPRARGS)
280 p_gpr[n_gpr++] = *(unsigned int *) arg;
281 else
282 p_ov[n_ov++] = *(unsigned int *) arg;
283 break;
284
285 case FFI_TYPE_INT:
286 case FFI_TYPE_SINT32:
287 if (n_gpr < MAX_GPRARGS)
288 p_gpr[n_gpr++] = *(signed int *) arg;
289 else
290 p_ov[n_ov++] = *(signed int *) arg;
291 break;
292
293 case FFI_TYPE_UINT16:
294 if (n_gpr < MAX_GPRARGS)
295 p_gpr[n_gpr++] = *(unsigned short *) arg;
296 else
297 p_ov[n_ov++] = *(unsigned short *) arg;
298 break;
299
300 case FFI_TYPE_SINT16:
301 if (n_gpr < MAX_GPRARGS)
302 p_gpr[n_gpr++] = *(signed short *) arg;
303 else
304 p_ov[n_ov++] = *(signed short *) arg;
305 break;
306
307 case FFI_TYPE_UINT8:
308 if (n_gpr < MAX_GPRARGS)
309 p_gpr[n_gpr++] = *(unsigned char *) arg;
310 else
311 p_ov[n_ov++] = *(unsigned char *) arg;
312 break;
313
314 case FFI_TYPE_SINT8:
315 if (n_gpr < MAX_GPRARGS)
316 p_gpr[n_gpr++] = *(signed char *) arg;
317 else
318 p_ov[n_ov++] = *(signed char *) arg;
319 break;
320
321 default:
322 FFI_ASSERT (0);
323 break;
324 }
325 }
326}
327
22bcf65c
GT
328/*======================== End of Routine ============================*/
329
330/*====================================================================*/
331/* */
c4f17c6f 332/* Name - ffi_prep_cif_machdep. */
22bcf65c 333/* */
c4f17c6f 334/* Function - Perform machine dependent CIF processing. */
22bcf65c
GT
335/* */
336/*====================================================================*/
337
c4f17c6f
UW
338ffi_status
339ffi_prep_cif_machdep(ffi_cif *cif)
22bcf65c 340{
c4f17c6f
UW
341 size_t struct_size = 0;
342 int n_gpr = 0;
343 int n_fpr = 0;
344 int n_ov = 0;
345
346 ffi_type **ptr;
347 int i;
348
349 /* Determine return value handling. */
350
351 switch (cif->rtype->type)
352 {
353 /* Void is easy. */
354 case FFI_TYPE_VOID:
355 cif->flags = FFI390_RET_VOID;
356 break;
357
358 /* Structures are returned via a hidden pointer. */
359 case FFI_TYPE_STRUCT:
360 cif->flags = FFI390_RET_STRUCT;
361 n_gpr++; /* We need one GPR to pass the pointer. */
362 break;
363
364 /* Floating point values are returned in fpr 0. */
365 case FFI_TYPE_FLOAT:
366 cif->flags = FFI390_RET_FLOAT;
367 break;
368
369 case FFI_TYPE_DOUBLE:
370 cif->flags = FFI390_RET_DOUBLE;
371 break;
372
7a23933b
AK
373#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
374 case FFI_TYPE_LONGDOUBLE:
375 cif->flags = FFI390_RET_STRUCT;
376 n_gpr++;
377 break;
378#endif
c4f17c6f
UW
379 /* Integer values are returned in gpr 2 (and gpr 3
380 for 64-bit values on 31-bit machines). */
381 case FFI_TYPE_UINT64:
382 case FFI_TYPE_SINT64:
383 cif->flags = FFI390_RET_INT64;
384 break;
385
8177895b 386 case FFI_TYPE_POINTER:
c4f17c6f
UW
387 case FFI_TYPE_INT:
388 case FFI_TYPE_UINT32:
389 case FFI_TYPE_SINT32:
390 case FFI_TYPE_UINT16:
391 case FFI_TYPE_SINT16:
392 case FFI_TYPE_UINT8:
393 case FFI_TYPE_SINT8:
394 /* These are to be extended to word size. */
395#ifdef __s390x__
396 cif->flags = FFI390_RET_INT64;
397#else
398 cif->flags = FFI390_RET_INT32;
399#endif
400 break;
22bcf65c 401
c4f17c6f
UW
402 default:
403 FFI_ASSERT (0);
404 break;
405 }
406
407 /* Now for the arguments. */
22bcf65c 408
c4f17c6f
UW
409 for (ptr = cif->arg_types, i = cif->nargs;
410 i > 0;
411 i--, ptr++)
412 {
413 int type = (*ptr)->type;
414
7a23933b
AK
415#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
416 /* 16-byte long double is passed like a struct. */
417 if (type == FFI_TYPE_LONGDOUBLE)
418 type = FFI_TYPE_STRUCT;
419#endif
420
c4f17c6f
UW
421 /* Check how a structure type is passed. */
422 if (type == FFI_TYPE_STRUCT)
423 {
424 type = ffi_check_struct_type (*ptr);
425
426 /* If we pass the struct via pointer, we must reserve space
427 to copy its data for proper call-by-value semantics. */
428 if (type == FFI_TYPE_POINTER)
429 struct_size += ROUND_SIZE ((*ptr)->size);
430 }
431
432 /* Now handle all primitive int/float data types. */
433 switch (type)
434 {
435 /* The first MAX_FPRARGS floating point arguments
436 go in FPRs, the rest overflow to the stack. */
437
438 case FFI_TYPE_DOUBLE:
439 if (n_fpr < MAX_FPRARGS)
440 n_fpr++;
441 else
442 n_ov += sizeof (double) / sizeof (long);
443 break;
444
445 case FFI_TYPE_FLOAT:
446 if (n_fpr < MAX_FPRARGS)
447 n_fpr++;
448 else
449 n_ov++;
450 break;
451
452 /* On 31-bit machines, 64-bit integers are passed in GPR pairs,
453 if one is still available, or else on the stack. If only one
454 register is free, skip the register (it won't be used for any
455 subsequent argument either). */
456
457#ifndef __s390x__
458 case FFI_TYPE_UINT64:
459 case FFI_TYPE_SINT64:
460 if (n_gpr == MAX_GPRARGS-1)
461 n_gpr = MAX_GPRARGS;
462 if (n_gpr < MAX_GPRARGS)
463 n_gpr += 2;
464 else
465 n_ov += 2;
466 break;
467#endif
468
469 /* Everything else is passed in GPRs (until MAX_GPRARGS
470 have been used) or overflows to the stack. */
471
472 default:
473 if (n_gpr < MAX_GPRARGS)
474 n_gpr++;
475 else
476 n_ov++;
477 break;
478 }
479 }
480
481 /* Total stack space as required for overflow arguments
482 and temporary structure copies. */
483
484 cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
485
486 return FFI_OK;
22bcf65c
GT
487}
488
489/*======================== End of Routine ============================*/
490
491/*====================================================================*/
492/* */
c4f17c6f 493/* Name - ffi_call. */
22bcf65c 494/* */
c4f17c6f 495/* Function - Call the FFI routine. */
22bcf65c
GT
496/* */
497/*====================================================================*/
498
499void
c4f17c6f
UW
500ffi_call(ffi_cif *cif,
501 void (*fn)(),
502 void *rvalue,
503 void **avalue)
22bcf65c 504{
c4f17c6f
UW
505 int ret_type = cif->flags;
506 extended_cif ecif;
22bcf65c 507
c4f17c6f
UW
508 ecif.cif = cif;
509 ecif.avalue = avalue;
510 ecif.rvalue = rvalue;
511
512 /* If we don't have a return value, we need to fake one. */
513 if (rvalue == NULL)
514 {
515 if (ret_type == FFI390_RET_STRUCT)
516 ecif.rvalue = alloca (cif->rtype->size);
517 else
518 ret_type = FFI390_RET_VOID;
519 }
520
521 switch (cif->abi)
522 {
523 case FFI_SYSV:
524 ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
525 ret_type, ecif.rvalue, fn);
526 break;
527
528 default:
529 FFI_ASSERT (0);
530 break;
531 }
22bcf65c
GT
532}
533
534/*======================== End of Routine ============================*/
c4f17c6f 535
22bcf65c
GT
536/*====================================================================*/
537/* */
c4f17c6f 538/* Name - ffi_closure_helper_SYSV. */
22bcf65c 539/* */
c4f17c6f 540/* Function - Call a FFI closure target function. */
22bcf65c
GT
541/* */
542/*====================================================================*/
543
544void
c4f17c6f
UW
545ffi_closure_helper_SYSV (ffi_closure *closure,
546 unsigned long *p_gpr,
547 unsigned long long *p_fpr,
548 unsigned long *p_ov)
22bcf65c 549{
c4f17c6f
UW
550 unsigned long long ret_buffer;
551
552 void *rvalue = &ret_buffer;
553 void **avalue;
554 void **p_arg;
555
556 int n_gpr = 0;
557 int n_fpr = 0;
558 int n_ov = 0;
559
22bcf65c 560 ffi_type **ptr;
c4f17c6f
UW
561 int i;
562
563 /* Allocate buffer for argument list pointers. */
564
565 p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
566
567 /* If we returning a structure, pass the structure address
568 directly to the target function. Otherwise, have the target
569 function store the return value to the GPR save area. */
570
571 if (closure->cif->flags == FFI390_RET_STRUCT)
572 rvalue = (void *) p_gpr[n_gpr++];
573
22bcf65c 574 /* Now for the arguments. */
c4f17c6f
UW
575
576 for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
22bcf65c 577 i > 0;
c4f17c6f 578 i--, p_arg++, ptr++)
22bcf65c 579 {
c4f17c6f
UW
580 int deref_struct_pointer = 0;
581 int type = (*ptr)->type;
582
7a23933b
AK
583#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
584 /* 16-byte long double is passed like a struct. */
585 if (type == FFI_TYPE_LONGDOUBLE)
586 type = FFI_TYPE_STRUCT;
587#endif
588
c4f17c6f
UW
589 /* Check how a structure type is passed. */
590 if (type == FFI_TYPE_STRUCT)
591 {
592 type = ffi_check_struct_type (*ptr);
593
594 /* If we pass the struct via pointer, remember to
595 retrieve the pointer later. */
596 if (type == FFI_TYPE_POINTER)
597 deref_struct_pointer = 1;
598 }
599
600 /* Pointers are passed like UINTs of the same size. */
601 if (type == FFI_TYPE_POINTER)
602#ifdef __s390x__
603 type = FFI_TYPE_UINT64;
604#else
605 type = FFI_TYPE_UINT32;
606#endif
607
608 /* Now handle all primitive int/float data types. */
609 switch (type)
610 {
611 case FFI_TYPE_DOUBLE:
612 if (n_fpr < MAX_FPRARGS)
613 *p_arg = &p_fpr[n_fpr++];
614 else
615 *p_arg = &p_ov[n_ov],
616 n_ov += sizeof (double) / sizeof (long);
617 break;
618
619 case FFI_TYPE_FLOAT:
620 if (n_fpr < MAX_FPRARGS)
621 *p_arg = &p_fpr[n_fpr++];
622 else
623 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
624 break;
625
626 case FFI_TYPE_UINT64:
627 case FFI_TYPE_SINT64:
628#ifdef __s390x__
629 if (n_gpr < MAX_GPRARGS)
630 *p_arg = &p_gpr[n_gpr++];
631 else
632 *p_arg = &p_ov[n_ov++];
633#else
634 if (n_gpr == MAX_GPRARGS-1)
635 n_gpr = MAX_GPRARGS;
636 if (n_gpr < MAX_GPRARGS)
637 *p_arg = &p_gpr[n_gpr], n_gpr += 2;
638 else
639 *p_arg = &p_ov[n_ov], n_ov += 2;
640#endif
641 break;
642
643 case FFI_TYPE_INT:
644 case FFI_TYPE_UINT32:
645 case FFI_TYPE_SINT32:
646 if (n_gpr < MAX_GPRARGS)
647 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
648 else
649 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
650 break;
651
652 case FFI_TYPE_UINT16:
653 case FFI_TYPE_SINT16:
654 if (n_gpr < MAX_GPRARGS)
655 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
656 else
657 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
658 break;
659
660 case FFI_TYPE_UINT8:
661 case FFI_TYPE_SINT8:
662 if (n_gpr < MAX_GPRARGS)
663 *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
664 else
665 *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
666 break;
667
668 default:
669 FFI_ASSERT (0);
670 break;
671 }
672
673 /* If this is a struct passed via pointer, we need to
674 actually retrieve that pointer. */
675 if (deref_struct_pointer)
676 *p_arg = *(void **)*p_arg;
677 }
678
679
680 /* Call the target function. */
681 (closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
682
683 /* Convert the return value. */
684 switch (closure->cif->rtype->type)
685 {
686 /* Void is easy, and so is struct. */
687 case FFI_TYPE_VOID:
688 case FFI_TYPE_STRUCT:
7a23933b
AK
689#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
690 case FFI_TYPE_LONGDOUBLE:
691#endif
c4f17c6f
UW
692 break;
693
694 /* Floating point values are returned in fpr 0. */
22bcf65c 695 case FFI_TYPE_FLOAT:
c4f17c6f 696 p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
22bcf65c 697 break;
c4f17c6f 698
22bcf65c 699 case FFI_TYPE_DOUBLE:
c4f17c6f 700 p_fpr[0] = *(unsigned long long *) rvalue;
22bcf65c 701 break;
c4f17c6f
UW
702
703 /* Integer values are returned in gpr 2 (and gpr 3
704 for 64-bit values on 31-bit machines). */
22bcf65c
GT
705 case FFI_TYPE_UINT64:
706 case FFI_TYPE_SINT64:
c4f17c6f
UW
707#ifdef __s390x__
708 p_gpr[0] = *(unsigned long *) rvalue;
709#else
710 p_gpr[0] = ((unsigned long *) rvalue)[0],
711 p_gpr[1] = ((unsigned long *) rvalue)[1];
712#endif
22bcf65c 713 break;
c4f17c6f 714
8177895b 715 case FFI_TYPE_POINTER:
c4f17c6f 716 case FFI_TYPE_UINT32:
8177895b
UW
717 case FFI_TYPE_UINT16:
718 case FFI_TYPE_UINT8:
719 p_gpr[0] = *(unsigned long *) rvalue;
22bcf65c 720 break;
c4f17c6f
UW
721
722 case FFI_TYPE_INT:
723 case FFI_TYPE_SINT32:
22bcf65c 724 case FFI_TYPE_SINT16:
c4f17c6f 725 case FFI_TYPE_SINT8:
8177895b 726 p_gpr[0] = *(signed long *) rvalue;
22bcf65c 727 break;
c4f17c6f
UW
728
729 default:
730 FFI_ASSERT (0);
731 break;
22bcf65c
GT
732 }
733}
22bcf65c 734
c4f17c6f
UW
735/*======================== End of Routine ============================*/
736
22bcf65c
GT
737/*====================================================================*/
738/* */
18fa3240 739/* Name - ffi_prep_closure_loc. */
22bcf65c 740/* */
c4f17c6f 741/* Function - Prepare a FFI closure. */
22bcf65c
GT
742/* */
743/*====================================================================*/
744
745ffi_status
18fa3240
AO
746ffi_prep_closure_loc (ffi_closure *closure,
747 ffi_cif *cif,
748 void (*fun) (ffi_cif *, void *, void **, void *),
749 void *user_data,
750 void *codeloc)
22bcf65c 751{
c4f17c6f
UW
752 FFI_ASSERT (cif->abi == FFI_SYSV);
753
754#ifndef __s390x__
755 *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
756 *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
757 *(short *)&closure->tramp [4] = 0x1006;
758 *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
18fa3240 759 *(long *)&closure->tramp [8] = (long)codeloc;
c4f17c6f
UW
760 *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
761#else
762 *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
763 *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
764 *(short *)&closure->tramp [4] = 0x100e;
765 *(short *)&closure->tramp [6] = 0x0004;
766 *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
18fa3240 767 *(long *)&closure->tramp[16] = (long)codeloc;
c4f17c6f
UW
768 *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
769#endif
770
771 closure->cif = cif;
772 closure->user_data = user_data;
773 closure->fun = fun;
22bcf65c
GT
774
775 return FFI_OK;
776}
c4f17c6f 777
22bcf65c
GT
778/*======================== End of Routine ============================*/
779