1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2011 Timothy Wall
3 Copyright (c) 2011 Plausible Labs Cooperative, Inc.
4 Copyright (c) 2011 Anthony Green
5 Copyright (c) 2011 Free Software Foundation
6 Copyright (c) 1998, 2008, 2011 Red Hat, Inc.
7
8 ARM Foreign Function Interface
9
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 ``Software''), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice shall be included
19 in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29 ----------------------------------------------------------------------- */
30
31 #if defined(__arm__) || defined(_M_ARM)
32 #include <fficonfig.h>
33 #include <ffi.h>
34 #include <ffi_common.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <tramp.h>
38 #include "internal.h"
39
40 #if defined(_WIN32)
41 #define WIN32_LEAN_AND_MEAN
42 #include <windows.h>
43 #endif
44
45 #if FFI_EXEC_TRAMPOLINE_TABLE
46
47 #ifdef __MACH__
48 #include <mach/machine/vm_param.h>
49 #endif
50
51 #else
52 #ifndef _WIN32
53 extern unsigned int ffi_arm_trampoline[2] FFI_HIDDEN;
54 #else
55 // Declare this as an array of char, instead of array of int,
56 // otherwise Clang optimizes out the "& 0xFFFFFFFE" for clearing
57 // the thumb bit.
58 extern unsigned char ffi_arm_trampoline[12] FFI_HIDDEN;
59 #endif
60 #endif
61
62 #if defined(__FreeBSD__) && defined(__arm__)
63 #include <sys/types.h>
64 #include <machine/sysarch.h>
65 #endif
66
67 /* Forward declares. */
68 static int vfp_type_p (const ffi_type *);
69 static void layout_vfp_args (ffi_cif *);
70
71 static void *
72 ffi_align (ffi_type *ty, void *p)
73 {
74 /* Align if necessary */
75 size_t alignment;
76 #ifdef _WIN32_WCE
77 alignment = 4;
78 #else
79 alignment = ty->alignment;
80 if (alignment < 4)
81 alignment = 4;
82 #endif
83 return (void *) FFI_ALIGN (p, alignment);
84 }
85
86 static size_t
87 ffi_put_arg (ffi_type *ty, void *src, void *dst)
88 {
89 size_t z = ty->size;
90
91 switch (ty->type)
92 {
93 case FFI_TYPE_SINT8:
94 *(UINT32 *)dst = *(SINT8 *)src;
95 break;
96 case FFI_TYPE_UINT8:
97 *(UINT32 *)dst = *(UINT8 *)src;
98 break;
99 case FFI_TYPE_SINT16:
100 *(UINT32 *)dst = *(SINT16 *)src;
101 break;
102 case FFI_TYPE_UINT16:
103 *(UINT32 *)dst = *(UINT16 *)src;
104 break;
105
106 case FFI_TYPE_INT:
107 case FFI_TYPE_SINT32:
108 case FFI_TYPE_UINT32:
109 case FFI_TYPE_POINTER:
110 #ifndef _WIN32
111 case FFI_TYPE_FLOAT:
112 #endif
113 *(UINT32 *)dst = *(UINT32 *)src;
114 break;
115
116 #ifdef _WIN32
117 // casting a float* to a UINT32* doesn't work on Windows
118 case FFI_TYPE_FLOAT:
119 *(uintptr_t *)dst = 0;
120 *(float *)dst = *(float *)src;
121 break;
122 #endif
123
124 case FFI_TYPE_SINT64:
125 case FFI_TYPE_UINT64:
126 case FFI_TYPE_DOUBLE:
127 *(UINT64 *)dst = *(UINT64 *)src;
128 break;
129
130 case FFI_TYPE_STRUCT:
131 case FFI_TYPE_COMPLEX:
132 memcpy (dst, src, z);
133 break;
134
135 default:
136 abort();
137 }
138
139 return FFI_ALIGN (z, 4);
140 }
141
142 /* ffi_prep_args is called once stack space has been allocated
143 for the function's arguments.
144
145 The vfp_space parameter is the load area for VFP regs, the return
146 value is cif->vfp_used (word bitset of VFP regs used for passing
147 arguments). These are only used for the VFP hard-float ABI.
148 */
149 static void
150 ffi_prep_args_SYSV (ffi_cif *cif, int flags, void *rvalue,
151 void **avalue, char *argp)
152 {
153 ffi_type **arg_types = cif->arg_types;
154 int i, n;
155
156 if (flags == ARM_TYPE_STRUCT)
157 {
158 *(void **) argp = rvalue;
159 argp += 4;
160 }
161
162 for (i = 0, n = cif->nargs; i < n; i++)
163 {
164 ffi_type *ty = arg_types[i];
165 argp = ffi_align (ty, argp);
166 argp += ffi_put_arg (ty, avalue[i], argp);
167 }
168 }
169
170 static void
171 ffi_prep_args_VFP (ffi_cif *cif, int flags, void *rvalue,
172 void **avalue, char *stack, char *vfp_space)
173 {
174 ffi_type **arg_types = cif->arg_types;
175 int i, n, vi = 0;
176 char *argp, *regp, *eo_regp;
177 char stack_used = 0;
178 char done_with_regs = 0;
179
180 /* The first 4 words on the stack are used for values
181 passed in core registers. */
182 regp = stack;
183 eo_regp = argp = regp + 16;
184
185 /* If the function returns an FFI_TYPE_STRUCT in memory,
186 that address is passed in r0 to the function. */
187 if (flags == ARM_TYPE_STRUCT)
188 {
189 *(void **) regp = rvalue;
190 regp += 4;
191 }
192
193 for (i = 0, n = cif->nargs; i < n; i++)
194 {
195 ffi_type *ty = arg_types[i];
196 void *a = avalue[i];
197 int is_vfp_type = vfp_type_p (ty);
198
199 /* Allocated in VFP registers. */
200 if (vi < cif->vfp_nargs && is_vfp_type)
201 {
202 char *vfp_slot = vfp_space + cif->vfp_args[vi++] * 4;
203 ffi_put_arg (ty, a, vfp_slot);
204 continue;
205 }
206 /* Try allocating in core registers. */
207 else if (!done_with_regs && !is_vfp_type)
208 {
209 char *tregp = ffi_align (ty, regp);
210 size_t size = ty->size;
211 size = (size < 4) ? 4 : size; // pad
212 /* Check if there is space left in the aligned register
213 area to place the argument. */
214 if (tregp + size <= eo_regp)
215 {
216 regp = tregp + ffi_put_arg (ty, a, tregp);
217 done_with_regs = (regp == argp);
218 // ensure we did not write into the stack area
219 FFI_ASSERT (regp <= argp);
220 continue;
221 }
222 /* In case there are no arguments in the stack area yet,
223 the argument is passed in the remaining core registers
224 and on the stack. */
225 else if (!stack_used)
226 {
227 stack_used = 1;
228 done_with_regs = 1;
229 argp = tregp + ffi_put_arg (ty, a, tregp);
230 FFI_ASSERT (eo_regp < argp);
231 continue;
232 }
233 }
234 /* Base case, arguments are passed on the stack */
235 stack_used = 1;
236 argp = ffi_align (ty, argp);
237 argp += ffi_put_arg (ty, a, argp);
238 }
239 }
240
241 /* Perform machine dependent cif processing */
242 ffi_status FFI_HIDDEN
243 ffi_prep_cif_machdep (ffi_cif *cif)
244 {
245 int flags = 0, cabi = cif->abi;
246 size_t bytes = cif->bytes;
247
248 /* Map out the register placements of VFP register args. The VFP
249 hard-float calling conventions are slightly more sophisticated
250 than the base calling conventions, so we do it here instead of
251 in ffi_prep_args(). */
252 if (cabi == FFI_VFP)
253 layout_vfp_args (cif);
254
255 /* Set the return type flag */
256 switch (cif->rtype->type)
257 {
258 case FFI_TYPE_VOID:
259 flags = ARM_TYPE_VOID;
260 break;
261
262 case FFI_TYPE_INT:
263 case FFI_TYPE_UINT8:
264 case FFI_TYPE_SINT8:
265 case FFI_TYPE_UINT16:
266 case FFI_TYPE_SINT16:
267 case FFI_TYPE_UINT32:
268 case FFI_TYPE_SINT32:
269 case FFI_TYPE_POINTER:
270 flags = ARM_TYPE_INT;
271 break;
272
273 case FFI_TYPE_SINT64:
274 case FFI_TYPE_UINT64:
275 flags = ARM_TYPE_INT64;
276 break;
277
278 case FFI_TYPE_FLOAT:
279 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_S : ARM_TYPE_INT);
280 break;
281 case FFI_TYPE_DOUBLE:
282 flags = (cabi == FFI_VFP ? ARM_TYPE_VFP_D : ARM_TYPE_INT64);
283 break;
284
285 case FFI_TYPE_STRUCT:
286 case FFI_TYPE_COMPLEX:
287 if (cabi == FFI_VFP)
288 {
289 int h = vfp_type_p (cif->rtype);
290
291 flags = ARM_TYPE_VFP_N;
292 if (h == 0x100 + FFI_TYPE_FLOAT)
293 flags = ARM_TYPE_VFP_S;
294 if (h == 0x100 + FFI_TYPE_DOUBLE)
295 flags = ARM_TYPE_VFP_D;
296 if (h != 0)
297 break;
298 }
299
300 /* A Composite Type not larger than 4 bytes is returned in r0.
301 A Composite Type larger than 4 bytes, or whose size cannot
302 be determined statically ... is stored in memory at an
303 address passed [in r0]. */
304 if (cif->rtype->size <= 4)
305 flags = ARM_TYPE_INT;
306 else
307 {
308 flags = ARM_TYPE_STRUCT;
309 bytes += 4;
310 }
311 break;
312
313 default:
314 abort();
315 }
316
317 /* Round the stack up to a multiple of 8 bytes. This isn't needed
318 everywhere, but it is on some platforms, and it doesn't harm anything
319 when it isn't needed. */
320 bytes = FFI_ALIGN (bytes, 8);
321
322 /* Minimum stack space is the 4 register arguments that we pop. */
323 if (bytes < 4*4)
324 bytes = 4*4;
325
326 cif->bytes = bytes;
327 cif->flags = flags;
328
329 return FFI_OK;
330 }
331
332 /* Perform machine dependent cif processing for variadic calls */
333 ffi_status FFI_HIDDEN
334 ffi_prep_cif_machdep_var (ffi_cif * cif,
335 unsigned int nfixedargs, unsigned int ntotalargs)
336 {
337 /* VFP variadic calls actually use the SYSV ABI */
338 if (cif->abi == FFI_VFP)
339 cif->abi = FFI_SYSV;
340
341 return ffi_prep_cif_machdep (cif);
342 }
343
344 /* Prototypes for assembly functions, in sysv.S. */
345
346 struct call_frame
347 {
348 void *fp;
349 void *lr;
350 void *rvalue;
351 int flags;
352 void *closure;
353 };
354
355 extern void ffi_call_SYSV (void *stack, struct call_frame *,
356 void (*fn) (void)) FFI_HIDDEN;
357 extern void ffi_call_VFP (void *vfp_space, struct call_frame *,
358 void (*fn) (void), unsigned vfp_used) FFI_HIDDEN;
359
360 static void
361 ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue,
362 void **avalue, void *closure)
363 {
364 int flags = cif->flags;
365 ffi_type *rtype = cif->rtype;
366 size_t bytes, rsize, vfp_size;
367 char *stack, *vfp_space, *new_rvalue;
368 struct call_frame *frame;
369
370 rsize = 0;
371 if (rvalue == NULL)
372 {
373 /* If the return value is a struct and we don't have a return
374 value address then we need to make one. Otherwise the return
375 value is in registers and we can ignore them. */
376 if (flags == ARM_TYPE_STRUCT)
377 rsize = rtype->size;
378 else
379 flags = ARM_TYPE_VOID;
380 }
381 else if (flags == ARM_TYPE_VFP_N)
382 {
383 /* Largest case is double x 4. */
384 rsize = 32;
385 }
386 else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT)
387 rsize = 4;
388
389 /* Largest case. */
390 vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0);
391
392 bytes = cif->bytes;
393 stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize);
394
395 vfp_space = NULL;
396 if (vfp_size)
397 {
398 vfp_space = stack;
399 stack += vfp_size;
400 }
401
402 frame = (struct call_frame *)(stack + bytes);
403
404 new_rvalue = rvalue;
405 if (rsize)
406 new_rvalue = (void *)(frame + 1);
407
408 frame->rvalue = new_rvalue;
409 frame->flags = flags;
410 frame->closure = closure;
411
412 if (vfp_space)
413 {
414 ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space);
415 ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used);
416 }
417 else
418 {
419 ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack);
420 ffi_call_SYSV (stack, frame, fn);
421 }
422
423 if (rvalue && rvalue != new_rvalue)
424 memcpy (rvalue, new_rvalue, rtype->size);
425 }
426
427 void
428 ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
429 {
430 ffi_call_int (cif, fn, rvalue, avalue, NULL);
431 }
432
433 #ifdef FFI_GO_CLOSURES
434 void
435 ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue,
436 void **avalue, void *closure)
437 {
438 ffi_call_int (cif, fn, rvalue, avalue, closure);
439 }
440 #endif
441
442 static void *
443 ffi_prep_incoming_args_SYSV (ffi_cif *cif, void *rvalue,
444 char *argp, void **avalue)
445 {
446 ffi_type **arg_types = cif->arg_types;
447 int i, n;
448
449 if (cif->flags == ARM_TYPE_STRUCT)
450 {
451 rvalue = *(void **) argp;
452 argp += 4;
453 }
454 else
455 {
456 if (cif->rtype->size && cif->rtype->size < 4)
457 *(uint32_t *) rvalue = 0;
458 }
459
460 for (i = 0, n = cif->nargs; i < n; i++)
461 {
462 ffi_type *ty = arg_types[i];
463 size_t z = ty->size;
464
465 argp = ffi_align (ty, argp);
466 avalue[i] = (void *) argp;
467 argp += z;
468 }
469
470 return rvalue;
471 }
472
473 static void *
474 ffi_prep_incoming_args_VFP (ffi_cif *cif, void *rvalue, char *stack,
475 char *vfp_space, void **avalue)
476 {
477 ffi_type **arg_types = cif->arg_types;
478 int i, n, vi = 0;
479 char *argp, *regp, *eo_regp;
480 char done_with_regs = 0;
481 char stack_used = 0;
482
483 regp = stack;
484 eo_regp = argp = regp + 16;
485
486 if (cif->flags == ARM_TYPE_STRUCT)
487 {
488 rvalue = *(void **) regp;
489 regp += 4;
490 }
491
492 for (i = 0, n = cif->nargs; i < n; i++)
493 {
494 ffi_type *ty = arg_types[i];
495 int is_vfp_type = vfp_type_p (ty);
496 size_t z = ty->size;
497
498 if (vi < cif->vfp_nargs && is_vfp_type)
499 {
500 avalue[i] = vfp_space + cif->vfp_args[vi++] * 4;
501 continue;
502 }
503 else if (!done_with_regs && !is_vfp_type)
504 {
505 char *tregp = ffi_align (ty, regp);
506
507 z = (z < 4) ? 4 : z; // pad
508
509 /* If the arguments either fits into the registers or uses registers
510 and stack, while we haven't read other things from the stack */
511 if (tregp + z <= eo_regp || !stack_used)
512 {
513 /* Because we're little endian, this is what it turns into. */
514 avalue[i] = (void *) tregp;
515 regp = tregp + z;
516
517 /* If we read past the last core register, make sure we
518 have not read from the stack before and continue
519 reading after regp. */
520 if (regp > eo_regp)
521 {
522 FFI_ASSERT (!stack_used);
523 argp = regp;
524 }
525 if (regp >= eo_regp)
526 {
527 done_with_regs = 1;
528 stack_used = 1;
529 }
530 continue;
531 }
532 }
533
534 stack_used = 1;
535 argp = ffi_align (ty, argp);
536 avalue[i] = (void *) argp;
537 argp += z;
538 }
539
540 return rvalue;
541 }
542
543 #if FFI_CLOSURES
544
545 struct closure_frame
546 {
547 char vfp_space[8*8] __attribute__((aligned(8)));
548 char result[8*4];
549 char argp[];
550 };
551
552 int FFI_HIDDEN
553 ffi_closure_inner_SYSV (ffi_cif *cif,
554 void (*fun) (ffi_cif *, void *, void **, void *),
555 void *user_data,
556 struct closure_frame *frame)
557 {
558 void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
559 void *rvalue = ffi_prep_incoming_args_SYSV (cif, frame->result,
560 frame->argp, avalue);
561 fun (cif, rvalue, avalue, user_data);
562 return cif->flags;
563 }
564
565 int FFI_HIDDEN
566 ffi_closure_inner_VFP (ffi_cif *cif,
567 void (*fun) (ffi_cif *, void *, void **, void *),
568 void *user_data,
569 struct closure_frame *frame)
570 {
571 void **avalue = (void **) alloca (cif->nargs * sizeof (void *));
572 void *rvalue = ffi_prep_incoming_args_VFP (cif, frame->result, frame->argp,
573 frame->vfp_space, avalue);
574 fun (cif, rvalue, avalue, user_data);
575 return cif->flags;
576 }
577
578 void ffi_closure_SYSV (void) FFI_HIDDEN;
579 void ffi_closure_VFP (void) FFI_HIDDEN;
580 #if defined(FFI_EXEC_STATIC_TRAMP)
581 void ffi_closure_SYSV_alt (void) FFI_HIDDEN;
582 void ffi_closure_VFP_alt (void) FFI_HIDDEN;
583 #endif
584
585 #ifdef FFI_GO_CLOSURES
586 void ffi_go_closure_SYSV (void) FFI_HIDDEN;
587 void ffi_go_closure_VFP (void) FFI_HIDDEN;
588 #endif
589
590 /* the cif must already be prep'ed */
591
592 #if defined(__FreeBSD__) && defined(__arm__)
593 #define __clear_cache(start, end) do { \
594 struct arm_sync_icache_args ua; \
595 \
596 ua.addr = (uintptr_t)(start); \
597 ua.len = (char *)(end) - (char *)start; \
598 sysarch(ARM_SYNC_ICACHE, &ua); \
599 } while (0);
600 #endif
601
602 ffi_status
603 ffi_prep_closure_loc (ffi_closure * closure,
604 ffi_cif * cif,
605 void (*fun) (ffi_cif *, void *, void **, void *),
606 void *user_data, void *codeloc)
607 {
608 void (*closure_func) (void) = ffi_closure_SYSV;
609
610 if (cif->abi == FFI_VFP)
611 {
612 /* We only need take the vfp path if there are vfp arguments. */
613 if (cif->vfp_used)
614 closure_func = ffi_closure_VFP;
615 }
616 else if (cif->abi != FFI_SYSV)
617 return FFI_BAD_ABI;
618
619 #if FFI_EXEC_TRAMPOLINE_TABLE
620 void **config = (void **)((uint8_t *)codeloc - PAGE_MAX_SIZE);
621 config[0] = closure;
622 config[1] = closure_func;
623 #else
624
625 #if defined(FFI_EXEC_STATIC_TRAMP)
626 if (ffi_tramp_is_present(closure))
627 {
628 /* Initialize the static trampoline's parameters. */
629 if (closure_func == ffi_closure_SYSV)
630 closure_func = ffi_closure_SYSV_alt;
631 else
632 closure_func = ffi_closure_VFP_alt;
633 ffi_tramp_set_parms (closure->ftramp, closure_func, closure);
634 goto out;
635 }
636 #endif
637
638 /* Initialize the dynamic trampoline. */
639 #ifndef _WIN32
640 memcpy(closure->tramp, ffi_arm_trampoline, 8);
641 #else
642 // cast away function type so MSVC doesn't set the lower bit of the function pointer
643 memcpy(closure->tramp, (void*)((uintptr_t)ffi_arm_trampoline & 0xFFFFFFFE), FFI_TRAMPOLINE_CLOSURE_OFFSET);
644 #endif
645
646 #if defined (__QNX__)
647 msync(closure->tramp, 8, 0x1000000); /* clear data map */
648 msync(codeloc, 8, 0x1000000); /* clear insn map */
649 #elif defined(_WIN32)
650 FlushInstructionCache(GetCurrentProcess(), closure->tramp, FFI_TRAMPOLINE_SIZE);
651 #else
652 __clear_cache(closure->tramp, closure->tramp + 8); /* clear data map */
653 __clear_cache(codeloc, codeloc + 8); /* clear insn map */
654 #endif
655 #ifdef _WIN32
656 *(void(**)(void))(closure->tramp + FFI_TRAMPOLINE_CLOSURE_FUNCTION) = closure_func;
657 #else
658 *(void (**)(void))(closure->tramp + 8) = closure_func;
659 #endif
660 out:
661 #endif
662
663 closure->cif = cif;
664 closure->fun = fun;
665 closure->user_data = user_data;
666
667 return FFI_OK;
668 }
669
670 #ifdef FFI_GO_CLOSURES
671 ffi_status
672 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
673 void (*fun) (ffi_cif *, void *, void **, void *))
674 {
675 void (*closure_func) (void) = ffi_go_closure_SYSV;
676
677 if (cif->abi == FFI_VFP)
678 {
679 /* We only need take the vfp path if there are vfp arguments. */
680 if (cif->vfp_used)
681 closure_func = ffi_go_closure_VFP;
682 }
683 else if (cif->abi != FFI_SYSV)
684 return FFI_BAD_ABI;
685
686 closure->tramp = closure_func;
687 closure->cif = cif;
688 closure->fun = fun;
689
690 return FFI_OK;
691 }
692 #endif
693
694 #endif /* FFI_CLOSURES */
695
696 /* Below are routines for VFP hard-float support. */
697
698 /* A subroutine of vfp_type_p. Given a structure type, return the type code
699 of the first non-structure element. Recurse for structure elements.
700 Return -1 if the structure is in fact empty, i.e. no nested elements. */
701
702 static int
703 is_hfa0 (const ffi_type *ty)
704 {
705 ffi_type **elements = ty->elements;
706 int i, ret = -1;
707
708 if (elements != NULL)
709 for (i = 0; elements[i]; ++i)
710 {
711 ret = elements[i]->type;
712 if (ret == FFI_TYPE_STRUCT || ret == FFI_TYPE_COMPLEX)
713 {
714 ret = is_hfa0 (elements[i]);
715 if (ret < 0)
716 continue;
717 }
718 break;
719 }
720
721 return ret;
722 }
723
724 /* A subroutine of vfp_type_p. Given a structure type, return true if all
725 of the non-structure elements are the same as CANDIDATE. */
726
727 static int
728 is_hfa1 (const ffi_type *ty, int candidate)
729 {
730 ffi_type **elements = ty->elements;
731 int i;
732
733 if (elements != NULL)
734 for (i = 0; elements[i]; ++i)
735 {
736 int t = elements[i]->type;
737 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
738 {
739 if (!is_hfa1 (elements[i], candidate))
740 return 0;
741 }
742 else if (t != candidate)
743 return 0;
744 }
745
746 return 1;
747 }
748
749 /* Determine if TY is an homogenous floating point aggregate (HFA).
750 That is, a structure consisting of 1 to 4 members of all the same type,
751 where that type is a floating point scalar.
752
753 Returns non-zero iff TY is an HFA. The result is an encoded value where
754 bits 0-7 contain the type code, and bits 8-10 contain the element count. */
755
756 static int
757 vfp_type_p (const ffi_type *ty)
758 {
759 ffi_type **elements;
760 int candidate, i;
761 size_t size, ele_count;
762
763 /* Quickest tests first. */
764 candidate = ty->type;
765 switch (ty->type)
766 {
767 default:
768 return 0;
769 case FFI_TYPE_FLOAT:
770 case FFI_TYPE_DOUBLE:
771 ele_count = 1;
772 goto done;
773 case FFI_TYPE_COMPLEX:
774 candidate = ty->elements[0]->type;
775 if (candidate != FFI_TYPE_FLOAT && candidate != FFI_TYPE_DOUBLE)
776 return 0;
777 ele_count = 2;
778 goto done;
779 case FFI_TYPE_STRUCT:
780 break;
781 }
782
783 /* No HFA types are smaller than 4 bytes, or larger than 32 bytes. */
784 size = ty->size;
785 if (size < 4 || size > 32)
786 return 0;
787
788 /* Find the type of the first non-structure member. */
789 elements = ty->elements;
790 candidate = elements[0]->type;
791 if (candidate == FFI_TYPE_STRUCT || candidate == FFI_TYPE_COMPLEX)
792 {
793 for (i = 0; ; ++i)
794 {
795 candidate = is_hfa0 (elements[i]);
796 if (candidate >= 0)
797 break;
798 }
799 }
800
801 /* If the first member is not a floating point type, it's not an HFA.
802 Also quickly re-check the size of the structure. */
803 switch (candidate)
804 {
805 case FFI_TYPE_FLOAT:
806 ele_count = size / sizeof(float);
807 if (size != ele_count * sizeof(float))
808 return 0;
809 break;
810 case FFI_TYPE_DOUBLE:
811 ele_count = size / sizeof(double);
812 if (size != ele_count * sizeof(double))
813 return 0;
814 break;
815 default:
816 return 0;
817 }
818 if (ele_count > 4)
819 return 0;
820
821 /* Finally, make sure that all scalar elements are the same type. */
822 for (i = 0; elements[i]; ++i)
823 {
824 int t = elements[i]->type;
825 if (t == FFI_TYPE_STRUCT || t == FFI_TYPE_COMPLEX)
826 {
827 if (!is_hfa1 (elements[i], candidate))
828 return 0;
829 }
830 else if (t != candidate)
831 return 0;
832 }
833
834 /* All tests succeeded. Encode the result. */
835 done:
836 return (ele_count << 8) | candidate;
837 }
838
839 static int
840 place_vfp_arg (ffi_cif *cif, int h)
841 {
842 unsigned short reg = cif->vfp_reg_free;
843 int align = 1, nregs = h >> 8;
844
845 if ((h & 0xff) == FFI_TYPE_DOUBLE)
846 align = 2, nregs *= 2;
847
848 /* Align register number. */
849 if ((reg & 1) && align == 2)
850 reg++;
851
852 while (reg + nregs <= 16)
853 {
854 int s, new_used = 0;
855 for (s = reg; s < reg + nregs; s++)
856 {
857 new_used |= (1 << s);
858 if (cif->vfp_used & (1 << s))
859 {
860 reg += align;
861 goto next_reg;
862 }
863 }
864 /* Found regs to allocate. */
865 cif->vfp_used |= new_used;
866 cif->vfp_args[cif->vfp_nargs++] = (signed char)reg;
867
868 /* Update vfp_reg_free. */
869 if (cif->vfp_used & (1 << cif->vfp_reg_free))
870 {
871 reg += nregs;
872 while (cif->vfp_used & (1 << reg))
873 reg += 1;
874 cif->vfp_reg_free = reg;
875 }
876 return 0;
877 next_reg:;
878 }
879 // done, mark all regs as used
880 cif->vfp_reg_free = 16;
881 cif->vfp_used = 0xFFFF;
882 return 1;
883 }
884
885 static void
886 layout_vfp_args (ffi_cif * cif)
887 {
888 unsigned int i;
889 /* Init VFP fields */
890 cif->vfp_used = 0;
891 cif->vfp_nargs = 0;
892 cif->vfp_reg_free = 0;
893 memset (cif->vfp_args, -1, 16); /* Init to -1. */
894
895 for (i = 0; i < cif->nargs; i++)
896 {
897 int h = vfp_type_p (cif->arg_types[i]);
898 if (h && place_vfp_arg (cif, h) == 1)
899 break;
900 }
901 }
902
903 #if defined(FFI_EXEC_STATIC_TRAMP)
904 void *
905 ffi_tramp_arch (size_t *tramp_size, size_t *map_size)
906 {
907 extern void *trampoline_code_table;
908
909 *tramp_size = ARM_TRAMP_SIZE;
910 *map_size = ARM_TRAMP_MAP_SIZE;
911 return &trampoline_code_table;
912 }
913 #endif
914
915 #endif /* __arm__ or _M_ARM */