xref: /aosp_15_r20/external/libffi/src/alpha/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
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