1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2012 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc.
4*1fd5a2e1SPrashanth Swaminathan
5*1fd5a2e1SPrashanth Swaminathan Alpha Foreign Function Interface
6*1fd5a2e1SPrashanth Swaminathan
7*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
8*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
9*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
10*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
11*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
12*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
13*1fd5a2e1SPrashanth Swaminathan the following conditions:
14*1fd5a2e1SPrashanth Swaminathan
15*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
16*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
17*1fd5a2e1SPrashanth Swaminathan
18*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
26*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
27*1fd5a2e1SPrashanth Swaminathan
28*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
29*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
30*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
31*1fd5a2e1SPrashanth Swaminathan #include "internal.h"
32*1fd5a2e1SPrashanth Swaminathan
33*1fd5a2e1SPrashanth Swaminathan /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
34*1fd5a2e1SPrashanth Swaminathan all further uses in this file will refer to the 128-bit type. */
35*1fd5a2e1SPrashanth Swaminathan #if defined(__LONG_DOUBLE_128__)
36*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != 4
37*1fd5a2e1SPrashanth Swaminathan # error FFI_TYPE_LONGDOUBLE out of date
38*1fd5a2e1SPrashanth Swaminathan # endif
39*1fd5a2e1SPrashanth Swaminathan #else
40*1fd5a2e1SPrashanth Swaminathan # undef FFI_TYPE_LONGDOUBLE
41*1fd5a2e1SPrashanth Swaminathan # define FFI_TYPE_LONGDOUBLE 4
42*1fd5a2e1SPrashanth Swaminathan #endif
43*1fd5a2e1SPrashanth Swaminathan
44*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
45*1fd5a2e1SPrashanth Swaminathan void *raddr, void (*fn)(void), void *closure)
46*1fd5a2e1SPrashanth Swaminathan FFI_HIDDEN;
47*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_osf(void) FFI_HIDDEN;
48*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_osf(void) FFI_HIDDEN;
49*1fd5a2e1SPrashanth Swaminathan
50*1fd5a2e1SPrashanth Swaminathan /* Promote a float value to its in-register double representation.
51*1fd5a2e1SPrashanth Swaminathan Unlike actually casting to double, this does not trap on NaN. */
lds(void * ptr)52*1fd5a2e1SPrashanth Swaminathan static inline UINT64 lds(void *ptr)
53*1fd5a2e1SPrashanth Swaminathan {
54*1fd5a2e1SPrashanth Swaminathan UINT64 ret;
55*1fd5a2e1SPrashanth Swaminathan asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
56*1fd5a2e1SPrashanth Swaminathan return ret;
57*1fd5a2e1SPrashanth Swaminathan }
58*1fd5a2e1SPrashanth Swaminathan
59*1fd5a2e1SPrashanth Swaminathan /* And the reverse. */
sts(void * ptr,UINT64 val)60*1fd5a2e1SPrashanth Swaminathan static inline void sts(void *ptr, UINT64 val)
61*1fd5a2e1SPrashanth Swaminathan {
62*1fd5a2e1SPrashanth Swaminathan asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
63*1fd5a2e1SPrashanth Swaminathan }
64*1fd5a2e1SPrashanth Swaminathan
65*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)66*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep(ffi_cif *cif)
67*1fd5a2e1SPrashanth Swaminathan {
68*1fd5a2e1SPrashanth Swaminathan size_t bytes = 0;
69*1fd5a2e1SPrashanth Swaminathan int flags, i, avn;
70*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype, *itype;
71*1fd5a2e1SPrashanth Swaminathan
72*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_OSF)
73*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
74*1fd5a2e1SPrashanth Swaminathan
75*1fd5a2e1SPrashanth Swaminathan /* Compute the size of the argument area. */
76*1fd5a2e1SPrashanth Swaminathan for (i = 0, avn = cif->nargs; i < avn; i++)
77*1fd5a2e1SPrashanth Swaminathan {
78*1fd5a2e1SPrashanth Swaminathan itype = cif->arg_types[i];
79*1fd5a2e1SPrashanth Swaminathan switch (itype->type)
80*1fd5a2e1SPrashanth Swaminathan {
81*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
82*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
83*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
84*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
85*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
86*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
87*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
88*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
89*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
90*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
91*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
92*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
93*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
94*1fd5a2e1SPrashanth Swaminathan /* All take one 8 byte slot. */
95*1fd5a2e1SPrashanth Swaminathan bytes += 8;
96*1fd5a2e1SPrashanth Swaminathan break;
97*1fd5a2e1SPrashanth Swaminathan
98*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
99*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
100*1fd5a2e1SPrashanth Swaminathan /* Passed by value in N slots. */
101*1fd5a2e1SPrashanth Swaminathan bytes += FFI_ALIGN(itype->size, FFI_SIZEOF_ARG);
102*1fd5a2e1SPrashanth Swaminathan break;
103*1fd5a2e1SPrashanth Swaminathan
104*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
105*1fd5a2e1SPrashanth Swaminathan /* _Complex long double passed by reference; others in 2 slots. */
106*1fd5a2e1SPrashanth Swaminathan if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
107*1fd5a2e1SPrashanth Swaminathan bytes += 8;
108*1fd5a2e1SPrashanth Swaminathan else
109*1fd5a2e1SPrashanth Swaminathan bytes += 16;
110*1fd5a2e1SPrashanth Swaminathan break;
111*1fd5a2e1SPrashanth Swaminathan
112*1fd5a2e1SPrashanth Swaminathan default:
113*1fd5a2e1SPrashanth Swaminathan abort();
114*1fd5a2e1SPrashanth Swaminathan }
115*1fd5a2e1SPrashanth Swaminathan }
116*1fd5a2e1SPrashanth Swaminathan
117*1fd5a2e1SPrashanth Swaminathan /* Set the return type flag */
118*1fd5a2e1SPrashanth Swaminathan rtype = cif->rtype;
119*1fd5a2e1SPrashanth Swaminathan switch (rtype->type)
120*1fd5a2e1SPrashanth Swaminathan {
121*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
122*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
123*1fd5a2e1SPrashanth Swaminathan break;
124*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
125*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
126*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
127*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
128*1fd5a2e1SPrashanth Swaminathan break;
129*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
130*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
131*1fd5a2e1SPrashanth Swaminathan break;
132*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
133*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
134*1fd5a2e1SPrashanth Swaminathan break;
135*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
136*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
137*1fd5a2e1SPrashanth Swaminathan break;
138*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
139*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
140*1fd5a2e1SPrashanth Swaminathan break;
141*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
142*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
143*1fd5a2e1SPrashanth Swaminathan break;
144*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
145*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
146*1fd5a2e1SPrashanth Swaminathan break;
147*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
148*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
149*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
150*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
151*1fd5a2e1SPrashanth Swaminathan break;
152*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
153*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
154*1fd5a2e1SPrashanth Swaminathan /* Passed in memory, with a hidden pointer. */
155*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_RET_IN_MEM;
156*1fd5a2e1SPrashanth Swaminathan break;
157*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
158*1fd5a2e1SPrashanth Swaminathan itype = rtype->elements[0];
159*1fd5a2e1SPrashanth Swaminathan switch (itype->type)
160*1fd5a2e1SPrashanth Swaminathan {
161*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
162*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
163*1fd5a2e1SPrashanth Swaminathan break;
164*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
165*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
166*1fd5a2e1SPrashanth Swaminathan break;
167*1fd5a2e1SPrashanth Swaminathan default:
168*1fd5a2e1SPrashanth Swaminathan if (rtype->size <= 8)
169*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
170*1fd5a2e1SPrashanth Swaminathan else
171*1fd5a2e1SPrashanth Swaminathan flags = ALPHA_RET_IN_MEM;
172*1fd5a2e1SPrashanth Swaminathan break;
173*1fd5a2e1SPrashanth Swaminathan }
174*1fd5a2e1SPrashanth Swaminathan break;
175*1fd5a2e1SPrashanth Swaminathan default:
176*1fd5a2e1SPrashanth Swaminathan abort();
177*1fd5a2e1SPrashanth Swaminathan }
178*1fd5a2e1SPrashanth Swaminathan cif->flags = flags;
179*1fd5a2e1SPrashanth Swaminathan
180*1fd5a2e1SPrashanth Swaminathan /* Include the hidden structure pointer in args requirement. */
181*1fd5a2e1SPrashanth Swaminathan if (flags == ALPHA_RET_IN_MEM)
182*1fd5a2e1SPrashanth Swaminathan bytes += 8;
183*1fd5a2e1SPrashanth Swaminathan /* Minimum size is 6 slots, so that ffi_call_osf can pop them. */
184*1fd5a2e1SPrashanth Swaminathan if (bytes < 6*8)
185*1fd5a2e1SPrashanth Swaminathan bytes = 6*8;
186*1fd5a2e1SPrashanth Swaminathan cif->bytes = bytes;
187*1fd5a2e1SPrashanth Swaminathan
188*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
189*1fd5a2e1SPrashanth Swaminathan }
190*1fd5a2e1SPrashanth Swaminathan
191*1fd5a2e1SPrashanth Swaminathan static unsigned long
extend_basic_type(void * valp,int type,int argn)192*1fd5a2e1SPrashanth Swaminathan extend_basic_type(void *valp, int type, int argn)
193*1fd5a2e1SPrashanth Swaminathan {
194*1fd5a2e1SPrashanth Swaminathan switch (type)
195*1fd5a2e1SPrashanth Swaminathan {
196*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
197*1fd5a2e1SPrashanth Swaminathan return *(SINT8 *)valp;
198*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
199*1fd5a2e1SPrashanth Swaminathan return *(UINT8 *)valp;
200*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
201*1fd5a2e1SPrashanth Swaminathan return *(SINT16 *)valp;
202*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
203*1fd5a2e1SPrashanth Swaminathan return *(UINT16 *)valp;
204*1fd5a2e1SPrashanth Swaminathan
205*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
206*1fd5a2e1SPrashanth Swaminathan if (argn < 6)
207*1fd5a2e1SPrashanth Swaminathan return lds(valp);
208*1fd5a2e1SPrashanth Swaminathan /* FALLTHRU */
209*1fd5a2e1SPrashanth Swaminathan
210*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
211*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
212*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
213*1fd5a2e1SPrashanth Swaminathan /* Note that unsigned 32-bit quantities are sign extended. */
214*1fd5a2e1SPrashanth Swaminathan return *(SINT32 *)valp;
215*1fd5a2e1SPrashanth Swaminathan
216*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
217*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
218*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
219*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
220*1fd5a2e1SPrashanth Swaminathan return *(UINT64 *)valp;
221*1fd5a2e1SPrashanth Swaminathan
222*1fd5a2e1SPrashanth Swaminathan default:
223*1fd5a2e1SPrashanth Swaminathan abort();
224*1fd5a2e1SPrashanth Swaminathan }
225*1fd5a2e1SPrashanth Swaminathan }
226*1fd5a2e1SPrashanth Swaminathan
227*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)228*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
229*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
230*1fd5a2e1SPrashanth Swaminathan {
231*1fd5a2e1SPrashanth Swaminathan unsigned long *argp;
232*1fd5a2e1SPrashanth Swaminathan long i, avn, argn, flags = cif->flags;
233*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types;
234*1fd5a2e1SPrashanth Swaminathan void *frame;
235*1fd5a2e1SPrashanth Swaminathan
236*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return
237*1fd5a2e1SPrashanth Swaminathan value address then we need to make one. */
238*1fd5a2e1SPrashanth Swaminathan if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
239*1fd5a2e1SPrashanth Swaminathan rvalue = alloca(cif->rtype->size);
240*1fd5a2e1SPrashanth Swaminathan
241*1fd5a2e1SPrashanth Swaminathan /* Allocate the space for the arguments, plus 4 words of temp
242*1fd5a2e1SPrashanth Swaminathan space for ffi_call_osf. */
243*1fd5a2e1SPrashanth Swaminathan argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
244*1fd5a2e1SPrashanth Swaminathan frame += cif->bytes;
245*1fd5a2e1SPrashanth Swaminathan
246*1fd5a2e1SPrashanth Swaminathan argn = 0;
247*1fd5a2e1SPrashanth Swaminathan if (flags == ALPHA_RET_IN_MEM)
248*1fd5a2e1SPrashanth Swaminathan argp[argn++] = (unsigned long)rvalue;
249*1fd5a2e1SPrashanth Swaminathan
250*1fd5a2e1SPrashanth Swaminathan avn = cif->nargs;
251*1fd5a2e1SPrashanth Swaminathan arg_types = cif->arg_types;
252*1fd5a2e1SPrashanth Swaminathan
253*1fd5a2e1SPrashanth Swaminathan for (i = 0, avn = cif->nargs; i < avn; i++)
254*1fd5a2e1SPrashanth Swaminathan {
255*1fd5a2e1SPrashanth Swaminathan ffi_type *ty = arg_types[i];
256*1fd5a2e1SPrashanth Swaminathan void *valp = avalue[i];
257*1fd5a2e1SPrashanth Swaminathan int type = ty->type;
258*1fd5a2e1SPrashanth Swaminathan size_t size;
259*1fd5a2e1SPrashanth Swaminathan
260*1fd5a2e1SPrashanth Swaminathan switch (type)
261*1fd5a2e1SPrashanth Swaminathan {
262*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
263*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
264*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
265*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
266*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
267*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
268*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
269*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
270*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
271*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
272*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
273*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
274*1fd5a2e1SPrashanth Swaminathan argp[argn] = extend_basic_type(valp, type, argn);
275*1fd5a2e1SPrashanth Swaminathan argn++;
276*1fd5a2e1SPrashanth Swaminathan break;
277*1fd5a2e1SPrashanth Swaminathan
278*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
279*1fd5a2e1SPrashanth Swaminathan by_reference:
280*1fd5a2e1SPrashanth Swaminathan /* Note that 128-bit long double is passed by reference. */
281*1fd5a2e1SPrashanth Swaminathan argp[argn++] = (unsigned long)valp;
282*1fd5a2e1SPrashanth Swaminathan break;
283*1fd5a2e1SPrashanth Swaminathan
284*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
285*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
286*1fd5a2e1SPrashanth Swaminathan size = ty->size;
287*1fd5a2e1SPrashanth Swaminathan memcpy(argp + argn, valp, size);
288*1fd5a2e1SPrashanth Swaminathan argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
289*1fd5a2e1SPrashanth Swaminathan break;
290*1fd5a2e1SPrashanth Swaminathan
291*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
292*1fd5a2e1SPrashanth Swaminathan type = ty->elements[0]->type;
293*1fd5a2e1SPrashanth Swaminathan if (type == FFI_TYPE_LONGDOUBLE)
294*1fd5a2e1SPrashanth Swaminathan goto by_reference;
295*1fd5a2e1SPrashanth Swaminathan
296*1fd5a2e1SPrashanth Swaminathan /* Most complex types passed as two separate arguments. */
297*1fd5a2e1SPrashanth Swaminathan size = ty->elements[0]->size;
298*1fd5a2e1SPrashanth Swaminathan argp[argn] = extend_basic_type(valp, type, argn);
299*1fd5a2e1SPrashanth Swaminathan argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
300*1fd5a2e1SPrashanth Swaminathan argn += 2;
301*1fd5a2e1SPrashanth Swaminathan break;
302*1fd5a2e1SPrashanth Swaminathan
303*1fd5a2e1SPrashanth Swaminathan default:
304*1fd5a2e1SPrashanth Swaminathan abort();
305*1fd5a2e1SPrashanth Swaminathan }
306*1fd5a2e1SPrashanth Swaminathan }
307*1fd5a2e1SPrashanth Swaminathan
308*1fd5a2e1SPrashanth Swaminathan flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
309*1fd5a2e1SPrashanth Swaminathan ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
310*1fd5a2e1SPrashanth Swaminathan }
311*1fd5a2e1SPrashanth Swaminathan
312*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)313*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
314*1fd5a2e1SPrashanth Swaminathan {
315*1fd5a2e1SPrashanth Swaminathan ffi_call_int(cif, fn, rvalue, avalue, NULL);
316*1fd5a2e1SPrashanth Swaminathan }
317*1fd5a2e1SPrashanth Swaminathan
318*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)319*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
320*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
321*1fd5a2e1SPrashanth Swaminathan {
322*1fd5a2e1SPrashanth Swaminathan ffi_call_int(cif, fn, rvalue, avalue, closure);
323*1fd5a2e1SPrashanth Swaminathan }
324*1fd5a2e1SPrashanth Swaminathan
325*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)326*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
327*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
328*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
329*1fd5a2e1SPrashanth Swaminathan void *user_data,
330*1fd5a2e1SPrashanth Swaminathan void *codeloc)
331*1fd5a2e1SPrashanth Swaminathan {
332*1fd5a2e1SPrashanth Swaminathan unsigned int *tramp;
333*1fd5a2e1SPrashanth Swaminathan
334*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_OSF)
335*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
336*1fd5a2e1SPrashanth Swaminathan
337*1fd5a2e1SPrashanth Swaminathan tramp = (unsigned int *) &closure->tramp[0];
338*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0x47fb0401; /* mov $27,$1 */
339*1fd5a2e1SPrashanth Swaminathan tramp[1] = 0xa77b0010; /* ldq $27,16($27) */
340*1fd5a2e1SPrashanth Swaminathan tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */
341*1fd5a2e1SPrashanth Swaminathan tramp[3] = 0x47ff041f; /* nop */
342*1fd5a2e1SPrashanth Swaminathan *(void **) &tramp[4] = ffi_closure_osf;
343*1fd5a2e1SPrashanth Swaminathan
344*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
345*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
346*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
347*1fd5a2e1SPrashanth Swaminathan
348*1fd5a2e1SPrashanth Swaminathan /* Flush the Icache.
349*1fd5a2e1SPrashanth Swaminathan
350*1fd5a2e1SPrashanth Swaminathan Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
351*1fd5a2e1SPrashanth Swaminathan instead, since both Compaq as and gas can handle it.
352*1fd5a2e1SPrashanth Swaminathan
353*1fd5a2e1SPrashanth Swaminathan 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */
354*1fd5a2e1SPrashanth Swaminathan asm volatile ("call_pal 0x86" : : : "memory");
355*1fd5a2e1SPrashanth Swaminathan
356*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
357*1fd5a2e1SPrashanth Swaminathan }
358*1fd5a2e1SPrashanth Swaminathan
359*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))360*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure* closure,
361*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
362*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*))
363*1fd5a2e1SPrashanth Swaminathan {
364*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_OSF)
365*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
366*1fd5a2e1SPrashanth Swaminathan
367*1fd5a2e1SPrashanth Swaminathan closure->tramp = (void *)ffi_go_closure_osf;
368*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
369*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
370*1fd5a2e1SPrashanth Swaminathan
371*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
372*1fd5a2e1SPrashanth Swaminathan }
373*1fd5a2e1SPrashanth Swaminathan
374*1fd5a2e1SPrashanth Swaminathan long FFI_HIDDEN
ffi_closure_osf_inner(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,unsigned long * argp)375*1fd5a2e1SPrashanth Swaminathan ffi_closure_osf_inner (ffi_cif *cif,
376*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
377*1fd5a2e1SPrashanth Swaminathan void *user_data,
378*1fd5a2e1SPrashanth Swaminathan void *rvalue, unsigned long *argp)
379*1fd5a2e1SPrashanth Swaminathan {
380*1fd5a2e1SPrashanth Swaminathan void **avalue;
381*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types;
382*1fd5a2e1SPrashanth Swaminathan long i, avn, argn, flags;
383*1fd5a2e1SPrashanth Swaminathan
384*1fd5a2e1SPrashanth Swaminathan avalue = alloca(cif->nargs * sizeof(void *));
385*1fd5a2e1SPrashanth Swaminathan flags = cif->flags;
386*1fd5a2e1SPrashanth Swaminathan argn = 0;
387*1fd5a2e1SPrashanth Swaminathan
388*1fd5a2e1SPrashanth Swaminathan /* Copy the caller's structure return address to that the closure
389*1fd5a2e1SPrashanth Swaminathan returns the data directly to the caller. */
390*1fd5a2e1SPrashanth Swaminathan if (flags == ALPHA_RET_IN_MEM)
391*1fd5a2e1SPrashanth Swaminathan {
392*1fd5a2e1SPrashanth Swaminathan rvalue = (void *) argp[0];
393*1fd5a2e1SPrashanth Swaminathan argn = 1;
394*1fd5a2e1SPrashanth Swaminathan }
395*1fd5a2e1SPrashanth Swaminathan
396*1fd5a2e1SPrashanth Swaminathan arg_types = cif->arg_types;
397*1fd5a2e1SPrashanth Swaminathan
398*1fd5a2e1SPrashanth Swaminathan /* Grab the addresses of the arguments from the stack frame. */
399*1fd5a2e1SPrashanth Swaminathan for (i = 0, avn = cif->nargs; i < avn; i++)
400*1fd5a2e1SPrashanth Swaminathan {
401*1fd5a2e1SPrashanth Swaminathan ffi_type *ty = arg_types[i];
402*1fd5a2e1SPrashanth Swaminathan int type = ty->type;
403*1fd5a2e1SPrashanth Swaminathan void *valp = &argp[argn];
404*1fd5a2e1SPrashanth Swaminathan size_t size;
405*1fd5a2e1SPrashanth Swaminathan
406*1fd5a2e1SPrashanth Swaminathan switch (type)
407*1fd5a2e1SPrashanth Swaminathan {
408*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
409*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
410*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
411*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
412*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
413*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
414*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
415*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
416*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
417*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
418*1fd5a2e1SPrashanth Swaminathan argn += 1;
419*1fd5a2e1SPrashanth Swaminathan break;
420*1fd5a2e1SPrashanth Swaminathan
421*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
422*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
423*1fd5a2e1SPrashanth Swaminathan size = ty->size;
424*1fd5a2e1SPrashanth Swaminathan argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
425*1fd5a2e1SPrashanth Swaminathan break;
426*1fd5a2e1SPrashanth Swaminathan
427*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
428*1fd5a2e1SPrashanth Swaminathan /* Floats coming from registers need conversion from double
429*1fd5a2e1SPrashanth Swaminathan back to float format. */
430*1fd5a2e1SPrashanth Swaminathan if (argn < 6)
431*1fd5a2e1SPrashanth Swaminathan {
432*1fd5a2e1SPrashanth Swaminathan valp = &argp[argn - 6];
433*1fd5a2e1SPrashanth Swaminathan sts(valp, argp[argn - 6]);
434*1fd5a2e1SPrashanth Swaminathan }
435*1fd5a2e1SPrashanth Swaminathan argn += 1;
436*1fd5a2e1SPrashanth Swaminathan break;
437*1fd5a2e1SPrashanth Swaminathan
438*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
439*1fd5a2e1SPrashanth Swaminathan if (argn < 6)
440*1fd5a2e1SPrashanth Swaminathan valp = &argp[argn - 6];
441*1fd5a2e1SPrashanth Swaminathan argn += 1;
442*1fd5a2e1SPrashanth Swaminathan break;
443*1fd5a2e1SPrashanth Swaminathan
444*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
445*1fd5a2e1SPrashanth Swaminathan by_reference:
446*1fd5a2e1SPrashanth Swaminathan /* 128-bit long double is passed by reference. */
447*1fd5a2e1SPrashanth Swaminathan valp = (void *)argp[argn];
448*1fd5a2e1SPrashanth Swaminathan argn += 1;
449*1fd5a2e1SPrashanth Swaminathan break;
450*1fd5a2e1SPrashanth Swaminathan
451*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
452*1fd5a2e1SPrashanth Swaminathan type = ty->elements[0]->type;
453*1fd5a2e1SPrashanth Swaminathan switch (type)
454*1fd5a2e1SPrashanth Swaminathan {
455*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
456*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
457*1fd5a2e1SPrashanth Swaminathan /* Passed as separate arguments, but they wind up sequential. */
458*1fd5a2e1SPrashanth Swaminathan break;
459*1fd5a2e1SPrashanth Swaminathan
460*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
461*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
462*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
463*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
464*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
465*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
466*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
467*1fd5a2e1SPrashanth Swaminathan /* Passed as separate arguments. Disjoint, but there's room
468*1fd5a2e1SPrashanth Swaminathan enough in one slot to hold the pair. */
469*1fd5a2e1SPrashanth Swaminathan size = ty->elements[0]->size;
470*1fd5a2e1SPrashanth Swaminathan memcpy(valp + size, valp + 8, size);
471*1fd5a2e1SPrashanth Swaminathan break;
472*1fd5a2e1SPrashanth Swaminathan
473*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
474*1fd5a2e1SPrashanth Swaminathan /* Passed as separate arguments. Disjoint, and each piece
475*1fd5a2e1SPrashanth Swaminathan may need conversion back to float. */
476*1fd5a2e1SPrashanth Swaminathan if (argn < 6)
477*1fd5a2e1SPrashanth Swaminathan {
478*1fd5a2e1SPrashanth Swaminathan valp = &argp[argn - 6];
479*1fd5a2e1SPrashanth Swaminathan sts(valp, argp[argn - 6]);
480*1fd5a2e1SPrashanth Swaminathan }
481*1fd5a2e1SPrashanth Swaminathan if (argn + 1 < 6)
482*1fd5a2e1SPrashanth Swaminathan sts(valp + 4, argp[argn + 1 - 6]);
483*1fd5a2e1SPrashanth Swaminathan else
484*1fd5a2e1SPrashanth Swaminathan *(UINT32 *)(valp + 4) = argp[argn + 1];
485*1fd5a2e1SPrashanth Swaminathan break;
486*1fd5a2e1SPrashanth Swaminathan
487*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
488*1fd5a2e1SPrashanth Swaminathan /* Passed as separate arguments. Only disjoint if one part
489*1fd5a2e1SPrashanth Swaminathan is in fp regs and the other is on the stack. */
490*1fd5a2e1SPrashanth Swaminathan if (argn < 5)
491*1fd5a2e1SPrashanth Swaminathan valp = &argp[argn - 6];
492*1fd5a2e1SPrashanth Swaminathan else if (argn == 5)
493*1fd5a2e1SPrashanth Swaminathan {
494*1fd5a2e1SPrashanth Swaminathan valp = alloca(16);
495*1fd5a2e1SPrashanth Swaminathan ((UINT64 *)valp)[0] = argp[5 - 6];
496*1fd5a2e1SPrashanth Swaminathan ((UINT64 *)valp)[1] = argp[6];
497*1fd5a2e1SPrashanth Swaminathan }
498*1fd5a2e1SPrashanth Swaminathan break;
499*1fd5a2e1SPrashanth Swaminathan
500*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
501*1fd5a2e1SPrashanth Swaminathan goto by_reference;
502*1fd5a2e1SPrashanth Swaminathan
503*1fd5a2e1SPrashanth Swaminathan default:
504*1fd5a2e1SPrashanth Swaminathan abort();
505*1fd5a2e1SPrashanth Swaminathan }
506*1fd5a2e1SPrashanth Swaminathan argn += 2;
507*1fd5a2e1SPrashanth Swaminathan break;
508*1fd5a2e1SPrashanth Swaminathan
509*1fd5a2e1SPrashanth Swaminathan default:
510*1fd5a2e1SPrashanth Swaminathan abort ();
511*1fd5a2e1SPrashanth Swaminathan }
512*1fd5a2e1SPrashanth Swaminathan
513*1fd5a2e1SPrashanth Swaminathan avalue[i] = valp;
514*1fd5a2e1SPrashanth Swaminathan }
515*1fd5a2e1SPrashanth Swaminathan
516*1fd5a2e1SPrashanth Swaminathan /* Invoke the closure. */
517*1fd5a2e1SPrashanth Swaminathan fun (cif, rvalue, avalue, user_data);
518*1fd5a2e1SPrashanth Swaminathan
519*1fd5a2e1SPrashanth Swaminathan /* Tell ffi_closure_osf how to perform return type promotions. */
520*1fd5a2e1SPrashanth Swaminathan return (flags >> ALPHA_LD_SHIFT) & 0xff;
521*1fd5a2e1SPrashanth Swaminathan }
522