ada: Disable PIE mode during the build of the Ada front-end
[official-gcc.git] / libffi / src / metag / ffi.c
blob3aecb0b8115631efdacea339e75a43c3da5b855b
1 /* ----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2013 Imagination Technologies
4 Meta Foreign Function Interface
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 `Software''), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED `AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
23 ----------------------------------------------------------------------- */
25 #include <ffi.h>
26 #include <ffi_common.h>
28 #include <stdlib.h>
30 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
33 * ffi_prep_args is called by the assembly routine once stack space has been
34 * allocated for the function's arguments
37 unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
39 register unsigned int i;
40 register void **p_argv;
41 register char *argp;
42 register ffi_type **p_arg;
44 argp = stack;
46 /* Store return value */
47 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
48 argp -= 4;
49 *(void **) argp = ecif->rvalue;
52 p_argv = ecif->avalue;
54 /* point to next location */
55 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
57 size_t z;
59 /* Move argp to address of argument */
60 z = (*p_arg)->size;
61 argp -= z;
63 /* Align if necessary */
64 argp = (char *) FFI_ALIGN_DOWN(FFI_ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
66 if (z < sizeof(int)) {
67 z = sizeof(int);
68 switch ((*p_arg)->type)
70 case FFI_TYPE_SINT8:
71 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
72 break;
73 case FFI_TYPE_UINT8:
74 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
75 break;
76 case FFI_TYPE_SINT16:
77 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
78 break;
79 case FFI_TYPE_UINT16:
80 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
81 case FFI_TYPE_STRUCT:
82 memcpy(argp, *p_argv, (*p_arg)->size);
83 break;
84 default:
85 FFI_ASSERT(0);
87 } else if ( z == sizeof(int)) {
88 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
89 } else {
90 memcpy(argp, *p_argv, z);
94 /* return the size of the arguments to be passed in registers,
95 padded to an 8 byte boundary to preserve stack alignment */
96 return FFI_ALIGN(MIN(stack - argp, 6*4), 8);
99 /* Perform machine dependent cif processing */
100 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
102 ffi_type **ptr;
103 unsigned i, bytes = 0;
105 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
106 if ((*ptr)->size == 0)
107 return FFI_BAD_TYPEDEF;
109 /* Perform a sanity check on the argument type, do this
110 check after the initialization. */
111 FFI_ASSERT_VALID_TYPE(*ptr);
113 /* Add any padding if necessary */
114 if (((*ptr)->alignment - 1) & bytes)
115 bytes = FFI_ALIGN(bytes, (*ptr)->alignment);
117 bytes += FFI_ALIGN((*ptr)->size, 4);
120 /* Ensure arg space is aligned to an 8-byte boundary */
121 bytes = FFI_ALIGN(bytes, 8);
123 /* Make space for the return structure pointer */
124 if (cif->rtype->type == FFI_TYPE_STRUCT) {
125 bytes += sizeof(void*);
127 /* Ensure stack is aligned to an 8-byte boundary */
128 bytes = FFI_ALIGN(bytes, 8);
131 cif->bytes = bytes;
133 /* Set the return type flag */
134 switch (cif->rtype->type) {
135 case FFI_TYPE_VOID:
136 case FFI_TYPE_FLOAT:
137 case FFI_TYPE_DOUBLE:
138 cif->flags = (unsigned) cif->rtype->type;
139 break;
140 case FFI_TYPE_SINT64:
141 case FFI_TYPE_UINT64:
142 cif->flags = (unsigned) FFI_TYPE_SINT64;
143 break;
144 case FFI_TYPE_STRUCT:
145 /* Meta can store return values which are <= 64 bits */
146 if (cif->rtype->size <= 4)
147 /* Returned to D0Re0 as 32-bit value */
148 cif->flags = (unsigned)FFI_TYPE_INT;
149 else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
150 /* Returned valued is stored to D1Re0|R0Re0 */
151 cif->flags = (unsigned)FFI_TYPE_DOUBLE;
152 else
153 /* value stored in memory */
154 cif->flags = (unsigned)FFI_TYPE_STRUCT;
155 break;
156 default:
157 cif->flags = (unsigned)FFI_TYPE_INT;
158 break;
160 return FFI_OK;
163 extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
166 * Exported in API. Entry point
167 * cif -> ffi_cif object
168 * fn -> function pointer
169 * rvalue -> pointer to return value
170 * avalue -> vector of void * pointers pointing to memory locations holding the
171 * arguments
173 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
175 extended_cif ecif;
177 int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
178 ecif.cif = cif;
179 ecif.avalue = avalue;
181 double temp;
184 * If the return value is a struct and we don't have a return value address
185 * then we need to make one
188 if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
189 ecif.rvalue = alloca(cif->rtype->size);
190 else if (small_struct)
191 ecif.rvalue = &temp;
192 else
193 ecif.rvalue = rvalue;
195 switch (cif->abi) {
196 case FFI_SYSV:
197 ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
198 break;
199 default:
200 FFI_ASSERT(0);
201 break;
204 if (small_struct)
205 memcpy (rvalue, &temp, cif->rtype->size);
208 /* private members */
210 static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
211 ffi_cif*, float *);
213 void ffi_closure_SYSV (ffi_closure *);
215 /* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
216 extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
218 /* end of private members */
221 * __tramp: trampoline memory location
222 * __fun: assembly routine
223 * __ctx: memory location for wrapper
225 * At this point, tramp[0] == __ctx !
227 void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
228 memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
229 *(unsigned int*) &__tramp[40] = __ctx;
230 *(unsigned int*) &__tramp[44] = __fun;
231 /* This will flush the instruction cache */
232 __builtin_meta2_cachewd(&__tramp[0], 1);
233 __builtin_meta2_cachewd(&__tramp[47], 1);
238 /* the cif must already be prepared */
240 ffi_status
241 ffi_prep_closure_loc (ffi_closure *closure,
242 ffi_cif* cif,
243 void (*fun)(ffi_cif*,void*,void**,void*),
244 void *user_data,
245 void *codeloc)
247 void (*closure_func)(ffi_closure*) = NULL;
249 if (cif->abi == FFI_SYSV)
250 closure_func = &ffi_closure_SYSV;
251 else
252 return FFI_BAD_ABI;
254 ffi_init_trampoline(
255 (unsigned char*)&closure->tramp[0],
256 (unsigned int)closure_func,
257 (unsigned int)codeloc);
259 closure->cif = cif;
260 closure->user_data = user_data;
261 closure->fun = fun;
263 return FFI_OK;
267 /* This function is jumped to by the trampoline */
268 unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
269 ffi_closure *closure;
270 void **respp;
271 void *args;
272 void *vfp_args;
274 ffi_cif *cif;
275 void **arg_area;
277 cif = closure->cif;
278 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
281 * This call will initialize ARG_AREA, such that each
282 * element in that array points to the corresponding
283 * value on the stack; and if the function returns
284 * a structure, it will re-set RESP to point to the
285 * structure return address.
287 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
289 (closure->fun) ( cif, *respp, arg_area, closure->user_data);
291 return cif->flags;
294 static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
295 void **avalue, ffi_cif *cif,
296 float *vfp_stack)
298 register unsigned int i;
299 register void **p_argv;
300 register char *argp;
301 register ffi_type **p_arg;
303 /* stack points to original arguments */
304 argp = stack;
306 /* Store return value */
307 if ( cif->flags == FFI_TYPE_STRUCT ) {
308 argp -= 4;
309 *rvalue = *(void **) argp;
312 p_argv = avalue;
314 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
315 size_t z;
316 size_t alignment;
318 alignment = (*p_arg)->alignment;
319 if (alignment < 4)
320 alignment = 4;
321 if ((alignment - 1) & (unsigned)argp)
322 argp = (char *) FFI_ALIGN(argp, alignment);
324 z = (*p_arg)->size;
325 *p_argv = (void*) argp;
326 p_argv++;
327 argp -= z;
329 return;