]> git.ipfire.org Git - thirdparty/gcc.git/blob - libffi/src/sh/ffi.c
ffi.h.in (ffi_closure_alloc, [...]): New.
[thirdparty/gcc.git] / libffi / src / sh / ffi.c
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Kaz Kojima
3
4 SuperH Foreign Function Interface
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 ----------------------------------------------------------------------- */
25
26 #include <ffi.h>
27 #include <ffi_common.h>
28
29 #include <stdlib.h>
30
31 #define NGREGARG 4
32 #if defined(__SH4__)
33 #define NFREGARG 8
34 #endif
35
36 #if defined(__HITACHI__)
37 #define STRUCT_VALUE_ADDRESS_WITH_ARG 1
38 #else
39 #define STRUCT_VALUE_ADDRESS_WITH_ARG 0
40 #endif
41
42 /* If the structure has essentialy an unique element, return its type. */
43 static int
44 simple_type (ffi_type *arg)
45 {
46 if (arg->type != FFI_TYPE_STRUCT)
47 return arg->type;
48 else if (arg->elements[1])
49 return FFI_TYPE_STRUCT;
50
51 return simple_type (arg->elements[0]);
52 }
53
54 static int
55 return_type (ffi_type *arg)
56 {
57 unsigned short type;
58
59 if (arg->type != FFI_TYPE_STRUCT)
60 return arg->type;
61
62 type = simple_type (arg->elements[0]);
63 if (! arg->elements[1])
64 {
65 switch (type)
66 {
67 case FFI_TYPE_SINT8:
68 case FFI_TYPE_UINT8:
69 case FFI_TYPE_SINT16:
70 case FFI_TYPE_UINT16:
71 case FFI_TYPE_SINT32:
72 case FFI_TYPE_UINT32:
73 return FFI_TYPE_INT;
74
75 default:
76 return type;
77 }
78 }
79
80 /* gcc uses r0/r1 pair for some kind of structures. */
81 if (arg->size <= 2 * sizeof (int))
82 {
83 int i = 0;
84 ffi_type *e;
85
86 while ((e = arg->elements[i++]))
87 {
88 type = simple_type (e);
89 switch (type)
90 {
91 case FFI_TYPE_SINT32:
92 case FFI_TYPE_UINT32:
93 case FFI_TYPE_INT:
94 case FFI_TYPE_FLOAT:
95 return FFI_TYPE_UINT64;
96
97 default:
98 break;
99 }
100 }
101 }
102
103 return FFI_TYPE_STRUCT;
104 }
105
106 /* ffi_prep_args is called by the assembly routine once stack space
107 has been allocated for the function's arguments */
108
109 void ffi_prep_args(char *stack, extended_cif *ecif)
110 {
111 register unsigned int i;
112 register int tmp;
113 register unsigned int avn;
114 register void **p_argv;
115 register char *argp;
116 register ffi_type **p_arg;
117 int greg, ireg;
118 #if defined(__SH4__)
119 int freg = 0;
120 #endif
121
122 tmp = 0;
123 argp = stack;
124
125 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
126 {
127 *(void **) argp = ecif->rvalue;
128 argp += 4;
129 ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
130 }
131 else
132 ireg = 0;
133
134 /* Set arguments for registers. */
135 greg = ireg;
136 avn = ecif->cif->nargs;
137 p_argv = ecif->avalue;
138
139 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
140 {
141 size_t z;
142
143 z = (*p_arg)->size;
144 if (z < sizeof(int))
145 {
146 if (greg++ >= NGREGARG)
147 continue;
148
149 z = sizeof(int);
150 switch ((*p_arg)->type)
151 {
152 case FFI_TYPE_SINT8:
153 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
154 break;
155
156 case FFI_TYPE_UINT8:
157 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
158 break;
159
160 case FFI_TYPE_SINT16:
161 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
162 break;
163
164 case FFI_TYPE_UINT16:
165 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
166 break;
167
168 case FFI_TYPE_STRUCT:
169 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
170 break;
171
172 default:
173 FFI_ASSERT(0);
174 }
175 argp += z;
176 }
177 else if (z == sizeof(int))
178 {
179 #if defined(__SH4__)
180 if ((*p_arg)->type == FFI_TYPE_FLOAT)
181 {
182 if (freg++ >= NFREGARG)
183 continue;
184 }
185 else
186 #endif
187 {
188 if (greg++ >= NGREGARG)
189 continue;
190 }
191 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
192 argp += z;
193 }
194 #if defined(__SH4__)
195 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
196 {
197 if (freg + 1 >= NFREGARG)
198 continue;
199 freg = (freg + 1) & ~1;
200 freg += 2;
201 memcpy (argp, *p_argv, z);
202 argp += z;
203 }
204 #endif
205 else
206 {
207 int n = (z + sizeof (int) - 1) / sizeof (int);
208 #if defined(__SH4__)
209 if (greg + n - 1 >= NGREGARG)
210 continue;
211 #else
212 if (greg >= NGREGARG)
213 continue;
214 #endif
215 greg += n;
216 memcpy (argp, *p_argv, z);
217 argp += n * sizeof (int);
218 }
219 }
220
221 /* Set arguments on stack. */
222 greg = ireg;
223 #if defined(__SH4__)
224 freg = 0;
225 #endif
226 p_argv = ecif->avalue;
227
228 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
229 {
230 size_t z;
231
232 z = (*p_arg)->size;
233 if (z < sizeof(int))
234 {
235 if (greg++ < NGREGARG)
236 continue;
237
238 z = sizeof(int);
239 switch ((*p_arg)->type)
240 {
241 case FFI_TYPE_SINT8:
242 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
243 break;
244
245 case FFI_TYPE_UINT8:
246 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
247 break;
248
249 case FFI_TYPE_SINT16:
250 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
251 break;
252
253 case FFI_TYPE_UINT16:
254 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
255 break;
256
257 case FFI_TYPE_STRUCT:
258 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
259 break;
260
261 default:
262 FFI_ASSERT(0);
263 }
264 argp += z;
265 }
266 else if (z == sizeof(int))
267 {
268 #if defined(__SH4__)
269 if ((*p_arg)->type == FFI_TYPE_FLOAT)
270 {
271 if (freg++ < NFREGARG)
272 continue;
273 }
274 else
275 #endif
276 {
277 if (greg++ < NGREGARG)
278 continue;
279 }
280 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
281 argp += z;
282 }
283 #if defined(__SH4__)
284 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
285 {
286 if (freg + 1 < NFREGARG)
287 {
288 freg = (freg + 1) & ~1;
289 freg += 2;
290 continue;
291 }
292 memcpy (argp, *p_argv, z);
293 argp += z;
294 }
295 #endif
296 else
297 {
298 int n = (z + sizeof (int) - 1) / sizeof (int);
299 if (greg + n - 1 < NGREGARG)
300 {
301 greg += n;
302 continue;
303 }
304 #if (! defined(__SH4__))
305 else if (greg < NGREGARG)
306 {
307 greg = NGREGARG;
308 continue;
309 }
310 #endif
311 memcpy (argp, *p_argv, z);
312 argp += n * sizeof (int);
313 }
314 }
315
316 return;
317 }
318
319 /* Perform machine dependent cif processing */
320 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
321 {
322 int i, j;
323 int size, type;
324 int n, m;
325 int greg;
326 #if defined(__SH4__)
327 int freg = 0;
328 #endif
329
330 cif->flags = 0;
331
332 greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
333 STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
334
335 #if defined(__SH4__)
336 for (i = j = 0; i < cif->nargs && j < 12; i++)
337 {
338 type = (cif->arg_types)[i]->type;
339 switch (type)
340 {
341 case FFI_TYPE_FLOAT:
342 if (freg >= NFREGARG)
343 continue;
344 freg++;
345 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
346 j++;
347 break;
348
349 case FFI_TYPE_DOUBLE:
350 if ((freg + 1) >= NFREGARG)
351 continue;
352 freg = (freg + 1) & ~1;
353 freg += 2;
354 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
355 j++;
356 break;
357
358 default:
359 size = (cif->arg_types)[i]->size;
360 n = (size + sizeof (int) - 1) / sizeof (int);
361 if (greg + n - 1 >= NGREGARG)
362 continue;
363 greg += n;
364 for (m = 0; m < n; m++)
365 cif->flags += FFI_TYPE_INT << (2 * j++);
366 break;
367 }
368 }
369 #else
370 for (i = j = 0; i < cif->nargs && j < 4; i++)
371 {
372 size = (cif->arg_types)[i]->size;
373 n = (size + sizeof (int) - 1) / sizeof (int);
374 if (greg >= NGREGARG)
375 continue;
376 else if (greg + n - 1 >= NGREGARG)
377 n = NGREGARG - greg;
378 greg += n;
379 for (m = 0; m < n; m++)
380 cif->flags += FFI_TYPE_INT << (2 * j++);
381 }
382 #endif
383
384 /* Set the return type flag */
385 switch (cif->rtype->type)
386 {
387 case FFI_TYPE_STRUCT:
388 cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
389 break;
390
391 case FFI_TYPE_VOID:
392 case FFI_TYPE_FLOAT:
393 case FFI_TYPE_DOUBLE:
394 case FFI_TYPE_SINT64:
395 case FFI_TYPE_UINT64:
396 cif->flags += (unsigned) cif->rtype->type << 24;
397 break;
398
399 default:
400 cif->flags += FFI_TYPE_INT << 24;
401 break;
402 }
403
404 return FFI_OK;
405 }
406
407 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
408 unsigned, unsigned, unsigned *, void (*fn)());
409
410 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
411 {
412 extended_cif ecif;
413 UINT64 trvalue;
414
415 ecif.cif = cif;
416 ecif.avalue = avalue;
417
418 /* If the return value is a struct and we don't have a return */
419 /* value address then we need to make one */
420
421 if (cif->rtype->type == FFI_TYPE_STRUCT
422 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
423 ecif.rvalue = &trvalue;
424 else if ((rvalue == NULL) &&
425 (cif->rtype->type == FFI_TYPE_STRUCT))
426 {
427 ecif.rvalue = alloca(cif->rtype->size);
428 }
429 else
430 ecif.rvalue = rvalue;
431
432 switch (cif->abi)
433 {
434 case FFI_SYSV:
435 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
436 fn);
437 break;
438 default:
439 FFI_ASSERT(0);
440 break;
441 }
442
443 if (rvalue
444 && cif->rtype->type == FFI_TYPE_STRUCT
445 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
446 memcpy (rvalue, &trvalue, cif->rtype->size);
447 }
448
449 extern void ffi_closure_SYSV (void);
450 #if defined(__SH4__)
451 extern void __ic_invalidate (void *line);
452 #endif
453
454 ffi_status
455 ffi_prep_closure_loc (ffi_closure* closure,
456 ffi_cif* cif,
457 void (*fun)(ffi_cif*, void*, void**, void*),
458 void *user_data,
459 void *codeloc)
460 {
461 unsigned int *tramp;
462 unsigned short insn;
463
464 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
465
466 tramp = (unsigned int *) &closure->tramp[0];
467 /* Set T bit if the function returns a struct pointed with R2. */
468 insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT
469 ? 0x0018 /* sett */
470 : 0x0008 /* clrt */);
471
472 #ifdef __LITTLE_ENDIAN__
473 tramp[0] = 0xd301d102;
474 tramp[1] = 0x0000412b | (insn << 16);
475 #else
476 tramp[0] = 0xd102d301;
477 tramp[1] = 0x412b0000 | insn;
478 #endif
479 *(void **) &tramp[2] = (void *)codeloc; /* ctx */
480 *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
481
482 closure->cif = cif;
483 closure->fun = fun;
484 closure->user_data = user_data;
485
486 #if defined(__SH4__)
487 /* Flush the icache. */
488 __ic_invalidate(codeloc);
489 #endif
490
491 return FFI_OK;
492 }
493
494 /* Basically the trampoline invokes ffi_closure_SYSV, and on
495 * entry, r3 holds the address of the closure.
496 * After storing the registers that could possibly contain
497 * parameters to be passed into the stack frame and setting
498 * up space for a return value, ffi_closure_SYSV invokes the
499 * following helper function to do most of the work.
500 */
501
502 #ifdef __LITTLE_ENDIAN__
503 #define OFS_INT8 0
504 #define OFS_INT16 0
505 #else
506 #define OFS_INT8 3
507 #define OFS_INT16 2
508 #endif
509
510 int
511 ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
512 unsigned long *pgr, unsigned long *pfr,
513 unsigned long *pst)
514 {
515 void **avalue;
516 ffi_type **p_arg;
517 int i, avn;
518 int ireg, greg = 0;
519 #if defined(__SH4__)
520 int freg = 0;
521 #endif
522 ffi_cif *cif;
523
524 cif = closure->cif;
525 avalue = alloca(cif->nargs * sizeof(void *));
526
527 /* Copy the caller's structure return value address so that the closure
528 returns the data directly to the caller. */
529 if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG)
530 {
531 rvalue = (void *) *pgr++;
532 ireg = 1;
533 }
534 else
535 ireg = 0;
536
537 cif = closure->cif;
538 greg = ireg;
539 avn = cif->nargs;
540
541 /* Grab the addresses of the arguments from the stack frame. */
542 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
543 {
544 size_t z;
545
546 z = (*p_arg)->size;
547 if (z < sizeof(int))
548 {
549 if (greg++ >= NGREGARG)
550 continue;
551
552 z = sizeof(int);
553 switch ((*p_arg)->type)
554 {
555 case FFI_TYPE_SINT8:
556 case FFI_TYPE_UINT8:
557 avalue[i] = (((char *)pgr) + OFS_INT8);
558 break;
559
560 case FFI_TYPE_SINT16:
561 case FFI_TYPE_UINT16:
562 avalue[i] = (((char *)pgr) + OFS_INT16);
563 break;
564
565 case FFI_TYPE_STRUCT:
566 avalue[i] = pgr;
567 break;
568
569 default:
570 FFI_ASSERT(0);
571 }
572 pgr++;
573 }
574 else if (z == sizeof(int))
575 {
576 #if defined(__SH4__)
577 if ((*p_arg)->type == FFI_TYPE_FLOAT)
578 {
579 if (freg++ >= NFREGARG)
580 continue;
581 avalue[i] = pfr;
582 pfr++;
583 }
584 else
585 #endif
586 {
587 if (greg++ >= NGREGARG)
588 continue;
589 avalue[i] = pgr;
590 pgr++;
591 }
592 }
593 #if defined(__SH4__)
594 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
595 {
596 if (freg + 1 >= NFREGARG)
597 continue;
598 if (freg & 1)
599 pfr++;
600 freg = (freg + 1) & ~1;
601 freg += 2;
602 avalue[i] = pfr;
603 pfr += 2;
604 }
605 #endif
606 else
607 {
608 int n = (z + sizeof (int) - 1) / sizeof (int);
609 #if defined(__SH4__)
610 if (greg + n - 1 >= NGREGARG)
611 continue;
612 #else
613 if (greg >= NGREGARG)
614 continue;
615 #endif
616 greg += n;
617 avalue[i] = pgr;
618 pgr += n;
619 }
620 }
621
622 greg = ireg;
623 #if defined(__SH4__)
624 freg = 0;
625 #endif
626
627 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
628 {
629 size_t z;
630
631 z = (*p_arg)->size;
632 if (z < sizeof(int))
633 {
634 if (greg++ < NGREGARG)
635 continue;
636
637 z = sizeof(int);
638 switch ((*p_arg)->type)
639 {
640 case FFI_TYPE_SINT8:
641 case FFI_TYPE_UINT8:
642 avalue[i] = (((char *)pst) + OFS_INT8);
643 break;
644
645 case FFI_TYPE_SINT16:
646 case FFI_TYPE_UINT16:
647 avalue[i] = (((char *)pst) + OFS_INT16);
648 break;
649
650 case FFI_TYPE_STRUCT:
651 avalue[i] = pst;
652 break;
653
654 default:
655 FFI_ASSERT(0);
656 }
657 pst++;
658 }
659 else if (z == sizeof(int))
660 {
661 #if defined(__SH4__)
662 if ((*p_arg)->type == FFI_TYPE_FLOAT)
663 {
664 if (freg++ < NFREGARG)
665 continue;
666 }
667 else
668 #endif
669 {
670 if (greg++ < NGREGARG)
671 continue;
672 }
673 avalue[i] = pst;
674 pst++;
675 }
676 #if defined(__SH4__)
677 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
678 {
679 if (freg + 1 < NFREGARG)
680 {
681 freg = (freg + 1) & ~1;
682 freg += 2;
683 continue;
684 }
685 avalue[i] = pst;
686 pst += 2;
687 }
688 #endif
689 else
690 {
691 int n = (z + sizeof (int) - 1) / sizeof (int);
692 if (greg + n - 1 < NGREGARG)
693 {
694 greg += n;
695 continue;
696 }
697 #if (! defined(__SH4__))
698 else if (greg < NGREGARG)
699 {
700 greg += n;
701 pst += greg - NGREGARG;
702 continue;
703 }
704 #endif
705 avalue[i] = pst;
706 pst += n;
707 }
708 }
709
710 (closure->fun) (cif, rvalue, avalue, closure->user_data);
711
712 /* Tell ffi_closure_SYSV how to perform return type promotions. */
713 return return_type (cif->rtype);
714 }