]> git.ipfire.org Git - thirdparty/gcc.git/blame - libffi/src/sparc/ffi.c
i386: Change Diamond Rapids feature detect when model number could not be distinguished
[thirdparty/gcc.git] / libffi / src / sparc / ffi.c
CommitLineData
63e5e3e0 1/* -----------------------------------------------------------------------
b1760f7f 2 ffi.c - Copyright (c) 2011, 2013 Anthony Green
34fa7690 3 Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
b1760f7f 4
0ce78f01 5 SPARC Foreign Function Interface
63e5e3e0 6
63e5e3e0
AG
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
5f933ef0
AH
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.
63e5e3e0
AG
26 ----------------------------------------------------------------------- */
27
28#include <ffi.h>
29#include <ffi_common.h>
63e5e3e0 30#include <stdlib.h>
b1760f7f 31#include "internal.h"
63e5e3e0 32
b1760f7f 33#ifndef SPARC64
c75c7793 34
b1760f7f
RH
35/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
36 all further uses in this file will refer to the 128-bit type. */
37#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
38# if FFI_TYPE_LONGDOUBLE != 4
39# error FFI_TYPE_LONGDOUBLE out of date
40# endif
41#else
42# undef FFI_TYPE_LONGDOUBLE
43# define FFI_TYPE_LONGDOUBLE 4
3791773c
JJ
44#endif
45
b1760f7f
RH
46/* Perform machine dependent cif processing */
47ffi_status FFI_HIDDEN
48ffi_prep_cif_machdep(ffi_cif *cif)
49{
50 ffi_type *rtype = cif->rtype;
51 int rtt = rtype->type;
52 size_t bytes;
53 int i, n, flags;
3791773c 54
b1760f7f
RH
55 /* Set the return type flag */
56 switch (rtt)
3791773c 57 {
b1760f7f
RH
58 case FFI_TYPE_VOID:
59 flags = SPARC_RET_VOID;
60 break;
61 case FFI_TYPE_FLOAT:
62 flags = SPARC_RET_F_1;
63 break;
64 case FFI_TYPE_DOUBLE:
65 flags = SPARC_RET_F_2;
66 break;
67 case FFI_TYPE_LONGDOUBLE:
68 case FFI_TYPE_STRUCT:
69 flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
70 flags |= SPARC_RET_STRUCT;
71 break;
72 case FFI_TYPE_SINT8:
73 flags = SPARC_RET_SINT8;
74 break;
75 case FFI_TYPE_UINT8:
76 flags = SPARC_RET_UINT8;
77 break;
78 case FFI_TYPE_SINT16:
79 flags = SPARC_RET_SINT16;
80 break;
81 case FFI_TYPE_UINT16:
82 flags = SPARC_RET_UINT16;
83 break;
84 case FFI_TYPE_INT:
85 case FFI_TYPE_SINT32:
86 case FFI_TYPE_UINT32:
87 case FFI_TYPE_POINTER:
88 flags = SPARC_RET_UINT32;
89 break;
90 case FFI_TYPE_SINT64:
91 case FFI_TYPE_UINT64:
92 flags = SPARC_RET_INT64;
93 break;
94 case FFI_TYPE_COMPLEX:
95 rtt = rtype->elements[0]->type;
96 switch (rtt)
97 {
98 case FFI_TYPE_FLOAT:
99 flags = SPARC_RET_F_2;
100 break;
101 case FFI_TYPE_DOUBLE:
102 flags = SPARC_RET_F_4;
103 break;
104 case FFI_TYPE_LONGDOUBLE:
105 flags = SPARC_RET_F_8;
106 break;
107 case FFI_TYPE_SINT64:
108 case FFI_TYPE_UINT64:
109 flags = SPARC_RET_INT128;
110 break;
111 case FFI_TYPE_INT:
112 case FFI_TYPE_SINT32:
113 case FFI_TYPE_UINT32:
114 flags = SPARC_RET_INT64;
115 break;
116 case FFI_TYPE_SINT16:
117 case FFI_TYPE_UINT16:
118 flags = SP_V8_RET_CPLX16;
119 break;
120 case FFI_TYPE_SINT8:
121 case FFI_TYPE_UINT8:
122 flags = SP_V8_RET_CPLX8;
123 break;
124 default:
125 abort();
126 }
127 break;
128 default:
129 abort();
3791773c 130 }
b1760f7f 131 cif->flags = flags;
3791773c 132
b1760f7f
RH
133 bytes = 0;
134 for (i = 0, n = cif->nargs; i < n; ++i)
3791773c 135 {
b1760f7f
RH
136 ffi_type *ty = cif->arg_types[i];
137 size_t z = ty->size;
138 int tt = ty->type;
3791773c 139
b1760f7f 140 switch (tt)
3791773c
JJ
141 {
142 case FFI_TYPE_STRUCT:
3791773c 143 case FFI_TYPE_LONGDOUBLE:
b1760f7f
RH
144 by_reference:
145 /* Passed by reference. */
146 z = 4;
3791773c 147 break;
b1760f7f
RH
148
149 case FFI_TYPE_COMPLEX:
150 tt = ty->elements[0]->type;
151 if (tt == FFI_TYPE_FLOAT || z > 8)
152 goto by_reference;
153 /* FALLTHRU */
154
155 default:
92456a4e 156 z = FFI_ALIGN(z, 4);
3791773c 157 }
b1760f7f
RH
158 bytes += z;
159 }
3791773c 160
b1760f7f
RH
161 /* Sparc call frames require that space is allocated for 6 args,
162 even if they aren't used. Make that space if necessary. */
163 if (bytes < 6 * 4)
164 bytes = 6 * 4;
3791773c 165
b1760f7f
RH
166 /* The ABI always requires space for the struct return pointer. */
167 bytes += 4;
3791773c 168
b1760f7f 169 /* The stack must be 2 word aligned, so round bytes up appropriately. */
92456a4e 170 bytes = FFI_ALIGN(bytes, 2 * 4);
3791773c 171
b1760f7f
RH
172 /* Include the call frame to prep_args. */
173 bytes += 4*16 + 4*8;
174 cif->bytes = bytes;
3791773c 175
b1760f7f
RH
176 return FFI_OK;
177}
3791773c 178
b1760f7f
RH
179extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
180 void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
3791773c 181
b1760f7f
RH
182int FFI_HIDDEN
183ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
184{
185 ffi_type **p_arg;
186 int flags = cif->flags;
187 int i, nargs;
3791773c 188
b1760f7f
RH
189 if (rvalue == NULL)
190 {
191 if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
3791773c 192 {
b1760f7f
RH
193 /* Since we pass the pointer to the callee, we need a value.
194 We allowed for this space in ffi_call, before ffi_call_v8
195 alloca'd the space. */
196 rvalue = (char *)argp + cif->bytes;
3791773c
JJ
197 }
198 else
199 {
b1760f7f
RH
200 /* Otherwise, we can ignore the return value. */
201 flags = SPARC_RET_VOID;
3791773c 202 }
3791773c
JJ
203 }
204
b1760f7f
RH
205 /* This could only really be done when we are returning a structure.
206 However, the space is reserved so we can do it unconditionally. */
207 *argp++ = (unsigned long)rvalue;
248d745a
EB
208
209#ifdef USING_PURIFY
b1760f7f
RH
210 /* Purify will probably complain in our assembly routine,
211 unless we zero out this memory. */
212 memset(argp, 0, 6*4);
248d745a
EB
213#endif
214
b1760f7f
RH
215 p_arg = cif->arg_types;
216 for (i = 0, nargs = cif->nargs; i < nargs; i++)
248d745a 217 {
b1760f7f
RH
218 ffi_type *ty = p_arg[i];
219 void *a = avalue[i];
220 int tt = ty->type;
248d745a
EB
221 size_t z;
222
b1760f7f
RH
223 switch (tt)
224 {
225 case FFI_TYPE_STRUCT:
226 case FFI_TYPE_LONGDOUBLE:
227 by_reference:
228 *argp++ = (unsigned long)a;
229 break;
230
231 case FFI_TYPE_DOUBLE:
232 case FFI_TYPE_UINT64:
233 case FFI_TYPE_SINT64:
234 memcpy(argp, a, 8);
235 argp += 2;
236 break;
237
238 case FFI_TYPE_INT:
239 case FFI_TYPE_FLOAT:
240 case FFI_TYPE_UINT32:
241 case FFI_TYPE_SINT32:
242 case FFI_TYPE_POINTER:
243 *argp++ = *(unsigned *)a;
244 break;
245
246 case FFI_TYPE_UINT8:
247 *argp++ = *(UINT8 *)a;
248 break;
249 case FFI_TYPE_SINT8:
250 *argp++ = *(SINT8 *)a;
251 break;
252 case FFI_TYPE_UINT16:
253 *argp++ = *(UINT16 *)a;
254 break;
255 case FFI_TYPE_SINT16:
256 *argp++ = *(SINT16 *)a;
257 break;
258
259 case FFI_TYPE_COMPLEX:
260 tt = ty->elements[0]->type;
261 z = ty->size;
262 if (tt == FFI_TYPE_FLOAT || z > 8)
263 goto by_reference;
264 if (z < 4)
248d745a 265 {
b1760f7f
RH
266 memcpy((char *)argp + 4 - z, a, z);
267 argp++;
248d745a
EB
268 }
269 else
270 {
b1760f7f
RH
271 memcpy(argp, a, z);
272 argp += z / 4;
248d745a 273 }
b1760f7f 274 break;
3791773c 275
b1760f7f
RH
276 default:
277 abort();
278 }
3791773c 279 }
63e5e3e0 280
b1760f7f
RH
281 return flags;
282}
63e5e3e0 283
b1760f7f
RH
284static void
285ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
286 void **avalue, void *closure)
287{
288 size_t bytes = cif->bytes;
61aa380b
RO
289 size_t i, nargs = cif->nargs;
290 ffi_type **arg_types = cif->arg_types;
63e5e3e0 291
b1760f7f 292 FFI_ASSERT (cif->abi == FFI_V8);
63e5e3e0 293
b1760f7f
RH
294 /* If we've not got a return value, we need to create one if we've
295 got to pass the return value to the callee. Otherwise ignore it. */
296 if (rvalue == NULL
297 && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
92456a4e 298 bytes += FFI_ALIGN (cif->rtype->size, 8);
da17a98b 299
61aa380b
RO
300 /* If we have any structure arguments, make a copy so we are passing
301 by value. */
302 for (i = 0; i < nargs; i++)
303 {
304 ffi_type *at = arg_types[i];
305 int size = at->size;
306 if (at->type == FFI_TYPE_STRUCT)
307 {
308 char *argcopy = alloca (size);
309 memcpy (argcopy, avalue[i], size);
310 avalue[i] = argcopy;
311 }
312 }
313
b1760f7f 314 ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
63e5e3e0
AG
315}
316
b1760f7f
RH
317void
318ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
30255340 319{
b1760f7f 320 ffi_call_int (cif, fn, rvalue, avalue, NULL);
30255340
EB
321}
322
b1760f7f
RH
323void
324ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
325 void **avalue, void *closure)
30255340 326{
b1760f7f 327 ffi_call_int (cif, fn, rvalue, avalue, closure);
30255340
EB
328}
329
b1760f7f
RH
330#ifdef __GNUC__
331static inline void
332ffi_flush_icache (void *p)
3791773c 333{
b1760f7f
RH
334 /* SPARC v8 requires 5 instructions for flush to be visible */
335 asm volatile ("iflush %0; iflush %0+8; nop; nop; nop; nop; nop"
336 : : "r" (p) : "memory");
3791773c 337}
3791773c 338#else
b1760f7f 339extern void ffi_flush_icache (void *) FFI_HIDDEN;
34fa7690 340#endif
c75c7793 341
b1760f7f
RH
342extern void ffi_closure_v8(void) FFI_HIDDEN;
343extern void ffi_go_closure_v8(void) FFI_HIDDEN;
0ce78f01 344
c75c7793 345ffi_status
b1760f7f
RH
346ffi_prep_closure_loc (ffi_closure *closure,
347 ffi_cif *cif,
18fa3240
AO
348 void (*fun)(ffi_cif*, void*, void**, void*),
349 void *user_data,
350 void *codeloc)
c75c7793
JS
351{
352 unsigned int *tramp = (unsigned int *) &closure->tramp[0];
b1760f7f
RH
353 unsigned long ctx = (unsigned long) closure;
354 unsigned long fn = (unsigned long) ffi_closure_v8;
355
356 if (cif->abi != FFI_V8)
34fa7690 357 return FFI_BAD_ABI;
b1760f7f 358
c75c7793
JS
359 tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */
360 tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */
361 tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */
362 tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */
c75c7793
JS
363
364 closure->cif = cif;
365 closure->fun = fun;
366 closure->user_data = user_data;
367
b1760f7f 368 ffi_flush_icache (closure);
c75c7793
JS
369
370 return FFI_OK;
371}
372
b1760f7f
RH
373ffi_status
374ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
375 void (*fun)(ffi_cif*, void*, void**, void*))
376{
377 if (cif->abi != FFI_V8)
378 return FFI_BAD_ABI;
0ce78f01 379
b1760f7f
RH
380 closure->tramp = ffi_go_closure_v8;
381 closure->cif = cif;
382 closure->fun = fun;
383
384 return FFI_OK;
385}
386
387int FFI_HIDDEN
388ffi_closure_sparc_inner_v8(ffi_cif *cif,
389 void (*fun)(ffi_cif*, void*, void**, void*),
390 void *user_data, void *rvalue,
391 unsigned long *argp)
0ce78f01 392{
0ce78f01
EB
393 ffi_type **arg_types;
394 void **avalue;
b1760f7f 395 int i, nargs, flags;
0ce78f01 396
0ce78f01 397 arg_types = cif->arg_types;
b1760f7f
RH
398 nargs = cif->nargs;
399 flags = cif->flags;
400 avalue = alloca(nargs * sizeof(void *));
0ce78f01
EB
401
402 /* Copy the caller's structure return address so that the closure
b1760f7f
RH
403 returns the data directly to the caller. Also install it so we
404 can return the address in %o0. */
405 if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
c75c7793 406 {
b1760f7f
RH
407 void *new_rvalue = (void *)*argp;
408 *(void **)rvalue = new_rvalue;
409 rvalue = new_rvalue;
c75c7793 410 }
0ce78f01 411
b1760f7f
RH
412 /* Always skip the structure return address. */
413 argp++;
c75c7793 414
c75c7793 415 /* Grab the addresses of the arguments from the stack frame. */
b1760f7f 416 for (i = 0; i < nargs; i++)
c75c7793 417 {
b1760f7f
RH
418 ffi_type *ty = arg_types[i];
419 int tt = ty->type;
420 void *a = argp;
421 size_t z;
30255340 422
b1760f7f 423 switch (tt)
0ce78f01 424 {
b1760f7f
RH
425 case FFI_TYPE_STRUCT:
426 case FFI_TYPE_LONGDOUBLE:
427 by_reference:
428 /* Straight copy of invisible reference. */
429 a = (void *)*argp;
430 break;
431
432 case FFI_TYPE_DOUBLE:
433 case FFI_TYPE_SINT64:
434 case FFI_TYPE_UINT64:
435 if ((unsigned long)a & 7)
0ce78f01 436 {
b1760f7f
RH
437 /* Align on a 8-byte boundary. */
438 UINT64 *tmp = alloca(8);
439 *tmp = ((UINT64)argp[0] << 32) | argp[1];
440 a = tmp;
0ce78f01 441 }
b1760f7f
RH
442 argp++;
443 break;
248d745a 444
b1760f7f
RH
445 case FFI_TYPE_INT:
446 case FFI_TYPE_FLOAT:
447 case FFI_TYPE_UINT32:
448 case FFI_TYPE_SINT32:
449 case FFI_TYPE_POINTER:
450 break;
451 case FFI_TYPE_UINT16:
452 case FFI_TYPE_SINT16:
453 a += 2;
454 break;
455 case FFI_TYPE_UINT8:
456 case FFI_TYPE_SINT8:
457 a += 3;
458 break;
248d745a 459
b1760f7f
RH
460 case FFI_TYPE_COMPLEX:
461 tt = ty->elements[0]->type;
462 z = ty->size;
463 if (tt == FFI_TYPE_FLOAT || z > 8)
464 goto by_reference;
465 if (z < 4)
466 a += 4 - z;
467 else if (z > 4)
468 argp++;
469 break;
248d745a 470
b1760f7f
RH
471 default:
472 abort();
248d745a 473 }
b1760f7f
RH
474 argp++;
475 avalue[i] = a;
248d745a
EB
476 }
477
478 /* Invoke the closure. */
b1760f7f 479 fun (cif, rvalue, avalue, user_data);
248d745a
EB
480
481 /* Tell ffi_closure_sparc how to perform return type promotions. */
b1760f7f 482 return flags;
248d745a 483}
b1760f7f 484#endif /* !SPARC64 */