2009-05-22 Dave Korn <dave.korn.cygwin@gmail.com>
[libffi.git] / libffi / src / sh64 / ffi.c
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004, 2006 Kaz Kojima
3 Copyright (c) 2008 Anthony Green
4
5 SuperH SHmedia Foreign Function Interface
6
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 ``Software''), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
27
28 #include <ffi.h>
29 #include <ffi_common.h>
30
31 #include <stdlib.h>
32
33 #define NGREGARG 8
34 #define NFREGARG 12
35
36 static int
37 return_type (ffi_type *arg)
38 {
39
40 if (arg->type != FFI_TYPE_STRUCT)
41 return arg->type;
42
43 /* gcc uses r2 if the result can be packed in on register. */
44 if (arg->size <= sizeof (UINT8))
45 return FFI_TYPE_UINT8;
46 else if (arg->size <= sizeof (UINT16))
47 return FFI_TYPE_UINT16;
48 else if (arg->size <= sizeof (UINT32))
49 return FFI_TYPE_UINT32;
50 else if (arg->size <= sizeof (UINT64))
51 return FFI_TYPE_UINT64;
52
53 return FFI_TYPE_STRUCT;
54 }
55
56 /* ffi_prep_args is called by the assembly routine once stack space
57 has been allocated for the function's arguments */
58
59 /*@-exportheader@*/
60 void ffi_prep_args(char *stack, extended_cif *ecif)
61 /*@=exportheader@*/
62 {
63 register unsigned int i;
64 register unsigned int avn;
65 register void **p_argv;
66 register char *argp;
67 register ffi_type **p_arg;
68
69 argp = stack;
70
71 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
72 {
73 *(void **) argp = ecif->rvalue;
74 argp += sizeof (UINT64);
75 }
76
77 avn = ecif->cif->nargs;
78 p_argv = ecif->avalue;
79
80 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
81 {
82 size_t z;
83 int align;
84
85 z = (*p_arg)->size;
86 align = (*p_arg)->alignment;
87 if (z < sizeof (UINT32))
88 {
89 switch ((*p_arg)->type)
90 {
91 case FFI_TYPE_SINT8:
92 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
93 break;
94
95 case FFI_TYPE_UINT8:
96 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
97 break;
98
99 case FFI_TYPE_SINT16:
100 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
101 break;
102
103 case FFI_TYPE_UINT16:
104 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
105 break;
106
107 case FFI_TYPE_STRUCT:
108 memcpy (argp, *p_argv, z);
109 break;
110
111 default:
112 FFI_ASSERT(0);
113 }
114 argp += sizeof (UINT64);
115 }
116 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
117 {
118 switch ((*p_arg)->type)
119 {
120 case FFI_TYPE_INT:
121 case FFI_TYPE_SINT32:
122 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
123 break;
124
125 case FFI_TYPE_FLOAT:
126 case FFI_TYPE_POINTER:
127 case FFI_TYPE_UINT32:
128 case FFI_TYPE_STRUCT:
129 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
130 break;
131
132 default:
133 FFI_ASSERT(0);
134 break;
135 }
136 argp += sizeof (UINT64);
137 }
138 else if (z == sizeof (UINT64)
139 && align == sizeof (UINT64)
140 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
141 {
142 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
143 argp += sizeof (UINT64);
144 }
145 else
146 {
147 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
148
149 memcpy (argp, *p_argv, z);
150 argp += n * sizeof (UINT64);
151 }
152 }
153
154 return;
155 }
156
157 /* Perform machine dependent cif processing */
158 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
159 {
160 int i, j;
161 int size, type;
162 int n, m;
163 int greg;
164 int freg;
165 int fpair = -1;
166
167 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
168 freg = 0;
169 cif->flags2 = 0;
170
171 for (i = j = 0; i < cif->nargs; i++)
172 {
173 type = (cif->arg_types)[i]->type;
174 switch (type)
175 {
176 case FFI_TYPE_FLOAT:
177 greg++;
178 cif->bytes += sizeof (UINT64) - sizeof (float);
179 if (freg >= NFREGARG - 1)
180 continue;
181 if (fpair < 0)
182 {
183 fpair = freg;
184 freg += 2;
185 }
186 else
187 fpair = -1;
188 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
189 break;
190
191 case FFI_TYPE_DOUBLE:
192 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
193 continue;
194 if ((freg + 1) < NFREGARG)
195 {
196 freg += 2;
197 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
198 }
199 else
200 cif->flags2 += FFI_TYPE_INT << (2 * j++);
201 break;
202
203 default:
204 size = (cif->arg_types)[i]->size;
205 if (size < sizeof (UINT64))
206 cif->bytes += sizeof (UINT64) - size;
207 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
208 if (greg >= NGREGARG)
209 continue;
210 else if (greg + n - 1 >= NGREGARG)
211 greg = NGREGARG;
212 else
213 greg += n;
214 for (m = 0; m < n; m++)
215 cif->flags2 += FFI_TYPE_INT << (2 * j++);
216 break;
217 }
218 }
219
220 /* Set the return type flag */
221 switch (cif->rtype->type)
222 {
223 case FFI_TYPE_STRUCT:
224 cif->flags = return_type (cif->rtype);
225 break;
226
227 case FFI_TYPE_VOID:
228 case FFI_TYPE_FLOAT:
229 case FFI_TYPE_DOUBLE:
230 case FFI_TYPE_SINT64:
231 case FFI_TYPE_UINT64:
232 cif->flags = cif->rtype->type;
233 break;
234
235 default:
236 cif->flags = FFI_TYPE_INT;
237 break;
238 }
239
240 return FFI_OK;
241 }
242
243 /*@-declundef@*/
244 /*@-exportheader@*/
245 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
246 /*@out@*/ extended_cif *,
247 unsigned, unsigned, long long,
248 /*@out@*/ unsigned *,
249 void (*fn)(void));
250 /*@=declundef@*/
251 /*@=exportheader@*/
252
253 void ffi_call(/*@dependent@*/ ffi_cif *cif,
254 void (*fn)(void),
255 /*@out@*/ void *rvalue,
256 /*@dependent@*/ void **avalue)
257 {
258 extended_cif ecif;
259 UINT64 trvalue;
260
261 ecif.cif = cif;
262 ecif.avalue = avalue;
263
264 /* If the return value is a struct and we don't have a return */
265 /* value address then we need to make one */
266
267 if (cif->rtype->type == FFI_TYPE_STRUCT
268 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
269 ecif.rvalue = &trvalue;
270 else if ((rvalue == NULL) &&
271 (cif->rtype->type == FFI_TYPE_STRUCT))
272 {
273 /*@-sysunrecog@*/
274 ecif.rvalue = alloca(cif->rtype->size);
275 /*@=sysunrecog@*/
276 }
277 else
278 ecif.rvalue = rvalue;
279
280 switch (cif->abi)
281 {
282 case FFI_SYSV:
283 /*@-usedef@*/
284 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
285 cif->flags, cif->flags2, ecif.rvalue, fn);
286 /*@=usedef@*/
287 break;
288 default:
289 FFI_ASSERT(0);
290 break;
291 }
292
293 if (rvalue
294 && cif->rtype->type == FFI_TYPE_STRUCT
295 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
296 memcpy (rvalue, &trvalue, cif->rtype->size);
297 }
298
299 extern void ffi_closure_SYSV (void);
300 extern void __ic_invalidate (void *line);
301
302 ffi_status
303 ffi_prep_closure (ffi_closure *closure,
304 ffi_cif *cif,
305 void (*fun)(ffi_cif*, void*, void**, void*),
306 void *user_data)
307 {
308 unsigned int *tramp;
309
310 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
311
312 tramp = (unsigned int *) &closure->tramp[0];
313 /* Since ffi_closure is an aligned object, the ffi trampoline is
314 called as an SHcompact code. Sigh.
315 SHcompact part:
316 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
317 SHmedia part:
318 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
319 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
320 #ifdef __LITTLE_ENDIAN__
321 tramp[0] = 0x7001c701;
322 tramp[1] = 0x0009402b;
323 #else
324 tramp[0] = 0xc7017001;
325 tramp[1] = 0x402b0009;
326 #endif
327 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
328 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
329 tramp[4] = 0x6bf10600;
330 tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
331 tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
332 tramp[7] = 0x4401fff0;
333
334 closure->cif = cif;
335 closure->fun = fun;
336 closure->user_data = user_data;
337
338 /* Flush the icache. */
339 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
340
341 return FFI_OK;
342 }
343
344 /* Basically the trampoline invokes ffi_closure_SYSV, and on
345 * entry, r3 holds the address of the closure.
346 * After storing the registers that could possibly contain
347 * parameters to be passed into the stack frame and setting
348 * up space for a return value, ffi_closure_SYSV invokes the
349 * following helper function to do most of the work.
350 */
351
352 int
353 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
354 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
355 {
356 void **avalue;
357 ffi_type **p_arg;
358 int i, avn;
359 int greg, freg;
360 ffi_cif *cif;
361 int fpair = -1;
362
363 cif = closure->cif;
364 avalue = alloca (cif->nargs * sizeof (void *));
365
366 /* Copy the caller's structure return value address so that the closure
367 returns the data directly to the caller. */
368 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
369 {
370 rvalue = (UINT64 *) *pgr;
371 greg = 1;
372 }
373 else
374 greg = 0;
375
376 freg = 0;
377 cif = closure->cif;
378 avn = cif->nargs;
379
380 /* Grab the addresses of the arguments from the stack frame. */
381 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
382 {
383 size_t z;
384 void *p;
385
386 z = (*p_arg)->size;
387 if (z < sizeof (UINT32))
388 {
389 p = pgr + greg++;
390
391 switch ((*p_arg)->type)
392 {
393 case FFI_TYPE_SINT8:
394 case FFI_TYPE_UINT8:
395 case FFI_TYPE_SINT16:
396 case FFI_TYPE_UINT16:
397 case FFI_TYPE_STRUCT:
398 #ifdef __LITTLE_ENDIAN__
399 avalue[i] = p;
400 #else
401 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
402 #endif
403 break;
404
405 default:
406 FFI_ASSERT(0);
407 }
408 }
409 else if (z == sizeof (UINT32))
410 {
411 if ((*p_arg)->type == FFI_TYPE_FLOAT)
412 {
413 if (freg < NFREGARG - 1)
414 {
415 if (fpair >= 0)
416 {
417 avalue[i] = (UINT32 *) pfr + fpair;
418 fpair = -1;
419 }
420 else
421 {
422 #ifdef __LITTLE_ENDIAN__
423 fpair = freg;
424 avalue[i] = (UINT32 *) pfr + (1 ^ freg);
425 #else
426 fpair = 1 ^ freg;
427 avalue[i] = (UINT32 *) pfr + freg;
428 #endif
429 freg += 2;
430 }
431 }
432 else
433 #ifdef __LITTLE_ENDIAN__
434 avalue[i] = pgr + greg;
435 #else
436 avalue[i] = (UINT32 *) (pgr + greg) + 1;
437 #endif
438 }
439 else
440 #ifdef __LITTLE_ENDIAN__
441 avalue[i] = pgr + greg;
442 #else
443 avalue[i] = (UINT32 *) (pgr + greg) + 1;
444 #endif
445 greg++;
446 }
447 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
448 {
449 if (freg + 1 >= NFREGARG)
450 avalue[i] = pgr + greg;
451 else
452 {
453 avalue[i] = pfr + (freg >> 1);
454 freg += 2;
455 }
456 greg++;
457 }
458 else
459 {
460 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
461
462 avalue[i] = pgr + greg;
463 greg += n;
464 }
465 }
466
467 (closure->fun) (cif, rvalue, avalue, closure->user_data);
468
469 /* Tell ffi_closure_SYSV how to perform return type promotions. */
470 return return_type (cif->rtype);
471 }
472