PR c++/5247
[official-gcc.git] / libffi / src / m68k / ffi.c
blob600cf20527ff9d1c81fb5c9ad8010e8d82a88c03
1 /* -----------------------------------------------------------------------
2 ffi.c
4 m68k Foreign Function Interface
5 ----------------------------------------------------------------------- */
7 #include <ffi.h>
8 #include <ffi_common.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/syscall.h>
13 #include <asm/cachectl.h>
15 void ffi_call_SYSV (extended_cif *,
16 unsigned, unsigned,
17 void *, void (*fn) ());
18 void *ffi_prep_args (void *stack, extended_cif *ecif);
19 void ffi_closure_SYSV (ffi_closure *);
20 void ffi_closure_struct_SYSV (ffi_closure *);
21 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
22 void *resp, void *args);
24 /* ffi_prep_args is called by the assembly routine once stack space has
25 been allocated for the function's arguments. */
27 void *
28 ffi_prep_args (void *stack, extended_cif *ecif)
30 unsigned int i;
31 void **p_argv;
32 char *argp;
33 ffi_type **p_arg;
34 void *struct_value_ptr;
36 argp = stack;
38 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
39 && !ecif->cif->flags)
40 struct_value_ptr = ecif->rvalue;
41 else
42 struct_value_ptr = NULL;
44 p_argv = ecif->avalue;
46 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
47 i != 0;
48 i--, p_arg++)
50 size_t z;
52 z = (*p_arg)->size;
53 if (z < sizeof (int))
55 switch ((*p_arg)->type)
57 case FFI_TYPE_SINT8:
58 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
59 break;
61 case FFI_TYPE_UINT8:
62 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
63 break;
65 case FFI_TYPE_SINT16:
66 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
67 break;
69 case FFI_TYPE_UINT16:
70 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
71 break;
73 case FFI_TYPE_STRUCT:
74 memcpy (argp + sizeof (int) - z, *p_argv, z);
75 break;
77 default:
78 FFI_ASSERT (0);
80 z = sizeof (int);
82 else
84 memcpy (argp, *p_argv, z);
86 /* Align if necessary. */
87 if ((sizeof(int) - 1) & z)
88 z = ALIGN(z, sizeof(int));
91 p_argv++;
92 argp += z;
95 return struct_value_ptr;
98 #define CIF_FLAGS_INT 1
99 #define CIF_FLAGS_DINT 2
100 #define CIF_FLAGS_FLOAT 4
101 #define CIF_FLAGS_DOUBLE 8
102 #define CIF_FLAGS_LDOUBLE 16
103 #define CIF_FLAGS_POINTER 32
104 #define CIF_FLAGS_STRUCT1 64
105 #define CIF_FLAGS_STRUCT2 128
107 /* Perform machine dependent cif processing */
108 ffi_status
109 ffi_prep_cif_machdep (ffi_cif *cif)
111 /* Set the return type flag */
112 switch (cif->rtype->type)
114 case FFI_TYPE_VOID:
115 cif->flags = 0;
116 break;
118 case FFI_TYPE_STRUCT:
119 switch (cif->rtype->size)
121 case 1:
122 cif->flags = CIF_FLAGS_STRUCT1;
123 break;
124 case 2:
125 cif->flags = CIF_FLAGS_STRUCT2;
126 break;
127 case 4:
128 cif->flags = CIF_FLAGS_INT;
129 break;
130 case 8:
131 cif->flags = CIF_FLAGS_DINT;
132 break;
133 default:
134 cif->flags = 0;
135 break;
137 break;
139 case FFI_TYPE_FLOAT:
140 cif->flags = CIF_FLAGS_FLOAT;
141 break;
143 case FFI_TYPE_DOUBLE:
144 cif->flags = CIF_FLAGS_DOUBLE;
145 break;
147 case FFI_TYPE_LONGDOUBLE:
148 cif->flags = CIF_FLAGS_LDOUBLE;
149 break;
151 case FFI_TYPE_POINTER:
152 cif->flags = CIF_FLAGS_POINTER;
153 break;
155 case FFI_TYPE_SINT64:
156 case FFI_TYPE_UINT64:
157 cif->flags = CIF_FLAGS_DINT;
158 break;
160 default:
161 cif->flags = CIF_FLAGS_INT;
162 break;
165 return FFI_OK;
168 void
169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
171 extended_cif ecif;
173 ecif.cif = cif;
174 ecif.avalue = avalue;
176 /* If the return value is a struct and we don't have a return value
177 address then we need to make one. */
179 if (rvalue == NULL
180 && cif->rtype->type == FFI_TYPE_STRUCT
181 && cif->rtype->size > 8)
182 ecif.rvalue = alloca (cif->rtype->size);
183 else
184 ecif.rvalue = rvalue;
186 switch (cif->abi)
188 case FFI_SYSV:
189 ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
190 ecif.rvalue, fn);
191 break;
193 default:
194 FFI_ASSERT (0);
195 break;
199 static void
200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
202 unsigned int i;
203 void **p_argv;
204 char *argp;
205 ffi_type **p_arg;
207 argp = stack;
208 p_argv = avalue;
210 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
212 size_t z;
214 z = (*p_arg)->size;
215 if (z <= 4)
217 *p_argv = (void *) (argp + 4 - z);
219 z = 4;
221 else
223 *p_argv = (void *) argp;
225 /* Align if necessary */
226 if ((sizeof(int) - 1) & z)
227 z = ALIGN(z, sizeof(int));
230 p_argv++;
231 argp += z;
235 unsigned int
236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
238 ffi_cif *cif;
239 void **arg_area;
241 cif = closure->cif;
242 arg_area = (void**) alloca (cif->nargs * sizeof (void *));
244 ffi_prep_incoming_args_SYSV(args, arg_area, cif);
246 (closure->fun) (cif, resp, arg_area, closure->user_data);
248 return cif->flags;
251 ffi_status
252 ffi_prep_closure_loc (ffi_closure* closure,
253 ffi_cif* cif,
254 void (*fun)(ffi_cif*,void*,void**,void*),
255 void *user_data,
256 void *codeloc)
258 FFI_ASSERT (cif->abi == FFI_SYSV);
260 *(unsigned short *)closure->tramp = 0x207c;
261 *(void **)(closure->tramp + 2) = codeloc;
262 *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
263 if (cif->rtype->type == FFI_TYPE_STRUCT
264 && !cif->flags)
265 *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
266 else
267 *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
269 syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
270 FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
272 closure->cif = cif;
273 closure->user_data = user_data;
274 closure->fun = fun;
276 return FFI_OK;