PR tree-optimization/84946
[official-gcc.git] / libffi / src / sparc / ffi64.c
blob340b19823211d973d9ecf5a76dc8d273e2f92cc5
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2011, 2013 Anthony Green
3 Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
5 SPARC Foreign Function Interface
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:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
28 #include <ffi.h>
29 #include <ffi_common.h>
30 #include <stdlib.h>
31 #include "internal.h"
33 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
34 all further uses in this file will refer to the 128-bit type. */
35 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
36 # if FFI_TYPE_LONGDOUBLE != 4
37 # error FFI_TYPE_LONGDOUBLE out of date
38 # endif
39 #else
40 # undef FFI_TYPE_LONGDOUBLE
41 # define FFI_TYPE_LONGDOUBLE 4
42 #endif
44 #ifdef SPARC64
46 /* Flatten the contents of a structure to the parts that are passed in
47 floating point registers. The return is a bit mask wherein bit N
48 set means bytes [4*n, 4*n+3] are passed in %fN.
50 We encode both the (running) size (maximum 32) and mask (maxumum 255)
51 into one integer. The size is placed in the low byte, so that align
52 and addition work correctly. The mask is placed in the second byte. */
54 static int
55 ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
57 ffi_type **elts;
58 ffi_type *t;
60 if (outer_type->type == FFI_TYPE_COMPLEX)
62 int m = 0, tt = outer_type->elements[0]->type;
63 size_t z = outer_type->size;
65 if (tt == FFI_TYPE_FLOAT
66 || tt == FFI_TYPE_DOUBLE
67 || tt == FFI_TYPE_LONGDOUBLE)
68 m = (1 << (z / 4)) - 1;
69 return (m << 8) | z;
71 FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
73 for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
75 size_t z = t->size;
76 int o, m, tt;
78 size_mask = ALIGN(size_mask, t->alignment);
79 switch (t->type)
81 case FFI_TYPE_STRUCT:
82 size_mask = ffi_struct_float_mask (t, size_mask);
83 continue;
84 case FFI_TYPE_COMPLEX:
85 tt = t->elements[0]->type;
86 if (tt != FFI_TYPE_FLOAT
87 && tt != FFI_TYPE_DOUBLE
88 && tt != FFI_TYPE_LONGDOUBLE)
89 break;
90 /* FALLTHRU */
91 case FFI_TYPE_FLOAT:
92 case FFI_TYPE_DOUBLE:
93 case FFI_TYPE_LONGDOUBLE:
94 m = (1 << (z / 4)) - 1; /* compute mask for type */
95 o = (size_mask >> 2) & 0x3f; /* extract word offset */
96 size_mask |= m << (o + 8); /* insert mask into place */
97 break;
99 size_mask += z;
102 size_mask = ALIGN(size_mask, outer_type->alignment);
103 FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
105 return size_mask;
108 /* Merge floating point data into integer data. If the structure is
109 entirely floating point, simply return a pointer to the fp data. */
111 static void *
112 ffi_struct_float_merge (int size_mask, void *vi, void *vf)
114 int size = size_mask & 0xff;
115 int mask = size_mask >> 8;
116 int n = size >> 2;
118 if (mask == 0)
119 return vi;
120 else if (mask == (1 << n) - 1)
121 return vf;
122 else
124 unsigned int *wi = vi, *wf = vf;
125 int i;
127 for (i = 0; i < n; ++i)
128 if ((mask >> i) & 1)
129 wi[i] = wf[i];
131 return vi;
135 /* Similar, but place the data into VD in the end. */
137 void FFI_HIDDEN
138 ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
140 int size = size_mask & 0xff;
141 int mask = size_mask >> 8;
142 int n = size >> 2;
144 if (mask == 0)
146 else if (mask == (1 << n) - 1)
147 vi = vf;
148 else
150 unsigned int *wd = vd, *wi = vi, *wf = vf;
151 int i;
153 for (i = 0; i < n; ++i)
154 wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
155 return;
157 memcpy (vd, vi, size);
160 /* Perform machine dependent cif processing */
162 static ffi_status
163 ffi_prep_cif_machdep_core(ffi_cif *cif)
165 ffi_type *rtype = cif->rtype;
166 int rtt = rtype->type;
167 size_t bytes = 0;
168 int i, n, flags;
170 /* Set the return type flag */
171 switch (rtt)
173 case FFI_TYPE_VOID:
174 flags = SPARC_RET_VOID;
175 break;
176 case FFI_TYPE_FLOAT:
177 flags = SPARC_RET_F_1;
178 break;
179 case FFI_TYPE_DOUBLE:
180 flags = SPARC_RET_F_2;
181 break;
182 case FFI_TYPE_LONGDOUBLE:
183 flags = SPARC_RET_F_4;
184 break;
186 case FFI_TYPE_COMPLEX:
187 case FFI_TYPE_STRUCT:
188 if (rtype->size > 32)
190 flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
191 bytes = 8;
193 else
195 int size_mask = ffi_struct_float_mask (rtype, 0);
196 int word_size = (size_mask >> 2) & 0x3f;
197 int all_mask = (1 << word_size) - 1;
198 int fp_mask = size_mask >> 8;
200 flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
202 /* For special cases of all-int or all-fp, we can return
203 the value directly without popping through a struct copy. */
204 if (fp_mask == 0)
206 if (rtype->alignment >= 8)
208 if (rtype->size == 8)
209 flags = SPARC_RET_INT64;
210 else if (rtype->size == 16)
211 flags = SPARC_RET_INT128;
214 else if (fp_mask == all_mask)
215 switch (word_size)
217 case 1: flags = SPARC_RET_F_1; break;
218 case 2: flags = SPARC_RET_F_2; break;
219 case 3: flags = SP_V9_RET_F_3; break;
220 case 4: flags = SPARC_RET_F_4; break;
221 /* 5 word structures skipped; handled via RET_STRUCT. */
222 case 6: flags = SPARC_RET_F_6; break;
223 /* 7 word structures skipped; handled via RET_STRUCT. */
224 case 8: flags = SPARC_RET_F_8; break;
227 break;
229 case FFI_TYPE_SINT8:
230 flags = SPARC_RET_SINT8;
231 break;
232 case FFI_TYPE_UINT8:
233 flags = SPARC_RET_UINT8;
234 break;
235 case FFI_TYPE_SINT16:
236 flags = SPARC_RET_SINT16;
237 break;
238 case FFI_TYPE_UINT16:
239 flags = SPARC_RET_UINT16;
240 break;
241 case FFI_TYPE_INT:
242 case FFI_TYPE_SINT32:
243 flags = SP_V9_RET_SINT32;
244 break;
245 case FFI_TYPE_UINT32:
246 flags = SPARC_RET_UINT32;
247 break;
248 case FFI_TYPE_SINT64:
249 case FFI_TYPE_UINT64:
250 case FFI_TYPE_POINTER:
251 flags = SPARC_RET_INT64;
252 break;
254 default:
255 abort();
258 bytes = 0;
259 for (i = 0, n = cif->nargs; i < n; ++i)
261 ffi_type *ty = cif->arg_types[i];
262 size_t z = ty->size;
263 size_t a = ty->alignment;
265 switch (ty->type)
267 case FFI_TYPE_COMPLEX:
268 case FFI_TYPE_STRUCT:
269 /* Large structs passed by reference. */
270 if (z > 16)
272 a = z = 8;
273 break;
275 /* Small structs may be passed in integer or fp regs or both. */
276 if (bytes >= 16*8)
277 break;
278 if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
279 break;
280 /* FALLTHRU */
281 case FFI_TYPE_FLOAT:
282 case FFI_TYPE_DOUBLE:
283 case FFI_TYPE_LONGDOUBLE:
284 flags |= SPARC_FLAG_FP_ARGS;
285 break;
287 bytes = ALIGN(bytes, a);
288 bytes += ALIGN(z, 8);
291 /* Sparc call frames require that space is allocated for 6 args,
292 even if they aren't used. Make that space if necessary. */
293 if (bytes < 6 * 8)
294 bytes = 6 * 8;
296 /* The stack must be 2 word aligned, so round bytes up appropriately. */
297 bytes = ALIGN(bytes, 16);
299 /* Include the call frame to prep_args. */
300 bytes += 8*16 + 8*8;
302 cif->bytes = bytes;
303 cif->flags = flags;
304 return FFI_OK;
307 ffi_status FFI_HIDDEN
308 ffi_prep_cif_machdep(ffi_cif *cif)
310 cif->nfixedargs = cif->nargs;
311 return ffi_prep_cif_machdep_core(cif);
314 ffi_status FFI_HIDDEN
315 ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
317 cif->nfixedargs = nfixedargs;
318 return ffi_prep_cif_machdep_core(cif);
321 extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
322 void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
324 /* ffi_prep_args is called by the assembly routine once stack space
325 has been allocated for the function's arguments */
327 int FFI_HIDDEN
328 ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
330 ffi_type **p_arg;
331 int flags = cif->flags;
332 int i, nargs;
334 if (rvalue == NULL)
336 if (flags & SPARC_FLAG_RET_IN_MEM)
338 /* Since we pass the pointer to the callee, we need a value.
339 We allowed for this space in ffi_call, before ffi_call_v8
340 alloca'd the space. */
341 rvalue = (char *)argp + cif->bytes;
343 else
345 /* Otherwise, we can ignore the return value. */
346 flags = SPARC_RET_VOID;
350 #ifdef USING_PURIFY
351 /* Purify will probably complain in our assembly routine,
352 unless we zero out this memory. */
353 memset(argp, 0, 6*8);
354 #endif
356 if (flags & SPARC_FLAG_RET_IN_MEM)
357 *argp++ = (unsigned long)rvalue;
359 p_arg = cif->arg_types;
360 for (i = 0, nargs = cif->nargs; i < nargs; i++)
362 ffi_type *ty = p_arg[i];
363 void *a = avalue[i];
364 size_t z;
366 switch (ty->type)
368 case FFI_TYPE_SINT8:
369 *argp++ = *(SINT8 *)a;
370 break;
371 case FFI_TYPE_UINT8:
372 *argp++ = *(UINT8 *)a;
373 break;
374 case FFI_TYPE_SINT16:
375 *argp++ = *(SINT16 *)a;
376 break;
377 case FFI_TYPE_UINT16:
378 *argp++ = *(UINT16 *)a;
379 break;
380 case FFI_TYPE_INT:
381 case FFI_TYPE_SINT32:
382 *argp++ = *(SINT32 *)a;
383 break;
384 case FFI_TYPE_UINT32:
385 case FFI_TYPE_FLOAT:
386 *argp++ = *(UINT32 *)a;
387 break;
388 case FFI_TYPE_SINT64:
389 case FFI_TYPE_UINT64:
390 case FFI_TYPE_POINTER:
391 case FFI_TYPE_DOUBLE:
392 *argp++ = *(UINT64 *)a;
393 break;
395 case FFI_TYPE_LONGDOUBLE:
396 case FFI_TYPE_COMPLEX:
397 case FFI_TYPE_STRUCT:
398 z = ty->size;
399 if (z > 16)
401 /* For structures larger than 16 bytes we pass reference. */
402 *argp++ = (unsigned long)a;
403 break;
405 if (((unsigned long)argp & 15) && ty->alignment > 8)
406 argp++;
407 memcpy(argp, a, z);
408 argp += ALIGN(z, 8) / 8;
409 break;
411 default:
412 abort();
416 return flags;
419 static void
420 ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
421 void **avalue, void *closure)
423 size_t bytes = cif->bytes;
425 FFI_ASSERT (cif->abi == FFI_V9);
427 if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
428 bytes += ALIGN (cif->rtype->size, 16);
430 ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
433 void
434 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
436 ffi_call_int(cif, fn, rvalue, avalue, NULL);
439 void
440 ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue,
441 void **avalue, void *closure)
443 ffi_call_int(cif, fn, rvalue, avalue, closure);
446 #ifdef __GNUC__
447 static inline void
448 ffi_flush_icache (void *p)
450 asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory");
452 #else
453 extern void ffi_flush_icache (void *) FFI_HIDDEN;
454 #endif
456 extern void ffi_closure_v9(void) FFI_HIDDEN;
457 extern void ffi_go_closure_v9(void) FFI_HIDDEN;
459 ffi_status
460 ffi_prep_closure_loc (ffi_closure* closure,
461 ffi_cif* cif,
462 void (*fun)(ffi_cif*, void*, void**, void*),
463 void *user_data,
464 void *codeloc)
466 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
467 unsigned long fn;
469 if (cif->abi != FFI_V9)
470 return FFI_BAD_ABI;
472 /* Trampoline address is equal to the closure address. We take advantage
473 of that to reduce the trampoline size by 8 bytes. */
474 fn = (unsigned long) ffi_closure_v9;
475 tramp[0] = 0x83414000; /* rd %pc, %g1 */
476 tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
477 tramp[2] = 0x81c14000; /* jmp %g5 */
478 tramp[3] = 0x01000000; /* nop */
479 *((unsigned long *) &tramp[4]) = fn;
481 closure->cif = cif;
482 closure->fun = fun;
483 closure->user_data = user_data;
485 ffi_flush_icache (closure);
487 return FFI_OK;
490 ffi_status
491 ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
492 void (*fun)(ffi_cif*, void*, void**, void*))
494 if (cif->abi != FFI_V9)
495 return FFI_BAD_ABI;
497 closure->tramp = ffi_go_closure_v9;
498 closure->cif = cif;
499 closure->fun = fun;
501 return FFI_OK;
504 int FFI_HIDDEN
505 ffi_closure_sparc_inner_v9(ffi_cif *cif,
506 void (*fun)(ffi_cif*, void*, void**, void*),
507 void *user_data, void *rvalue,
508 unsigned long *gpr, unsigned long *fpr)
510 ffi_type **arg_types;
511 void **avalue;
512 int i, argn, argx, nargs, flags, nfixedargs;
514 arg_types = cif->arg_types;
515 nargs = cif->nargs;
516 flags = cif->flags;
517 nfixedargs = cif->nfixedargs;
519 avalue = alloca(nargs * sizeof(void *));
521 /* Copy the caller's structure return address so that the closure
522 returns the data directly to the caller. */
523 if (flags & SPARC_FLAG_RET_IN_MEM)
525 rvalue = (void *) gpr[0];
526 /* Skip the structure return address. */
527 argn = 1;
529 else
530 argn = 0;
532 /* Grab the addresses of the arguments from the stack frame. */
533 for (i = 0; i < nargs; i++, argn = argx)
535 int named = i < nfixedargs;
536 ffi_type *ty = arg_types[i];
537 void *a = &gpr[argn];
538 size_t z;
540 argx = argn + 1;
541 switch (ty->type)
543 case FFI_TYPE_COMPLEX:
544 case FFI_TYPE_STRUCT:
545 z = ty->size;
546 if (z > 16)
547 a = *(void **)a;
548 else
550 argx = argn + ALIGN (z, 8) / 8;
551 if (named && argn < 16)
553 int size_mask = ffi_struct_float_mask (ty, 0);
554 int argn_mask = (0xffff00 >> argn) & 0xff00;
556 /* Eliminate fp registers off the end. */
557 size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
558 a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
561 break;
563 case FFI_TYPE_LONGDOUBLE:
564 argn = ALIGN (argn, 2);
565 a = (named && argn < 16 ? fpr : gpr) + argn;
566 argx = argn + 2;
567 break;
568 case FFI_TYPE_DOUBLE:
569 if (named && argn < 16)
570 a = fpr + argn;
571 break;
572 case FFI_TYPE_FLOAT:
573 if (named && argn < 16)
574 a = fpr + argn;
575 a += 4;
576 break;
578 case FFI_TYPE_UINT64:
579 case FFI_TYPE_SINT64:
580 case FFI_TYPE_POINTER:
581 break;
582 case FFI_TYPE_INT:
583 case FFI_TYPE_UINT32:
584 case FFI_TYPE_SINT32:
585 a += 4;
586 break;
587 case FFI_TYPE_UINT16:
588 case FFI_TYPE_SINT16:
589 a += 6;
590 break;
591 case FFI_TYPE_UINT8:
592 case FFI_TYPE_SINT8:
593 a += 7;
594 break;
596 default:
597 abort();
599 avalue[i] = a;
602 /* Invoke the closure. */
603 fun (cif, rvalue, avalue, user_data);
605 /* Tell ffi_closure_sparc how to perform return type promotions. */
606 return flags;
608 #endif /* SPARC64 */