OSDN Git Service

f557013a4b4afdd29850376372ec8272550ac3b0
[pf3gnuchains/gcc-fork.git] / libffi / src / sparc / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1996 Cygnus Solutions
3    
4    Sparc 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 <ffi.h>
27 #include <ffi_common.h>
28
29 #include <stdlib.h>
30
31 /* ffi_prep_args is called by the assembly routine once stack space
32    has been allocated for the function's arguments */
33
34 void ffi_prep_args_v8(char *stack, extended_cif *ecif)
35 {
36   int i;
37   int tmp;
38   int avn;
39   void **p_argv;
40   char *argp;
41   ffi_type **p_arg;
42
43   tmp = 0;
44
45   /* Skip 16 words for the window save area */
46   argp = stack + 16*sizeof(int);
47
48   /* This should only really be done when we are returning a structure,
49      however, it's faster just to do it all the time...
50
51   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
52   *(int *) argp = (long)ecif->rvalue;
53
54   /* And 1 word for the  structure return value. */
55   argp += sizeof(int);
56
57 #ifdef USING_PURIFY
58   /* Purify will probably complain in our assembly routine, unless we
59      zero out this memory. */
60
61   ((int*)argp)[0] = 0;
62   ((int*)argp)[1] = 0;
63   ((int*)argp)[2] = 0;
64   ((int*)argp)[3] = 0;
65   ((int*)argp)[4] = 0;
66   ((int*)argp)[5] = 0;
67 #endif
68
69   avn = ecif->cif->nargs;
70   p_argv = ecif->avalue;
71
72   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
73        i && avn;
74        i--, p_arg++)
75     {
76       size_t z;
77
78       if (avn) 
79         {
80           avn--;
81           if ((*p_arg)->type == FFI_TYPE_STRUCT
82 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
83               || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
84 #endif
85               )
86             {
87               *(unsigned int *) argp = (unsigned long)(* p_argv);
88               z = sizeof(int);
89             }
90           else
91             {
92               z = (*p_arg)->size;
93               if (z < sizeof(int))
94                 {
95                   z = sizeof(int);
96                   switch ((*p_arg)->type)
97                     {
98                     case FFI_TYPE_SINT8:
99                       *(signed int *) argp = *(SINT8 *)(* p_argv);
100                       break;
101                       
102                     case FFI_TYPE_UINT8:
103                       *(unsigned int *) argp = *(UINT8 *)(* p_argv);
104                       break;
105                       
106                     case FFI_TYPE_SINT16:
107                       *(signed int *) argp = *(SINT16 *)(* p_argv);
108                       break;
109                       
110                     case FFI_TYPE_UINT16:
111                       *(unsigned int *) argp = *(UINT16 *)(* p_argv);
112                       break;
113
114                     default:
115                       FFI_ASSERT(0);
116                     }
117                 }
118               else
119                 {
120                   memcpy(argp, *p_argv, z);
121                 }
122             }
123           p_argv++;
124           argp += z;
125         }
126     }
127   
128   return;
129 }
130
131 int ffi_prep_args_v9(char *stack, extended_cif *ecif)
132 {
133   int i, ret = 0;
134   int tmp;
135   void **p_argv;
136   char *argp;
137   ffi_type **p_arg;
138
139   tmp = 0;
140
141   /* Skip 16 words for the window save area */
142   argp = stack + 16*sizeof(long long);
143
144 #ifdef USING_PURIFY
145   /* Purify will probably complain in our assembly routine, unless we
146      zero out this memory. */
147
148   ((long long*)argp)[0] = 0;
149   ((long long*)argp)[1] = 0;
150   ((long long*)argp)[2] = 0;
151   ((long long*)argp)[3] = 0;
152   ((long long*)argp)[4] = 0;
153   ((long long*)argp)[5] = 0;
154 #endif
155
156   p_argv = ecif->avalue;
157
158   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
159       ecif->cif->rtype->size > 32)
160     {
161       *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
162       tmp = 1;
163     }
164
165   for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
166        i++, p_arg++)
167     {
168       size_t z;
169
170       z = (*p_arg)->size;
171       switch ((*p_arg)->type)
172         {
173         case FFI_TYPE_STRUCT:
174           if (z > 16)
175             {
176               /* For structures larger than 16 bytes we pass reference.  */
177               *(unsigned long long *) argp = (unsigned long)* p_argv;
178               argp += sizeof(long long);
179               tmp++;
180               p_argv++;
181               continue;
182             }
183           /* FALLTHROUGH */
184         case FFI_TYPE_FLOAT:
185         case FFI_TYPE_DOUBLE:
186 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
187         case FFI_TYPE_LONGDOUBLE:
188 #endif
189           ret = 1; /* We should promote into FP regs as well as integer.  */
190           break;
191         }
192       if (z < sizeof(long long))
193         {
194           switch ((*p_arg)->type)
195             {
196             case FFI_TYPE_SINT8:
197               *(signed long long *) argp = *(SINT8 *)(* p_argv);
198               break;
199
200             case FFI_TYPE_UINT8:
201               *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
202               break;
203
204             case FFI_TYPE_SINT16:
205               *(signed long long *) argp = *(SINT16 *)(* p_argv);
206               break;
207
208             case FFI_TYPE_UINT16:
209               *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
210               break;
211
212             case FFI_TYPE_SINT32:
213               *(signed long long *) argp = *(SINT32 *)(* p_argv);
214               break;
215
216             case FFI_TYPE_UINT32:
217               *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
218               break;
219
220             case FFI_TYPE_FLOAT:
221               *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
222               break;
223
224             case FFI_TYPE_STRUCT:
225               memcpy(argp, *p_argv, z);
226               break;
227
228             default:
229               FFI_ASSERT(0);
230             }
231           z = sizeof(long long);
232           tmp++;
233         }
234       else if (z == sizeof(long long))
235         {
236           memcpy(argp, *p_argv, z);
237           z = sizeof(long long);
238           tmp++;
239         }
240       else
241         {
242           if ((tmp & 1) && (*p_arg)->alignment > 8)
243             {
244               tmp++;
245               argp += sizeof(long long);
246             }
247           memcpy(argp, *p_argv, z);
248           z = 2 * sizeof(long long);
249           tmp += 2;
250         }
251       p_argv++;
252       argp += z;
253     }
254
255   return ret;
256 }
257
258 /* Perform machine dependent cif processing */
259 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
260 {
261   int wordsize;
262
263   if (cif->abi != FFI_V9)
264     {
265       wordsize = 4;
266
267       /* If we are returning a struct, this will already have been added.
268          Otherwise we need to add it because it's always got to be there! */
269
270       if (cif->rtype->type != FFI_TYPE_STRUCT)
271         cif->bytes += wordsize;
272
273       /* sparc call frames require that space is allocated for 6 args,
274          even if they aren't used. Make that space if necessary. */
275   
276       if (cif->bytes < 4*6+4)
277         cif->bytes = 4*6+4;
278     }
279   else
280     {
281       wordsize = 8;
282
283       /* sparc call frames require that space is allocated for 6 args,
284          even if they aren't used. Make that space if necessary. */
285   
286       if (cif->bytes < 8*6)
287         cif->bytes = 8*6;
288     }
289
290   /* Adjust cif->bytes. to include 16 words for the window save area,
291      and maybe the struct/union return pointer area, */
292
293   cif->bytes += 16 * wordsize;
294
295   /* The stack must be 2 word aligned, so round bytes up
296      appropriately. */
297
298   cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
299
300   /* Set the return type flag */
301   switch (cif->rtype->type)
302     {
303     case FFI_TYPE_VOID:
304     case FFI_TYPE_FLOAT:
305     case FFI_TYPE_DOUBLE:
306 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
307     case FFI_TYPE_LONGDOUBLE:
308 #endif
309       cif->flags = cif->rtype->type;
310       break;
311
312     case FFI_TYPE_STRUCT:
313       if (cif->abi == FFI_V9 && cif->rtype->size > 32)
314         cif->flags = FFI_TYPE_VOID;
315       else
316         cif->flags = FFI_TYPE_STRUCT;
317       break;
318
319     case FFI_TYPE_SINT64:
320     case FFI_TYPE_UINT64:
321       if (cif->abi != FFI_V9)
322         {
323           cif->flags = FFI_TYPE_SINT64;
324           break;
325         }
326       /* FALLTHROUGH */
327     default:
328       cif->flags = FFI_TYPE_INT;
329       break;
330     }
331   return FFI_OK;
332 }
333
334 int ffi_V9_return_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
335 {
336   ffi_type **ptr = &arg->elements[0];
337
338   while (*ptr != NULL)
339     {
340       if (off & ((*ptr)->alignment - 1))
341         off = ALIGN(off, (*ptr)->alignment);
342
343       switch ((*ptr)->type)
344         {
345         case FFI_TYPE_STRUCT:
346           off = ffi_V9_return_struct(*ptr, off, ret, intg, flt);
347           break;
348         case FFI_TYPE_FLOAT:
349         case FFI_TYPE_DOUBLE:
350 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
351         case FFI_TYPE_LONGDOUBLE:
352 #endif
353           memcpy(ret + off, flt + off, (*ptr)->size);
354           off += (*ptr)->size;
355           break;
356         default:
357           memcpy(ret + off, intg + off, (*ptr)->size);
358           off += (*ptr)->size;
359           break;
360         }
361       ptr++;
362     }
363   return off;
364 }
365
366 extern int ffi_call_V8(void *, extended_cif *, unsigned, 
367                        unsigned, unsigned *, void (*fn)());
368 extern int ffi_call_V9(void *, extended_cif *, unsigned, 
369                        unsigned, unsigned *, void (*fn)());
370
371 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
372 {
373   extended_cif ecif;
374   void *rval = rvalue;
375
376   ecif.cif = cif;
377   ecif.avalue = avalue;
378
379   /* If the return value is a struct and we don't have a return */
380   /* value address then we need to make one                     */
381
382   ecif.rvalue = rvalue;
383   if (cif->rtype->type == FFI_TYPE_STRUCT)
384     {
385       if (cif->rtype->size <= 32)
386         rval = alloca(64);
387       else
388         {
389           rval = NULL;
390           if (rvalue == NULL)
391             ecif.rvalue = alloca(cif->rtype->size);
392         }
393     }
394
395   switch (cif->abi) 
396     {
397     case FFI_V8:
398 #ifdef SPARC64
399       /* We don't yet support calling 32bit code from 64bit */
400       FFI_ASSERT(0);
401 #else
402       ffi_call_V8(ffi_prep_args_v8, &ecif, cif->bytes, 
403                   cif->flags, rvalue, fn);
404 #endif
405       break;
406     case FFI_V9:
407 #ifdef SPARC64
408       ffi_call_V9(ffi_prep_args_v9, &ecif, cif->bytes,
409                   cif->flags, rval, fn);
410       if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
411         ffi_V9_return_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
412 #else
413       /* And vice versa */
414       FFI_ASSERT(0);
415 #endif
416       break;
417     default:
418       FFI_ASSERT(0);
419       break;
420     }
421
422 }