Imported File#ftype spec from rubyspecs.
[rbx.git] / shotgun / external_libs / libffi / src / sh64 / ffi.c
blob72713537eca4cae6feae3a8aafbe56cc3bbdb29c
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004 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 /*@-exportheader@*/
59 void ffi_prep_args(char *stack, extended_cif *ecif)
60 /*@=exportheader@*/
62 register unsigned int i;
63 register unsigned int avn;
64 register void **p_argv;
65 register char *argp;
66 register ffi_type **p_arg;
68 argp = stack;
70 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
72 *(void **) argp = ecif->rvalue;
73 argp += sizeof (UINT64);
76 avn = ecif->cif->nargs;
77 p_argv = ecif->avalue;
79 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
81 size_t z;
82 int align;
84 z = (*p_arg)->size;
85 align = (*p_arg)->alignment;
86 if (z < sizeof (UINT32))
88 switch ((*p_arg)->type)
90 case FFI_TYPE_SINT8:
91 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
92 break;
94 case FFI_TYPE_UINT8:
95 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
96 break;
98 case FFI_TYPE_SINT16:
99 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
100 break;
102 case FFI_TYPE_UINT16:
103 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
104 break;
106 case FFI_TYPE_STRUCT:
107 memcpy (argp, *p_argv, z);
108 break;
110 default:
111 FFI_ASSERT(0);
113 argp += sizeof (UINT64);
115 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
117 switch ((*p_arg)->type)
119 case FFI_TYPE_INT:
120 case FFI_TYPE_SINT32:
121 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
122 break;
124 case FFI_TYPE_FLOAT:
125 case FFI_TYPE_POINTER:
126 case FFI_TYPE_UINT32:
127 case FFI_TYPE_STRUCT:
128 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
129 break;
131 default:
132 FFI_ASSERT(0);
133 break;
135 argp += sizeof (UINT64);
137 else if (z == sizeof (UINT64)
138 && align == sizeof (UINT64)
139 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
141 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
142 argp += sizeof (UINT64);
144 else
146 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
148 memcpy (argp, *p_argv, z);
149 argp += n * sizeof (UINT64);
153 return;
156 /* Perform machine dependent cif processing */
157 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
159 int i, j;
160 int size, type;
161 int n, m;
162 int greg;
163 int freg;
165 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
166 freg = 0;
167 cif->flags2 = 0;
169 for (i = j = 0; i < cif->nargs; i++)
171 type = (cif->arg_types)[i]->type;
172 switch (type)
174 case FFI_TYPE_FLOAT:
175 greg++;
176 cif->bytes += sizeof (UINT64) - sizeof (float);
177 if (freg >= NFREGARG - 1)
178 continue;
179 freg++;
180 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
181 break;
183 case FFI_TYPE_DOUBLE:
184 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
185 continue;
186 if ((freg + 1) < NFREGARG)
188 freg = (freg + 1) & ~1;
189 freg += 2;
190 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
192 else
193 cif->flags2 += FFI_TYPE_INT << (2 * j++);
194 break;
196 default:
197 size = (cif->arg_types)[i]->size;
198 if (size < sizeof (UINT64))
199 cif->bytes += sizeof (UINT64) - size;
200 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
201 if (greg >= NGREGARG)
202 continue;
203 else if (greg + n - 1 >= NGREGARG)
204 greg = NGREGARG;
205 else
206 greg += n;
207 for (m = 0; m < n; m++)
208 cif->flags2 += FFI_TYPE_INT << (2 * j++);
209 break;
213 /* Set the return type flag */
214 switch (cif->rtype->type)
216 case FFI_TYPE_STRUCT:
217 cif->flags = return_type (cif->rtype);
218 break;
220 case FFI_TYPE_VOID:
221 case FFI_TYPE_FLOAT:
222 case FFI_TYPE_DOUBLE:
223 case FFI_TYPE_SINT64:
224 case FFI_TYPE_UINT64:
225 cif->flags = cif->rtype->type;
226 break;
228 default:
229 cif->flags = FFI_TYPE_INT;
230 break;
233 return FFI_OK;
236 /*@-declundef@*/
237 /*@-exportheader@*/
238 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
239 /*@out@*/ extended_cif *,
240 unsigned, unsigned, long long,
241 /*@out@*/ unsigned *,
242 void (*fn)());
243 /*@=declundef@*/
244 /*@=exportheader@*/
246 void ffi_call(/*@dependent@*/ ffi_cif *cif,
247 void (*fn)(),
248 /*@out@*/ void *rvalue,
249 /*@dependent@*/ void **avalue)
251 extended_cif ecif;
252 UINT64 trvalue;
254 ecif.cif = cif;
255 ecif.avalue = avalue;
257 /* If the return value is a struct and we don't have a return */
258 /* value address then we need to make one */
260 if (cif->rtype->type == FFI_TYPE_STRUCT
261 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
262 ecif.rvalue = &trvalue;
263 else if ((rvalue == NULL) &&
264 (cif->rtype->type == FFI_TYPE_STRUCT))
266 /*@-sysunrecog@*/
267 ecif.rvalue = alloca(cif->rtype->size);
268 /*@=sysunrecog@*/
270 else
271 ecif.rvalue = rvalue;
273 switch (cif->abi)
275 case FFI_SYSV:
276 /*@-usedef@*/
277 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
278 cif->flags, cif->flags2, ecif.rvalue, fn);
279 /*@=usedef@*/
280 break;
281 default:
282 FFI_ASSERT(0);
283 break;
286 if (rvalue
287 && cif->rtype->type == FFI_TYPE_STRUCT
288 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
289 memcpy (rvalue, &trvalue, cif->rtype->size);
292 extern void ffi_closure_SYSV (void);
293 extern void __ic_invalidate (void *line);
295 ffi_status
296 ffi_prep_closure (ffi_closure *closure,
297 ffi_cif *cif,
298 void (*fun)(ffi_cif*, void*, void**, void*),
299 void *user_data)
301 unsigned int *tramp;
303 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
305 tramp = (unsigned int *) &closure->tramp[0];
306 /* Since ffi_closure is an aligned object, the ffi trampoline is
307 called as an SHcompact code. Sigh.
308 SHcompact part:
309 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
310 SHmedia part:
311 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
312 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
313 #ifdef __LITTLE_ENDIAN__
314 tramp[0] = 0x7001c701;
315 tramp[1] = 0x0009402b;
316 #else
317 tramp[0] = 0xc7017001;
318 tramp[1] = 0x402b0009;
319 #endif
320 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
321 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
322 tramp[4] = 0x6bf10600;
323 tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
324 tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
325 tramp[7] = 0x4401fff0;
327 closure->cif = cif;
328 closure->fun = fun;
329 closure->user_data = user_data;
331 /* Flush the icache. */
332 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
334 return FFI_OK;
337 /* Basically the trampoline invokes ffi_closure_SYSV, and on
338 * entry, r3 holds the address of the closure.
339 * After storing the registers that could possibly contain
340 * parameters to be passed into the stack frame and setting
341 * up space for a return value, ffi_closure_SYSV invokes the
342 * following helper function to do most of the work.
346 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
347 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
349 void **avalue;
350 ffi_type **p_arg;
351 int i, avn;
352 int greg, freg;
353 ffi_cif *cif;
355 cif = closure->cif;
356 avalue = alloca (cif->nargs * sizeof (void *));
358 /* Copy the caller's structure return value address so that the closure
359 returns the data directly to the caller. */
360 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
362 rvalue = *pgr;
363 greg = 1;
365 else
366 greg = 0;
368 freg = 0;
369 cif = closure->cif;
370 avn = cif->nargs;
372 /* Grab the addresses of the arguments from the stack frame. */
373 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
375 size_t z;
376 void *p;
378 z = (*p_arg)->size;
379 if (z < sizeof (UINT32))
381 p = pgr + greg++;
383 switch ((*p_arg)->type)
385 case FFI_TYPE_SINT8:
386 case FFI_TYPE_UINT8:
387 case FFI_TYPE_SINT16:
388 case FFI_TYPE_UINT16:
389 case FFI_TYPE_STRUCT:
390 #ifdef __LITTLE_ENDIAN__
391 avalue[i] = p;
392 #else
393 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
394 #endif
395 break;
397 default:
398 FFI_ASSERT(0);
401 else if (z == sizeof (UINT32))
403 if ((*p_arg)->type == FFI_TYPE_FLOAT)
405 if (freg < NFREGARG - 1)
406 #ifdef __LITTLE_ENDIAN__
407 avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
408 #else
409 avalue[i] = (UINT32 *) pfr + freg++;
410 #endif
411 else
412 #ifdef __LITTLE_ENDIAN__
413 avalue[i] = pgr + greg;
414 #else
415 avalue[i] = (UINT32 *) (pgr + greg) + 1;
416 #endif
418 else
419 #ifdef __LITTLE_ENDIAN__
420 avalue[i] = pgr + greg;
421 #else
422 avalue[i] = (UINT32 *) (pgr + greg) + 1;
423 #endif
424 greg++;
426 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
428 if (freg + 1 >= NFREGARG)
429 avalue[i] = pgr + greg;
430 else
432 freg = (freg + 1) & ~1;
433 avalue[i] = pfr + (freg >> 1);
434 freg += 2;
436 greg++;
438 else
440 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
442 avalue[i] = pgr + greg;
443 greg += n;
447 (closure->fun) (cif, rvalue, avalue, closure->user_data);
449 /* Tell ffi_closure_SYSV how to perform return type promotions. */
450 return return_type (cif->rtype);