* configure.ac: Bump version to 2.99.7.
[libffi.git] / libffi / src / sh64 / ffi.c
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004 Kaz Kojima
3
4 SuperH SHmedia Foreign Function Interface
5
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:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
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 ----------------------------------------------------------------------- */
26
27 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31
32 #define NGREGARG 8
33 #define NFREGARG 12
34
35 static int
36 return_type (ffi_type *arg)
37 {
38
39 if (arg->type != FFI_TYPE_STRUCT)
40 return arg->type;
41
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;
51
52 return FFI_TYPE_STRUCT;
53 }
54
55 /* ffi_prep_args is called by the assembly routine once stack space
56 has been allocated for the function's arguments */
57
58 /*@-exportheader@*/
59 void ffi_prep_args(char *stack, extended_cif *ecif)
60 /*@=exportheader@*/
61 {
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;
67
68 argp = stack;
69
70 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
71 {
72 *(void **) argp = ecif->rvalue;
73 argp += sizeof (UINT64);
74 }
75
76 avn = ecif->cif->nargs;
77 p_argv = ecif->avalue;
78
79 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
80 {
81 size_t z;
82 int align;
83
84 z = (*p_arg)->size;
85 align = (*p_arg)->alignment;
86 if (z < sizeof (UINT32))
87 {
88 switch ((*p_arg)->type)
89 {
90 case FFI_TYPE_SINT8:
91 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
92 break;
93
94 case FFI_TYPE_UINT8:
95 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
96 break;
97
98 case FFI_TYPE_SINT16:
99 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
100 break;
101
102 case FFI_TYPE_UINT16:
103 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
104 break;
105
106 case FFI_TYPE_STRUCT:
107 memcpy (argp, *p_argv, z);
108 break;
109
110 default:
111 FFI_ASSERT(0);
112 }
113 argp += sizeof (UINT64);
114 }
115 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
116 {
117 switch ((*p_arg)->type)
118 {
119 case FFI_TYPE_INT:
120 case FFI_TYPE_SINT32:
121 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
122 break;
123
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;
130
131 default:
132 FFI_ASSERT(0);
133 break;
134 }
135 argp += sizeof (UINT64);
136 }
137 else if (z == sizeof (UINT64)
138 && align == sizeof (UINT64)
139 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
140 {
141 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
142 argp += sizeof (UINT64);
143 }
144 else
145 {
146 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
147
148 memcpy (argp, *p_argv, z);
149 argp += n * sizeof (UINT64);
150 }
151 }
152
153 return;
154 }
155
156 /* Perform machine dependent cif processing */
157 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
158 {
159 int i, j;
160 int size, type;
161 int n, m;
162 int greg;
163 int freg;
164
165 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
166 freg = 0;
167 cif->flags2 = 0;
168
169 for (i = j = 0; i < cif->nargs; i++)
170 {
171 type = (cif->arg_types)[i]->type;
172 switch (type)
173 {
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;
182
183 case FFI_TYPE_DOUBLE:
184 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
185 continue;
186 if ((freg + 1) < NFREGARG)
187 {
188 freg = (freg + 1) & ~1;
189 freg += 2;
190 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
191 }
192 else
193 cif->flags2 += FFI_TYPE_INT << (2 * j++);
194 break;
195
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;
210 }
211 }
212
213 /* Set the return type flag */
214 switch (cif->rtype->type)
215 {
216 case FFI_TYPE_STRUCT:
217 cif->flags = return_type (cif->rtype);
218 break;
219
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;
227
228 default:
229 cif->flags = FFI_TYPE_INT;
230 break;
231 }
232
233 return FFI_OK;
234 }
235
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@*/
245
246 void ffi_call(/*@dependent@*/ ffi_cif *cif,
247 void (*fn)(),
248 /*@out@*/ void *rvalue,
249 /*@dependent@*/ void **avalue)
250 {
251 extended_cif ecif;
252 UINT64 trvalue;
253
254 ecif.cif = cif;
255 ecif.avalue = avalue;
256
257 /* If the return value is a struct and we don't have a return */
258 /* value address then we need to make one */
259
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))
265 {
266 /*@-sysunrecog@*/
267 ecif.rvalue = alloca(cif->rtype->size);
268 /*@=sysunrecog@*/
269 }
270 else
271 ecif.rvalue = rvalue;
272
273 switch (cif->abi)
274 {
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;
284 }
285
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);
290 }
291
292 extern void ffi_closure_SYSV (void);
293 extern void __ic_invalidate (void *line);
294
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)
300 {
301 unsigned int *tramp;
302
303 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
304
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;
326
327 closure->cif = cif;
328 closure->fun = fun;
329 closure->user_data = user_data;
330
331 /* Flush the icache. */
332 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
333
334 return FFI_OK;
335 }
336
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.
343 */
344
345 int
346 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
347 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
348 {
349 void **avalue;
350 ffi_type **p_arg;
351 int i, avn;
352 int greg, freg;
353 ffi_cif *cif;
354
355 cif = closure->cif;
356 avalue = alloca (cif->nargs * sizeof (void *));
357
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)
361 {
362 rvalue = *pgr;
363 greg = 1;
364 }
365 else
366 greg = 0;
367
368 freg = 0;
369 cif = closure->cif;
370 avn = cif->nargs;
371
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++)
374 {
375 size_t z;
376 void *p;
377
378 z = (*p_arg)->size;
379 if (z < sizeof (UINT32))
380 {
381 p = pgr + greg++;
382
383 switch ((*p_arg)->type)
384 {
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;
396
397 default:
398 FFI_ASSERT(0);
399 }
400 }
401 else if (z == sizeof (UINT32))
402 {
403 if ((*p_arg)->type == FFI_TYPE_FLOAT)
404 {
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
417 }
418 else
419 #ifdef __LITTLE_ENDIAN__
420 avalue[i] = pgr + greg;
421 #else
422 avalue[i] = (UINT32 *) (pgr + greg) + 1;
423 #endif
424 greg++;
425 }
426 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
427 {
428 if (freg + 1 >= NFREGARG)
429 avalue[i] = pgr + greg;
430 else
431 {
432 freg = (freg + 1) & ~1;
433 avalue[i] = pfr + (freg >> 1);
434 freg += 2;
435 }
436 greg++;
437 }
438 else
439 {
440 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
441
442 avalue[i] = pgr + greg;
443 greg += n;
444 }
445 }
446
447 (closure->fun) (cif, rvalue, avalue, closure->user_data);
448
449 /* Tell ffi_closure_SYSV how to perform return type promotions. */
450 return return_type (cif->rtype);
451 }
452