b17cf2c67446ce786f8f7cae024689c320ec1174
[libffi.git] / libffi / src / sh64 / ffi.c
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004 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
166 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
167 freg = 0;
168 cif->flags2 = 0;
169
170 for (i = j = 0; i < cif->nargs; i++)
171 {
172 type = (cif->arg_types)[i]->type;
173 switch (type)
174 {
175 case FFI_TYPE_FLOAT:
176 greg++;
177 cif->bytes += sizeof (UINT64) - sizeof (float);
178 if (freg >= NFREGARG - 1)
179 continue;
180 freg++;
181 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
182 break;
183
184 case FFI_TYPE_DOUBLE:
185 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
186 continue;
187 if ((freg + 1) < NFREGARG)
188 {
189 freg = (freg + 1) & ~1;
190 freg += 2;
191 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
192 }
193 else
194 cif->flags2 += FFI_TYPE_INT << (2 * j++);
195 break;
196
197 default:
198 size = (cif->arg_types)[i]->size;
199 if (size < sizeof (UINT64))
200 cif->bytes += sizeof (UINT64) - size;
201 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
202 if (greg >= NGREGARG)
203 continue;
204 else if (greg + n - 1 >= NGREGARG)
205 greg = NGREGARG;
206 else
207 greg += n;
208 for (m = 0; m < n; m++)
209 cif->flags2 += FFI_TYPE_INT << (2 * j++);
210 break;
211 }
212 }
213
214 /* Set the return type flag */
215 switch (cif->rtype->type)
216 {
217 case FFI_TYPE_STRUCT:
218 cif->flags = return_type (cif->rtype);
219 break;
220
221 case FFI_TYPE_VOID:
222 case FFI_TYPE_FLOAT:
223 case FFI_TYPE_DOUBLE:
224 case FFI_TYPE_SINT64:
225 case FFI_TYPE_UINT64:
226 cif->flags = cif->rtype->type;
227 break;
228
229 default:
230 cif->flags = FFI_TYPE_INT;
231 break;
232 }
233
234 return FFI_OK;
235 }
236
237 /*@-declundef@*/
238 /*@-exportheader@*/
239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
240 /*@out@*/ extended_cif *,
241 unsigned, unsigned, long long,
242 /*@out@*/ unsigned *,
243 void (*fn)(void));
244 /*@=declundef@*/
245 /*@=exportheader@*/
246
247 void ffi_call(/*@dependent@*/ ffi_cif *cif,
248 void (*fn)(void),
249 /*@out@*/ void *rvalue,
250 /*@dependent@*/ void **avalue)
251 {
252 extended_cif ecif;
253 UINT64 trvalue;
254
255 ecif.cif = cif;
256 ecif.avalue = avalue;
257
258 /* If the return value is a struct and we don't have a return */
259 /* value address then we need to make one */
260
261 if (cif->rtype->type == FFI_TYPE_STRUCT
262 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
263 ecif.rvalue = &trvalue;
264 else if ((rvalue == NULL) &&
265 (cif->rtype->type == FFI_TYPE_STRUCT))
266 {
267 /*@-sysunrecog@*/
268 ecif.rvalue = alloca(cif->rtype->size);
269 /*@=sysunrecog@*/
270 }
271 else
272 ecif.rvalue = rvalue;
273
274 switch (cif->abi)
275 {
276 case FFI_SYSV:
277 /*@-usedef@*/
278 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
279 cif->flags, cif->flags2, ecif.rvalue, fn);
280 /*@=usedef@*/
281 break;
282 default:
283 FFI_ASSERT(0);
284 break;
285 }
286
287 if (rvalue
288 && cif->rtype->type == FFI_TYPE_STRUCT
289 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290 memcpy (rvalue, &trvalue, cif->rtype->size);
291 }
292
293 extern void ffi_closure_SYSV (void);
294 extern void __ic_invalidate (void *line);
295
296 ffi_status
297 ffi_prep_closure (ffi_closure *closure,
298 ffi_cif *cif,
299 void (*fun)(ffi_cif*, void*, void**, void*),
300 void *user_data)
301 {
302 unsigned int *tramp;
303
304 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
305
306 tramp = (unsigned int *) &closure->tramp[0];
307 /* Since ffi_closure is an aligned object, the ffi trampoline is
308 called as an SHcompact code. Sigh.
309 SHcompact part:
310 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
311 SHmedia part:
312 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
313 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
314 #ifdef __LITTLE_ENDIAN__
315 tramp[0] = 0x7001c701;
316 tramp[1] = 0x0009402b;
317 #else
318 tramp[0] = 0xc7017001;
319 tramp[1] = 0x402b0009;
320 #endif
321 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
322 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
323 tramp[4] = 0x6bf10600;
324 tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
325 tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
326 tramp[7] = 0x4401fff0;
327
328 closure->cif = cif;
329 closure->fun = fun;
330 closure->user_data = user_data;
331
332 /* Flush the icache. */
333 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
334
335 return FFI_OK;
336 }
337
338 /* Basically the trampoline invokes ffi_closure_SYSV, and on
339 * entry, r3 holds the address of the closure.
340 * After storing the registers that could possibly contain
341 * parameters to be passed into the stack frame and setting
342 * up space for a return value, ffi_closure_SYSV invokes the
343 * following helper function to do most of the work.
344 */
345
346 int
347 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
348 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
349 {
350 void **avalue;
351 ffi_type **p_arg;
352 int i, avn;
353 int greg, freg;
354 ffi_cif *cif;
355
356 cif = closure->cif;
357 avalue = alloca (cif->nargs * sizeof (void *));
358
359 /* Copy the caller's structure return value address so that the closure
360 returns the data directly to the caller. */
361 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
362 {
363 rvalue = *pgr;
364 greg = 1;
365 }
366 else
367 greg = 0;
368
369 freg = 0;
370 cif = closure->cif;
371 avn = cif->nargs;
372
373 /* Grab the addresses of the arguments from the stack frame. */
374 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
375 {
376 size_t z;
377 void *p;
378
379 z = (*p_arg)->size;
380 if (z < sizeof (UINT32))
381 {
382 p = pgr + greg++;
383
384 switch ((*p_arg)->type)
385 {
386 case FFI_TYPE_SINT8:
387 case FFI_TYPE_UINT8:
388 case FFI_TYPE_SINT16:
389 case FFI_TYPE_UINT16:
390 case FFI_TYPE_STRUCT:
391 #ifdef __LITTLE_ENDIAN__
392 avalue[i] = p;
393 #else
394 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
395 #endif
396 break;
397
398 default:
399 FFI_ASSERT(0);
400 }
401 }
402 else if (z == sizeof (UINT32))
403 {
404 if ((*p_arg)->type == FFI_TYPE_FLOAT)
405 {
406 if (freg < NFREGARG - 1)
407 #ifdef __LITTLE_ENDIAN__
408 avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
409 #else
410 avalue[i] = (UINT32 *) pfr + freg++;
411 #endif
412 else
413 #ifdef __LITTLE_ENDIAN__
414 avalue[i] = pgr + greg;
415 #else
416 avalue[i] = (UINT32 *) (pgr + greg) + 1;
417 #endif
418 }
419 else
420 #ifdef __LITTLE_ENDIAN__
421 avalue[i] = pgr + greg;
422 #else
423 avalue[i] = (UINT32 *) (pgr + greg) + 1;
424 #endif
425 greg++;
426 }
427 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
428 {
429 if (freg + 1 >= NFREGARG)
430 avalue[i] = pgr + greg;
431 else
432 {
433 freg = (freg + 1) & ~1;
434 avalue[i] = pfr + (freg >> 1);
435 freg += 2;
436 }
437 greg++;
438 }
439 else
440 {
441 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
442
443 avalue[i] = pgr + greg;
444 greg += n;
445 }
446 }
447
448 (closure->fun) (cif, rvalue, avalue, closure->user_data);
449
450 /* Tell ffi_closure_SYSV how to perform return type promotions. */
451 return return_type (cif->rtype);
452 }
453