]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/sparc/ffi.c
ffi.c (ffi_prep_args_v9): Shift the parameter array when the structure return address...
[thirdparty/gcc.git] / libffi / src / sparc / ffi.c
CommitLineData
63e5e3e0 1/* -----------------------------------------------------------------------
0ce78f01 2 ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc.
63e5e3e0 3
0ce78f01 4 SPARC Foreign Function Interface
63e5e3e0 5
63e5e3e0
AG
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
c75c7793 31
63e5e3e0
AG
32/* ffi_prep_args is called by the assembly routine once stack space
33 has been allocated for the function's arguments */
34
3791773c 35void ffi_prep_args_v8(char *stack, extended_cif *ecif)
63e5e3e0
AG
36{
37 int i;
63e5e3e0
AG
38 void **p_argv;
39 char *argp;
40 ffi_type **p_arg;
41
63e5e3e0 42 /* Skip 16 words for the window save area */
3791773c 43 argp = stack + 16*sizeof(int);
63e5e3e0
AG
44
45 /* This should only really be done when we are returning a structure,
46 however, it's faster just to do it all the time...
47
48 if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
3791773c 49 *(int *) argp = (long)ecif->rvalue;
63e5e3e0
AG
50
51 /* And 1 word for the structure return value. */
3791773c 52 argp += sizeof(int);
63e5e3e0
AG
53
54#ifdef USING_PURIFY
55 /* Purify will probably complain in our assembly routine, unless we
56 zero out this memory. */
57
58 ((int*)argp)[0] = 0;
59 ((int*)argp)[1] = 0;
60 ((int*)argp)[2] = 0;
61 ((int*)argp)[3] = 0;
62 ((int*)argp)[4] = 0;
63 ((int*)argp)[5] = 0;
64#endif
65
63e5e3e0
AG
66 p_argv = ecif->avalue;
67
c94974ca 68 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
63e5e3e0
AG
69 {
70 size_t z;
71
63e5e3e0 72 if ((*p_arg)->type == FFI_TYPE_STRUCT
3791773c
JJ
73#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
74 || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
75#endif
76 )
63e5e3e0 77 {
3791773c
JJ
78 *(unsigned int *) argp = (unsigned long)(* p_argv);
79 z = sizeof(int);
63e5e3e0
AG
80 }
81 else
82 {
83 z = (*p_arg)->size;
84 if (z < sizeof(int))
85 {
86 z = sizeof(int);
87 switch ((*p_arg)->type)
88 {
89 case FFI_TYPE_SINT8:
90 *(signed int *) argp = *(SINT8 *)(* p_argv);
91 break;
92
93 case FFI_TYPE_UINT8:
94 *(unsigned int *) argp = *(UINT8 *)(* p_argv);
95 break;
96
97 case FFI_TYPE_SINT16:
98 *(signed int *) argp = *(SINT16 *)(* p_argv);
99 break;
100
101 case FFI_TYPE_UINT16:
102 *(unsigned int *) argp = *(UINT16 *)(* p_argv);
103 break;
3791773c 104
63e5e3e0
AG
105 default:
106 FFI_ASSERT(0);
107 }
108 }
109 else
110 {
111 memcpy(argp, *p_argv, z);
112 }
113 }
114 p_argv++;
115 argp += z;
63e5e3e0
AG
116 }
117
118 return;
119}
120
3791773c
JJ
121int ffi_prep_args_v9(char *stack, extended_cif *ecif)
122{
123 int i, ret = 0;
124 int tmp;
125 void **p_argv;
126 char *argp;
127 ffi_type **p_arg;
128
129 tmp = 0;
130
131 /* Skip 16 words for the window save area */
132 argp = stack + 16*sizeof(long long);
133
134#ifdef USING_PURIFY
135 /* Purify will probably complain in our assembly routine, unless we
136 zero out this memory. */
137
138 ((long long*)argp)[0] = 0;
139 ((long long*)argp)[1] = 0;
140 ((long long*)argp)[2] = 0;
141 ((long long*)argp)[3] = 0;
142 ((long long*)argp)[4] = 0;
143 ((long long*)argp)[5] = 0;
144#endif
145
146 p_argv = ecif->avalue;
147
148 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
149 ecif->cif->rtype->size > 32)
150 {
151 *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
0ce78f01 152 argp += sizeof(long long);
3791773c
JJ
153 tmp = 1;
154 }
155
156 for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
157 i++, p_arg++)
158 {
159 size_t z;
160
161 z = (*p_arg)->size;
162 switch ((*p_arg)->type)
163 {
164 case FFI_TYPE_STRUCT:
165 if (z > 16)
166 {
167 /* For structures larger than 16 bytes we pass reference. */
168 *(unsigned long long *) argp = (unsigned long)* p_argv;
169 argp += sizeof(long long);
170 tmp++;
171 p_argv++;
172 continue;
173 }
174 /* FALLTHROUGH */
175 case FFI_TYPE_FLOAT:
176 case FFI_TYPE_DOUBLE:
177#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
178 case FFI_TYPE_LONGDOUBLE:
179#endif
180 ret = 1; /* We should promote into FP regs as well as integer. */
181 break;
182 }
183 if (z < sizeof(long long))
184 {
185 switch ((*p_arg)->type)
186 {
187 case FFI_TYPE_SINT8:
188 *(signed long long *) argp = *(SINT8 *)(* p_argv);
189 break;
190
191 case FFI_TYPE_UINT8:
192 *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
193 break;
194
195 case FFI_TYPE_SINT16:
196 *(signed long long *) argp = *(SINT16 *)(* p_argv);
197 break;
198
199 case FFI_TYPE_UINT16:
200 *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
201 break;
202
203 case FFI_TYPE_SINT32:
204 *(signed long long *) argp = *(SINT32 *)(* p_argv);
205 break;
206
207 case FFI_TYPE_UINT32:
208 *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
209 break;
210
211 case FFI_TYPE_FLOAT:
212 *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
213 break;
214
215 case FFI_TYPE_STRUCT:
216 memcpy(argp, *p_argv, z);
217 break;
218
219 default:
220 FFI_ASSERT(0);
221 }
222 z = sizeof(long long);
223 tmp++;
224 }
225 else if (z == sizeof(long long))
226 {
227 memcpy(argp, *p_argv, z);
228 z = sizeof(long long);
229 tmp++;
230 }
231 else
232 {
233 if ((tmp & 1) && (*p_arg)->alignment > 8)
234 {
235 tmp++;
236 argp += sizeof(long long);
237 }
238 memcpy(argp, *p_argv, z);
239 z = 2 * sizeof(long long);
240 tmp += 2;
241 }
242 p_argv++;
243 argp += z;
244 }
245
246 return ret;
247}
248
63e5e3e0
AG
249/* Perform machine dependent cif processing */
250ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
251{
3791773c
JJ
252 int wordsize;
253
254 if (cif->abi != FFI_V9)
255 {
256 wordsize = 4;
63e5e3e0 257
3791773c
JJ
258 /* If we are returning a struct, this will already have been added.
259 Otherwise we need to add it because it's always got to be there! */
63e5e3e0 260
3791773c
JJ
261 if (cif->rtype->type != FFI_TYPE_STRUCT)
262 cif->bytes += wordsize;
263
264 /* sparc call frames require that space is allocated for 6 args,
265 even if they aren't used. Make that space if necessary. */
63e5e3e0 266
3791773c
JJ
267 if (cif->bytes < 4*6+4)
268 cif->bytes = 4*6+4;
269 }
270 else
271 {
272 wordsize = 8;
273
274 /* sparc call frames require that space is allocated for 6 args,
275 even if they aren't used. Make that space if necessary. */
276
277 if (cif->bytes < 8*6)
278 cif->bytes = 8*6;
279 }
63e5e3e0
AG
280
281 /* Adjust cif->bytes. to include 16 words for the window save area,
282 and maybe the struct/union return pointer area, */
283
3791773c 284 cif->bytes += 16 * wordsize;
63e5e3e0 285
3791773c 286 /* The stack must be 2 word aligned, so round bytes up
63e5e3e0
AG
287 appropriately. */
288
3791773c 289 cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
63e5e3e0
AG
290
291 /* Set the return type flag */
292 switch (cif->rtype->type)
293 {
294 case FFI_TYPE_VOID:
63e5e3e0 295 case FFI_TYPE_FLOAT:
3791773c
JJ
296 case FFI_TYPE_DOUBLE:
297#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
298 case FFI_TYPE_LONGDOUBLE:
299#endif
300 cif->flags = cif->rtype->type;
63e5e3e0
AG
301 break;
302
3791773c
JJ
303 case FFI_TYPE_STRUCT:
304 if (cif->abi == FFI_V9 && cif->rtype->size > 32)
305 cif->flags = FFI_TYPE_VOID;
306 else
307 cif->flags = FFI_TYPE_STRUCT;
63e5e3e0
AG
308 break;
309
3791773c
JJ
310 case FFI_TYPE_SINT64:
311 case FFI_TYPE_UINT64:
312 if (cif->abi != FFI_V9)
313 {
314 cif->flags = FFI_TYPE_SINT64;
315 break;
316 }
317 /* FALLTHROUGH */
63e5e3e0
AG
318 default:
319 cif->flags = FFI_TYPE_INT;
320 break;
321 }
63e5e3e0
AG
322 return FFI_OK;
323}
324
0ce78f01 325int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
3791773c
JJ
326{
327 ffi_type **ptr = &arg->elements[0];
328
329 while (*ptr != NULL)
330 {
331 if (off & ((*ptr)->alignment - 1))
332 off = ALIGN(off, (*ptr)->alignment);
333
334 switch ((*ptr)->type)
335 {
336 case FFI_TYPE_STRUCT:
0ce78f01
EB
337 off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
338 off = ALIGN(off, FFI_SIZEOF_ARG);
3791773c
JJ
339 break;
340 case FFI_TYPE_FLOAT:
341 case FFI_TYPE_DOUBLE:
342#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
343 case FFI_TYPE_LONGDOUBLE:
344#endif
0ce78f01 345 memmove(ret + off, flt + off, (*ptr)->size);
3791773c
JJ
346 off += (*ptr)->size;
347 break;
348 default:
0ce78f01 349 memmove(ret + off, intg + off, (*ptr)->size);
3791773c
JJ
350 off += (*ptr)->size;
351 break;
352 }
353 ptr++;
354 }
355 return off;
356}
357
0ce78f01
EB
358
359#ifdef SPARC64
360extern int ffi_call_v9(void *, extended_cif *, unsigned,
63e5e3e0 361 unsigned, unsigned *, void (*fn)());
0ce78f01
EB
362#else
363extern int ffi_call_v8(void *, extended_cif *, unsigned,
3791773c 364 unsigned, unsigned *, void (*fn)());
0ce78f01 365#endif
63e5e3e0
AG
366
367void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
368{
369 extended_cif ecif;
3791773c 370 void *rval = rvalue;
63e5e3e0
AG
371
372 ecif.cif = cif;
373 ecif.avalue = avalue;
3791773c 374
63e5e3e0
AG
375 /* If the return value is a struct and we don't have a return */
376 /* value address then we need to make one */
3791773c
JJ
377
378 ecif.rvalue = rvalue;
379 if (cif->rtype->type == FFI_TYPE_STRUCT)
380 {
381 if (cif->rtype->size <= 32)
382 rval = alloca(64);
383 else
384 {
385 rval = NULL;
386 if (rvalue == NULL)
387 ecif.rvalue = alloca(cif->rtype->size);
388 }
389 }
390
63e5e3e0
AG
391 switch (cif->abi)
392 {
393 case FFI_V8:
3791773c
JJ
394#ifdef SPARC64
395 /* We don't yet support calling 32bit code from 64bit */
396 FFI_ASSERT(0);
397#else
0ce78f01 398 ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
63e5e3e0 399 cif->flags, rvalue, fn);
3791773c
JJ
400#endif
401 break;
402 case FFI_V9:
403#ifdef SPARC64
0ce78f01 404 ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
3791773c
JJ
405 cif->flags, rval, fn);
406 if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
0ce78f01 407 ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
3791773c
JJ
408#else
409 /* And vice versa */
410 FFI_ASSERT(0);
411#endif
63e5e3e0
AG
412 break;
413 default:
414 FFI_ASSERT(0);
415 break;
416 }
3791773c 417
63e5e3e0 418}
c75c7793 419
0ce78f01
EB
420
421#ifdef SPARC64
422extern void ffi_closure_v9(void);
423#else
424extern void ffi_closure_v8(void);
425#endif
426
c75c7793
JS
427ffi_status
428ffi_prep_closure (ffi_closure* closure,
429 ffi_cif* cif,
430 void (*fun)(ffi_cif*, void*, void**, void*),
431 void *user_data)
432{
433 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
434 unsigned long fn;
c75c7793
JS
435#ifdef SPARC64
436 /* Trampoline address is equal to the closure address. We take advantage
437 of that to reduce the trampoline size by 8 bytes. */
438 FFI_ASSERT (cif->abi == FFI_V9);
439 fn = (unsigned long) ffi_closure_v9;
440 tramp[0] = 0x83414000; /* rd %pc, %g1 */
441 tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
442 tramp[2] = 0x81c14000; /* jmp %g5 */
443 tramp[3] = 0x01000000; /* nop */
444 *((unsigned long *) &tramp[4]) = fn;
445#else
0ce78f01 446 unsigned long ctx = (unsigned long) closure;
c75c7793
JS
447 FFI_ASSERT (cif->abi == FFI_V8);
448 fn = (unsigned long) ffi_closure_v8;
449 tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
450 tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
451 tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
452 tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
453#endif
454
455 closure->cif = cif;
456 closure->fun = fun;
457 closure->user_data = user_data;
458
459 /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */
460#ifdef SPARC64
461 asm volatile ("flush %0" : : "r" (closure) : "memory");
462 asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory");
463#else
464 asm volatile ("iflush %0" : : "r" (closure) : "memory");
465 asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory");
466#endif
467
468 return FFI_OK;
469}
470
471int
0ce78f01
EB
472ffi_closure_sparc_inner_v8(ffi_closure *closure,
473 void *rvalue, unsigned long *gpr)
c75c7793
JS
474{
475 ffi_cif *cif;
c75c7793 476 ffi_type **arg_types;
0ce78f01
EB
477 void **avalue;
478 int i, argn;
c75c7793
JS
479
480 cif = closure->cif;
0ce78f01 481 arg_types = cif->arg_types;
c75c7793
JS
482 avalue = alloca(cif->nargs * sizeof(void *));
483
0ce78f01
EB
484 /* Copy the caller's structure return address so that the closure
485 returns the data directly to the caller. */
486 if (cif->flags == FFI_TYPE_STRUCT
487#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
488 || cif->flags == FFI_TYPE_LONGDOUBLE
489#endif
490 )
491 rvalue = (void *) gpr[0];
492
493 /* Always skip the structure return address. */
494 argn = 1;
495
496 /* Grab the addresses of the arguments from the stack frame. */
497 for (i = 0; i < cif->nargs; i++)
498 {
499 if (arg_types[i]->type == FFI_TYPE_STRUCT
500#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
501 || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
502#endif
503 )
504 {
505 /* Straight copy of invisible reference. */
506 avalue[i] = (void *)gpr[argn++];
507 }
508 else
509 {
510 /* Always right-justify. */
511 argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
512 avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
513 }
514 }
c75c7793 515
0ce78f01
EB
516 /* Invoke the closure. */
517 (closure->fun) (cif, rvalue, avalue, closure->user_data);
518
519 /* Tell ffi_closure_sparc how to perform return type promotions. */
520 return cif->rtype->type;
521}
522
523int
524ffi_closure_sparc_inner_v9(ffi_closure *closure,
525 void *rvalue, unsigned long *gpr, double *fpr)
526{
527 ffi_cif *cif;
528 ffi_type **arg_types;
529 void **avalue;
530 int i, argn, fp_slot_max;
531
532 cif = closure->cif;
533 arg_types = cif->arg_types;
534 avalue = alloca(cif->nargs * sizeof(void *));
535
536 /* Copy the caller's structure return address so that the closure
c75c7793 537 returns the data directly to the caller. */
0ce78f01
EB
538 if (cif->flags == FFI_TYPE_VOID
539 && cif->rtype->type == FFI_TYPE_STRUCT)
c75c7793
JS
540 {
541 rvalue = (void *) gpr[0];
0ce78f01 542 /* Skip the structure return address. */
c75c7793
JS
543 argn = 1;
544 }
0ce78f01
EB
545 else
546 argn = 0;
547
548 fp_slot_max = 16 - argn;
c75c7793 549
c75c7793 550 /* Grab the addresses of the arguments from the stack frame. */
0ce78f01 551 for (i = 0; i < cif->nargs; i++)
c75c7793 552 {
0ce78f01
EB
553 if (arg_types[i]->type == FFI_TYPE_STRUCT)
554 {
555 if (arg_types[i]->size > 16)
556 {
557 /* Straight copy of invisible reference. */
558 avalue[i] = (void *)gpr[argn++];
559 }
560 else
561 {
562 /* Left-justify. */
563 ffi_v9_layout_struct(arg_types[i],
564 0,
565 (char *) &gpr[argn],
566 (char *) &gpr[argn],
567 (char *) &fpr[argn]);
568 avalue[i] = &gpr[argn];
569 argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
570 }
571 }
572 else
573 {
574 /* Right-justify. */
575 argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
c75c7793 576
0ce78f01
EB
577 if (i < fp_slot_max
578 && (arg_types[i]->type == FFI_TYPE_FLOAT
579 || arg_types[i]->type == FFI_TYPE_DOUBLE
c75c7793 580#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
0ce78f01 581 || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
c75c7793 582#endif
0ce78f01
EB
583 ))
584 avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
585 else
586 avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
587 }
c75c7793
JS
588 }
589
590 /* Invoke the closure. */
591 (closure->fun) (cif, rvalue, avalue, closure->user_data);
592
593 /* Tell ffi_closure_sparc how to perform return type promotions. */
594 return cif->rtype->type;
595}