Daily bump.
[official-gcc.git] / libffi / src / cris / ffi.c
blobaaca5b1cbaa4d17732a0b3d8c8b612d8be9e1f64
1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998 Cygnus Solutions
3 Copyright (c) 2004 Simon Posnjak
4 Copyright (c) 2005 Axis Communications AB
5 Copyright (C) 2007 Free Software Foundation, Inc.
7 CRIS Foreign Function Interface
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 ``Software''), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27 ----------------------------------------------------------------------- */
29 #include <ffi.h>
30 #include <ffi_common.h>
32 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
34 static ffi_status
35 initialize_aggregate_packed_struct (ffi_type * arg)
37 ffi_type **ptr;
39 FFI_ASSERT (arg != NULL);
41 FFI_ASSERT (arg->elements != NULL);
42 FFI_ASSERT (arg->size == 0);
43 FFI_ASSERT (arg->alignment == 0);
45 ptr = &(arg->elements[0]);
47 while ((*ptr) != NULL)
49 if (((*ptr)->size == 0)
50 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51 return FFI_BAD_TYPEDEF;
53 FFI_ASSERT (ffi_type_test ((*ptr)));
55 arg->size += (*ptr)->size;
57 arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58 arg->alignment : (*ptr)->alignment;
60 ptr++;
63 if (arg->size == 0)
64 return FFI_BAD_TYPEDEF;
65 else
66 return FFI_OK;
69 int
70 ffi_prep_args (char *stack, extended_cif * ecif)
72 unsigned int i;
73 unsigned int struct_count = 0;
74 void **p_argv;
75 char *argp;
76 ffi_type **p_arg;
78 argp = stack;
80 p_argv = ecif->avalue;
82 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83 (i != 0); i--, p_arg++)
85 size_t z;
87 switch ((*p_arg)->type)
89 case FFI_TYPE_STRUCT:
91 z = (*p_arg)->size;
92 if (z <= 4)
94 memcpy (argp, *p_argv, z);
95 z = 4;
97 else if (z <= 8)
99 memcpy (argp, *p_argv, z);
100 z = 8;
102 else
104 unsigned int uiLocOnStack;
105 z = sizeof (void *);
106 uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
107 struct_count = struct_count + (*p_arg)->size;
108 *(unsigned int *) argp =
109 (unsigned int) (UINT32 *) (stack + uiLocOnStack);
110 memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
112 break;
114 default:
115 z = (*p_arg)->size;
116 if (z < sizeof (int))
118 switch ((*p_arg)->type)
120 case FFI_TYPE_SINT8:
121 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122 break;
124 case FFI_TYPE_UINT8:
125 *(unsigned int *) argp =
126 (unsigned int) *(UINT8 *) (*p_argv);
127 break;
129 case FFI_TYPE_SINT16:
130 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131 break;
133 case FFI_TYPE_UINT16:
134 *(unsigned int *) argp =
135 (unsigned int) *(UINT16 *) (*p_argv);
136 break;
138 default:
139 FFI_ASSERT (0);
141 z = sizeof (int);
143 else if (z == sizeof (int))
144 *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
145 else
146 memcpy (argp, *p_argv, z);
147 break;
149 p_argv++;
150 argp += z;
153 return (struct_count);
156 ffi_status FFI_HIDDEN
157 ffi_prep_cif_core (ffi_cif * cif,
158 ffi_abi abi, unsigned int isvariadic,
159 unsigned int nfixedargs, unsigned int ntotalargs,
160 ffi_type * rtype, ffi_type ** atypes)
162 unsigned bytes = 0;
163 unsigned int i;
164 ffi_type **ptr;
166 FFI_ASSERT (cif != NULL);
167 FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
168 FFI_ASSERT(nfixedargs <= ntotalargs);
169 FFI_ASSERT (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI);
171 cif->abi = abi;
172 cif->arg_types = atypes;
173 cif->nargs = ntotalargs;
174 cif->rtype = rtype;
176 cif->flags = 0;
178 if ((cif->rtype->size == 0)
179 && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
180 return FFI_BAD_TYPEDEF;
182 FFI_ASSERT_VALID_TYPE (cif->rtype);
184 for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
186 if (((*ptr)->size == 0)
187 && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
188 return FFI_BAD_TYPEDEF;
190 FFI_ASSERT_VALID_TYPE (*ptr);
192 if (((*ptr)->alignment - 1) & bytes)
193 bytes = ALIGN (bytes, (*ptr)->alignment);
194 if ((*ptr)->type == FFI_TYPE_STRUCT)
196 if ((*ptr)->size > 8)
198 bytes += (*ptr)->size;
199 bytes += sizeof (void *);
201 else
203 if ((*ptr)->size > 4)
204 bytes += 8;
205 else
206 bytes += 4;
209 else
210 bytes += STACK_ARG_SIZE ((*ptr)->size);
213 cif->bytes = bytes;
215 return ffi_prep_cif_machdep (cif);
218 ffi_status
219 ffi_prep_cif_machdep (ffi_cif * cif)
221 switch (cif->rtype->type)
223 case FFI_TYPE_VOID:
224 case FFI_TYPE_STRUCT:
225 case FFI_TYPE_FLOAT:
226 case FFI_TYPE_DOUBLE:
227 case FFI_TYPE_SINT64:
228 case FFI_TYPE_UINT64:
229 cif->flags = (unsigned) cif->rtype->type;
230 break;
232 default:
233 cif->flags = FFI_TYPE_INT;
234 break;
237 return FFI_OK;
240 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
241 extended_cif *,
242 unsigned, unsigned, unsigned *, void (*fn) ())
243 __attribute__ ((__visibility__ ("hidden")));
245 void
246 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
248 extended_cif ecif;
250 ecif.cif = cif;
251 ecif.avalue = avalue;
253 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
255 ecif.rvalue = alloca (cif->rtype->size);
257 else
258 ecif.rvalue = rvalue;
260 switch (cif->abi)
262 case FFI_SYSV:
263 ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
264 cif->flags, ecif.rvalue, fn);
265 break;
266 default:
267 FFI_ASSERT (0);
268 break;
272 /* Because the following variables are not exported outside libffi, we
273 mark them hidden. */
275 /* Assembly code for the jump stub. */
276 extern const char ffi_cris_trampoline_template[]
277 __attribute__ ((__visibility__ ("hidden")));
279 /* Offset into ffi_cris_trampoline_template of where to put the
280 ffi_prep_closure_inner function. */
281 extern const int ffi_cris_trampoline_fn_offset
282 __attribute__ ((__visibility__ ("hidden")));
284 /* Offset into ffi_cris_trampoline_template of where to put the
285 closure data. */
286 extern const int ffi_cris_trampoline_closure_offset
287 __attribute__ ((__visibility__ ("hidden")));
289 /* This function is sibling-called (jumped to) by the closure
290 trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
291 PARAMS[4] to simplify handling of a straddling parameter. A copy
292 of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are
293 put at the appropriate place in CLOSURE which is then executed and
294 the return value is passed back to the caller. */
296 static unsigned long long
297 ffi_prep_closure_inner (void **params, ffi_closure* closure)
299 char *register_args = (char *) params;
300 void *struct_ret = params[5];
301 char *stack_args = params[6];
302 char *ptr = register_args;
303 ffi_cif *cif = closure->cif;
304 ffi_type **arg_types = cif->arg_types;
306 /* Max room needed is number of arguments as 64-bit values. */
307 void **avalue = alloca (closure->cif->nargs * sizeof(void *));
308 int i;
309 int doing_regs;
310 long long llret = 0;
312 /* Find the address of each argument. */
313 for (i = 0, doing_regs = 1; i < cif->nargs; i++)
315 /* Types up to and including 8 bytes go by-value. */
316 if (arg_types[i]->size <= 4)
318 avalue[i] = ptr;
319 ptr += 4;
321 else if (arg_types[i]->size <= 8)
323 avalue[i] = ptr;
324 ptr += 8;
326 else
328 FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
330 /* Passed by-reference, so copy the pointer. */
331 avalue[i] = *(void **) ptr;
332 ptr += 4;
335 /* If we've handled more arguments than fit in registers, start
336 looking at the those passed on the stack. Step over the
337 first one if we had a straddling parameter. */
338 if (doing_regs && ptr >= register_args + 4*4)
340 ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
341 doing_regs = 0;
345 /* Invoke the closure. */
346 (closure->fun) (cif,
348 cif->rtype->type == FFI_TYPE_STRUCT
349 /* The caller allocated space for the return
350 structure, and passed a pointer to this space in
351 R9. */
352 ? struct_ret
354 /* We take advantage of being able to ignore that
355 the high part isn't set if the return value is
356 not in R10:R11, but in R10 only. */
357 : (void *) &llret,
359 avalue, closure->user_data);
361 return llret;
364 /* API function: Prepare the trampoline. */
366 ffi_status
367 ffi_prep_closure_loc (ffi_closure* closure,
368 ffi_cif* cif,
369 void (*fun)(ffi_cif *, void *, void **, void*),
370 void *user_data,
371 void *codeloc)
373 void *innerfn = ffi_prep_closure_inner;
374 FFI_ASSERT (cif->abi == FFI_SYSV);
375 closure->cif = cif;
376 closure->user_data = user_data;
377 closure->fun = fun;
378 memcpy (closure->tramp, ffi_cris_trampoline_template,
379 FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
380 memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
381 &innerfn, sizeof (void *));
382 memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
383 &codeloc, sizeof (void *));
385 return FFI_OK;