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 ----------------------------------------------------------------------- */
34 #include "ffi_common.h"
35 #include "ffi_powerpc.h"
38 /* About the LINUX64 ABI. */
40 NUM_GPR_ARG_REGISTERS64
= 8,
41 NUM_FPR_ARG_REGISTERS64
= 13
43 enum { ASM_NEEDS_REGISTERS64
= 4 };
46 #if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
47 /* Adjust size of ffi_type_longdouble. */
49 ffi_prep_types_linux64 (ffi_abi abi
)
51 if ((abi
& (FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
)) == FFI_LINUX
)
53 ffi_type_longdouble
.size
= 8;
54 ffi_type_longdouble
.alignment
= 8;
58 ffi_type_longdouble
.size
= 16;
59 ffi_type_longdouble
.alignment
= 16;
66 discover_homogeneous_aggregate (const ffi_type
*t
, unsigned int *elnum
)
75 case FFI_TYPE_STRUCT
:;
77 unsigned int base_elt
= 0, total_elnum
= 0;
78 ffi_type
**el
= t
->elements
;
81 unsigned int el_elt
, el_elnum
= 0;
82 el_elt
= discover_homogeneous_aggregate (*el
, &el_elnum
);
84 || (base_elt
&& base_elt
!= el_elt
))
87 total_elnum
+= el_elnum
;
107 /* Perform machine dependent cif processing */
109 ffi_prep_cif_linux64_core (ffi_cif
*cif
)
113 unsigned i
, fparg_count
= 0, intarg_count
= 0;
114 unsigned flags
= cif
->flags
;
115 unsigned int elt
, elnum
;
117 #if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
118 /* If compiled without long double support.. */
119 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
123 /* The machine-independent calculation of cif->bytes doesn't work
124 for us. Redo the calculation. */
126 /* Space for backchain, CR, LR, TOC and the asm's temp regs. */
127 bytes
= (4 + ASM_NEEDS_REGISTERS64
) * sizeof (long);
129 /* Space for the general registers. */
130 bytes
+= NUM_GPR_ARG_REGISTERS64
* sizeof (long);
132 /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
134 bytes
= (6 + ASM_NEEDS_REGISTERS64
) * sizeof (long);
136 /* Space for the mandatory parm save area and general registers. */
137 bytes
+= 2 * NUM_GPR_ARG_REGISTERS64
* sizeof (long);
140 /* Return value handling. */
141 switch (cif
->rtype
->type
)
143 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
144 case FFI_TYPE_LONGDOUBLE
:
145 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
146 flags
|= FLAG_RETURNS_128BITS
;
149 case FFI_TYPE_DOUBLE
:
150 flags
|= FLAG_RETURNS_64BITS
;
153 flags
|= FLAG_RETURNS_FP
;
156 case FFI_TYPE_UINT128
:
157 flags
|= FLAG_RETURNS_128BITS
;
159 case FFI_TYPE_UINT64
:
160 case FFI_TYPE_SINT64
:
161 case FFI_TYPE_POINTER
:
162 flags
|= FLAG_RETURNS_64BITS
;
165 case FFI_TYPE_STRUCT
:
167 elt
= discover_homogeneous_aggregate (cif
->rtype
, &elnum
);
170 if (elt
== FFI_TYPE_DOUBLE
)
171 flags
|= FLAG_RETURNS_64BITS
;
172 flags
|= FLAG_RETURNS_FP
| FLAG_RETURNS_SMST
;
175 if (cif
->rtype
->size
<= 16)
177 flags
|= FLAG_RETURNS_SMST
;
182 flags
|= FLAG_RETVAL_REFERENCE
;
185 flags
|= FLAG_RETURNS_NOTHING
;
189 /* Returns 32-bit integer, or similar. Nothing to do here. */
193 for (ptr
= cif
->arg_types
, i
= cif
->nargs
; i
> 0; i
--, ptr
++)
197 switch ((*ptr
)->type
)
199 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
200 case FFI_TYPE_LONGDOUBLE
:
201 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
208 case FFI_TYPE_DOUBLE
:
212 if (fparg_count
> NUM_FPR_ARG_REGISTERS64
)
213 flags
|= FLAG_ARG_NEEDS_PSAVE
;
216 case FFI_TYPE_STRUCT
:
217 if ((cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
219 align
= (*ptr
)->alignment
;
224 intarg_count
= ALIGN (intarg_count
, align
);
226 intarg_count
+= ((*ptr
)->size
+ 7) / 8;
227 elt
= discover_homogeneous_aggregate (*ptr
, &elnum
);
230 fparg_count
+= elnum
;
231 if (fparg_count
> NUM_FPR_ARG_REGISTERS64
)
232 flags
|= FLAG_ARG_NEEDS_PSAVE
;
236 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
237 flags
|= FLAG_ARG_NEEDS_PSAVE
;
241 case FFI_TYPE_POINTER
:
242 case FFI_TYPE_UINT64
:
243 case FFI_TYPE_SINT64
:
245 case FFI_TYPE_UINT32
:
246 case FFI_TYPE_SINT32
:
247 case FFI_TYPE_UINT16
:
248 case FFI_TYPE_SINT16
:
251 /* Everything else is passed as a 8-byte word in a GPR, either
252 the object itself or a pointer to it. */
254 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
255 flags
|= FLAG_ARG_NEEDS_PSAVE
;
262 if (fparg_count
!= 0)
263 flags
|= FLAG_FP_ARGUMENTS
;
264 if (intarg_count
> 4)
265 flags
|= FLAG_4_GPR_ARGUMENTS
;
267 /* Space for the FPR registers, if needed. */
268 if (fparg_count
!= 0)
269 bytes
+= NUM_FPR_ARG_REGISTERS64
* sizeof (double);
273 if ((flags
& FLAG_ARG_NEEDS_PSAVE
) != 0)
274 bytes
+= intarg_count
* sizeof (long);
276 if (intarg_count
> NUM_GPR_ARG_REGISTERS64
)
277 bytes
+= (intarg_count
- NUM_GPR_ARG_REGISTERS64
) * sizeof (long);
280 /* The stack space allocated needs to be a multiple of 16 bytes. */
281 bytes
= (bytes
+ 15) & ~0xF;
289 ffi_status FFI_HIDDEN
290 ffi_prep_cif_linux64 (ffi_cif
*cif
)
292 if ((cif
->abi
& FFI_LINUX
) != 0)
293 cif
->nfixedargs
= cif
->nargs
;
295 else if (cif
->abi
== FFI_COMPAT_LINUX64
)
297 /* This call is from old code. Don't touch cif->nfixedargs
298 since old code will be using a smaller cif. */
299 cif
->flags
|= FLAG_COMPAT
;
300 /* Translate to new abi value. */
301 cif
->abi
= FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
;
306 return ffi_prep_cif_linux64_core (cif
);
309 ffi_status FFI_HIDDEN
310 ffi_prep_cif_linux64_var (ffi_cif
*cif
,
311 unsigned int nfixedargs
,
312 unsigned int ntotalargs MAYBE_UNUSED
)
314 if ((cif
->abi
& FFI_LINUX
) != 0)
315 cif
->nfixedargs
= nfixedargs
;
317 else if (cif
->abi
== FFI_COMPAT_LINUX64
)
319 /* This call is from old code. Don't touch cif->nfixedargs
320 since old code will be using a smaller cif. */
321 cif
->flags
|= FLAG_COMPAT
;
322 /* Translate to new abi value. */
323 cif
->abi
= FFI_LINUX
| FFI_LINUX_LONG_DOUBLE_128
;
329 cif
->flags
|= FLAG_ARG_NEEDS_PSAVE
;
331 return ffi_prep_cif_linux64_core (cif
);
335 /* ffi_prep_args64 is called by the assembly routine once stack space
336 has been allocated for the function's arguments.
338 The stack layout we want looks like this:
340 | Ret addr from ffi_call_LINUX64 8bytes | higher addresses
341 |--------------------------------------------|
342 | CR save area 8bytes |
343 |--------------------------------------------|
344 | Previous backchain pointer 8 | stack pointer here
345 |--------------------------------------------|<+ <<< on entry to
346 | Saved r28-r31 4*8 | | ffi_call_LINUX64
347 |--------------------------------------------| |
348 | GPR registers r3-r10 8*8 | |
349 |--------------------------------------------| |
350 | FPR registers f1-f13 (optional) 13*8 | |
351 |--------------------------------------------| |
352 | Parameter save area | |
353 |--------------------------------------------| |
354 | TOC save area 8 | |
355 |--------------------------------------------| | stack |
356 | Linker doubleword 8 | | grows |
357 |--------------------------------------------| | down V
358 | Compiler doubleword 8 | |
359 |--------------------------------------------| | lower addresses
360 | Space for callee's LR 8 | |
361 |--------------------------------------------| |
363 |--------------------------------------------| | stack pointer here
364 | Current backchain pointer 8 |-/ during
365 |--------------------------------------------| <<< ffi_call_LINUX64
370 ffi_prep_args64 (extended_cif
*ecif
, unsigned long *const stack
)
372 const unsigned long bytes
= ecif
->cif
->bytes
;
373 const unsigned long flags
= ecif
->cif
->flags
;
384 /* 'stacktop' points at the previous backchain pointer. */
387 /* 'next_arg' points at the space for gpr3, and grows upwards as
388 we use GPR registers, then continues at rest. */
394 /* 'fpr_base' points at the space for fpr3, and grows upwards as
395 we use FPR registers. */
397 unsigned int fparg_count
;
399 unsigned int i
, words
, nargs
, nfixedargs
;
416 unsigned long gprvalue
;
419 stacktop
.c
= (char *) stack
+ bytes
;
420 gpr_base
.ul
= stacktop
.ul
- ASM_NEEDS_REGISTERS64
- NUM_GPR_ARG_REGISTERS64
;
421 gpr_end
.ul
= gpr_base
.ul
+ NUM_GPR_ARG_REGISTERS64
;
423 rest
.ul
= stack
+ 4 + NUM_GPR_ARG_REGISTERS64
;
425 rest
.ul
= stack
+ 6 + NUM_GPR_ARG_REGISTERS64
;
427 fpr_base
.d
= gpr_base
.d
- NUM_FPR_ARG_REGISTERS64
;
429 next_arg
.ul
= gpr_base
.ul
;
431 /* Check that everything starts aligned properly. */
432 FFI_ASSERT (((unsigned long) (char *) stack
& 0xF) == 0);
433 FFI_ASSERT (((unsigned long) stacktop
.c
& 0xF) == 0);
434 FFI_ASSERT ((bytes
& 0xF) == 0);
436 /* Deal with return values that are actually pass-by-reference. */
437 if (flags
& FLAG_RETVAL_REFERENCE
)
438 *next_arg
.ul
++ = (unsigned long) (char *) ecif
->rvalue
;
440 /* Now for the arguments. */
441 p_argv
.v
= ecif
->avalue
;
442 nargs
= ecif
->cif
->nargs
;
444 nfixedargs
= (unsigned) -1;
445 if ((flags
& FLAG_COMPAT
) == 0)
447 nfixedargs
= ecif
->cif
->nfixedargs
;
448 for (ptr
= ecif
->cif
->arg_types
, i
= 0;
450 i
++, ptr
++, p_argv
.v
++)
452 unsigned int elt
, elnum
;
454 switch ((*ptr
)->type
)
456 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
457 case FFI_TYPE_LONGDOUBLE
:
458 if ((ecif
->cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
460 double_tmp
= (*p_argv
.d
)[0];
461 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
463 *fpr_base
.d
++ = double_tmp
;
465 if ((flags
& FLAG_COMPAT
) != 0)
466 *next_arg
.d
= double_tmp
;
470 *next_arg
.d
= double_tmp
;
471 if (++next_arg
.ul
== gpr_end
.ul
)
472 next_arg
.ul
= rest
.ul
;
474 double_tmp
= (*p_argv
.d
)[1];
475 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
477 *fpr_base
.d
++ = double_tmp
;
479 if ((flags
& FLAG_COMPAT
) != 0)
480 *next_arg
.d
= double_tmp
;
484 *next_arg
.d
= double_tmp
;
485 if (++next_arg
.ul
== gpr_end
.ul
)
486 next_arg
.ul
= rest
.ul
;
488 FFI_ASSERT (__LDBL_MANT_DIG__
== 106);
489 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
494 case FFI_TYPE_DOUBLE
:
496 double_tmp
= **p_argv
.d
;
497 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
499 *fpr_base
.d
++ = double_tmp
;
501 if ((flags
& FLAG_COMPAT
) != 0)
502 *next_arg
.d
= double_tmp
;
506 *next_arg
.d
= double_tmp
;
507 if (++next_arg
.ul
== gpr_end
.ul
)
508 next_arg
.ul
= rest
.ul
;
510 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
515 double_tmp
= **p_argv
.f
;
516 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
518 *fpr_base
.d
++ = double_tmp
;
520 if ((flags
& FLAG_COMPAT
) != 0)
522 # ifndef __LITTLE_ENDIAN__
523 next_arg
.f
[1] = (float) double_tmp
;
525 next_arg
.f
[0] = (float) double_tmp
;
532 # ifndef __LITTLE_ENDIAN__
533 next_arg
.f
[1] = (float) double_tmp
;
535 next_arg
.f
[0] = (float) double_tmp
;
538 if (++next_arg
.ul
== gpr_end
.ul
)
539 next_arg
.ul
= rest
.ul
;
541 FFI_ASSERT (flags
& FLAG_FP_ARGUMENTS
);
544 case FFI_TYPE_STRUCT
:
545 if ((ecif
->cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
547 align
= (*ptr
)->alignment
;
551 next_arg
.p
= ALIGN (next_arg
.p
, align
);
553 elt
= discover_homogeneous_aggregate (*ptr
, &elnum
);
564 if (elt
== FFI_TYPE_FLOAT
)
568 double_tmp
= *arg
.f
++;
569 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
571 *fpr_base
.d
++ = double_tmp
;
573 *next_arg
.f
= (float) double_tmp
;
574 if (++next_arg
.f
== gpr_end
.f
)
578 while (--elnum
!= 0);
579 if ((next_arg
.p
& 3) != 0)
581 if (++next_arg
.f
== gpr_end
.f
)
588 double_tmp
= *arg
.d
++;
589 if (fparg_count
< NUM_FPR_ARG_REGISTERS64
&& i
< nfixedargs
)
590 *fpr_base
.d
++ = double_tmp
;
592 *next_arg
.d
= double_tmp
;
593 if (++next_arg
.d
== gpr_end
.d
)
597 while (--elnum
!= 0);
599 if (elt
== FFI_TYPE_FLOAT
)
607 words
= ((*ptr
)->size
+ 7) / 8;
608 if (next_arg
.ul
>= gpr_base
.ul
&& next_arg
.ul
+ words
> gpr_end
.ul
)
610 size_t first
= gpr_end
.c
- next_arg
.c
;
611 memcpy (next_arg
.c
, *p_argv
.c
, first
);
612 memcpy (rest
.c
, *p_argv
.c
+ first
, (*ptr
)->size
- first
);
613 next_arg
.c
= rest
.c
+ words
* 8 - first
;
617 char *where
= next_arg
.c
;
619 #ifndef __LITTLE_ENDIAN__
620 /* Structures with size less than eight bytes are passed
622 if ((*ptr
)->size
< 8)
623 where
+= 8 - (*ptr
)->size
;
625 memcpy (where
, *p_argv
.c
, (*ptr
)->size
);
626 next_arg
.ul
+= words
;
627 if (next_arg
.ul
== gpr_end
.ul
)
628 next_arg
.ul
= rest
.ul
;
634 gprvalue
= **p_argv
.uc
;
637 gprvalue
= **p_argv
.sc
;
639 case FFI_TYPE_UINT16
:
640 gprvalue
= **p_argv
.us
;
642 case FFI_TYPE_SINT16
:
643 gprvalue
= **p_argv
.ss
;
645 case FFI_TYPE_UINT32
:
646 gprvalue
= **p_argv
.ui
;
649 case FFI_TYPE_SINT32
:
650 gprvalue
= **p_argv
.si
;
653 case FFI_TYPE_UINT64
:
654 case FFI_TYPE_SINT64
:
655 case FFI_TYPE_POINTER
:
656 gprvalue
= **p_argv
.ul
;
658 *next_arg
.ul
++ = gprvalue
;
659 if (next_arg
.ul
== gpr_end
.ul
)
660 next_arg
.ul
= rest
.ul
;
665 FFI_ASSERT (flags
& FLAG_4_GPR_ARGUMENTS
666 || (next_arg
.ul
>= gpr_base
.ul
667 && next_arg
.ul
<= gpr_base
.ul
+ 4));
672 #define MIN_CACHE_LINE_SIZE 8
675 flush_icache (char *wraddr
, char *xaddr
, int size
)
678 for (i
= 0; i
< size
; i
+= MIN_CACHE_LINE_SIZE
)
679 __asm__
volatile ("icbi 0,%0;" "dcbf 0,%1;"
680 : : "r" (xaddr
+ i
), "r" (wraddr
+ i
) : "memory");
681 __asm__
volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
682 : : "r"(xaddr
+ size
- 1), "r"(wraddr
+ size
- 1)
688 ffi_status FFI_HIDDEN
689 ffi_prep_closure_loc_linux64 (ffi_closure
*closure
,
691 void (*fun
) (ffi_cif
*, void *, void **, void *),
696 unsigned int *tramp
= (unsigned int *) &closure
->tramp
[0];
698 if (cif
->abi
< FFI_LINUX
|| cif
->abi
>= FFI_LAST_ABI
)
701 tramp
[0] = 0xe96c0018; /* 0: ld 11,2f-0b(12) */
702 tramp
[1] = 0xe98c0010; /* ld 12,1f-0b(12) */
703 tramp
[2] = 0x7d8903a6; /* mtctr 12 */
704 tramp
[3] = 0x4e800420; /* bctr */
705 /* 1: .quad function_addr */
706 /* 2: .quad context */
707 *(void **) &tramp
[4] = (void *) ffi_closure_LINUX64
;
708 *(void **) &tramp
[6] = codeloc
;
709 flush_icache ((char *) tramp
, (char *) codeloc
, 4 * 4);
711 void **tramp
= (void **) &closure
->tramp
[0];
713 if (cif
->abi
< FFI_LINUX
|| cif
->abi
>= FFI_LAST_ABI
)
716 /* Copy function address and TOC from ffi_closure_LINUX64 OPD. */
717 memcpy (&tramp
[0], (void **) ffi_closure_LINUX64
, sizeof (void *));
719 memcpy (&tramp
[2], (void **) ffi_closure_LINUX64
+ 1, sizeof (void *));
724 closure
->user_data
= user_data
;
731 ffi_closure_helper_LINUX64 (ffi_cif
*cif
,
732 void (*fun
) (ffi_cif
*, void *, void **, void *),
738 /* rvalue is the pointer to space for return value in closure assembly */
739 /* pst is the pointer to parameter save area
740 (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
741 /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
744 ffi_type
**arg_types
;
745 unsigned long i
, avn
, nfixedargs
;
746 ffi_dblfl
*end_pfr
= pfr
+ NUM_FPR_ARG_REGISTERS64
;
749 avalue
= alloca (cif
->nargs
* sizeof (void *));
751 /* Copy the caller's structure return value address so that the
752 closure returns the data directly to the caller. */
753 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
754 && (cif
->flags
& FLAG_RETURNS_SMST
) == 0)
756 rvalue
= (void *) *pst
;
763 nfixedargs
= (unsigned) -1;
764 if ((cif
->flags
& FLAG_COMPAT
) == 0)
766 nfixedargs
= cif
->nfixedargs
;
767 arg_types
= cif
->arg_types
;
769 /* Grab the addresses of the arguments from the stack frame. */
772 unsigned int elt
, elnum
;
774 switch (arg_types
[i
]->type
)
778 #ifndef __LITTLE_ENDIAN__
779 avalue
[i
] = (char *) pst
+ 7;
784 case FFI_TYPE_SINT16
:
785 case FFI_TYPE_UINT16
:
786 #ifndef __LITTLE_ENDIAN__
787 avalue
[i
] = (char *) pst
+ 6;
792 case FFI_TYPE_SINT32
:
793 case FFI_TYPE_UINT32
:
794 #ifndef __LITTLE_ENDIAN__
795 avalue
[i
] = (char *) pst
+ 4;
800 case FFI_TYPE_SINT64
:
801 case FFI_TYPE_UINT64
:
802 case FFI_TYPE_POINTER
:
807 case FFI_TYPE_STRUCT
:
808 if ((cif
->abi
& FFI_LINUX_STRUCT_ALIGN
) != 0)
810 align
= arg_types
[i
]->alignment
;
814 pst
= (unsigned long *) ALIGN ((size_t) pst
, align
);
816 elt
= discover_homogeneous_aggregate (arg_types
[i
], &elnum
);
828 /* Repackage the aggregate from its parts. The
829 aggregate size is not greater than the space taken by
830 the registers so store back to the register/parameter
832 if (pfr
+ elnum
<= end_pfr
)
839 if (elt
== FFI_TYPE_FLOAT
)
843 if (pfr
< end_pfr
&& i
< nfixedargs
)
845 *to
.f
= (float) pfr
->d
;
853 while (--elnum
!= 0);
859 if (pfr
< end_pfr
&& i
< nfixedargs
)
869 while (--elnum
!= 0);
872 if (elt
== FFI_TYPE_FLOAT
)
880 #ifndef __LITTLE_ENDIAN__
881 /* Structures with size less than eight bytes are passed
883 if (arg_types
[i
]->size
< 8)
884 avalue
[i
] = (char *) pst
+ 8 - arg_types
[i
]->size
;
889 pst
+= (arg_types
[i
]->size
+ 7) / 8;
892 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
893 case FFI_TYPE_LONGDOUBLE
:
894 if ((cif
->abi
& FFI_LINUX_LONG_DOUBLE_128
) != 0)
896 if (pfr
+ 1 < end_pfr
&& i
+ 1 < nfixedargs
)
903 if (pfr
< end_pfr
&& i
< nfixedargs
)
905 /* Passed partly in f13 and partly on the stack.
906 Move it all to the stack. */
907 *pst
= *(unsigned long *) pfr
;
917 case FFI_TYPE_DOUBLE
:
919 /* On the outgoing stack all values are aligned to 8 */
920 /* there are 13 64bit floating point registers */
922 if (pfr
< end_pfr
&& i
< nfixedargs
)
934 if (pfr
< end_pfr
&& i
< nfixedargs
)
936 /* Float values are stored as doubles in the
937 ffi_closure_LINUX64 code. Fix them here. */
938 pfr
->f
= (float) pfr
->d
;
944 #ifndef __LITTLE_ENDIAN__
945 avalue
[i
] = (char *) pst
+ 4;
960 (*fun
) (cif
, rvalue
, avalue
, user_data
);
962 /* Tell ffi_closure_LINUX64 how to perform return type promotions. */
963 if ((cif
->flags
& FLAG_RETURNS_SMST
) != 0)
965 if ((cif
->flags
& FLAG_RETURNS_FP
) == 0)
966 return FFI_V2_TYPE_SMALL_STRUCT
+ cif
->rtype
->size
- 1;
967 else if ((cif
->flags
& FLAG_RETURNS_64BITS
) != 0)
968 return FFI_V2_TYPE_DOUBLE_HOMOG
;
970 return FFI_V2_TYPE_FLOAT_HOMOG
;
972 return cif
->rtype
->type
;