Fix xfail for 32-bit hppa*-*-* in gcc.dg/pr84877.c
[official-gcc.git] / libffi / src / powerpc / ffi_linux64.c
blob3454dacd3d641654929152271535f68493bf55be
1 /* -----------------------------------------------------------------------
2 ffi_linux64.c - Copyright (C) 2013 IBM
3 Copyright (C) 2011 Anthony Green
4 Copyright (C) 2011 Kyle Moffett
5 Copyright (C) 2008 Red Hat, Inc
6 Copyright (C) 2007, 2008 Free Software Foundation, Inc
7 Copyright (c) 1998 Geoffrey Keating
9 PowerPC Foreign Function Interface
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 ``Software''), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, sublicense, and/or sell copies of the Software, and to
16 permit persons to whom the Software is furnished to do so, subject to
17 the following conditions:
19 The above copyright notice and this permission notice shall be included
20 in all copies or substantial portions of the Software.
22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 OTHER DEALINGS IN THE SOFTWARE.
29 ----------------------------------------------------------------------- */
31 #include "ffi.h"
33 #ifdef POWERPC64
34 #include "ffi_common.h"
35 #include "ffi_powerpc.h"
38 /* About the LINUX64 ABI. */
39 enum {
40 NUM_GPR_ARG_REGISTERS64 = 8,
41 NUM_FPR_ARG_REGISTERS64 = 13,
42 NUM_VEC_ARG_REGISTERS64 = 12,
44 enum { ASM_NEEDS_REGISTERS64 = 4 };
47 #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
48 /* Adjust size of ffi_type_longdouble. */
49 void FFI_HIDDEN
50 ffi_prep_types_linux64 (ffi_abi abi)
52 if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
54 ffi_type_longdouble.size = 8;
55 ffi_type_longdouble.alignment = 8;
57 else
59 ffi_type_longdouble.size = 16;
60 ffi_type_longdouble.alignment = 16;
63 #endif
66 static unsigned int
67 discover_homogeneous_aggregate (ffi_abi abi,
68 const ffi_type *t,
69 unsigned int *elnum)
71 switch (t->type)
73 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
74 case FFI_TYPE_LONGDOUBLE:
75 /* 64-bit long doubles are equivalent to doubles. */
76 if ((abi & FFI_LINUX_LONG_DOUBLE_128) == 0)
78 *elnum = 1;
79 return FFI_TYPE_DOUBLE;
81 /* IBM extended precision values use unaligned pairs
82 of FPRs, but according to the ABI must be considered
83 distinct from doubles. They are also limited to a
84 maximum of four members in a homogeneous aggregate. */
85 else if ((abi & FFI_LINUX_LONG_DOUBLE_IEEE128) == 0)
87 *elnum = 2;
88 return FFI_TYPE_LONGDOUBLE;
90 /* Fall through. */
91 #endif
92 case FFI_TYPE_FLOAT:
93 case FFI_TYPE_DOUBLE:
94 *elnum = 1;
95 return (int) t->type;
97 case FFI_TYPE_STRUCT:;
99 unsigned int base_elt = 0, total_elnum = 0;
100 ffi_type **el = t->elements;
101 while (*el)
103 unsigned int el_elt, el_elnum = 0;
104 el_elt = discover_homogeneous_aggregate (abi, *el, &el_elnum);
105 if (el_elt == 0
106 || (base_elt && base_elt != el_elt))
107 return 0;
108 base_elt = el_elt;
109 total_elnum += el_elnum;
110 #if _CALL_ELF == 2
111 if (total_elnum > 8)
112 return 0;
113 #else
114 if (total_elnum > 1)
115 return 0;
116 #endif
117 el++;
119 *elnum = total_elnum;
120 return base_elt;
123 default:
124 return 0;
129 /* Perform machine dependent cif processing */
130 static ffi_status
131 ffi_prep_cif_linux64_core (ffi_cif *cif)
133 ffi_type **ptr;
134 unsigned bytes;
135 unsigned i, fparg_count = 0, intarg_count = 0, vecarg_count = 0;
136 unsigned flags = cif->flags;
137 unsigned elt, elnum, rtype;
139 #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
140 /* If compiled without long double support... */
141 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0 ||
142 (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
143 return FFI_BAD_ABI;
144 #elif !defined(__VEC__)
145 /* If compiled without vector register support (used by assembly)... */
146 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
147 return FFI_BAD_ABI;
148 #else
149 /* If the IEEE128 flag is set, but long double is only 64 bits wide... */
150 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) == 0 &&
151 (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
152 return FFI_BAD_ABI;
153 #endif
155 /* The machine-independent calculation of cif->bytes doesn't work
156 for us. Redo the calculation. */
157 #if _CALL_ELF == 2
158 /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
159 bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
161 /* Space for the general registers. */
162 bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
163 #else
164 /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
165 regs. */
166 bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
168 /* Space for the mandatory parm save area and general registers. */
169 bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
170 #endif
172 /* Return value handling. */
173 rtype = cif->rtype->type;
174 #if _CALL_ELF == 2
175 homogeneous:
176 #endif
177 switch (rtype)
179 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
180 case FFI_TYPE_LONGDOUBLE:
181 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
183 flags |= FLAG_RETURNS_VEC;
184 break;
186 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
187 flags |= FLAG_RETURNS_128BITS;
188 /* Fall through. */
189 #endif
190 case FFI_TYPE_DOUBLE:
191 flags |= FLAG_RETURNS_64BITS;
192 /* Fall through. */
193 case FFI_TYPE_FLOAT:
194 flags |= FLAG_RETURNS_FP;
195 break;
197 case FFI_TYPE_UINT128:
198 flags |= FLAG_RETURNS_128BITS;
199 /* Fall through. */
200 case FFI_TYPE_UINT64:
201 case FFI_TYPE_SINT64:
202 case FFI_TYPE_POINTER:
203 flags |= FLAG_RETURNS_64BITS;
204 break;
206 case FFI_TYPE_STRUCT:
207 #if _CALL_ELF == 2
208 elt = discover_homogeneous_aggregate (cif->abi, cif->rtype, &elnum);
209 if (elt)
211 flags |= FLAG_RETURNS_SMST;
212 rtype = elt;
213 goto homogeneous;
215 if (cif->rtype->size <= 16)
217 flags |= FLAG_RETURNS_SMST;
218 break;
220 #endif
221 intarg_count++;
222 flags |= FLAG_RETVAL_REFERENCE;
223 /* Fall through. */
224 case FFI_TYPE_VOID:
225 flags |= FLAG_RETURNS_NOTHING;
226 break;
228 default:
229 /* Returns 32-bit integer, or similar. Nothing to do here. */
230 break;
233 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
235 unsigned int align;
237 switch ((*ptr)->type)
239 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
240 case FFI_TYPE_LONGDOUBLE:
241 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
243 vecarg_count++;
244 /* Align to 16 bytes, plus the 16-byte argument. */
245 intarg_count = (intarg_count + 3) & ~0x1;
246 if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
247 flags |= FLAG_ARG_NEEDS_PSAVE;
248 break;
250 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
252 fparg_count++;
253 intarg_count++;
255 /* Fall through. */
256 #endif
257 case FFI_TYPE_DOUBLE:
258 case FFI_TYPE_FLOAT:
259 fparg_count++;
260 intarg_count++;
261 if (fparg_count > NUM_FPR_ARG_REGISTERS64)
262 flags |= FLAG_ARG_NEEDS_PSAVE;
263 break;
265 case FFI_TYPE_STRUCT:
266 if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
268 align = (*ptr)->alignment;
269 if (align > 16)
270 align = 16;
271 align = align / 8;
272 if (align > 1)
273 intarg_count = FFI_ALIGN (intarg_count, align);
275 intarg_count += ((*ptr)->size + 7) / 8;
276 elt = discover_homogeneous_aggregate (cif->abi, *ptr, &elnum);
277 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
278 if (elt == FFI_TYPE_LONGDOUBLE &&
279 (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
281 vecarg_count += elnum;
282 if (vecarg_count > NUM_VEC_ARG_REGISTERS64)
283 flags |= FLAG_ARG_NEEDS_PSAVE;
284 break;
286 else
287 #endif
288 if (elt)
290 fparg_count += elnum;
291 if (fparg_count > NUM_FPR_ARG_REGISTERS64)
292 flags |= FLAG_ARG_NEEDS_PSAVE;
294 else
296 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
297 flags |= FLAG_ARG_NEEDS_PSAVE;
299 break;
301 case FFI_TYPE_POINTER:
302 case FFI_TYPE_UINT64:
303 case FFI_TYPE_SINT64:
304 case FFI_TYPE_INT:
305 case FFI_TYPE_UINT32:
306 case FFI_TYPE_SINT32:
307 case FFI_TYPE_UINT16:
308 case FFI_TYPE_SINT16:
309 case FFI_TYPE_UINT8:
310 case FFI_TYPE_SINT8:
311 /* Everything else is passed as a 8-byte word in a GPR, either
312 the object itself or a pointer to it. */
313 intarg_count++;
314 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
315 flags |= FLAG_ARG_NEEDS_PSAVE;
316 break;
317 default:
318 FFI_ASSERT (0);
322 if (fparg_count != 0)
323 flags |= FLAG_FP_ARGUMENTS;
324 if (intarg_count > 4)
325 flags |= FLAG_4_GPR_ARGUMENTS;
326 if (vecarg_count != 0)
327 flags |= FLAG_VEC_ARGUMENTS;
329 /* Space for the FPR registers, if needed. */
330 if (fparg_count != 0)
331 bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
332 /* Space for the vector registers, if needed, aligned to 16 bytes. */
333 if (vecarg_count != 0) {
334 bytes = (bytes + 15) & ~0xF;
335 bytes += NUM_VEC_ARG_REGISTERS64 * sizeof (float128);
338 /* Stack space. */
339 #if _CALL_ELF == 2
340 if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
341 bytes += intarg_count * sizeof (long);
342 #else
343 if (intarg_count > NUM_GPR_ARG_REGISTERS64)
344 bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
345 #endif
347 /* The stack space allocated needs to be a multiple of 16 bytes. */
348 bytes = (bytes + 15) & ~0xF;
350 cif->flags = flags;
351 cif->bytes = bytes;
353 return FFI_OK;
356 ffi_status FFI_HIDDEN
357 ffi_prep_cif_linux64 (ffi_cif *cif)
359 if ((cif->abi & FFI_LINUX) != 0)
360 cif->nfixedargs = cif->nargs;
361 #if _CALL_ELF != 2
362 else if (cif->abi == FFI_COMPAT_LINUX64)
364 /* This call is from old code. Don't touch cif->nfixedargs
365 since old code will be using a smaller cif. */
366 cif->flags |= FLAG_COMPAT;
367 /* Translate to new abi value. */
368 cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
370 #endif
371 else
372 return FFI_BAD_ABI;
373 return ffi_prep_cif_linux64_core (cif);
376 ffi_status FFI_HIDDEN
377 ffi_prep_cif_linux64_var (ffi_cif *cif,
378 unsigned int nfixedargs,
379 unsigned int ntotalargs MAYBE_UNUSED)
381 if ((cif->abi & FFI_LINUX) != 0)
382 cif->nfixedargs = nfixedargs;
383 #if _CALL_ELF != 2
384 else if (cif->abi == FFI_COMPAT_LINUX64)
386 /* This call is from old code. Don't touch cif->nfixedargs
387 since old code will be using a smaller cif. */
388 cif->flags |= FLAG_COMPAT;
389 /* Translate to new abi value. */
390 cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
392 #endif
393 else
394 return FFI_BAD_ABI;
395 #if _CALL_ELF == 2
396 cif->flags |= FLAG_ARG_NEEDS_PSAVE;
397 #endif
398 return ffi_prep_cif_linux64_core (cif);
402 /* ffi_prep_args64 is called by the assembly routine once stack space
403 has been allocated for the function's arguments.
405 The stack layout we want looks like this:
407 | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
408 |--------------------------------------------|
409 | CR save area 8bytes |
410 |--------------------------------------------|
411 | Previous backchain pointer 8 | stack pointer here
412 |--------------------------------------------|<+ <<< on entry to
413 | Saved r28-r31 4*8 | | ffi_call_LINUX64
414 |--------------------------------------------| |
415 | GPR registers r3-r10 8*8 | |
416 |--------------------------------------------| |
417 | FPR registers f1-f13 (optional) 13*8 | |
418 |--------------------------------------------| |
419 | VEC registers v2-v13 (optional) 12*16 | |
420 |--------------------------------------------| |
421 | Parameter save area | |
422 |--------------------------------------------| |
423 | TOC save area 8 | |
424 |--------------------------------------------| | stack |
425 | Linker doubleword 8 | | grows |
426 |--------------------------------------------| | down V
427 | Compiler doubleword 8 | |
428 |--------------------------------------------| | lower addresses
429 | Space for callee's LR 8 | |
430 |--------------------------------------------| |
431 | CR save area 8 | |
432 |--------------------------------------------| | stack pointer here
433 | Current backchain pointer 8 |-/ during
434 |--------------------------------------------| <<< ffi_call_LINUX64
438 void FFI_HIDDEN
439 ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
441 const unsigned long bytes = ecif->cif->bytes;
442 const unsigned long flags = ecif->cif->flags;
444 typedef union
446 char *c;
447 unsigned long *ul;
448 float *f;
449 double *d;
450 float128 *f128;
451 size_t p;
452 } valp;
454 /* 'stacktop' points at the previous backchain pointer. */
455 valp stacktop;
457 /* 'next_arg' points at the space for gpr3, and grows upwards as
458 we use GPR registers, then continues at rest. */
459 valp gpr_base;
460 valp gpr_end;
461 valp rest;
462 valp next_arg;
464 /* 'fpr_base' points at the space for f1, and grows upwards as
465 we use FPR registers. */
466 valp fpr_base;
467 unsigned int fparg_count;
469 /* 'vec_base' points at the space for v2, and grows upwards as
470 we use vector registers. */
471 valp vec_base;
472 unsigned int vecarg_count;
474 unsigned int i, words, nargs, nfixedargs;
475 ffi_type **ptr;
476 double double_tmp;
477 union
479 void **v;
480 char **c;
481 signed char **sc;
482 unsigned char **uc;
483 signed short **ss;
484 unsigned short **us;
485 signed int **si;
486 unsigned int **ui;
487 unsigned long **ul;
488 float **f;
489 double **d;
490 float128 **f128;
491 } p_argv;
492 unsigned long gprvalue;
493 unsigned long align;
495 stacktop.c = (char *) stack + bytes;
496 gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
497 gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
498 #if _CALL_ELF == 2
499 rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
500 #else
501 rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
502 #endif
503 fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
504 fparg_count = 0;
505 /* Place the vector args below the FPRs, if used, else the GPRs. */
506 if (ecif->cif->flags & FLAG_FP_ARGUMENTS)
507 vec_base.p = fpr_base.p & ~0xF;
508 else
509 vec_base.p = gpr_base.p;
510 vec_base.f128 -= NUM_VEC_ARG_REGISTERS64;
511 vecarg_count = 0;
512 next_arg.ul = gpr_base.ul;
514 /* Check that everything starts aligned properly. */
515 FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
516 FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
517 FFI_ASSERT (((unsigned long) gpr_base.c & 0xF) == 0);
518 FFI_ASSERT (((unsigned long) gpr_end.c & 0xF) == 0);
519 FFI_ASSERT (((unsigned long) vec_base.c & 0xF) == 0);
520 FFI_ASSERT ((bytes & 0xF) == 0);
522 /* Deal with return values that are actually pass-by-reference. */
523 if (flags & FLAG_RETVAL_REFERENCE)
524 *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
526 /* Now for the arguments. */
527 p_argv.v = ecif->avalue;
528 nargs = ecif->cif->nargs;
529 #if _CALL_ELF != 2
530 nfixedargs = (unsigned) -1;
531 if ((flags & FLAG_COMPAT) == 0)
532 #endif
533 nfixedargs = ecif->cif->nfixedargs;
534 for (ptr = ecif->cif->arg_types, i = 0;
535 i < nargs;
536 i++, ptr++, p_argv.v++)
538 unsigned int elt, elnum;
540 switch ((*ptr)->type)
542 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
543 case FFI_TYPE_LONGDOUBLE:
544 if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
546 next_arg.p = FFI_ALIGN (next_arg.p, 16);
547 if (next_arg.ul == gpr_end.ul)
548 next_arg.ul = rest.ul;
549 if (vecarg_count < NUM_VEC_ARG_REGISTERS64 && i < nfixedargs)
550 memcpy (vec_base.f128++, *p_argv.f128, sizeof (float128));
551 else
552 memcpy (next_arg.f128, *p_argv.f128, sizeof (float128));
553 if (++next_arg.f128 == gpr_end.f128)
554 next_arg.f128 = rest.f128;
555 vecarg_count++;
556 FFI_ASSERT (__LDBL_MANT_DIG__ == 113);
557 FFI_ASSERT (flags & FLAG_VEC_ARGUMENTS);
558 break;
560 if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
562 double_tmp = (*p_argv.d)[0];
563 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
565 *fpr_base.d++ = double_tmp;
566 # if _CALL_ELF != 2
567 if ((flags & FLAG_COMPAT) != 0)
568 *next_arg.d = double_tmp;
569 # endif
571 else
572 *next_arg.d = double_tmp;
573 if (++next_arg.ul == gpr_end.ul)
574 next_arg.ul = rest.ul;
575 fparg_count++;
576 double_tmp = (*p_argv.d)[1];
577 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
579 *fpr_base.d++ = double_tmp;
580 # if _CALL_ELF != 2
581 if ((flags & FLAG_COMPAT) != 0)
582 *next_arg.d = double_tmp;
583 # endif
585 else
586 *next_arg.d = double_tmp;
587 if (++next_arg.ul == gpr_end.ul)
588 next_arg.ul = rest.ul;
589 fparg_count++;
590 FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
591 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
592 break;
594 /* Fall through. */
595 #endif
596 case FFI_TYPE_DOUBLE:
597 #if _CALL_ELF != 2
598 do_double:
599 #endif
600 double_tmp = **p_argv.d;
601 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
603 *fpr_base.d++ = double_tmp;
604 #if _CALL_ELF != 2
605 if ((flags & FLAG_COMPAT) != 0)
606 *next_arg.d = double_tmp;
607 #endif
609 else
610 *next_arg.d = double_tmp;
611 if (++next_arg.ul == gpr_end.ul)
612 next_arg.ul = rest.ul;
613 fparg_count++;
614 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
615 break;
617 case FFI_TYPE_FLOAT:
618 #if _CALL_ELF != 2
619 do_float:
620 #endif
621 double_tmp = **p_argv.f;
622 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
624 *fpr_base.d++ = double_tmp;
625 #if _CALL_ELF != 2
626 if ((flags & FLAG_COMPAT) != 0)
628 # ifndef __LITTLE_ENDIAN__
629 next_arg.f[1] = (float) double_tmp;
630 # else
631 next_arg.f[0] = (float) double_tmp;
632 # endif
634 #endif
636 else
638 # ifndef __LITTLE_ENDIAN__
639 next_arg.f[1] = (float) double_tmp;
640 # else
641 next_arg.f[0] = (float) double_tmp;
642 # endif
644 if (++next_arg.ul == gpr_end.ul)
645 next_arg.ul = rest.ul;
646 fparg_count++;
647 FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
648 break;
650 case FFI_TYPE_STRUCT:
651 if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
653 align = (*ptr)->alignment;
654 if (align > 16)
655 align = 16;
656 if (align > 1)
658 next_arg.p = FFI_ALIGN (next_arg.p, align);
659 if (next_arg.ul == gpr_end.ul)
660 next_arg.ul = rest.ul;
663 elt = discover_homogeneous_aggregate (ecif->cif->abi, *ptr, &elnum);
664 if (elt)
666 #if _CALL_ELF == 2
667 union {
668 void *v;
669 float *f;
670 double *d;
671 float128 *f128;
672 } arg;
674 arg.v = *p_argv.v;
675 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
676 if (elt == FFI_TYPE_LONGDOUBLE &&
677 (ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
681 if (vecarg_count < NUM_VEC_ARG_REGISTERS64
682 && i < nfixedargs)
683 memcpy (vec_base.f128++, arg.f128++, sizeof (float128));
684 else
685 memcpy (next_arg.f128, arg.f128++, sizeof (float128));
686 if (++next_arg.f128 == gpr_end.f128)
687 next_arg.f128 = rest.f128;
688 vecarg_count++;
690 while (--elnum != 0);
692 else
693 #endif
694 if (elt == FFI_TYPE_FLOAT)
698 double_tmp = *arg.f++;
699 if (fparg_count < NUM_FPR_ARG_REGISTERS64
700 && i < nfixedargs)
701 *fpr_base.d++ = double_tmp;
702 else
703 *next_arg.f = (float) double_tmp;
704 if (++next_arg.f == gpr_end.f)
705 next_arg.f = rest.f;
706 fparg_count++;
708 while (--elnum != 0);
709 if ((next_arg.p & 7) != 0)
710 if (++next_arg.f == gpr_end.f)
711 next_arg.f = rest.f;
713 else
716 double_tmp = *arg.d++;
717 if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
718 *fpr_base.d++ = double_tmp;
719 else
720 *next_arg.d = double_tmp;
721 if (++next_arg.d == gpr_end.d)
722 next_arg.d = rest.d;
723 fparg_count++;
725 while (--elnum != 0);
726 #else
727 if (elt == FFI_TYPE_FLOAT)
728 goto do_float;
729 else
730 goto do_double;
731 #endif
733 else
735 words = ((*ptr)->size + 7) / 8;
736 if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
738 size_t first = gpr_end.c - next_arg.c;
739 memcpy (next_arg.c, *p_argv.c, first);
740 memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
741 next_arg.c = rest.c + words * 8 - first;
743 else
745 char *where = next_arg.c;
747 #ifndef __LITTLE_ENDIAN__
748 /* Structures with size less than eight bytes are passed
749 left-padded. */
750 if ((*ptr)->size < 8)
751 where += 8 - (*ptr)->size;
752 #endif
753 memcpy (where, *p_argv.c, (*ptr)->size);
754 next_arg.ul += words;
755 if (next_arg.ul == gpr_end.ul)
756 next_arg.ul = rest.ul;
759 break;
761 case FFI_TYPE_UINT8:
762 gprvalue = **p_argv.uc;
763 goto putgpr;
764 case FFI_TYPE_SINT8:
765 gprvalue = **p_argv.sc;
766 goto putgpr;
767 case FFI_TYPE_UINT16:
768 gprvalue = **p_argv.us;
769 goto putgpr;
770 case FFI_TYPE_SINT16:
771 gprvalue = **p_argv.ss;
772 goto putgpr;
773 case FFI_TYPE_UINT32:
774 gprvalue = **p_argv.ui;
775 goto putgpr;
776 case FFI_TYPE_INT:
777 case FFI_TYPE_SINT32:
778 gprvalue = **p_argv.si;
779 goto putgpr;
781 case FFI_TYPE_UINT64:
782 case FFI_TYPE_SINT64:
783 case FFI_TYPE_POINTER:
784 gprvalue = **p_argv.ul;
785 putgpr:
786 *next_arg.ul++ = gprvalue;
787 if (next_arg.ul == gpr_end.ul)
788 next_arg.ul = rest.ul;
789 break;
793 FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
794 || (next_arg.ul >= gpr_base.ul
795 && next_arg.ul <= gpr_base.ul + 4));
799 #if _CALL_ELF == 2
800 #define MIN_CACHE_LINE_SIZE 8
802 static void
803 flush_icache (char *wraddr, char *xaddr, int size)
805 int i;
806 for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
807 __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
808 : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
809 __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
810 : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
811 : "memory");
813 #endif
816 ffi_status FFI_HIDDEN
817 ffi_prep_closure_loc_linux64 (ffi_closure *closure,
818 ffi_cif *cif,
819 void (*fun) (ffi_cif *, void *, void **, void *),
820 void *user_data,
821 void *codeloc)
823 #if _CALL_ELF == 2
824 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
826 if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
827 return FFI_BAD_ABI;
829 tramp[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
830 tramp[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
831 tramp[2] = 0x7d8903a6; /* mtctr 12 */
832 tramp[3] = 0x4e800420; /* bctr */
833 /* 1: .quad function_addr */
834 /* 2: .quad context */
835 *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
836 *(void **) &tramp[6] = codeloc;
837 flush_icache ((char *) tramp, (char *) codeloc, 4 * 4);
838 #else
839 void **tramp = (void **) &closure->tramp[0];
841 if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
842 return FFI_BAD_ABI;
844 /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */
845 memcpy (&tramp[0], (void **) ffi_closure_LINUX64, sizeof (void *));
846 tramp[1] = codeloc;
847 memcpy (&tramp[2], (void **) ffi_closure_LINUX64 + 1, sizeof (void *));
848 #endif
850 closure->cif = cif;
851 closure->fun = fun;
852 closure->user_data = user_data;
854 return FFI_OK;
858 int FFI_HIDDEN
859 ffi_closure_helper_LINUX64 (ffi_cif *cif,
860 void (*fun) (ffi_cif *, void *, void **, void *),
861 void *user_data,
862 void *rvalue,
863 unsigned long *pst,
864 ffi_dblfl *pfr,
865 float128 *pvec)
867 /* rvalue is the pointer to space for return value in closure assembly */
868 /* pst is the pointer to parameter save area
869 (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
870 /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
871 /* pvec is the pointer to where v2-v13 are stored in ffi_closure_LINUX64 */
873 void **avalue;
874 ffi_type **arg_types;
875 unsigned long i, avn, nfixedargs;
876 ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
877 float128 *end_pvec = pvec + NUM_VEC_ARG_REGISTERS64;
878 unsigned long align;
880 avalue = alloca (cif->nargs * sizeof (void *));
882 /* Copy the caller's structure return value address so that the
883 closure returns the data directly to the caller. */
884 if (cif->rtype->type == FFI_TYPE_STRUCT
885 && (cif->flags & FLAG_RETURNS_SMST) == 0)
887 rvalue = (void *) *pst;
888 pst++;
891 i = 0;
892 avn = cif->nargs;
893 #if _CALL_ELF != 2
894 nfixedargs = (unsigned) -1;
895 if ((cif->flags & FLAG_COMPAT) == 0)
896 #endif
897 nfixedargs = cif->nfixedargs;
898 arg_types = cif->arg_types;
900 /* Grab the addresses of the arguments from the stack frame. */
901 while (i < avn)
903 unsigned int elt, elnum;
905 switch (arg_types[i]->type)
907 case FFI_TYPE_SINT8:
908 case FFI_TYPE_UINT8:
909 #ifndef __LITTLE_ENDIAN__
910 avalue[i] = (char *) pst + 7;
911 pst++;
912 break;
913 #endif
915 case FFI_TYPE_SINT16:
916 case FFI_TYPE_UINT16:
917 #ifndef __LITTLE_ENDIAN__
918 avalue[i] = (char *) pst + 6;
919 pst++;
920 break;
921 #endif
923 case FFI_TYPE_SINT32:
924 case FFI_TYPE_UINT32:
925 #ifndef __LITTLE_ENDIAN__
926 avalue[i] = (char *) pst + 4;
927 pst++;
928 break;
929 #endif
931 case FFI_TYPE_SINT64:
932 case FFI_TYPE_UINT64:
933 case FFI_TYPE_POINTER:
934 avalue[i] = pst;
935 pst++;
936 break;
938 case FFI_TYPE_STRUCT:
939 if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
941 align = arg_types[i]->alignment;
942 if (align > 16)
943 align = 16;
944 if (align > 1)
945 pst = (unsigned long *) FFI_ALIGN ((size_t) pst, align);
947 elt = discover_homogeneous_aggregate (cif->abi, arg_types[i], &elnum);
948 if (elt)
950 #if _CALL_ELF == 2
951 union {
952 void *v;
953 unsigned long *ul;
954 float *f;
955 double *d;
956 float128 *f128;
957 size_t p;
958 } to, from;
960 /* Repackage the aggregate from its parts. The
961 aggregate size is not greater than the space taken by
962 the registers so store back to the register/parameter
963 save arrays. */
964 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
965 if (elt == FFI_TYPE_LONGDOUBLE &&
966 (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
968 if (pvec + elnum <= end_pvec)
969 to.v = pvec;
970 else
971 to.v = pst;
973 else
974 #endif
975 if (pfr + elnum <= end_pfr)
976 to.v = pfr;
977 else
978 to.v = pst;
980 avalue[i] = to.v;
981 from.ul = pst;
982 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
983 if (elt == FFI_TYPE_LONGDOUBLE &&
984 (cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
988 if (pvec < end_pvec && i < nfixedargs)
989 memcpy (to.f128, pvec++, sizeof (float128));
990 else
991 memcpy (to.f128, from.f128, sizeof (float128));
992 to.f128++;
993 from.f128++;
995 while (--elnum != 0);
997 else
998 #endif
999 if (elt == FFI_TYPE_FLOAT)
1003 if (pfr < end_pfr && i < nfixedargs)
1005 *to.f = (float) pfr->d;
1006 pfr++;
1008 else
1009 *to.f = *from.f;
1010 to.f++;
1011 from.f++;
1013 while (--elnum != 0);
1015 else
1019 if (pfr < end_pfr && i < nfixedargs)
1021 *to.d = pfr->d;
1022 pfr++;
1024 else
1025 *to.d = *from.d;
1026 to.d++;
1027 from.d++;
1029 while (--elnum != 0);
1031 #else
1032 if (elt == FFI_TYPE_FLOAT)
1033 goto do_float;
1034 else
1035 goto do_double;
1036 #endif
1038 else
1040 #ifndef __LITTLE_ENDIAN__
1041 /* Structures with size less than eight bytes are passed
1042 left-padded. */
1043 if (arg_types[i]->size < 8)
1044 avalue[i] = (char *) pst + 8 - arg_types[i]->size;
1045 else
1046 #endif
1047 avalue[i] = pst;
1049 pst += (arg_types[i]->size + 7) / 8;
1050 break;
1052 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
1053 case FFI_TYPE_LONGDOUBLE:
1054 if ((cif->abi & FFI_LINUX_LONG_DOUBLE_IEEE128) != 0)
1056 if (((unsigned long) pst & 0xF) != 0)
1057 ++pst;
1058 if (pvec < end_pvec && i < nfixedargs)
1059 avalue[i] = pvec++;
1060 else
1061 avalue[i] = pst;
1062 pst += 2;
1063 break;
1065 else if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
1067 if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
1069 avalue[i] = pfr;
1070 pfr += 2;
1072 else
1074 if (pfr < end_pfr && i < nfixedargs)
1076 /* Passed partly in f13 and partly on the stack.
1077 Move it all to the stack. */
1078 *pst = *(unsigned long *) pfr;
1079 pfr++;
1081 avalue[i] = pst;
1083 pst += 2;
1084 break;
1086 /* Fall through. */
1087 #endif
1088 case FFI_TYPE_DOUBLE:
1089 #if _CALL_ELF != 2
1090 do_double:
1091 #endif
1092 /* On the outgoing stack all values are aligned to 8 */
1093 /* there are 13 64bit floating point registers */
1095 if (pfr < end_pfr && i < nfixedargs)
1097 avalue[i] = pfr;
1098 pfr++;
1100 else
1101 avalue[i] = pst;
1102 pst++;
1103 break;
1105 case FFI_TYPE_FLOAT:
1106 #if _CALL_ELF != 2
1107 do_float:
1108 #endif
1109 if (pfr < end_pfr && i < nfixedargs)
1111 /* Float values are stored as doubles in the
1112 ffi_closure_LINUX64 code. Fix them here. */
1113 pfr->f = (float) pfr->d;
1114 avalue[i] = pfr;
1115 pfr++;
1117 else
1119 #ifndef __LITTLE_ENDIAN__
1120 avalue[i] = (char *) pst + 4;
1121 #else
1122 avalue[i] = pst;
1123 #endif
1125 pst++;
1126 break;
1128 default:
1129 FFI_ASSERT (0);
1132 i++;
1135 (*fun) (cif, rvalue, avalue, user_data);
1137 /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
1138 if ((cif->flags & FLAG_RETURNS_SMST) != 0)
1140 if ((cif->flags & (FLAG_RETURNS_FP | FLAG_RETURNS_VEC)) == 0)
1141 return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
1142 else if ((cif->flags & FLAG_RETURNS_VEC) != 0)
1143 return FFI_V2_TYPE_VECTOR_HOMOG;
1144 else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
1145 return FFI_V2_TYPE_DOUBLE_HOMOG;
1146 else
1147 return FFI_V2_TYPE_FLOAT_HOMOG;
1149 if ((cif->flags & FLAG_RETURNS_VEC) != 0)
1150 return FFI_V2_TYPE_VECTOR;
1151 return cif->rtype->type;
1153 #endif