source: trunk/gcc/libffi/src/sh/ffi.c

Last change on this file was 1389, checked in by bird, 21 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.6 KB
Line 
1/* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2002 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. */
43static int
44simple_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
54static int
55return_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/*@-exportheader@*/
110void ffi_prep_args(char *stack, extended_cif *ecif)
111/*@=exportheader@*/
112{
113 register unsigned int i;
114 register int tmp;
115 register unsigned int avn;
116 register void **p_argv;
117 register char *argp;
118 register ffi_type **p_arg;
119 int greg, ireg;
120#if defined(__SH4__)
121 int freg = 0;
122#endif
123
124 tmp = 0;
125 argp = stack;
126
127 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
128 {
129 *(void **) argp = ecif->rvalue;
130 argp += 4;
131 ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
132 }
133 else
134 ireg = 0;
135
136 /* Set arguments for registers. */
137 greg = ireg;
138 avn = ecif->cif->nargs;
139 p_argv = ecif->avalue;
140
141 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
142 {
143 size_t z;
144
145 z = (*p_arg)->size;
146 if (z < sizeof(int))
147 {
148 if (greg++ >= NGREGARG)
149 continue;
150
151 z = sizeof(int);
152 switch ((*p_arg)->type)
153 {
154 case FFI_TYPE_SINT8:
155 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
156 break;
157
158 case FFI_TYPE_UINT8:
159 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
160 break;
161
162 case FFI_TYPE_SINT16:
163 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
164 break;
165
166 case FFI_TYPE_UINT16:
167 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
168 break;
169
170 case FFI_TYPE_STRUCT:
171 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
172 break;
173
174 default:
175 FFI_ASSERT(0);
176 }
177 argp += z;
178 }
179 else if (z == sizeof(int))
180 {
181#if defined(__SH4__)
182 if ((*p_arg)->type == FFI_TYPE_FLOAT)
183 {
184 if (freg++ >= NFREGARG)
185 continue;
186 }
187 else
188#endif
189 {
190 if (greg++ >= NGREGARG)
191 continue;
192 }
193 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
194 argp += z;
195 }
196#if defined(__SH4__)
197 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
198 {
199 if (freg + 1 >= NFREGARG)
200 continue;
201 freg = (freg + 1) & ~1;
202 freg += 2;
203 memcpy (argp, *p_argv, z);
204 argp += z;
205 }
206#endif
207 else
208 {
209 int n = (z + sizeof (int) - 1) / sizeof (int);
210#if defined(__SH4__)
211 if (greg + n - 1 >= NGREGARG)
212 continue;
213 greg += n;
214#else
215 if (greg >= NGREGARG)
216 continue;
217 else if (greg + n - 1 >= NGREGARG)
218 greg = NGREGARG;
219 else
220 greg += n;
221#endif
222 memcpy (argp, *p_argv, z);
223 argp += z;
224 }
225 }
226
227 /* Set arguments on stack. */
228 greg = ireg;
229#if defined(__SH4__)
230 freg = 0;
231#endif
232 p_argv = ecif->avalue;
233
234 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
235 {
236 size_t z;
237
238 z = (*p_arg)->size;
239 if (z < sizeof(int))
240 {
241 if (greg++ < NGREGARG)
242 continue;
243
244 z = sizeof(int);
245 switch ((*p_arg)->type)
246 {
247 case FFI_TYPE_SINT8:
248 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
249 break;
250
251 case FFI_TYPE_UINT8:
252 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
253 break;
254
255 case FFI_TYPE_SINT16:
256 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
257 break;
258
259 case FFI_TYPE_UINT16:
260 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
261 break;
262
263 case FFI_TYPE_STRUCT:
264 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
265 break;
266
267 default:
268 FFI_ASSERT(0);
269 }
270 argp += z;
271 }
272 else if (z == sizeof(int))
273 {
274#if defined(__SH4__)
275 if ((*p_arg)->type == FFI_TYPE_FLOAT)
276 {
277 if (freg++ < NFREGARG)
278 continue;
279 }
280 else
281#endif
282 {
283 if (greg++ < NGREGARG)
284 continue;
285 }
286 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
287 argp += z;
288 }
289#if defined(__SH4__)
290 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
291 {
292 if (freg + 1 < NFREGARG)
293 {
294 freg = (freg + 1) & ~1;
295 freg += 2;
296 continue;
297 }
298 memcpy (argp, *p_argv, z);
299 argp += z;
300 }
301#endif
302 else
303 {
304 int n = (z + sizeof (int) - 1) / sizeof (int);
305 if (greg + n - 1 < NGREGARG)
306 {
307 greg += n;
308 continue;
309 }
310#if (! defined(__SH4__))
311 else if (greg < NGREGARG)
312 {
313 greg = NGREGARG;
314 continue;
315 }
316#endif
317 memcpy (argp, *p_argv, z);
318 argp += z;
319 }
320 }
321
322 return;
323}
324
325/* Perform machine dependent cif processing */
326ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
327{
328 int i, j;
329 int size, type;
330 int n, m;
331 int greg;
332#if defined(__SH4__)
333 int freg = 0;
334#endif
335
336 cif->flags = 0;
337
338 greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) &&
339 STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0;
340
341#if defined(__SH4__)
342 for (i = j = 0; i < cif->nargs && j < 12; i++)
343 {
344 type = (cif->arg_types)[i]->type;
345 switch (type)
346 {
347 case FFI_TYPE_FLOAT:
348 if (freg >= NFREGARG)
349 continue;
350 freg++;
351 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
352 j++;
353 break;
354
355 case FFI_TYPE_DOUBLE:
356 if ((freg + 1) >= NFREGARG)
357 continue;
358 freg = (freg + 1) & ~1;
359 freg += 2;
360 cif->flags += ((cif->arg_types)[i]->type) << (2 * j);
361 j++;
362 break;
363
364 default:
365 size = (cif->arg_types)[i]->size;
366 n = (size + sizeof (int) - 1) / sizeof (int);
367 if (greg + n - 1 >= NGREGARG)
368 continue;
369 greg += n;
370 for (m = 0; m < n; m++)
371 cif->flags += FFI_TYPE_INT << (2 * j++);
372 break;
373 }
374 }
375#else
376 for (i = j = 0; i < cif->nargs && j < 4; i++)
377 {
378 size = (cif->arg_types)[i]->size;
379 n = (size + sizeof (int) - 1) / sizeof (int);
380 if (greg >= NGREGARG)
381 continue;
382 else if (greg + n - 1 >= NGREGARG)
383 greg = NGREGARG;
384 else
385 greg += n;
386 for (m = 0; m < n; m++)
387 cif->flags += FFI_TYPE_INT << (2 * j++);
388 }
389#endif
390
391 /* Set the return type flag */
392 switch (cif->rtype->type)
393 {
394 case FFI_TYPE_STRUCT:
395 cif->flags += (unsigned) (return_type (cif->rtype)) << 24;
396 break;
397
398 case FFI_TYPE_VOID:
399 case FFI_TYPE_FLOAT:
400 case FFI_TYPE_DOUBLE:
401 case FFI_TYPE_SINT64:
402 case FFI_TYPE_UINT64:
403 cif->flags += (unsigned) cif->rtype->type << 24;
404 break;
405
406 default:
407 cif->flags += FFI_TYPE_INT << 24;
408 break;
409 }
410
411 return FFI_OK;
412}
413
414/*@-declundef@*/
415/*@-exportheader@*/
416extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
417 /*@out@*/ extended_cif *,
418 unsigned, unsigned,
419 /*@out@*/ unsigned *,
420 void (*fn)());
421/*@=declundef@*/
422/*@=exportheader@*/
423
424void ffi_call(/*@dependent@*/ ffi_cif *cif,
425 void (*fn)(),
426 /*@out@*/ void *rvalue,
427 /*@dependent@*/ void **avalue)
428{
429 extended_cif ecif;
430
431 ecif.cif = cif;
432 ecif.avalue = avalue;
433
434 /* If the return value is a struct and we don't have a return */
435 /* value address then we need to make one */
436
437 if ((rvalue == NULL) &&
438 (cif->rtype->type == FFI_TYPE_STRUCT))
439 {
440 /*@-sysunrecog@*/
441 ecif.rvalue = alloca(cif->rtype->size);
442 /*@=sysunrecog@*/
443 }
444 else
445 ecif.rvalue = rvalue;
446
447
448 switch (cif->abi)
449 {
450 case FFI_SYSV:
451 /*@-usedef@*/
452 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
453 cif->flags, ecif.rvalue, fn);
454 /*@=usedef@*/
455 break;
456 default:
457 FFI_ASSERT(0);
458 break;
459 }
460}
461
462extern void ffi_closure_SYSV (void);
463#if defined(__SH4__)
464extern void __ic_invalidate (void *line);
465#endif
466
467ffi_status
468ffi_prep_closure (ffi_closure* closure,
469 ffi_cif* cif,
470 void (*fun)(ffi_cif*, void*, void**, void*),
471 void *user_data)
472{
473 unsigned int *tramp;
474
475 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
476
477 tramp = (unsigned int *) &closure->tramp[0];
478#ifdef __LITTLE_ENDIAN__
479 tramp[0] = 0xd301d202;
480 tramp[1] = 0x0009422b;
481#else
482 tramp[0] = 0xd202d301;
483 tramp[1] = 0x422b0009;
484#endif
485 *(void **) &tramp[2] = (void *)closure; /* ctx */
486 *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */
487
488 closure->cif = cif;
489 closure->fun = fun;
490 closure->user_data = user_data;
491
492#if defined(__SH4__)
493 /* Flush the icache. */
494 __ic_invalidate(&closure->tramp[0]);
495#endif
496
497 return FFI_OK;
498}
499
500/* Basically the trampoline invokes ffi_closure_SYSV, and on
501 * entry, r3 holds the address of the closure.
502 * After storing the registers that could possibly contain
503 * parameters to be passed into the stack frame and setting
504 * up space for a return value, ffi_closure_SYSV invokes the
505 * following helper function to do most of the work.
506 */
507
508#ifdef __LITTLE_ENDIAN__
509#define OFS_INT8 0
510#define OFS_INT16 2
511#else
512#define OFS_INT8 3
513#define OFS_INT16 2
514#endif
515
516int
517ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue,
518 unsigned long *pgr, unsigned long *pfr,
519 unsigned long *pst)
520{
521 void **avalue;
522 ffi_type **p_arg;
523 int i, avn;
524 int ireg, greg = 0;
525#if defined(__SH4__)
526 int freg = 0;
527#endif
528 ffi_cif *cif;
529 double temp;
530
531 cif = closure->cif;
532 avalue = alloca(cif->nargs * sizeof(void *));
533
534 /* Copy the caller's structure return value address so that the closure
535 returns the data directly to the caller. */
536 if (cif->rtype->type == FFI_TYPE_STRUCT)
537 {
538 rvalue = *pgr++;
539 ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0;
540 }
541 else
542 ireg = 0;
543
544 cif = closure->cif;
545 greg = ireg;
546 avn = cif->nargs;
547
548 /* Grab the addresses of the arguments from the stack frame. */
549 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
550 {
551 size_t z;
552
553 z = (*p_arg)->size;
554 if (z < sizeof(int))
555 {
556 if (greg++ >= NGREGARG)
557 continue;
558
559 z = sizeof(int);
560 switch ((*p_arg)->type)
561 {
562 case FFI_TYPE_SINT8:
563 case FFI_TYPE_UINT8:
564 avalue[i] = (((char *)pgr) + OFS_INT8);
565 break;
566
567 case FFI_TYPE_SINT16:
568 case FFI_TYPE_UINT16:
569 avalue[i] = (((char *)pgr) + OFS_INT16);
570 break;
571
572 case FFI_TYPE_STRUCT:
573 avalue[i] = pgr;
574 break;
575
576 default:
577 FFI_ASSERT(0);
578 }
579 pgr++;
580 }
581 else if (z == sizeof(int))
582 {
583#if defined(__SH4__)
584 if ((*p_arg)->type == FFI_TYPE_FLOAT)
585 {
586 if (freg++ >= NFREGARG)
587 continue;
588 avalue[i] = pfr;
589 pfr++;
590 }
591 else
592#endif
593 {
594 if (greg++ >= NGREGARG)
595 continue;
596 avalue[i] = pgr;
597 pgr++;
598 }
599 }
600#if defined(__SH4__)
601 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
602 {
603 if (freg + 1 >= NFREGARG)
604 continue;
605 freg = (freg + 1) & ~1;
606 freg += 2;
607 avalue[i] = pfr;
608 pfr += 2;
609 }
610#endif
611 else
612 {
613 int n = (z + sizeof (int) - 1) / sizeof (int);
614#if defined(__SH4__)
615 if (greg + n - 1 >= NGREGARG)
616 continue;
617 greg += n;
618#else
619 if (greg >= NGREGARG)
620 continue;
621 else if (greg + n - 1 >= NGREGARG)
622 greg = NGREGARG;
623 else
624 greg += n;
625#endif
626 avalue[i] = pgr;
627 pgr += n;
628 }
629 }
630
631 greg = ireg;
632#if defined(__SH4__)
633 freg = 0;
634#endif
635
636 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
637 {
638 size_t z;
639
640 z = (*p_arg)->size;
641 if (z < sizeof(int))
642 {
643 if (greg++ < NGREGARG)
644 continue;
645
646 z = sizeof(int);
647 switch ((*p_arg)->type)
648 {
649 case FFI_TYPE_SINT8:
650 case FFI_TYPE_UINT8:
651 avalue[i] = (((char *)pst) + OFS_INT8);
652 break;
653
654 case FFI_TYPE_SINT16:
655 case FFI_TYPE_UINT16:
656 avalue[i] = (((char *)pst) + OFS_INT16);
657 break;
658
659 case FFI_TYPE_STRUCT:
660 avalue[i] = pst;
661 break;
662
663 default:
664 FFI_ASSERT(0);
665 }
666 pst++;
667 }
668 else if (z == sizeof(int))
669 {
670#if defined(__SH4__)
671 if ((*p_arg)->type == FFI_TYPE_FLOAT)
672 {
673 if (freg++ < NFREGARG)
674 continue;
675 }
676 else
677#endif
678 {
679 if (greg++ < NGREGARG)
680 continue;
681 }
682 avalue[i] = pst;
683 pst++;
684 }
685#if defined(__SH4__)
686 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
687 {
688 if (freg + 1 < NFREGARG)
689 {
690 freg = (freg + 1) & ~1;
691 freg += 2;
692 continue;
693 }
694 avalue[i] = pst;
695 pst += 2;
696 }
697#endif
698 else
699 {
700 int n = (z + sizeof (int) - 1) / sizeof (int);
701 if (greg + n - 1 < NGREGARG)
702 {
703 greg += n;
704 continue;
705 }
706#if (! defined(__SH4__))
707 else if (greg < NGREGARG)
708 {
709 greg = NGREGARG;
710 continue;
711 }
712#endif
713 avalue[i] = pst;
714 pst += n;
715 }
716 }
717
718 (closure->fun) (cif, rvalue, avalue, closure->user_data);
719
720 /* Tell ffi_closure_osf how to perform return type promotions. */
721 return cif->rtype->type;
722}
Note: See TracBrowser for help on using the repository browser.