OSDN Git Service

libffi:
[pf3gnuchains/gcc-fork.git] / libffi / src / mips / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1996 Cygnus Solutions
3    
4    MIPS Foreign Function Interface 
5
6    Permission is hereby granted, free of charge, to any person obtaining
7    a copy of this software and associated documentation files (the
8    ``Software''), to deal in the Software without restriction, including
9    without limitation the rights to use, copy, modify, merge, publish,
10    distribute, sublicense, and/or sell copies of the Software, and to
11    permit persons to whom the Software is furnished to do so, subject to
12    the following conditions:
13
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
16
17    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23    OTHER DEALINGS IN THE SOFTWARE.
24    ----------------------------------------------------------------------- */
25
26 #include <sgidefs.h>
27 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31
32 #if _MIPS_SIM == _ABIN32
33 #define FIX_ARGP \
34 FFI_ASSERT(argp <= &stack[bytes]); \
35 if (argp == &stack[bytes]) \
36 { \
37   argp = stack; \
38   ffi_stop_here(); \
39 }
40 #else
41 #define FIX_ARGP 
42 #endif
43
44
45 /* ffi_prep_args is called by the assembly routine once stack space
46    has been allocated for the function's arguments */
47
48 static void ffi_prep_args(char *stack, 
49                           extended_cif *ecif,
50                           int bytes,
51                           int flags)
52 {
53   register int i;
54   register void **p_argv;
55   register char *argp;
56   register ffi_type **p_arg;
57
58 #if _MIPS_SIM == _ABIN32
59   /* If more than 8 double words are used, the remainder go
60      on the stack. We reorder stuff on the stack here to 
61      support this easily. */
62   if (bytes > 8 * SIZEOF_ARG)
63     argp = &stack[bytes - (8 * SIZEOF_ARG)];
64   else
65     argp = stack;
66 #else
67   argp = stack;
68 #endif
69
70   memset(stack, 0, bytes);
71
72 #if _MIPS_SIM == _ABIN32
73   if ( ecif->cif->rstruct_flag != 0 )
74 #else
75   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT )
76 #endif  
77     {
78       *(SLOT_TYPE_UNSIGNED *) argp = (SLOT_TYPE_UNSIGNED) ecif->rvalue;
79       argp += sizeof(SLOT_TYPE_UNSIGNED);
80       FIX_ARGP;
81     }
82
83   p_argv = ecif->avalue;
84
85   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
86     {
87       size_t z;
88
89       /* Align if necessary */
90       if (((*p_arg)->alignment - 1) & (unsigned) argp) {
91         argp = (char *) ALIGN(argp, (*p_arg)->alignment);
92         FIX_ARGP;
93       }
94
95 #if _MIPS_SIM == _ABIO32
96 #define OFFSET 0
97 #else
98 #define OFFSET sizeof(int)
99 #endif      
100
101           z = (*p_arg)->size;
102           if (z < sizeof(SLOT_TYPE_UNSIGNED))
103             {
104               z = sizeof(SLOT_TYPE_UNSIGNED);
105
106               switch ((*p_arg)->type)
107                 {
108                 case FFI_TYPE_SINT8:
109                   *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT8 *)(* p_argv);
110                   break;
111                   
112                 case FFI_TYPE_UINT8:
113                   *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT8 *)(* p_argv);
114                   break;
115                   
116                 case FFI_TYPE_SINT16:
117                   *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT16 *)(* p_argv);
118                   break;
119                   
120                 case FFI_TYPE_UINT16:
121                   *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT16 *)(* p_argv);
122                   break;
123                   
124                 case FFI_TYPE_SINT32:
125                   *(SINT32 *) &argp[OFFSET] = (SINT32)*(SINT32 *)(* p_argv);
126                   break;
127                   
128                 case FFI_TYPE_UINT32:
129                 case FFI_TYPE_POINTER:
130                   *(UINT32 *) &argp[OFFSET] = (UINT32)*(UINT32 *)(* p_argv);
131                   break;
132
133                   /* This can only happen with 64bit slots */
134                 case FFI_TYPE_FLOAT:
135                   *(float *) argp = *(float *)(* p_argv);
136                   break;
137
138                   /* Handle small structures */
139                 case FFI_TYPE_STRUCT:
140                   memcpy(argp, *p_argv, (*p_arg)->size);
141                   break;
142
143                 default:
144                   FFI_ASSERT(0);
145                 }
146             }
147           else
148             {
149 #if _MIPS_SIM == _ABIO32              
150               memcpy(argp, *p_argv, z);
151 #else
152               {
153                 unsigned end = (unsigned) argp+z;
154                 unsigned cap = (unsigned) stack+bytes;
155
156                 /* Check if the data will fit within the register
157                    space. Handle it if it doesn't. */
158
159                 if (end <= cap)
160                   memcpy(argp, *p_argv, z);
161                 else
162                   {
163                     unsigned portion = end - cap;
164
165                     memcpy(argp, *p_argv, portion);
166                     argp = stack;
167                     memcpy(argp, 
168                            (void*)((unsigned)(*p_argv)+portion), z - portion);
169                   }
170               }
171 #endif
172             }
173           p_argv++;
174           argp += z;
175           FIX_ARGP;
176     }
177   
178   return;
179 }
180
181 #if _MIPS_SIM == _ABIN32
182
183 /* The n32 spec says that if "a chunk consists solely of a double 
184    float field (but not a double, which is part of a union), it
185    is passed in a floating point register. Any other chunk is
186    passed in an integer register". This code traverses structure
187    definitions and generates the appropriate flags. */
188
189 unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift)
190 {
191   unsigned flags = 0;
192   unsigned index = 0;
193
194   ffi_type *e;
195
196   while (e = arg->elements[index])
197     {
198       if (e->type == FFI_TYPE_DOUBLE)
199         {
200           flags += (FFI_TYPE_DOUBLE << *shift);
201           *shift += FFI_FLAG_BITS;
202         }
203       else if (e->type == FFI_TYPE_STRUCT)
204           flags += calc_n32_struct_flags(e, shift);
205       else
206         *shift += FFI_FLAG_BITS;
207
208       index++;
209     }
210
211   return flags;
212 }
213
214 unsigned calc_n32_return_struct_flags(ffi_type *arg)
215 {
216   unsigned flags = 0;
217   unsigned index = 0;
218   unsigned small = FFI_TYPE_SMALLSTRUCT;
219   ffi_type *e;
220
221   /* Returning structures under n32 is a tricky thing.
222      A struct with only one or two floating point fields 
223      is returned in $f0 (and $f2 if necessary). Any other
224      struct results at most 128 bits are returned in $2
225      (the first 64 bits) and $3 (remainder, if necessary).
226      Larger structs are handled normally. */
227   
228   if (arg->size > 16)
229     return 0;
230
231   if (arg->size > 8)
232     small = FFI_TYPE_SMALLSTRUCT2;
233
234   e = arg->elements[0];
235   if (e->type == FFI_TYPE_DOUBLE)
236     flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS;
237   else if (e->type == FFI_TYPE_FLOAT)
238     flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS;
239
240   if (flags && (e = arg->elements[1]))
241     {
242       if (e->type == FFI_TYPE_DOUBLE)
243         flags += FFI_TYPE_DOUBLE;
244       else if (e->type == FFI_TYPE_FLOAT)
245         flags += FFI_TYPE_FLOAT;
246       else 
247         return small;
248
249       if (flags && (arg->elements[2]))
250         {
251           /* There are three arguments and the first two are 
252              floats! This must be passed the old way. */
253           return small;
254         }
255     }
256   else
257     if (!flags)
258       return small;
259
260   return flags;
261 }
262
263 #endif
264
265 /* Perform machine dependent cif processing */
266 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
267 {
268   cif->flags = 0;
269
270 #if _MIPS_SIM == _ABIO32
271   /* Set the flags necessary for O32 processing */
272
273   if (cif->rtype->type != FFI_TYPE_STRUCT)
274     {
275       if (cif->nargs > 0)
276         {
277           switch ((cif->arg_types)[0]->type)
278             {
279             case FFI_TYPE_FLOAT:
280             case FFI_TYPE_DOUBLE:
281               cif->flags += (cif->arg_types)[0]->type;
282               break;
283               
284             default:
285               break;
286             }
287
288           if (cif->nargs > 1)
289             {
290               /* Only handle the second argument if the first
291                  is a float or double. */
292               if (cif->flags)
293                 {
294                   switch ((cif->arg_types)[1]->type)
295                     {
296                     case FFI_TYPE_FLOAT:
297                     case FFI_TYPE_DOUBLE:
298                       cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS;
299                       break;
300                       
301                     default:
302                       break;
303                     }
304                 }
305             }
306         }
307     }
308       
309   /* Set the return type flag */
310   switch (cif->rtype->type)
311     {
312     case FFI_TYPE_VOID:
313     case FFI_TYPE_STRUCT:
314     case FFI_TYPE_FLOAT:
315     case FFI_TYPE_DOUBLE:
316       cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2);
317       break;
318       
319     default:
320       cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2);
321       break;
322     }
323 #endif
324
325 #if _MIPS_SIM == _ABIN32
326   /* Set the flags necessary for N32 processing */
327   {
328     unsigned shift = 0;
329     unsigned count = (cif->nargs < 8) ? cif->nargs : 8;
330     unsigned index = 0;
331
332     unsigned struct_flags = 0;
333
334     if (cif->rtype->type == FFI_TYPE_STRUCT)
335       {
336         struct_flags = calc_n32_return_struct_flags(cif->rtype);
337
338         if (struct_flags == 0)
339           {
340             /* This means that the structure is being passed as
341                a hidden argument */
342
343             shift = FFI_FLAG_BITS;
344             count = (cif->nargs < 7) ? cif->nargs : 7;
345
346             cif->rstruct_flag = !0;
347           }
348         else
349             cif->rstruct_flag = 0;
350       }
351     else
352       cif->rstruct_flag = 0;
353
354     while (count-- > 0)
355       {
356         switch ((cif->arg_types)[index]->type)
357           {
358           case FFI_TYPE_FLOAT:
359           case FFI_TYPE_DOUBLE:
360             cif->flags += ((cif->arg_types)[index]->type << shift);
361             shift += FFI_FLAG_BITS;
362             break;
363
364           case FFI_TYPE_STRUCT:
365             cif->flags += calc_n32_struct_flags((cif->arg_types)[index],
366                                                 &shift);
367             break;
368
369           default:
370             shift += FFI_FLAG_BITS;
371           }
372
373         index++;
374       }
375
376   /* Set the return type flag */
377     switch (cif->rtype->type)
378       {
379       case FFI_TYPE_STRUCT:
380         {
381           if (struct_flags == 0)
382             {
383               /* The structure is returned through a hidden
384                  first argument. Do nothing, 'cause FFI_TYPE_VOID 
385                  is 0 */
386             }
387           else
388             {
389               /* The structure is returned via some tricky
390                  mechanism */
391               cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8);
392               cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8));
393             }
394           break;
395         }
396       
397       case FFI_TYPE_VOID:
398         /* Do nothing, 'cause FFI_TYPE_VOID is 0 */
399         break;
400         
401       case FFI_TYPE_FLOAT:
402       case FFI_TYPE_DOUBLE:
403         cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8);
404         break;
405         
406       default:
407         cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8);
408         break;
409       }
410   }
411 #endif
412   
413   return FFI_OK;
414 }
415
416 /* Low level routine for calling O32 functions */
417 extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), 
418                         extended_cif *, unsigned, 
419                         unsigned, unsigned *, void (*)());
420
421 /* Low level routine for calling N32 functions */
422 extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), 
423                         extended_cif *, unsigned, 
424                         unsigned, unsigned *, void (*)());
425
426 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
427 {
428   extended_cif ecif;
429
430   ecif.cif = cif;
431   ecif.avalue = avalue;
432   
433   /* If the return value is a struct and we don't have a return */
434   /* value address then we need to make one                     */
435   
436   if ((rvalue == NULL) && 
437       (cif->rtype->type == FFI_TYPE_STRUCT))
438     ecif.rvalue = alloca(cif->rtype->size);
439   else
440     ecif.rvalue = rvalue;
441     
442   switch (cif->abi) 
443     {
444 #if _MIPS_SIM == _ABIO32
445     case FFI_O32:
446       ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, 
447                    cif->flags, ecif.rvalue, fn);
448       break;
449 #endif
450
451 #if _MIPS_SIM == _ABIN32
452     case FFI_N32:
453       ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, 
454                    cif->flags, ecif.rvalue, fn);
455       break;
456 #endif
457
458     default:
459       FFI_ASSERT(0);
460       break;
461     }
462 }