]>
git.ipfire.org Git - thirdparty/gcc.git/blob - libffi/src/sparc/ffi.c
cf819ee673889d9e0eac99cbe8fd90399ad897b6
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 ----------------------------------------------------------------------- */
29 #include <ffi_common.h>
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
42 # undef FFI_TYPE_LONGDOUBLE
43 # define FFI_TYPE_LONGDOUBLE 4
46 /* Perform machine dependent cif processing */
48 ffi_prep_cif_machdep(ffi_cif
*cif
)
50 ffi_type
*rtype
= cif
->rtype
;
51 int rtt
= rtype
->type
;
55 /* Set the return type flag */
59 flags
= SPARC_RET_VOID
;
62 flags
= SPARC_RET_F_1
;
65 flags
= SPARC_RET_F_2
;
67 case FFI_TYPE_LONGDOUBLE
:
69 flags
= (rtype
->size
& 0xfff) << SPARC_SIZEMASK_SHIFT
;
70 flags
|= SPARC_RET_STRUCT
;
73 flags
= SPARC_RET_SINT8
;
76 flags
= SPARC_RET_UINT8
;
79 flags
= SPARC_RET_SINT16
;
82 flags
= SPARC_RET_UINT16
;
87 case FFI_TYPE_POINTER
:
88 flags
= SPARC_RET_UINT32
;
92 flags
= SPARC_RET_INT64
;
94 case FFI_TYPE_COMPLEX
:
95 rtt
= rtype
->elements
[0]->type
;
99 flags
= SPARC_RET_F_2
;
101 case FFI_TYPE_DOUBLE
:
102 flags
= SPARC_RET_F_4
;
104 case FFI_TYPE_LONGDOUBLE
:
105 flags
= SPARC_RET_F_8
;
107 case FFI_TYPE_SINT64
:
108 case FFI_TYPE_UINT64
:
109 flags
= SPARC_RET_INT128
;
112 case FFI_TYPE_SINT32
:
113 case FFI_TYPE_UINT32
:
114 flags
= SPARC_RET_INT64
;
116 case FFI_TYPE_SINT16
:
117 case FFI_TYPE_UINT16
:
118 flags
= SP_V8_RET_CPLX16
;
122 flags
= SP_V8_RET_CPLX8
;
134 for (i
= 0, n
= cif
->nargs
; i
< n
; ++i
)
136 ffi_type
*ty
= cif
->arg_types
[i
];
142 case FFI_TYPE_STRUCT
:
143 case FFI_TYPE_LONGDOUBLE
:
145 /* Passed by reference. */
149 case FFI_TYPE_COMPLEX
:
150 tt
= ty
->elements
[0]->type
;
151 if (tt
== FFI_TYPE_FLOAT
|| z
> 8)
161 /* Sparc call frames require that space is allocated for 6 args,
162 even if they aren't used. Make that space if necessary. */
166 /* The ABI always requires space for the struct return pointer. */
169 /* The stack must be 2 word aligned, so round bytes up appropriately. */
170 bytes
= FFI_ALIGN(bytes
, 2 * 4);
172 /* Include the call frame to prep_args. */
179 extern void ffi_call_v8(ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
180 void **avalue
, size_t bytes
, void *closure
) FFI_HIDDEN
;
183 ffi_prep_args_v8(ffi_cif
*cif
, unsigned long *argp
, void *rvalue
, void **avalue
)
186 int flags
= cif
->flags
;
191 if ((flags
& SPARC_FLAG_RET_MASK
) == SPARC_RET_STRUCT
)
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
;
200 /* Otherwise, we can ignore the return value. */
201 flags
= SPARC_RET_VOID
;
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
;
210 /* Purify will probably complain in our assembly routine,
211 unless we zero out this memory. */
212 memset(argp
, 0, 6*4);
215 p_arg
= cif
->arg_types
;
216 for (i
= 0, nargs
= cif
->nargs
; i
< nargs
; i
++)
218 ffi_type
*ty
= p_arg
[i
];
225 case FFI_TYPE_STRUCT
:
226 case FFI_TYPE_LONGDOUBLE
:
228 *argp
++ = (unsigned long)a
;
231 case FFI_TYPE_DOUBLE
:
232 case FFI_TYPE_UINT64
:
233 case FFI_TYPE_SINT64
:
240 case FFI_TYPE_UINT32
:
241 case FFI_TYPE_SINT32
:
242 case FFI_TYPE_POINTER
:
243 *argp
++ = *(unsigned *)a
;
247 *argp
++ = *(UINT8
*)a
;
250 *argp
++ = *(SINT8
*)a
;
252 case FFI_TYPE_UINT16
:
253 *argp
++ = *(UINT16
*)a
;
255 case FFI_TYPE_SINT16
:
256 *argp
++ = *(SINT16
*)a
;
259 case FFI_TYPE_COMPLEX
:
260 tt
= ty
->elements
[0]->type
;
262 if (tt
== FFI_TYPE_FLOAT
|| z
> 8)
266 memcpy((char *)argp
+ 4 - z
, a
, z
);
285 ffi_call_int (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
286 void **avalue
, void *closure
)
288 size_t bytes
= cif
->bytes
;
289 size_t i
, nargs
= cif
->nargs
;
290 ffi_type
**arg_types
= cif
->arg_types
;
292 FFI_ASSERT (cif
->abi
== FFI_V8
);
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. */
297 && (cif
->flags
& SPARC_FLAG_RET_MASK
) == SPARC_RET_STRUCT
)
298 bytes
+= FFI_ALIGN (cif
->rtype
->size
, 8);
300 /* If we have any structure arguments, make a copy so we are passing
302 for (i
= 0; i
< nargs
; i
++)
304 ffi_type
*at
= arg_types
[i
];
306 if (at
->type
== FFI_TYPE_STRUCT
)
308 char *argcopy
= alloca (size
);
309 memcpy (argcopy
, avalue
[i
], size
);
314 ffi_call_v8(cif
, fn
, rvalue
, avalue
, -bytes
, closure
);
318 ffi_call (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
, void **avalue
)
320 ffi_call_int (cif
, fn
, rvalue
, avalue
, NULL
);
324 ffi_call_go (ffi_cif
*cif
, void (*fn
)(void), void *rvalue
,
325 void **avalue
, void *closure
)
327 ffi_call_int (cif
, fn
, rvalue
, avalue
, closure
);
332 ffi_flush_icache (void *p
)
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");
339 extern void ffi_flush_icache (void *) FFI_HIDDEN
;
342 extern void ffi_closure_v8(void) FFI_HIDDEN
;
343 extern void ffi_go_closure_v8(void) FFI_HIDDEN
;
346 ffi_prep_closure_loc (ffi_closure
*closure
,
348 void (*fun
)(ffi_cif
*, void*, void**, void*),
352 unsigned int *tramp
= (unsigned int *) &closure
->tramp
[0];
353 unsigned long ctx
= (unsigned long) closure
;
354 unsigned long fn
= (unsigned long) ffi_closure_v8
;
356 if (cif
->abi
!= FFI_V8
)
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) */
366 closure
->user_data
= user_data
;
368 ffi_flush_icache (closure
);
374 ffi_prep_go_closure (ffi_go_closure
*closure
, ffi_cif
*cif
,
375 void (*fun
)(ffi_cif
*, void*, void**, void*))
377 if (cif
->abi
!= FFI_V8
)
380 closure
->tramp
= ffi_go_closure_v8
;
388 ffi_closure_sparc_inner_v8(ffi_cif
*cif
,
389 void (*fun
)(ffi_cif
*, void*, void**, void*),
390 void *user_data
, void *rvalue
,
393 ffi_type
**arg_types
;
397 arg_types
= cif
->arg_types
;
400 avalue
= alloca(nargs
* sizeof(void *));
402 /* Copy the caller's structure return address so that the closure
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
)
407 void *new_rvalue
= (void *)*argp
;
408 *(void **)rvalue
= new_rvalue
;
412 /* Always skip the structure return address. */
415 /* Grab the addresses of the arguments from the stack frame. */
416 for (i
= 0; i
< nargs
; i
++)
418 ffi_type
*ty
= arg_types
[i
];
425 case FFI_TYPE_STRUCT
:
426 case FFI_TYPE_LONGDOUBLE
:
428 /* Straight copy of invisible reference. */
432 case FFI_TYPE_DOUBLE
:
433 case FFI_TYPE_SINT64
:
434 case FFI_TYPE_UINT64
:
435 if ((unsigned long)a
& 7)
437 /* Align on a 8-byte boundary. */
438 UINT64
*tmp
= alloca(8);
439 *tmp
= ((UINT64
)argp
[0] << 32) | argp
[1];
447 case FFI_TYPE_UINT32
:
448 case FFI_TYPE_SINT32
:
449 case FFI_TYPE_POINTER
:
451 case FFI_TYPE_UINT16
:
452 case FFI_TYPE_SINT16
:
460 case FFI_TYPE_COMPLEX
:
461 tt
= ty
->elements
[0]->type
;
463 if (tt
== FFI_TYPE_FLOAT
|| z
> 8)
478 /* Invoke the closure. */
479 fun (cif
, rvalue
, avalue
, user_data
);
481 /* Tell ffi_closure_sparc how to perform return type promotions. */
484 #endif /* !SPARC64 */