OSDN Git Service

Code drop from //branches/cupcake/...@124589
[android-x86/external-libffi.git] / src / sh64 / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2003, 2004 Kaz Kojima
3            Copyright (c) 2008 Anthony Green
4    
5    SuperH SHmedia Foreign Function Interface 
6
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:
14
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
17
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    ----------------------------------------------------------------------- */
27
28 #include <ffi.h>
29 #include <ffi_common.h>
30
31 #include <stdlib.h>
32
33 #define NGREGARG 8
34 #define NFREGARG 12
35
36 static int
37 return_type (ffi_type *arg)
38 {
39
40   if (arg->type != FFI_TYPE_STRUCT)
41     return arg->type;
42
43   /* gcc uses r2 if the result can be packed in on register.  */
44   if (arg->size <= sizeof (UINT8))
45     return FFI_TYPE_UINT8;
46   else if (arg->size <= sizeof (UINT16))
47     return FFI_TYPE_UINT16;
48   else if (arg->size <= sizeof (UINT32))
49     return FFI_TYPE_UINT32;
50   else if (arg->size <= sizeof (UINT64))
51     return FFI_TYPE_UINT64;
52
53   return FFI_TYPE_STRUCT;
54 }
55
56 /* ffi_prep_args is called by the assembly routine once stack space
57    has been allocated for the function's arguments */
58
59 /*@-exportheader@*/
60 void ffi_prep_args(char *stack, extended_cif *ecif)
61 /*@=exportheader@*/
62 {
63   register unsigned int i;
64   register unsigned int avn;
65   register void **p_argv;
66   register char *argp;
67   register ffi_type **p_arg;
68
69   argp = stack;
70
71   if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
72     {
73       *(void **) argp = ecif->rvalue;
74       argp += sizeof (UINT64);
75     }
76
77   avn = ecif->cif->nargs;
78   p_argv = ecif->avalue;
79
80   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
81     {
82       size_t z;
83       int align;
84
85       z = (*p_arg)->size;
86       align = (*p_arg)->alignment;
87       if (z < sizeof (UINT32))
88         {
89           switch ((*p_arg)->type)
90             {
91             case FFI_TYPE_SINT8:
92               *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
93               break;
94   
95             case FFI_TYPE_UINT8:
96               *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
97               break;
98   
99             case FFI_TYPE_SINT16:
100               *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
101               break;
102   
103             case FFI_TYPE_UINT16:
104               *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
105               break;
106   
107             case FFI_TYPE_STRUCT:
108               memcpy (argp, *p_argv, z);
109               break;
110
111             default:
112               FFI_ASSERT(0);
113             }
114           argp += sizeof (UINT64);
115         }
116       else if (z == sizeof (UINT32) && align == sizeof (UINT32))
117         {
118           switch ((*p_arg)->type)
119             {
120             case FFI_TYPE_INT:
121             case FFI_TYPE_SINT32:
122               *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
123               break;
124
125             case FFI_TYPE_FLOAT:
126             case FFI_TYPE_POINTER:
127             case FFI_TYPE_UINT32:
128             case FFI_TYPE_STRUCT:
129               *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
130               break;
131
132             default:
133               FFI_ASSERT(0);
134               break;
135             }
136           argp += sizeof (UINT64);
137         }
138       else if (z == sizeof (UINT64)
139                && align == sizeof (UINT64)
140                && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
141         {
142           *(UINT64 *) argp = *(UINT64 *) (*p_argv);
143           argp += sizeof (UINT64);
144         }
145       else
146         {
147           int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
148
149           memcpy (argp, *p_argv, z);
150           argp += n * sizeof (UINT64);
151         }
152     }
153
154   return;
155 }
156
157 /* Perform machine dependent cif processing */
158 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
159 {
160   int i, j;
161   int size, type;
162   int n, m;
163   int greg;
164   int freg;
165
166   greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
167   freg = 0;
168   cif->flags2 = 0;
169
170   for (i = j = 0; i < cif->nargs; i++)
171     {
172       type = (cif->arg_types)[i]->type;
173       switch (type)
174         {
175         case FFI_TYPE_FLOAT:
176           greg++;
177           cif->bytes += sizeof (UINT64) - sizeof (float);
178           if (freg >= NFREGARG - 1)
179             continue;
180           freg++;
181           cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
182           break;
183
184         case FFI_TYPE_DOUBLE:
185           if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
186             continue;
187           if ((freg + 1) < NFREGARG)
188             {
189               freg = (freg + 1) & ~1;
190               freg += 2;
191               cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
192             }
193           else
194             cif->flags2 += FFI_TYPE_INT << (2 * j++);
195           break;
196               
197         default:
198           size = (cif->arg_types)[i]->size;
199           if (size < sizeof (UINT64))
200             cif->bytes += sizeof (UINT64) - size;
201           n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
202           if (greg >= NGREGARG)
203             continue;
204           else if (greg + n - 1 >= NGREGARG)
205             greg = NGREGARG;
206           else
207             greg += n;
208           for (m = 0; m < n; m++)
209             cif->flags2 += FFI_TYPE_INT << (2 * j++);
210           break;
211         }
212     }
213
214   /* Set the return type flag */
215   switch (cif->rtype->type)
216     {
217     case FFI_TYPE_STRUCT:
218       cif->flags = return_type (cif->rtype);
219       break;
220
221     case FFI_TYPE_VOID:
222     case FFI_TYPE_FLOAT:
223     case FFI_TYPE_DOUBLE:
224     case FFI_TYPE_SINT64:
225     case FFI_TYPE_UINT64:
226       cif->flags = 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 /*@-declundef@*/
238 /*@-exportheader@*/
239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 
240                           /*@out@*/ extended_cif *, 
241                           unsigned, unsigned, long long,
242                           /*@out@*/ unsigned *, 
243                           void (*fn)(void));
244 /*@=declundef@*/
245 /*@=exportheader@*/
246
247 void ffi_call(/*@dependent@*/ ffi_cif *cif, 
248               void (*fn)(void), 
249               /*@out@*/ void *rvalue, 
250               /*@dependent@*/ void **avalue)
251 {
252   extended_cif ecif;
253   UINT64 trvalue;
254
255   ecif.cif = cif;
256   ecif.avalue = avalue;
257   
258   /* If the return value is a struct and we don't have a return */
259   /* value address then we need to make one                     */
260
261   if (cif->rtype->type == FFI_TYPE_STRUCT
262       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
263     ecif.rvalue = &trvalue;
264   else if ((rvalue == NULL) && 
265       (cif->rtype->type == FFI_TYPE_STRUCT))
266     {
267       /*@-sysunrecog@*/
268       ecif.rvalue = alloca(cif->rtype->size);
269       /*@=sysunrecog@*/
270     }
271   else
272     ecif.rvalue = rvalue;
273
274   switch (cif->abi) 
275     {
276     case FFI_SYSV:
277       /*@-usedef@*/
278       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
279                     cif->flags, cif->flags2, ecif.rvalue, fn);
280       /*@=usedef@*/
281       break;
282     default:
283       FFI_ASSERT(0);
284       break;
285     }
286
287   if (rvalue
288       && cif->rtype->type == FFI_TYPE_STRUCT
289       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290     memcpy (rvalue, &trvalue, cif->rtype->size);
291 }
292
293 extern void ffi_closure_SYSV (void);
294 extern void __ic_invalidate (void *line);
295
296 ffi_status
297 ffi_prep_closure (ffi_closure *closure,
298                   ffi_cif *cif,
299                   void (*fun)(ffi_cif*, void*, void**, void*),
300                   void *user_data)
301 {
302   unsigned int *tramp;
303
304   FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
305
306   tramp = (unsigned int *) &closure->tramp[0];
307   /* Since ffi_closure is an aligned object, the ffi trampoline is
308      called as an SHcompact code.  Sigh.
309      SHcompact part:
310      mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
311      SHmedia part:
312      movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
313      movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
314 #ifdef __LITTLE_ENDIAN__
315   tramp[0] = 0x7001c701;
316   tramp[1] = 0x0009402b;
317 #else
318   tramp[0] = 0xc7017001;
319   tramp[1] = 0x402b0009;
320 #endif
321   tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
322   tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
323   tramp[4] = 0x6bf10600;
324   tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
325   tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
326   tramp[7] = 0x4401fff0;
327
328   closure->cif = cif;
329   closure->fun = fun;
330   closure->user_data = user_data;
331
332   /* Flush the icache.  */
333   asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
334
335   return FFI_OK;
336 }
337
338 /* Basically the trampoline invokes ffi_closure_SYSV, and on 
339  * entry, r3 holds the address of the closure.
340  * After storing the registers that could possibly contain
341  * parameters to be passed into the stack frame and setting
342  * up space for a return value, ffi_closure_SYSV invokes the 
343  * following helper function to do most of the work.
344  */
345
346 int
347 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, 
348                          UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
349 {
350   void **avalue;
351   ffi_type **p_arg;
352   int i, avn;
353   int greg, freg;
354   ffi_cif *cif;
355
356   cif = closure->cif;
357   avalue = alloca (cif->nargs * sizeof (void *));
358
359   /* Copy the caller's structure return value address so that the closure
360      returns the data directly to the caller.  */
361   if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
362     {
363       rvalue = *pgr;
364       greg = 1;
365     }
366   else
367     greg = 0;
368
369   freg = 0;
370   cif = closure->cif;
371   avn = cif->nargs;
372
373   /* Grab the addresses of the arguments from the stack frame.  */
374   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
375     {
376       size_t z;
377       void *p;
378
379       z = (*p_arg)->size;
380       if (z < sizeof (UINT32))
381         {
382           p = pgr + greg++;
383
384           switch ((*p_arg)->type)
385             {
386             case FFI_TYPE_SINT8:
387             case FFI_TYPE_UINT8:
388             case FFI_TYPE_SINT16:
389             case FFI_TYPE_UINT16:
390             case FFI_TYPE_STRUCT:
391 #ifdef __LITTLE_ENDIAN__
392               avalue[i] = p;
393 #else
394               avalue[i] = ((char *) p) + sizeof (UINT32) - z;
395 #endif
396               break;
397
398             default:
399               FFI_ASSERT(0);
400             }
401         }
402       else if (z == sizeof (UINT32))
403         {
404           if ((*p_arg)->type == FFI_TYPE_FLOAT)
405             {
406               if (freg < NFREGARG - 1)
407 #ifdef __LITTLE_ENDIAN__
408                 avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
409 #else
410                 avalue[i] = (UINT32 *) pfr + freg++;
411 #endif
412               else
413 #ifdef __LITTLE_ENDIAN__
414                 avalue[i] = pgr + greg;
415 #else
416                 avalue[i] = (UINT32 *) (pgr + greg) + 1;
417 #endif
418             }
419           else
420 #ifdef __LITTLE_ENDIAN__
421             avalue[i] = pgr + greg;
422 #else
423             avalue[i] = (UINT32 *) (pgr + greg) + 1;
424 #endif
425           greg++;
426         }
427       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
428         {
429           if (freg + 1 >= NFREGARG)
430             avalue[i] = pgr + greg;
431           else
432             {
433               freg = (freg + 1) & ~1;
434               avalue[i] = pfr + (freg >> 1);
435               freg += 2;
436             }
437           greg++;
438         }
439       else
440         {
441           int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
442
443           avalue[i] = pgr + greg;
444           greg += n;
445         }
446     }
447
448   (closure->fun) (cif, rvalue, avalue, closure->user_data);
449
450   /* Tell ffi_closure_SYSV how to perform return type promotions.  */
451   return return_type (cif->rtype);
452 }
453