Daily bump.
[official-gcc.git] / libffi / src / sh64 / ffi.c
blobcaca436fc2de7d1f5665aeb23e416e874648c7cf
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004, 2006 Kaz Kojima
4 SuperH SHmedia Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
26 #include <ffi.h>
27 #include <ffi_common.h>
29 #include <stdlib.h>
31 #define NGREGARG 8
32 #define NFREGARG 12
34 static int
35 return_type (ffi_type *arg)
38 if (arg->type != FFI_TYPE_STRUCT)
39 return arg->type;
41 /* gcc uses r2 if the result can be packed in on register. */
42 if (arg->size <= sizeof (UINT8))
43 return FFI_TYPE_UINT8;
44 else if (arg->size <= sizeof (UINT16))
45 return FFI_TYPE_UINT16;
46 else if (arg->size <= sizeof (UINT32))
47 return FFI_TYPE_UINT32;
48 else if (arg->size <= sizeof (UINT64))
49 return FFI_TYPE_UINT64;
51 return FFI_TYPE_STRUCT;
54 /* ffi_prep_args is called by the assembly routine once stack space
55 has been allocated for the function's arguments */
57 void ffi_prep_args(char *stack, extended_cif *ecif)
59 register unsigned int i;
60 register unsigned int avn;
61 register void **p_argv;
62 register char *argp;
63 register ffi_type **p_arg;
65 argp = stack;
67 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
69 *(void **) argp = ecif->rvalue;
70 argp += sizeof (UINT64);
73 avn = ecif->cif->nargs;
74 p_argv = ecif->avalue;
76 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
78 size_t z;
79 int align;
81 z = (*p_arg)->size;
82 align = (*p_arg)->alignment;
83 if (z < sizeof (UINT32))
85 switch ((*p_arg)->type)
87 case FFI_TYPE_SINT8:
88 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
89 break;
91 case FFI_TYPE_UINT8:
92 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
93 break;
95 case FFI_TYPE_SINT16:
96 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
97 break;
99 case FFI_TYPE_UINT16:
100 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
101 break;
103 case FFI_TYPE_STRUCT:
104 memcpy (argp, *p_argv, z);
105 break;
107 default:
108 FFI_ASSERT(0);
110 argp += sizeof (UINT64);
112 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
114 switch ((*p_arg)->type)
116 case FFI_TYPE_INT:
117 case FFI_TYPE_SINT32:
118 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
119 break;
121 case FFI_TYPE_FLOAT:
122 case FFI_TYPE_POINTER:
123 case FFI_TYPE_UINT32:
124 case FFI_TYPE_STRUCT:
125 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
126 break;
128 default:
129 FFI_ASSERT(0);
130 break;
132 argp += sizeof (UINT64);
134 else if (z == sizeof (UINT64)
135 && align == sizeof (UINT64)
136 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
138 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
139 argp += sizeof (UINT64);
141 else
143 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
145 memcpy (argp, *p_argv, z);
146 argp += n * sizeof (UINT64);
150 return;
153 /* Perform machine dependent cif processing */
154 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
156 int i, j;
157 int size, type;
158 int n, m;
159 int greg;
160 int freg;
161 int fpair = -1;
163 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
164 freg = 0;
165 cif->flags2 = 0;
167 for (i = j = 0; i < cif->nargs; i++)
169 type = (cif->arg_types)[i]->type;
170 switch (type)
172 case FFI_TYPE_FLOAT:
173 greg++;
174 cif->bytes += sizeof (UINT64) - sizeof (float);
175 if (freg >= NFREGARG - 1)
176 continue;
177 if (fpair < 0)
179 fpair = freg;
180 freg += 2;
182 else
183 fpair = -1;
184 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
185 break;
187 case FFI_TYPE_DOUBLE:
188 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
189 continue;
190 if ((freg + 1) < NFREGARG)
192 freg += 2;
193 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
195 else
196 cif->flags2 += FFI_TYPE_INT << (2 * j++);
197 break;
199 default:
200 size = (cif->arg_types)[i]->size;
201 if (size < sizeof (UINT64))
202 cif->bytes += sizeof (UINT64) - size;
203 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
204 if (greg >= NGREGARG)
205 continue;
206 else if (greg + n - 1 >= NGREGARG)
207 greg = NGREGARG;
208 else
209 greg += n;
210 for (m = 0; m < n; m++)
211 cif->flags2 += FFI_TYPE_INT << (2 * j++);
212 break;
216 /* Set the return type flag */
217 switch (cif->rtype->type)
219 case FFI_TYPE_STRUCT:
220 cif->flags = return_type (cif->rtype);
221 break;
223 case FFI_TYPE_VOID:
224 case FFI_TYPE_FLOAT:
225 case FFI_TYPE_DOUBLE:
226 case FFI_TYPE_SINT64:
227 case FFI_TYPE_UINT64:
228 cif->flags = cif->rtype->type;
229 break;
231 default:
232 cif->flags = FFI_TYPE_INT;
233 break;
236 return FFI_OK;
239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
240 unsigned, unsigned, long long, unsigned *,
241 void (*fn)());
243 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
245 extended_cif ecif;
246 UINT64 trvalue;
248 ecif.cif = cif;
249 ecif.avalue = avalue;
251 /* If the return value is a struct and we don't have a return */
252 /* value address then we need to make one */
254 if (cif->rtype->type == FFI_TYPE_STRUCT
255 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
256 ecif.rvalue = &trvalue;
257 else if ((rvalue == NULL) &&
258 (cif->rtype->type == FFI_TYPE_STRUCT))
260 ecif.rvalue = alloca(cif->rtype->size);
262 else
263 ecif.rvalue = rvalue;
265 switch (cif->abi)
267 case FFI_SYSV:
268 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
269 ecif.rvalue, fn);
270 break;
271 default:
272 FFI_ASSERT(0);
273 break;
276 if (rvalue
277 && cif->rtype->type == FFI_TYPE_STRUCT
278 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
279 memcpy (rvalue, &trvalue, cif->rtype->size);
282 extern void ffi_closure_SYSV (void);
283 extern void __ic_invalidate (void *line);
285 ffi_status
286 ffi_prep_closure (ffi_closure *closure,
287 ffi_cif *cif,
288 void (*fun)(ffi_cif*, void*, void**, void*),
289 void *user_data)
291 unsigned int *tramp;
293 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
295 tramp = (unsigned int *) &closure->tramp[0];
296 /* Since ffi_closure is an aligned object, the ffi trampoline is
297 called as an SHcompact code. Sigh.
298 SHcompact part:
299 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
300 SHmedia part:
301 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
302 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
303 #ifdef __LITTLE_ENDIAN__
304 tramp[0] = 0x7001c701;
305 tramp[1] = 0x0009402b;
306 #else
307 tramp[0] = 0xc7017001;
308 tramp[1] = 0x402b0009;
309 #endif
310 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
311 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
312 tramp[4] = 0x6bf10600;
313 tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
314 tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
315 tramp[7] = 0x4401fff0;
317 closure->cif = cif;
318 closure->fun = fun;
319 closure->user_data = user_data;
321 /* Flush the icache. */
322 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
324 return FFI_OK;
327 /* Basically the trampoline invokes ffi_closure_SYSV, and on
328 * entry, r3 holds the address of the closure.
329 * After storing the registers that could possibly contain
330 * parameters to be passed into the stack frame and setting
331 * up space for a return value, ffi_closure_SYSV invokes the
332 * following helper function to do most of the work.
336 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
337 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
339 void **avalue;
340 ffi_type **p_arg;
341 int i, avn;
342 int greg, freg;
343 ffi_cif *cif;
344 int fpair = -1;
346 cif = closure->cif;
347 avalue = alloca (cif->nargs * sizeof (void *));
349 /* Copy the caller's structure return value address so that the closure
350 returns the data directly to the caller. */
351 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
353 rvalue = (UINT64 *) *pgr;
354 greg = 1;
356 else
357 greg = 0;
359 freg = 0;
360 cif = closure->cif;
361 avn = cif->nargs;
363 /* Grab the addresses of the arguments from the stack frame. */
364 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
366 size_t z;
367 void *p;
369 z = (*p_arg)->size;
370 if (z < sizeof (UINT32))
372 p = pgr + greg++;
374 switch ((*p_arg)->type)
376 case FFI_TYPE_SINT8:
377 case FFI_TYPE_UINT8:
378 case FFI_TYPE_SINT16:
379 case FFI_TYPE_UINT16:
380 case FFI_TYPE_STRUCT:
381 #ifdef __LITTLE_ENDIAN__
382 avalue[i] = p;
383 #else
384 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
385 #endif
386 break;
388 default:
389 FFI_ASSERT(0);
392 else if (z == sizeof (UINT32))
394 if ((*p_arg)->type == FFI_TYPE_FLOAT)
396 if (freg < NFREGARG - 1)
398 if (fpair >= 0)
400 avalue[i] = (UINT32 *) pfr + fpair;
401 fpair = -1;
403 else
405 #ifdef __LITTLE_ENDIAN__
406 fpair = freg;
407 avalue[i] = (UINT32 *) pfr + (1 ^ freg);
408 #else
409 fpair = 1 ^ freg;
410 avalue[i] = (UINT32 *) pfr + freg;
411 #endif
412 freg += 2;
415 else
416 #ifdef __LITTLE_ENDIAN__
417 avalue[i] = pgr + greg;
418 #else
419 avalue[i] = (UINT32 *) (pgr + greg) + 1;
420 #endif
422 else
423 #ifdef __LITTLE_ENDIAN__
424 avalue[i] = pgr + greg;
425 #else
426 avalue[i] = (UINT32 *) (pgr + greg) + 1;
427 #endif
428 greg++;
430 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
432 if (freg + 1 >= NFREGARG)
433 avalue[i] = pgr + greg;
434 else
436 avalue[i] = pfr + (freg >> 1);
437 freg += 2;
439 greg++;
441 else
443 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
445 avalue[i] = pgr + greg;
446 greg += n;
450 (closure->fun) (cif, rvalue, avalue, closure->user_data);
452 /* Tell ffi_closure_SYSV how to perform return type promotions. */
453 return return_type (cif->rtype);