OSDN Git Service

Initial Contribution
[android-x86/external-libffi.git] / src / m32r / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2004  Renesas Technology
3    
4    M32R 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 RENESAS TECHNOLOGY 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
32    space has been allocated for the function's arguments.  */
33
34 void ffi_prep_args(char *stack, extended_cif *ecif)
35 {
36   unsigned int i;
37   int tmp;
38   unsigned int avn;
39   void **p_argv;
40   char *argp;
41   ffi_type **p_arg;
42
43   tmp = 0;
44   argp = stack;
45
46   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8)
47     {
48       *(void **) argp = ecif->rvalue;
49       argp += 4;
50     }
51
52   avn = ecif->cif->nargs;
53   p_argv = ecif->avalue;
54
55   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
56        (i != 0) && (avn != 0);
57        i--, p_arg++)
58     {
59       size_t z;
60
61       /* Align if necessary.  */
62       if (((*p_arg)->alignment - 1) & (unsigned) argp)
63         argp = (char *) ALIGN (argp, (*p_arg)->alignment);
64
65       if (avn != 0) 
66         {
67           avn--;
68           z = (*p_arg)->size;
69           if (z < sizeof (int))
70             {
71               z = sizeof (int);
72
73               switch ((*p_arg)->type)
74                 {
75                 case FFI_TYPE_SINT8:
76                   *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
77                   break;
78                   
79                 case FFI_TYPE_UINT8:
80                   *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
81                   break;
82                   
83                 case FFI_TYPE_SINT16:
84                   *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
85                   break;
86                   
87                 case FFI_TYPE_UINT16:
88                   *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
89                   break;
90                   
91                 case FFI_TYPE_STRUCT:
92                   z = (*p_arg)->size;
93                   if ((*p_arg)->alignment != 1)
94                     memcpy (argp, *p_argv, z);
95                   else
96                     memcpy (argp + 4 - z, *p_argv, z);
97                   z = sizeof (int);
98                   break;
99
100                 default:
101                   FFI_ASSERT(0);
102                 }
103             }
104           else if (z == sizeof (int))
105             {
106                *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
107             }
108           else
109             {
110               if ((*p_arg)->type == FFI_TYPE_STRUCT)
111                 {
112                   if (z > 8)
113                     {
114                       *(unsigned int *) argp = (unsigned int)(void *)(* p_argv);
115                       z = sizeof(void *);
116                     }
117                   else
118                     {
119                       memcpy(argp, *p_argv, z);
120                       z = 8;
121                     }
122                 }
123               else
124                 {
125                   /* Double or long long 64bit.  */
126                   memcpy (argp, *p_argv, z);
127                 }
128             }
129           p_argv++;
130           argp += z;
131         }
132     }
133   
134   return;
135 }
136
137 /* Perform machine dependent cif processing.  */
138 ffi_status
139 ffi_prep_cif_machdep(ffi_cif *cif)
140 {
141   /* Set the return type flag.  */
142   switch (cif->rtype->type)
143     {
144     case FFI_TYPE_VOID:
145       cif->flags = (unsigned) cif->rtype->type;
146       break;
147
148     case FFI_TYPE_STRUCT:
149       if (cif->rtype->size <= 4)
150         cif->flags = FFI_TYPE_INT;
151
152       else if (cif->rtype->size <= 8)
153         cif->flags = FFI_TYPE_DOUBLE;
154
155       else
156         cif->flags = (unsigned) cif->rtype->type;
157       break;
158
159     case FFI_TYPE_SINT64:
160     case FFI_TYPE_UINT64:
161     case FFI_TYPE_DOUBLE:
162       cif->flags = FFI_TYPE_DOUBLE;
163       break;
164
165     case FFI_TYPE_FLOAT:
166     default:
167       cif->flags = FFI_TYPE_INT;
168       break;
169     }
170
171   return FFI_OK;
172 }
173
174 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
175                           unsigned, unsigned, unsigned *, void (*fn)());
176
177 void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
178 {
179   extended_cif ecif;
180
181   ecif.cif = cif;
182   ecif.avalue = avalue;
183   
184   /* If the return value is a struct and we don't have
185      a return value address then we need to make one.  */
186   if ((rvalue == NULL) && 
187       (cif->rtype->type == FFI_TYPE_STRUCT))
188     {
189       ecif.rvalue = alloca (cif->rtype->size);
190     }
191   else
192     ecif.rvalue = rvalue;    
193   
194   switch (cif->abi) 
195     {
196     case FFI_SYSV:
197       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 
198                     cif->flags, ecif.rvalue, fn);
199       if (cif->rtype->type == FFI_TYPE_STRUCT)
200         {
201           int size = cif->rtype->size;
202           int align = cif->rtype->alignment;
203
204           if (size < 4)
205             {
206               if (align == 1)
207                 *(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8;
208             }
209           else if (4 < size && size < 8)
210             {
211               if (align == 1)
212                 {
213                   memcpy (ecif.rvalue, ecif.rvalue + 8-size, size);
214                 }
215               else if (align == 2)
216                 {
217                   if (size & 1)
218                     size += 1;
219
220                   if (size != 8)
221                     memcpy (ecif.rvalue, ecif.rvalue + 8-size, size);
222                 }
223             }
224         }
225       break;
226
227     default:
228       FFI_ASSERT(0);
229       break;
230     }
231 }