1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 1998, 2001, 2007 Red Hat, Inc.
4 Alpha Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
27 #include <ffi_common.h>
30 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
31 all further uses in this file will refer to the 128-bit type. */
32 #if defined(__LONG_DOUBLE_128__)
33 # if FFI_TYPE_LONGDOUBLE != 4
34 # error FFI_TYPE_LONGDOUBLE out of date
37 # undef FFI_TYPE_LONGDOUBLE
38 # define FFI_TYPE_LONGDOUBLE 4
41 extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)())
43 extern void ffi_closure_osf(void) FFI_HIDDEN;
47 ffi_prep_cif_machdep(ffi_cif *cif)
49 /* Adjust cif->bytes to represent a minimum 6 words for the temporary
50 register argument loading area. */
51 if (cif->bytes < 6*FFI_SIZEOF_ARG)
52 cif->bytes = 6*FFI_SIZEOF_ARG;
54 /* Set the return type flag */
55 switch (cif->rtype->type)
60 cif->flags = cif->rtype->type;
63 case FFI_TYPE_LONGDOUBLE:
64 /* 128-bit long double is returned in memory, like a struct. */
65 cif->flags = FFI_TYPE_STRUCT;
69 cif->flags = FFI_TYPE_INT;
78 ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
80 unsigned long *stack, *argp;
84 /* If the return value is a struct and we don't have a return
85 value address then we need to make one. */
86 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT)
87 rvalue = alloca(cif->rtype->size);
89 /* Allocate the space for the arguments, plus 4 words of temp
90 space for ffi_call_osf. */
91 argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
93 if (cif->flags == FFI_TYPE_STRUCT)
94 *(void **) argp++ = rvalue;
98 arg_types = cif->arg_types;
102 size_t size = (*arg_types)->size;
104 switch ((*arg_types)->type)
107 *(SINT64 *) argp = *(SINT8 *)(* avalue);
111 *(SINT64 *) argp = *(UINT8 *)(* avalue);
114 case FFI_TYPE_SINT16:
115 *(SINT64 *) argp = *(SINT16 *)(* avalue);
118 case FFI_TYPE_UINT16:
119 *(SINT64 *) argp = *(UINT16 *)(* avalue);
122 case FFI_TYPE_SINT32:
123 case FFI_TYPE_UINT32:
124 /* Note that unsigned 32-bit quantities are sign extended. */
125 *(SINT64 *) argp = *(SINT32 *)(* avalue);
128 case FFI_TYPE_SINT64:
129 case FFI_TYPE_UINT64:
130 case FFI_TYPE_POINTER:
131 *(UINT64 *) argp = *(UINT64 *)(* avalue);
135 if (argp - stack < 6)
137 /* Note the conversion -- all the fp regs are loaded as
138 doubles. The in-register format is the same. */
139 *(double *) argp = *(float *)(* avalue);
142 *(float *) argp = *(float *)(* avalue);
145 case FFI_TYPE_DOUBLE:
146 *(double *) argp = *(double *)(* avalue);
149 case FFI_TYPE_LONGDOUBLE:
150 /* 128-bit long double is passed by reference. */
151 *(long double **) argp = (long double *)(* avalue);
152 size = sizeof (long double *);
155 case FFI_TYPE_STRUCT:
156 memcpy(argp, *avalue, (*arg_types)->size);
163 argp += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
164 i++, arg_types++, avalue++;
167 ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn);
172 ffi_prep_closure_loc (ffi_closure* closure,
174 void (*fun)(ffi_cif*, void*, void**, void*),
180 tramp = (unsigned int *) &closure->tramp[0];
181 tramp[0] = 0x47fb0401; /* mov $27,$1 */
182 tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
183 tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
184 tramp[3] = 0x47ff041f; /* nop */
185 *(void **) &tramp[4] = ffi_closure_osf;
189 closure->user_data = user_data;
193 Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
194 instead, since both Compaq as and gas can handle it.
196 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
197 asm volatile ("call_pal 0x86" : : : "memory");
204 ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp)
208 ffi_type **arg_types;
212 avalue = alloca(cif->nargs * sizeof(void *));
216 /* Copy the caller's structure return address to that the closure
217 returns the data directly to the caller. */
218 if (cif->flags == FFI_TYPE_STRUCT)
220 rvalue = (void *) argp[0];
226 arg_types = cif->arg_types;
228 /* Grab the addresses of the arguments from the stack frame. */
231 size_t size = arg_types[i]->size;
233 switch (arg_types[i]->type)
237 case FFI_TYPE_SINT16:
238 case FFI_TYPE_UINT16:
239 case FFI_TYPE_SINT32:
240 case FFI_TYPE_UINT32:
241 case FFI_TYPE_SINT64:
242 case FFI_TYPE_UINT64:
243 case FFI_TYPE_POINTER:
244 case FFI_TYPE_STRUCT:
245 avalue[i] = &argp[argn];
251 /* Floats coming from registers need conversion from double
252 back to float format. */
253 *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6];
254 avalue[i] = &argp[argn - 6];
257 avalue[i] = &argp[argn];
260 case FFI_TYPE_DOUBLE:
261 avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)];
264 case FFI_TYPE_LONGDOUBLE:
265 /* 128-bit long double is passed by reference. */
266 avalue[i] = (long double *) argp[argn];
267 size = sizeof (long double *);
274 argn += ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
278 /* Invoke the closure. */
279 closure->fun (cif, rvalue, avalue, closure->user_data);
281 /* Tell ffi_closure_osf how to perform return type promotions. */
282 return cif->rtype->type;