Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(113549)

Side by Side Diff: Modules/_ctypes/libffi_ios/x86/ffi64_x86_64.c

Issue 23670: Modifications to support iOS as a development platform
Patch Set: Created 3 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Modules/_ctypes/libffi_ios/types.c ('k') | Modules/_ctypes/libffi_ios/x86/ffi_i386.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #ifdef __x86_64__
2
3 /* -----------------------------------------------------------------------
4 ffi64.c - Copyright (c) 2013 The Written Word, Inc.
5 Copyright (c) 2011 Anthony Green
6 Copyright (c) 2008, 2010 Red Hat, Inc.
7 Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
8
9 x86-64 Foreign Function Interface
10
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:
18
19 The above copyright notice and this permission notice shall be included
20 in all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 DEALINGS IN THE SOFTWARE.
30 ----------------------------------------------------------------------- */
31
32 #include <ffi.h>
33 #include <ffi_common.h>
34
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <stdint.h>
38 #include "internal64.h"
39
40 #ifdef __x86_64__
41
42 #define MAX_GPR_REGS 6
43 #define MAX_SSE_REGS 8
44
45 #if defined(__INTEL_COMPILER)
46 #include "xmmintrin.h"
47 #define UINT128 __m128
48 #else
49 #if defined(__SUNPRO_C)
50 #include <sunmedia_types.h>
51 #define UINT128 __m128i
52 #else
53 #define UINT128 __int128_t
54 #endif
55 #endif
56
57 union big_int_union
58 {
59 UINT32 i32;
60 UINT64 i64;
61 UINT128 i128;
62 };
63
64 struct register_args
65 {
66 /* Registers for argument passing. */
67 UINT64 gpr[MAX_GPR_REGS];
68 union big_int_union sse[MAX_SSE_REGS];
69 UINT64 rax; /* ssecount */
70 UINT64 r10; /* static chain */
71 };
72
73 extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
74 void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
75
76 /* All reference to register classes here is identical to the code in
77 gcc/config/i386/i386.c. Do *not* change one without the other. */
78
79 /* Register class used for passing given 64bit part of the argument.
80 These represent classes as documented by the PS ABI, with the
81 exception of SSESF, SSEDF classes, that are basically SSE class,
82 just gcc will use SF or DFmode move instead of DImode to avoid
83 reformatting penalties.
84
85 Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
86 whenever possible (upper half does contain padding). */
87 enum x86_64_reg_class
88 {
89 X86_64_NO_CLASS,
90 X86_64_INTEGER_CLASS,
91 X86_64_INTEGERSI_CLASS,
92 X86_64_SSE_CLASS,
93 X86_64_SSESF_CLASS,
94 X86_64_SSEDF_CLASS,
95 X86_64_SSEUP_CLASS,
96 X86_64_X87_CLASS,
97 X86_64_X87UP_CLASS,
98 X86_64_COMPLEX_X87_CLASS,
99 X86_64_MEMORY_CLASS
100 };
101
102 #define MAX_CLASSES 4
103
104 #define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
105
106 /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
107 of this code is to classify each 8bytes of incoming argument by the register
108 class and assign registers accordingly. */
109
110 /* Return the union class of CLASS1 and CLASS2.
111 See the x86-64 PS ABI for details. */
112
113 static enum x86_64_reg_class
114 merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
115 {
116 /* Rule #1: If both classes are equal, this is the resulting class. */
117 if (class1 == class2)
118 return class1;
119
120 /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
121 the other class. */
122 if (class1 == X86_64_NO_CLASS)
123 return class2;
124 if (class2 == X86_64_NO_CLASS)
125 return class1;
126
127 /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
128 if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
129 return X86_64_MEMORY_CLASS;
130
131 /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
132 if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
133 || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
134 return X86_64_INTEGERSI_CLASS;
135 if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
136 || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
137 return X86_64_INTEGER_CLASS;
138
139 /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
140 MEMORY is used. */
141 if (class1 == X86_64_X87_CLASS
142 || class1 == X86_64_X87UP_CLASS
143 || class1 == X86_64_COMPLEX_X87_CLASS
144 || class2 == X86_64_X87_CLASS
145 || class2 == X86_64_X87UP_CLASS
146 || class2 == X86_64_COMPLEX_X87_CLASS)
147 return X86_64_MEMORY_CLASS;
148
149 /* Rule #6: Otherwise class SSE is used. */
150 return X86_64_SSE_CLASS;
151 }
152
153 /* Classify the argument of type TYPE and mode MODE.
154 CLASSES will be filled by the register class used to pass each word
155 of the operand. The number of words is returned. In case the parameter
156 should be passed in memory, 0 is returned. As a special case for zero
157 sized containers, classes[0] will be NO_CLASS and 1 is returned.
158
159 See the x86-64 PS ABI for details.
160 */
161 static size_t
162 classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
163 size_t byte_offset)
164 {
165 switch (type->type)
166 {
167 case FFI_TYPE_UINT8:
168 case FFI_TYPE_SINT8:
169 case FFI_TYPE_UINT16:
170 case FFI_TYPE_SINT16:
171 case FFI_TYPE_UINT32:
172 case FFI_TYPE_SINT32:
173 case FFI_TYPE_UINT64:
174 case FFI_TYPE_SINT64:
175 case FFI_TYPE_POINTER:
176 do_integer:
177 {
178 size_t size = byte_offset + type->size;
179
180 if (size <= 4)
181 {
182 classes[0] = X86_64_INTEGERSI_CLASS;
183 return 1;
184 }
185 else if (size <= 8)
186 {
187 classes[0] = X86_64_INTEGER_CLASS;
188 return 1;
189 }
190 else if (size <= 12)
191 {
192 classes[0] = X86_64_INTEGER_CLASS;
193 classes[1] = X86_64_INTEGERSI_CLASS;
194 return 2;
195 }
196 else if (size <= 16)
197 {
198 classes[0] = classes[1] = X86_64_INTEGER_CLASS;
199 return 2;
200 }
201 else
202 FFI_ASSERT (0);
203 }
204 case FFI_TYPE_FLOAT:
205 if (!(byte_offset % 8))
206 classes[0] = X86_64_SSESF_CLASS;
207 else
208 classes[0] = X86_64_SSE_CLASS;
209 return 1;
210 case FFI_TYPE_DOUBLE:
211 classes[0] = X86_64_SSEDF_CLASS;
212 return 1;
213 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
214 case FFI_TYPE_LONGDOUBLE:
215 classes[0] = X86_64_X87_CLASS;
216 classes[1] = X86_64_X87UP_CLASS;
217 return 2;
218 #endif
219 case FFI_TYPE_STRUCT:
220 {
221 const size_t UNITS_PER_WORD = 8;
222 size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
223 ffi_type **ptr;
224 int i;
225 enum x86_64_reg_class subclasses[MAX_CLASSES];
226
227 /* If the struct is larger than 32 bytes, pass it on the stack. */
228 if (type->size > 32)
229 return 0;
230
231 for (i = 0; i < words; i++)
232 classes[i] = X86_64_NO_CLASS;
233
234 /* Zero sized arrays or structures are NO_CLASS. We return 0 to
235 signalize memory class, so handle it as special case. */
236 if (!words)
237 {
238 case FFI_TYPE_VOID:
239 classes[0] = X86_64_NO_CLASS;
240 return 1;
241 }
242
243 /* Merge the fields of structure. */
244 for (ptr = type->elements; *ptr != NULL; ptr++)
245 {
246 size_t num;
247
248 byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
249
250 num = classify_argument (*ptr, subclasses, byte_offset % 8);
251 if (num == 0)
252 return 0;
253 for (i = 0; i < num; i++)
254 {
255 size_t pos = byte_offset / 8;
256 classes[i + pos] =
257 merge_classes (subclasses[i], classes[i + pos]);
258 }
259
260 byte_offset += (*ptr)->size;
261 }
262
263 if (words > 2)
264 {
265 /* When size > 16 bytes, if the first one isn't
266 X86_64_SSE_CLASS or any other ones aren't
267 X86_64_SSEUP_CLASS, everything should be passed in
268 memory. */
269 if (classes[0] != X86_64_SSE_CLASS)
270 return 0;
271
272 for (i = 1; i < words; i++)
273 if (classes[i] != X86_64_SSEUP_CLASS)
274 return 0;
275 }
276
277 /* Final merger cleanup. */
278 for (i = 0; i < words; i++)
279 {
280 /* If one class is MEMORY, everything should be passed in
281 memory. */
282 if (classes[i] == X86_64_MEMORY_CLASS)
283 return 0;
284
285 /* The X86_64_SSEUP_CLASS should be always preceded by
286 X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
287 if (classes[i] == X86_64_SSEUP_CLASS
288 && classes[i - 1] != X86_64_SSE_CLASS
289 && classes[i - 1] != X86_64_SSEUP_CLASS)
290 {
291 /* The first one should never be X86_64_SSEUP_CLASS. */
292 FFI_ASSERT (i != 0);
293 classes[i] = X86_64_SSE_CLASS;
294 }
295
296 /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
297 everything should be passed in memory. */
298 if (classes[i] == X86_64_X87UP_CLASS
299 && (classes[i - 1] != X86_64_X87_CLASS))
300 {
301 /* The first one should never be X86_64_X87UP_CLASS. */
302 FFI_ASSERT (i != 0);
303 return 0;
304 }
305 }
306 return words;
307 }
308 case FFI_TYPE_COMPLEX:
309 {
310 ffi_type *inner = type->elements[0];
311 switch (inner->type)
312 {
313 case FFI_TYPE_INT:
314 case FFI_TYPE_UINT8:
315 case FFI_TYPE_SINT8:
316 case FFI_TYPE_UINT16:
317 case FFI_TYPE_SINT16:
318 case FFI_TYPE_UINT32:
319 case FFI_TYPE_SINT32:
320 case FFI_TYPE_UINT64:
321 case FFI_TYPE_SINT64:
322 goto do_integer;
323
324 case FFI_TYPE_FLOAT:
325 classes[0] = X86_64_SSE_CLASS;
326 if (byte_offset % 8)
327 {
328 classes[1] = X86_64_SSESF_CLASS;
329 return 2;
330 }
331 return 1;
332 case FFI_TYPE_DOUBLE:
333 classes[0] = classes[1] = X86_64_SSEDF_CLASS;
334 return 2;
335 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
336 case FFI_TYPE_LONGDOUBLE:
337 classes[0] = X86_64_COMPLEX_X87_CLASS;
338 return 1;
339 #endif
340 }
341 }
342 }
343 abort();
344 }
345
346 /* Examine the argument and return set number of register required in each
347 class. Return zero iff parameter should be passed in memory, otherwise
348 the number of registers. */
349
350 static size_t
351 examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
352 _Bool in_return, int *pngpr, int *pnsse)
353 {
354 size_t n;
355 int i, ngpr, nsse;
356
357 n = classify_argument (type, classes, 0);
358 if (n == 0)
359 return 0;
360
361 ngpr = nsse = 0;
362 for (i = 0; i < n; ++i)
363 switch (classes[i])
364 {
365 case X86_64_INTEGER_CLASS:
366 case X86_64_INTEGERSI_CLASS:
367 ngpr++;
368 break;
369 case X86_64_SSE_CLASS:
370 case X86_64_SSESF_CLASS:
371 case X86_64_SSEDF_CLASS:
372 nsse++;
373 break;
374 case X86_64_NO_CLASS:
375 case X86_64_SSEUP_CLASS:
376 break;
377 case X86_64_X87_CLASS:
378 case X86_64_X87UP_CLASS:
379 case X86_64_COMPLEX_X87_CLASS:
380 return in_return != 0;
381 default:
382 abort ();
383 }
384
385 *pngpr = ngpr;
386 *pnsse = nsse;
387
388 return n;
389 }
390
391 /* Perform machine dependent cif processing. */
392
393 ffi_status
394 ffi_prep_cif_machdep (ffi_cif *cif)
395 {
396 int gprcount, ssecount, i, avn, ngpr, nsse, flags;
397 enum x86_64_reg_class classes[MAX_CLASSES];
398 size_t bytes, n, rtype_size;
399 ffi_type *rtype;
400
401 if (cif->abi != FFI_UNIX64)
402 return FFI_BAD_ABI;
403
404 gprcount = ssecount = 0;
405
406 rtype = cif->rtype;
407 rtype_size = rtype->size;
408 switch (rtype->type)
409 {
410 case FFI_TYPE_VOID:
411 flags = UNIX64_RET_VOID;
412 break;
413 case FFI_TYPE_UINT8:
414 flags = UNIX64_RET_UINT8;
415 break;
416 case FFI_TYPE_SINT8:
417 flags = UNIX64_RET_SINT8;
418 break;
419 case FFI_TYPE_UINT16:
420 flags = UNIX64_RET_UINT16;
421 break;
422 case FFI_TYPE_SINT16:
423 flags = UNIX64_RET_SINT16;
424 break;
425 case FFI_TYPE_UINT32:
426 flags = UNIX64_RET_UINT32;
427 break;
428 case FFI_TYPE_INT:
429 case FFI_TYPE_SINT32:
430 flags = UNIX64_RET_SINT32;
431 break;
432 case FFI_TYPE_UINT64:
433 case FFI_TYPE_SINT64:
434 flags = UNIX64_RET_INT64;
435 break;
436 case FFI_TYPE_POINTER:
437 flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
438 break;
439 case FFI_TYPE_FLOAT:
440 flags = UNIX64_RET_XMM32;
441 break;
442 case FFI_TYPE_DOUBLE:
443 flags = UNIX64_RET_XMM64;
444 break;
445 case FFI_TYPE_LONGDOUBLE:
446 flags = UNIX64_RET_X87;
447 break;
448 case FFI_TYPE_STRUCT:
449 n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
450 if (n == 0)
451 {
452 /* The return value is passed in memory. A pointer to that
453 memory is the first argument. Allocate a register for it. */
454 gprcount++;
455 /* We don't have to do anything in asm for the return. */
456 flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
457 }
458 else
459 {
460 _Bool sse0 = SSE_CLASS_P (classes[0]);
461
462 if (rtype_size == 4 && sse0)
463 flags = UNIX64_RET_XMM32;
464 else if (rtype_size == 8)
465 flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
466 else
467 {
468 _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
469 if (sse0 && sse1)
470 flags = UNIX64_RET_ST_XMM0_XMM1;
471 else if (sse0)
472 flags = UNIX64_RET_ST_XMM0_RAX;
473 else if (sse1)
474 flags = UNIX64_RET_ST_RAX_XMM0;
475 else
476 flags = UNIX64_RET_ST_RAX_RDX;
477 flags |= rtype_size << UNIX64_SIZE_SHIFT;
478 }
479 }
480 break;
481 case FFI_TYPE_COMPLEX:
482 switch (rtype->elements[0]->type)
483 {
484 case FFI_TYPE_UINT8:
485 case FFI_TYPE_SINT8:
486 case FFI_TYPE_UINT16:
487 case FFI_TYPE_SINT16:
488 case FFI_TYPE_INT:
489 case FFI_TYPE_UINT32:
490 case FFI_TYPE_SINT32:
491 case FFI_TYPE_UINT64:
492 case FFI_TYPE_SINT64:
493 flags = UNIX64_RET_ST_RAX_RDX | (rtype_size << UNIX64_SIZE_SHIFT);
494 break;
495 case FFI_TYPE_FLOAT:
496 flags = UNIX64_RET_XMM64;
497 break;
498 case FFI_TYPE_DOUBLE:
499 flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
500 break;
501 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
502 case FFI_TYPE_LONGDOUBLE:
503 flags = UNIX64_RET_X87_2;
504 break;
505 #endif
506 default:
507 return FFI_BAD_TYPEDEF;
508 }
509 break;
510 default:
511 return FFI_BAD_TYPEDEF;
512 }
513
514 /* Go over all arguments and determine the way they should be passed.
515 If it's in a register and there is space for it, let that be so. If
516 not, add it's size to the stack byte count. */
517 for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
518 {
519 if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
520 || gprcount + ngpr > MAX_GPR_REGS
521 || ssecount + nsse > MAX_SSE_REGS)
522 {
523 long align = cif->arg_types[i]->alignment;
524
525 if (align < 8)
526 align = 8;
527
528 bytes = ALIGN (bytes, align);
529 bytes += cif->arg_types[i]->size;
530 }
531 else
532 {
533 gprcount += ngpr;
534 ssecount += nsse;
535 }
536 }
537 if (ssecount)
538 flags |= UNIX64_FLAG_XMM_ARGS;
539
540 cif->flags = flags;
541 cif->bytes = ALIGN (bytes, 8);
542
543 return FFI_OK;
544 }
545
546 static void
547 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
548 void **avalue, void *closure)
549 {
550 enum x86_64_reg_class classes[MAX_CLASSES];
551 char *stack, *argp;
552 ffi_type **arg_types;
553 int gprcount, ssecount, ngpr, nsse, i, avn, flags;
554 struct register_args *reg_args;
555
556 /* Can't call 32-bit mode from 64-bit mode. */
557 FFI_ASSERT (cif->abi == FFI_UNIX64);
558
559 /* If the return value is a struct and we don't have a return value
560 address then we need to make one. Otherwise we can ignore it. */
561 flags = cif->flags;
562 if (rvalue == NULL)
563 {
564 if (flags & UNIX64_FLAG_RET_IN_MEM)
565 rvalue = alloca (cif->rtype->size);
566 else
567 flags = UNIX64_RET_VOID;
568 }
569
570 /* Allocate the space for the arguments, plus 4 words of temp space. */
571 stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
572 reg_args = (struct register_args *) stack;
573 argp = stack + sizeof (struct register_args);
574
575 reg_args->r10 = (uintptr_t) closure;
576
577 gprcount = ssecount = 0;
578
579 /* If the return value is passed in memory, add the pointer as the
580 first integer argument. */
581 if (flags & UNIX64_FLAG_RET_IN_MEM)
582 reg_args->gpr[gprcount++] = (unsigned long) rvalue;
583
584 avn = cif->nargs;
585 arg_types = cif->arg_types;
586
587 for (i = 0; i < avn; ++i)
588 {
589 size_t n, size = arg_types[i]->size;
590
591 n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
592 if (n == 0
593 || gprcount + ngpr > MAX_GPR_REGS
594 || ssecount + nsse > MAX_SSE_REGS)
595 {
596 long align = arg_types[i]->alignment;
597
598 /* Stack arguments are *always* at least 8 byte aligned. */
599 if (align < 8)
600 align = 8;
601
602 /* Pass this argument in memory. */
603 argp = (void *) ALIGN (argp, align);
604 memcpy (argp, avalue[i], size);
605 argp += size;
606 }
607 else
608 {
609 /* The argument is passed entirely in registers. */
610 char *a = (char *) avalue[i];
611 int j;
612
613 for (j = 0; j < n; j++, a += 8, size -= 8)
614 {
615 switch (classes[j])
616 {
617 case X86_64_NO_CLASS:
618 case X86_64_SSEUP_CLASS:
619 break;
620 case X86_64_INTEGER_CLASS:
621 case X86_64_INTEGERSI_CLASS:
622 /* Sign-extend integer arguments passed in general
623 purpose registers, to cope with the fact that
624 LLVM incorrectly assumes that this will be done
625 (the x86-64 PS ABI does not specify this). */
626 switch (arg_types[i]->type)
627 {
628 case FFI_TYPE_SINT8:
629 reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
630 break;
631 case FFI_TYPE_SINT16:
632 reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
633 break;
634 case FFI_TYPE_SINT32:
635 reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
636 break;
637 default:
638 reg_args->gpr[gprcount] = 0;
639 memcpy (&reg_args->gpr[gprcount], a, size);
640 }
641 gprcount++;
642 break;
643 case X86_64_SSE_CLASS:
644 case X86_64_SSEDF_CLASS:
645 reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
646 break;
647 case X86_64_SSESF_CLASS:
648 reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
649 break;
650 default:
651 abort();
652 }
653 }
654 }
655 }
656 reg_args->rax = ssecount;
657
658 ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
659 flags, rvalue, fn);
660 }
661
662 void
663 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
664 {
665 ffi_call_int (cif, fn, rvalue, avalue, NULL);
666 }
667
668 void
669 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
670 void **avalue, void *closure)
671 {
672 ffi_call_int (cif, fn, rvalue, avalue, closure);
673 }
674
675 extern void ffi_closure_unix64(void) FFI_HIDDEN;
676 extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
677
678 ffi_status
679 ffi_prep_closure_loc (ffi_closure* closure,
680 ffi_cif* cif,
681 void (*fun)(ffi_cif*, void*, void**, void*),
682 void *user_data,
683 void *codeloc)
684 {
685 static const unsigned char trampoline[16] = {
686 /* leaq -0x7(%rip),%r10 # 0x0 */
687 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
688 /* jmpq *0x3(%rip) # 0x10 */
689 0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
690 /* nopl (%rax) */
691 0x0f, 0x1f, 0x00
692 };
693 void (*dest)(void);
694 char *tramp = closure->tramp;
695
696 if (cif->abi != FFI_UNIX64)
697 return FFI_BAD_ABI;
698
699 if (cif->flags & UNIX64_FLAG_XMM_ARGS)
700 dest = ffi_closure_unix64_sse;
701 else
702 dest = ffi_closure_unix64;
703
704 memcpy (tramp, trampoline, sizeof(trampoline));
705 *(UINT64 *)(tramp + 16) = (uintptr_t)dest;
706
707 closure->cif = cif;
708 closure->fun = fun;
709 closure->user_data = user_data;
710
711 return FFI_OK;
712 }
713
714 int FFI_HIDDEN
715 ffi_closure_unix64_inner(ffi_cif *cif,
716 void (*fun)(ffi_cif*, void*, void**, void*),
717 void *user_data,
718 void *rvalue,
719 struct register_args *reg_args,
720 char *argp)
721 {
722 void **avalue;
723 ffi_type **arg_types;
724 long i, avn;
725 int gprcount, ssecount, ngpr, nsse;
726 int flags;
727
728 avn = cif->nargs;
729 flags = cif->flags;
730 avalue = alloca(avn * sizeof(void *));
731 gprcount = ssecount = 0;
732
733 if (flags & UNIX64_FLAG_RET_IN_MEM)
734 {
735 /* On return, %rax will contain the address that was passed
736 by the caller in %rdi. */
737 void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
738 *(void **)rvalue = r;
739 rvalue = r;
740 flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
741 }
742
743 arg_types = cif->arg_types;
744 for (i = 0; i < avn; ++i)
745 {
746 enum x86_64_reg_class classes[MAX_CLASSES];
747 size_t n;
748
749 n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
750 if (n == 0
751 || gprcount + ngpr > MAX_GPR_REGS
752 || ssecount + nsse > MAX_SSE_REGS)
753 {
754 long align = arg_types[i]->alignment;
755
756 /* Stack arguments are *always* at least 8 byte aligned. */
757 if (align < 8)
758 align = 8;
759
760 /* Pass this argument in memory. */
761 argp = (void *) ALIGN (argp, align);
762 avalue[i] = argp;
763 argp += arg_types[i]->size;
764 }
765 /* If the argument is in a single register, or two consecutive
766 integer registers, then we can use that address directly. */
767 else if (n == 1
768 || (n == 2 && !(SSE_CLASS_P (classes[0])
769 || SSE_CLASS_P (classes[1]))))
770 {
771 /* The argument is in a single register. */
772 if (SSE_CLASS_P (classes[0]))
773 {
774 avalue[i] = &reg_args->sse[ssecount];
775 ssecount += n;
776 }
777 else
778 {
779 avalue[i] = &reg_args->gpr[gprcount];
780 gprcount += n;
781 }
782 }
783 /* Otherwise, allocate space to make them consecutive. */
784 else
785 {
786 char *a = alloca (16);
787 int j;
788
789 avalue[i] = a;
790 for (j = 0; j < n; j++, a += 8)
791 {
792 if (SSE_CLASS_P (classes[j]))
793 memcpy (a, &reg_args->sse[ssecount++], 8);
794 else
795 memcpy (a, &reg_args->gpr[gprcount++], 8);
796 }
797 }
798 }
799
800 /* Invoke the closure. */
801 fun (cif, rvalue, avalue, user_data);
802
803 /* Tell assembly how to perform return type promotions. */
804 return flags;
805 }
806
807 extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
808 extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
809
810 ffi_status
811 ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
812 void (*fun)(ffi_cif*, void*, void**, void*))
813 {
814 if (cif->abi != FFI_UNIX64)
815 return FFI_BAD_ABI;
816
817 closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
818 ? ffi_go_closure_unix64_sse
819 : ffi_go_closure_unix64);
820 closure->cif = cif;
821 closure->fun = fun;
822
823 return FFI_OK;
824 }
825
826 #endif /* __x86_64__ */
827
828
829 #endif
OLDNEW
« no previous file with comments | « Modules/_ctypes/libffi_ios/types.c ('k') | Modules/_ctypes/libffi_ios/x86/ffi_i386.c » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+