source: trunk/gcc/libffi/src/mips/ffi.c

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 10.6 KB
Line 
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 == _MIPS_SIM_NABI32
33#define FIX_ARGP \
34FFI_ASSERT(argp <= &stack[bytes]); \
35if (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
48static 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 == _MIPS_SIM_NABI32
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 == _MIPS_SIM_NABI32
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 == _MIPS_SIM_ABI32
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 == _MIPS_SIM_ABI32
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 == _MIPS_SIM_NABI32
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
189unsigned 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
214unsigned 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 */
266ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
267{
268 cif->flags = 0;
269
270#if _MIPS_SIM == _MIPS_SIM_ABI32
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 == _MIPS_SIM_NABI32
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 */
417extern 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 */
422extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int),
423 extended_cif *, unsigned,
424 unsigned, unsigned *, void (*)());
425
426void 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 == _MIPS_SIM_ABI32
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 == _MIPS_SIM_NABI32
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}
Note: See TracBrowser for help on using the repository browser.