2009-06-04 Andrew Haley <aph@redhat.com>
[official-gcc.git] / libffi / src / sh64 / ffi.c
blob4e6bd1bca8148b16256444e21437a1a40de64a8d
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004, 2006, 2007 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,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 DEALINGS IN THE SOFTWARE.
25 ----------------------------------------------------------------------- */
27 #include <ffi.h>
28 #include <ffi_common.h>
30 #include <stdlib.h>
32 #define NGREGARG 8
33 #define NFREGARG 12
35 static int
36 return_type (ffi_type *arg)
39 if (arg->type != FFI_TYPE_STRUCT)
40 return arg->type;
42 /* gcc uses r2 if the result can be packed in on register. */
43 if (arg->size <= sizeof (UINT8))
44 return FFI_TYPE_UINT8;
45 else if (arg->size <= sizeof (UINT16))
46 return FFI_TYPE_UINT16;
47 else if (arg->size <= sizeof (UINT32))
48 return FFI_TYPE_UINT32;
49 else if (arg->size <= sizeof (UINT64))
50 return FFI_TYPE_UINT64;
52 return FFI_TYPE_STRUCT;
55 /* ffi_prep_args is called by the assembly routine once stack space
56 has been allocated for the function's arguments */
58 void ffi_prep_args(char *stack, extended_cif *ecif)
60 register unsigned int i;
61 register unsigned int avn;
62 register void **p_argv;
63 register char *argp;
64 register ffi_type **p_arg;
66 argp = stack;
68 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
70 *(void **) argp = ecif->rvalue;
71 argp += sizeof (UINT64);
74 avn = ecif->cif->nargs;
75 p_argv = ecif->avalue;
77 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
79 size_t z;
80 int align;
82 z = (*p_arg)->size;
83 align = (*p_arg)->alignment;
84 if (z < sizeof (UINT32))
86 switch ((*p_arg)->type)
88 case FFI_TYPE_SINT8:
89 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
90 break;
92 case FFI_TYPE_UINT8:
93 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
94 break;
96 case FFI_TYPE_SINT16:
97 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
98 break;
100 case FFI_TYPE_UINT16:
101 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
102 break;
104 case FFI_TYPE_STRUCT:
105 memcpy (argp, *p_argv, z);
106 break;
108 default:
109 FFI_ASSERT(0);
111 argp += sizeof (UINT64);
113 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
115 switch ((*p_arg)->type)
117 case FFI_TYPE_INT:
118 case FFI_TYPE_SINT32:
119 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
120 break;
122 case FFI_TYPE_FLOAT:
123 case FFI_TYPE_POINTER:
124 case FFI_TYPE_UINT32:
125 case FFI_TYPE_STRUCT:
126 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
127 break;
129 default:
130 FFI_ASSERT(0);
131 break;
133 argp += sizeof (UINT64);
135 else if (z == sizeof (UINT64)
136 && align == sizeof (UINT64)
137 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
139 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
140 argp += sizeof (UINT64);
142 else
144 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
146 memcpy (argp, *p_argv, z);
147 argp += n * sizeof (UINT64);
151 return;
154 /* Perform machine dependent cif processing */
155 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
157 int i, j;
158 int size, type;
159 int n, m;
160 int greg;
161 int freg;
162 int fpair = -1;
164 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
165 freg = 0;
166 cif->flags2 = 0;
168 for (i = j = 0; i < cif->nargs; i++)
170 type = (cif->arg_types)[i]->type;
171 switch (type)
173 case FFI_TYPE_FLOAT:
174 greg++;
175 cif->bytes += sizeof (UINT64) - sizeof (float);
176 if (freg >= NFREGARG - 1)
177 continue;
178 if (fpair < 0)
180 fpair = freg;
181 freg += 2;
183 else
184 fpair = -1;
185 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
186 break;
188 case FFI_TYPE_DOUBLE:
189 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
190 continue;
191 if ((freg + 1) < NFREGARG)
193 freg += 2;
194 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
196 else
197 cif->flags2 += FFI_TYPE_INT << (2 * j++);
198 break;
200 default:
201 size = (cif->arg_types)[i]->size;
202 if (size < sizeof (UINT64))
203 cif->bytes += sizeof (UINT64) - size;
204 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
205 if (greg >= NGREGARG)
206 continue;
207 else if (greg + n - 1 >= NGREGARG)
208 greg = NGREGARG;
209 else
210 greg += n;
211 for (m = 0; m < n; m++)
212 cif->flags2 += FFI_TYPE_INT << (2 * j++);
213 break;
217 /* Set the return type flag */
218 switch (cif->rtype->type)
220 case FFI_TYPE_STRUCT:
221 cif->flags = return_type (cif->rtype);
222 break;
224 case FFI_TYPE_VOID:
225 case FFI_TYPE_FLOAT:
226 case FFI_TYPE_DOUBLE:
227 case FFI_TYPE_SINT64:
228 case FFI_TYPE_UINT64:
229 cif->flags = cif->rtype->type;
230 break;
232 default:
233 cif->flags = FFI_TYPE_INT;
234 break;
237 return FFI_OK;
240 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
241 unsigned, unsigned, long long, unsigned *,
242 void (*fn)());
244 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
246 extended_cif ecif;
247 UINT64 trvalue;
249 ecif.cif = cif;
250 ecif.avalue = avalue;
252 /* If the return value is a struct and we don't have a return */
253 /* value address then we need to make one */
255 if (cif->rtype->type == FFI_TYPE_STRUCT
256 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
257 ecif.rvalue = &trvalue;
258 else if ((rvalue == NULL) &&
259 (cif->rtype->type == FFI_TYPE_STRUCT))
261 ecif.rvalue = alloca(cif->rtype->size);
263 else
264 ecif.rvalue = rvalue;
266 switch (cif->abi)
268 case FFI_SYSV:
269 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
270 ecif.rvalue, fn);
271 break;
272 default:
273 FFI_ASSERT(0);
274 break;
277 if (rvalue
278 && cif->rtype->type == FFI_TYPE_STRUCT
279 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
280 memcpy (rvalue, &trvalue, cif->rtype->size);
283 extern void ffi_closure_SYSV (void);
284 extern void __ic_invalidate (void *line);
286 ffi_status
287 ffi_prep_closure_loc (ffi_closure *closure,
288 ffi_cif *cif,
289 void (*fun)(ffi_cif*, void*, void**, void*),
290 void *user_data,
291 void *codeloc)
293 unsigned int *tramp;
295 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
297 tramp = (unsigned int *) &closure->tramp[0];
298 /* Since ffi_closure is an aligned object, the ffi trampoline is
299 called as an SHcompact code. Sigh.
300 SHcompact part:
301 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
302 SHmedia part:
303 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
304 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
305 #ifdef __LITTLE_ENDIAN__
306 tramp[0] = 0x7001c701;
307 tramp[1] = 0x0009402b;
308 #else
309 tramp[0] = 0xc7017001;
310 tramp[1] = 0x402b0009;
311 #endif
312 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
313 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
314 tramp[4] = 0x6bf10600;
315 tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
316 tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
317 tramp[7] = 0x4401fff0;
319 closure->cif = cif;
320 closure->fun = fun;
321 closure->user_data = user_data;
323 /* Flush the icache. */
324 asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
325 "r"(codeloc));
327 return FFI_OK;
330 /* Basically the trampoline invokes ffi_closure_SYSV, and on
331 * entry, r3 holds the address of the closure.
332 * After storing the registers that could possibly contain
333 * parameters to be passed into the stack frame and setting
334 * up space for a return value, ffi_closure_SYSV invokes the
335 * following helper function to do most of the work.
339 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
340 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
342 void **avalue;
343 ffi_type **p_arg;
344 int i, avn;
345 int greg, freg;
346 ffi_cif *cif;
347 int fpair = -1;
349 cif = closure->cif;
350 avalue = alloca (cif->nargs * sizeof (void *));
352 /* Copy the caller's structure return value address so that the closure
353 returns the data directly to the caller. */
354 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
356 rvalue = (UINT64 *) *pgr;
357 greg = 1;
359 else
360 greg = 0;
362 freg = 0;
363 cif = closure->cif;
364 avn = cif->nargs;
366 /* Grab the addresses of the arguments from the stack frame. */
367 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
369 size_t z;
370 void *p;
372 z = (*p_arg)->size;
373 if (z < sizeof (UINT32))
375 p = pgr + greg++;
377 switch ((*p_arg)->type)
379 case FFI_TYPE_SINT8:
380 case FFI_TYPE_UINT8:
381 case FFI_TYPE_SINT16:
382 case FFI_TYPE_UINT16:
383 case FFI_TYPE_STRUCT:
384 #ifdef __LITTLE_ENDIAN__
385 avalue[i] = p;
386 #else
387 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
388 #endif
389 break;
391 default:
392 FFI_ASSERT(0);
395 else if (z == sizeof (UINT32))
397 if ((*p_arg)->type == FFI_TYPE_FLOAT)
399 if (freg < NFREGARG - 1)
401 if (fpair >= 0)
403 avalue[i] = (UINT32 *) pfr + fpair;
404 fpair = -1;
406 else
408 #ifdef __LITTLE_ENDIAN__
409 fpair = freg;
410 avalue[i] = (UINT32 *) pfr + (1 ^ freg);
411 #else
412 fpair = 1 ^ freg;
413 avalue[i] = (UINT32 *) pfr + freg;
414 #endif
415 freg += 2;
418 else
419 #ifdef __LITTLE_ENDIAN__
420 avalue[i] = pgr + greg;
421 #else
422 avalue[i] = (UINT32 *) (pgr + greg) + 1;
423 #endif
425 else
426 #ifdef __LITTLE_ENDIAN__
427 avalue[i] = pgr + greg;
428 #else
429 avalue[i] = (UINT32 *) (pgr + greg) + 1;
430 #endif
431 greg++;
433 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
435 if (freg + 1 >= NFREGARG)
436 avalue[i] = pgr + greg;
437 else
439 avalue[i] = pfr + (freg >> 1);
440 freg += 2;
442 greg++;
444 else
446 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
448 avalue[i] = pgr + greg;
449 greg += n;
453 (closure->fun) (cif, rvalue, avalue, closure->user_data);
455 /* Tell ffi_closure_SYSV how to perform return type promotions. */
456 return return_type (cif->rtype);