OSDN Git Service

* doc/tm.texi (defmac SMALL_REGISTER_CLASSES): Remove.
[pf3gnuchains/gcc-fork.git] / libffi / src / cris / ffi.c
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.
6
7    CRIS Foreign Function Interface
8
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:
16
17    The above copyright notice and this permission notice shall be included
18    in all copies or substantial portions of the Software.
19
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    ----------------------------------------------------------------------- */
28
29 #include <ffi.h>
30 #include <ffi_common.h>
31
32 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
33
34 static ffi_status
35 initialize_aggregate_packed_struct (ffi_type * arg)
36 {
37   ffi_type **ptr;
38
39   FFI_ASSERT (arg != NULL);
40
41   FFI_ASSERT (arg->elements != NULL);
42   FFI_ASSERT (arg->size == 0);
43   FFI_ASSERT (arg->alignment == 0);
44
45   ptr = &(arg->elements[0]);
46
47   while ((*ptr) != NULL)
48     {
49       if (((*ptr)->size == 0)
50           && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51         return FFI_BAD_TYPEDEF;
52
53       FFI_ASSERT (ffi_type_test ((*ptr)));
54
55       arg->size += (*ptr)->size;
56
57       arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58         arg->alignment : (*ptr)->alignment;
59
60       ptr++;
61     }
62
63   if (arg->size == 0)
64     return FFI_BAD_TYPEDEF;
65   else
66     return FFI_OK;
67 }
68
69 int
70 ffi_prep_args (char *stack, extended_cif * ecif)
71 {
72   unsigned int i;
73   unsigned int struct_count = 0;
74   void **p_argv;
75   char *argp;
76   ffi_type **p_arg;
77
78   argp = stack;
79
80   p_argv = ecif->avalue;
81
82   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83        (i != 0); i--, p_arg++)
84     {
85       size_t z;
86
87       switch ((*p_arg)->type)
88         {
89         case FFI_TYPE_STRUCT:
90           {
91             z = (*p_arg)->size;
92             if (z <= 4)
93               {
94                 memcpy (argp, *p_argv, z);
95                 z = 4;
96               }
97             else if (z <= 8)
98               {
99                 memcpy (argp, *p_argv, z);
100                 z = 8;
101               }
102             else
103               {
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);
111               }
112             break;
113           }
114         default:
115           z = (*p_arg)->size;
116           if (z < sizeof (int))
117             {
118               switch ((*p_arg)->type)
119                 {
120                 case FFI_TYPE_SINT8:
121                   *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122                   break;
123
124                 case FFI_TYPE_UINT8:
125                   *(unsigned int *) argp =
126                     (unsigned int) *(UINT8 *) (*p_argv);
127                   break;
128
129                 case FFI_TYPE_SINT16:
130                   *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131                   break;
132
133                 case FFI_TYPE_UINT16:
134                   *(unsigned int *) argp =
135                     (unsigned int) *(UINT16 *) (*p_argv);
136                   break;
137
138                 default:
139                   FFI_ASSERT (0);
140                 }
141               z = sizeof (int);
142             }
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;
148         }
149       p_argv++;
150       argp += z;
151     }
152
153   return (struct_count);
154 }
155
156 ffi_status
157 ffi_prep_cif (ffi_cif * cif,
158               ffi_abi abi, unsigned int nargs,
159               ffi_type * rtype, ffi_type ** atypes)
160 {
161   unsigned bytes = 0;
162   unsigned int i;
163   ffi_type **ptr;
164
165   FFI_ASSERT (cif != NULL);
166   FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
167
168   cif->abi = abi;
169   cif->arg_types = atypes;
170   cif->nargs = nargs;
171   cif->rtype = rtype;
172
173   cif->flags = 0;
174
175   if ((cif->rtype->size == 0)
176       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
177     return FFI_BAD_TYPEDEF;
178
179   FFI_ASSERT_VALID_TYPE (cif->rtype);
180
181   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
182     {
183       if (((*ptr)->size == 0)
184           && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
185         return FFI_BAD_TYPEDEF;
186
187       FFI_ASSERT_VALID_TYPE (*ptr);
188
189       if (((*ptr)->alignment - 1) & bytes)
190         bytes = ALIGN (bytes, (*ptr)->alignment);
191       if ((*ptr)->type == FFI_TYPE_STRUCT)
192         {
193           if ((*ptr)->size > 8)
194             {
195               bytes += (*ptr)->size;
196               bytes += sizeof (void *);
197             }
198           else
199             {
200               if ((*ptr)->size > 4)
201                 bytes += 8;
202               else
203                 bytes += 4;
204             }
205         }
206       else
207         bytes += STACK_ARG_SIZE ((*ptr)->size);
208     }
209
210   cif->bytes = bytes;
211
212   return ffi_prep_cif_machdep (cif);
213 }
214
215 ffi_status
216 ffi_prep_cif_machdep (ffi_cif * cif)
217 {
218   switch (cif->rtype->type)
219     {
220     case FFI_TYPE_VOID:
221     case FFI_TYPE_STRUCT:
222     case FFI_TYPE_FLOAT:
223     case FFI_TYPE_DOUBLE:
224     case FFI_TYPE_SINT64:
225     case FFI_TYPE_UINT64:
226       cif->flags = (unsigned) cif->rtype->type;
227       break;
228
229     default:
230       cif->flags = FFI_TYPE_INT;
231       break;
232     }
233
234   return FFI_OK;
235 }
236
237 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
238                            extended_cif *,
239                            unsigned, unsigned, unsigned *, void (*fn) ())
240      __attribute__ ((__visibility__ ("hidden")));
241
242 void
243 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
244 {
245   extended_cif ecif;
246
247   ecif.cif = cif;
248   ecif.avalue = avalue;
249
250   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
251     {
252       ecif.rvalue = alloca (cif->rtype->size);
253     }
254   else
255     ecif.rvalue = rvalue;
256
257   switch (cif->abi)
258     {
259     case FFI_SYSV:
260       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
261                      cif->flags, ecif.rvalue, fn);
262       break;
263     default:
264       FFI_ASSERT (0);
265       break;
266     }
267 }
268
269 /* Because the following variables are not exported outside libffi, we
270    mark them hidden.  */
271
272 /* Assembly code for the jump stub.  */
273 extern const char ffi_cris_trampoline_template[]
274  __attribute__ ((__visibility__ ("hidden")));
275
276 /* Offset into ffi_cris_trampoline_template of where to put the
277    ffi_prep_closure_inner function.  */
278 extern const int ffi_cris_trampoline_fn_offset
279  __attribute__ ((__visibility__ ("hidden")));
280
281 /* Offset into ffi_cris_trampoline_template of where to put the
282    closure data.  */
283 extern const int ffi_cris_trampoline_closure_offset
284  __attribute__ ((__visibility__ ("hidden")));
285
286 /* This function is sibling-called (jumped to) by the closure
287    trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
288    PARAMS[4] to simplify handling of a straddling parameter.  A copy
289    of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
290    put at the appropriate place in CLOSURE which is then executed and
291    the return value is passed back to the caller.  */
292
293 static unsigned long long
294 ffi_prep_closure_inner (void **params, ffi_closure* closure)
295 {
296   char *register_args = (char *) params;
297   void *struct_ret = params[5];
298   char *stack_args = params[6];
299   char *ptr = register_args;
300   ffi_cif *cif = closure->cif;
301   ffi_type **arg_types = cif->arg_types;
302
303   /* Max room needed is number of arguments as 64-bit values.  */
304   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
305   int i;
306   int doing_regs;
307   long long llret = 0;
308
309   /* Find the address of each argument.  */
310   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
311     {
312       /* Types up to and including 8 bytes go by-value.  */
313       if (arg_types[i]->size <= 4)
314         {
315           avalue[i] = ptr;
316           ptr += 4;
317         }
318       else if (arg_types[i]->size <= 8)
319         {
320           avalue[i] = ptr;
321           ptr += 8;
322         }
323       else
324         {
325           FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
326
327           /* Passed by-reference, so copy the pointer.  */
328           avalue[i] = *(void **) ptr;
329           ptr += 4;
330         }
331
332       /* If we've handled more arguments than fit in registers, start
333          looking at the those passed on the stack.  Step over the
334          first one if we had a straddling parameter.  */
335       if (doing_regs && ptr >= register_args + 4*4)
336         {
337           ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
338           doing_regs = 0;
339         }
340     }
341
342   /* Invoke the closure.  */
343   (closure->fun) (cif,
344
345                   cif->rtype->type == FFI_TYPE_STRUCT
346                   /* The caller allocated space for the return
347                      structure, and passed a pointer to this space in
348                      R9.  */
349                   ? struct_ret
350
351                   /* We take advantage of being able to ignore that
352                      the high part isn't set if the return value is
353                      not in R10:R11, but in R10 only.  */
354                   : (void *) &llret,
355
356                   avalue, closure->user_data);
357
358   return llret;
359 }
360
361 /* API function: Prepare the trampoline.  */
362
363 ffi_status
364 ffi_prep_closure_loc (ffi_closure* closure,
365                       ffi_cif* cif,
366                       void (*fun)(ffi_cif *, void *, void **, void*),
367                       void *user_data,
368                       void *codeloc)
369 {
370   void *innerfn = ffi_prep_closure_inner;
371   FFI_ASSERT (cif->abi == FFI_SYSV);
372   closure->cif  = cif;
373   closure->user_data = user_data;
374   closure->fun  = fun;
375   memcpy (closure->tramp, ffi_cris_trampoline_template,
376           FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
377   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
378           &innerfn, sizeof (void *));
379   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
380           &codeloc, sizeof (void *));
381
382   return FFI_OK;
383 }