xref: /aosp_15_r20/external/libffi/src/ia64/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc.
3*1fd5a2e1SPrashanth Swaminathan 	   Copyright (c) 2000 Hewlett Packard Company
4*1fd5a2e1SPrashanth Swaminathan 	   Copyright (c) 2011 Anthony Green
5*1fd5a2e1SPrashanth Swaminathan 
6*1fd5a2e1SPrashanth Swaminathan    IA64 Foreign Function Interface
7*1fd5a2e1SPrashanth Swaminathan 
8*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
9*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
10*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
11*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
12*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
13*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
14*1fd5a2e1SPrashanth Swaminathan    the following conditions:
15*1fd5a2e1SPrashanth Swaminathan 
16*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
17*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
18*1fd5a2e1SPrashanth Swaminathan 
19*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20*1fd5a2e1SPrashanth Swaminathan    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22*1fd5a2e1SPrashanth Swaminathan    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23*1fd5a2e1SPrashanth Swaminathan    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24*1fd5a2e1SPrashanth Swaminathan    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25*1fd5a2e1SPrashanth Swaminathan    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26*1fd5a2e1SPrashanth Swaminathan    DEALINGS IN THE SOFTWARE.
27*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
28*1fd5a2e1SPrashanth Swaminathan 
29*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
30*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
31*1fd5a2e1SPrashanth Swaminathan 
32*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
33*1fd5a2e1SPrashanth Swaminathan #include <stdbool.h>
34*1fd5a2e1SPrashanth Swaminathan #include <float.h>
35*1fd5a2e1SPrashanth Swaminathan 
36*1fd5a2e1SPrashanth Swaminathan #include "ia64_flags.h"
37*1fd5a2e1SPrashanth Swaminathan 
38*1fd5a2e1SPrashanth Swaminathan /* A 64-bit pointer value.  In LP64 mode, this is effectively a plain
39*1fd5a2e1SPrashanth Swaminathan    pointer.  In ILP32 mode, it's a pointer that's been extended to
40*1fd5a2e1SPrashanth Swaminathan    64 bits by "addp4".  */
41*1fd5a2e1SPrashanth Swaminathan typedef void *PTR64 __attribute__((mode(DI)));
42*1fd5a2e1SPrashanth Swaminathan 
43*1fd5a2e1SPrashanth Swaminathan /* Memory image of fp register contents.  This is the implementation
44*1fd5a2e1SPrashanth Swaminathan    specific format used by ldf.fill/stf.spill.  All we care about is
45*1fd5a2e1SPrashanth Swaminathan    that it wants a 16 byte aligned slot.  */
46*1fd5a2e1SPrashanth Swaminathan typedef struct
47*1fd5a2e1SPrashanth Swaminathan {
48*1fd5a2e1SPrashanth Swaminathan   UINT64 x[2] __attribute__((aligned(16)));
49*1fd5a2e1SPrashanth Swaminathan } fpreg;
50*1fd5a2e1SPrashanth Swaminathan 
51*1fd5a2e1SPrashanth Swaminathan 
52*1fd5a2e1SPrashanth Swaminathan /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner.  */
53*1fd5a2e1SPrashanth Swaminathan 
54*1fd5a2e1SPrashanth Swaminathan struct ia64_args
55*1fd5a2e1SPrashanth Swaminathan {
56*1fd5a2e1SPrashanth Swaminathan   fpreg fp_regs[8];	/* Contents of 8 fp arg registers.  */
57*1fd5a2e1SPrashanth Swaminathan   UINT64 gp_regs[8];	/* Contents of 8 gp arg registers.  */
58*1fd5a2e1SPrashanth Swaminathan   UINT64 other_args[];	/* Arguments passed on stack, variable size.  */
59*1fd5a2e1SPrashanth Swaminathan };
60*1fd5a2e1SPrashanth Swaminathan 
61*1fd5a2e1SPrashanth Swaminathan 
62*1fd5a2e1SPrashanth Swaminathan /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes.  */
63*1fd5a2e1SPrashanth Swaminathan 
64*1fd5a2e1SPrashanth Swaminathan static inline void *
endian_adjust(void * addr,size_t len)65*1fd5a2e1SPrashanth Swaminathan endian_adjust (void *addr, size_t len)
66*1fd5a2e1SPrashanth Swaminathan {
67*1fd5a2e1SPrashanth Swaminathan #ifdef __BIG_ENDIAN__
68*1fd5a2e1SPrashanth Swaminathan   return addr + (8 - len);
69*1fd5a2e1SPrashanth Swaminathan #else
70*1fd5a2e1SPrashanth Swaminathan   return addr;
71*1fd5a2e1SPrashanth Swaminathan #endif
72*1fd5a2e1SPrashanth Swaminathan }
73*1fd5a2e1SPrashanth Swaminathan 
74*1fd5a2e1SPrashanth Swaminathan /* Store VALUE to ADDR in the current cpu implementation's fp spill format.
75*1fd5a2e1SPrashanth Swaminathan    This is a macro instead of a function, so that it works for all 3 floating
76*1fd5a2e1SPrashanth Swaminathan    point types without type conversions.  Type conversion to long double breaks
77*1fd5a2e1SPrashanth Swaminathan    the denorm support.  */
78*1fd5a2e1SPrashanth Swaminathan 
79*1fd5a2e1SPrashanth Swaminathan #define stf_spill(addr, value)	\
80*1fd5a2e1SPrashanth Swaminathan   asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value));
81*1fd5a2e1SPrashanth Swaminathan 
82*1fd5a2e1SPrashanth Swaminathan /* Load a value from ADDR, which is in the current cpu implementation's
83*1fd5a2e1SPrashanth Swaminathan    fp spill format.  As above, this must also be a macro.  */
84*1fd5a2e1SPrashanth Swaminathan 
85*1fd5a2e1SPrashanth Swaminathan #define ldf_fill(result, addr)	\
86*1fd5a2e1SPrashanth Swaminathan   asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr));
87*1fd5a2e1SPrashanth Swaminathan 
88*1fd5a2e1SPrashanth Swaminathan /* Return the size of the C type associated with with TYPE.  Which will
89*1fd5a2e1SPrashanth Swaminathan    be one of the FFI_IA64_TYPE_HFA_* values.  */
90*1fd5a2e1SPrashanth Swaminathan 
91*1fd5a2e1SPrashanth Swaminathan static size_t
hfa_type_size(int type)92*1fd5a2e1SPrashanth Swaminathan hfa_type_size (int type)
93*1fd5a2e1SPrashanth Swaminathan {
94*1fd5a2e1SPrashanth Swaminathan   switch (type)
95*1fd5a2e1SPrashanth Swaminathan     {
96*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_FLOAT:
97*1fd5a2e1SPrashanth Swaminathan       return sizeof(float);
98*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_DOUBLE:
99*1fd5a2e1SPrashanth Swaminathan       return sizeof(double);
100*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_LDOUBLE:
101*1fd5a2e1SPrashanth Swaminathan       return sizeof(__float80);
102*1fd5a2e1SPrashanth Swaminathan     default:
103*1fd5a2e1SPrashanth Swaminathan       abort ();
104*1fd5a2e1SPrashanth Swaminathan     }
105*1fd5a2e1SPrashanth Swaminathan }
106*1fd5a2e1SPrashanth Swaminathan 
107*1fd5a2e1SPrashanth Swaminathan /* Load from ADDR a value indicated by TYPE.  Which will be one of
108*1fd5a2e1SPrashanth Swaminathan    the FFI_IA64_TYPE_HFA_* values.  */
109*1fd5a2e1SPrashanth Swaminathan 
110*1fd5a2e1SPrashanth Swaminathan static void
hfa_type_load(fpreg * fpaddr,int type,void * addr)111*1fd5a2e1SPrashanth Swaminathan hfa_type_load (fpreg *fpaddr, int type, void *addr)
112*1fd5a2e1SPrashanth Swaminathan {
113*1fd5a2e1SPrashanth Swaminathan   switch (type)
114*1fd5a2e1SPrashanth Swaminathan     {
115*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_FLOAT:
116*1fd5a2e1SPrashanth Swaminathan       stf_spill (fpaddr, *(float *) addr);
117*1fd5a2e1SPrashanth Swaminathan       return;
118*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_DOUBLE:
119*1fd5a2e1SPrashanth Swaminathan       stf_spill (fpaddr, *(double *) addr);
120*1fd5a2e1SPrashanth Swaminathan       return;
121*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_LDOUBLE:
122*1fd5a2e1SPrashanth Swaminathan       stf_spill (fpaddr, *(__float80 *) addr);
123*1fd5a2e1SPrashanth Swaminathan       return;
124*1fd5a2e1SPrashanth Swaminathan     default:
125*1fd5a2e1SPrashanth Swaminathan       abort ();
126*1fd5a2e1SPrashanth Swaminathan     }
127*1fd5a2e1SPrashanth Swaminathan }
128*1fd5a2e1SPrashanth Swaminathan 
129*1fd5a2e1SPrashanth Swaminathan /* Load VALUE into ADDR as indicated by TYPE.  Which will be one of
130*1fd5a2e1SPrashanth Swaminathan    the FFI_IA64_TYPE_HFA_* values.  */
131*1fd5a2e1SPrashanth Swaminathan 
132*1fd5a2e1SPrashanth Swaminathan static void
hfa_type_store(int type,void * addr,fpreg * fpaddr)133*1fd5a2e1SPrashanth Swaminathan hfa_type_store (int type, void *addr, fpreg *fpaddr)
134*1fd5a2e1SPrashanth Swaminathan {
135*1fd5a2e1SPrashanth Swaminathan   switch (type)
136*1fd5a2e1SPrashanth Swaminathan     {
137*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_FLOAT:
138*1fd5a2e1SPrashanth Swaminathan       {
139*1fd5a2e1SPrashanth Swaminathan 	float result;
140*1fd5a2e1SPrashanth Swaminathan 	ldf_fill (result, fpaddr);
141*1fd5a2e1SPrashanth Swaminathan 	*(float *) addr = result;
142*1fd5a2e1SPrashanth Swaminathan 	break;
143*1fd5a2e1SPrashanth Swaminathan       }
144*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_DOUBLE:
145*1fd5a2e1SPrashanth Swaminathan       {
146*1fd5a2e1SPrashanth Swaminathan 	double result;
147*1fd5a2e1SPrashanth Swaminathan 	ldf_fill (result, fpaddr);
148*1fd5a2e1SPrashanth Swaminathan 	*(double *) addr = result;
149*1fd5a2e1SPrashanth Swaminathan 	break;
150*1fd5a2e1SPrashanth Swaminathan       }
151*1fd5a2e1SPrashanth Swaminathan     case FFI_IA64_TYPE_HFA_LDOUBLE:
152*1fd5a2e1SPrashanth Swaminathan       {
153*1fd5a2e1SPrashanth Swaminathan 	__float80 result;
154*1fd5a2e1SPrashanth Swaminathan 	ldf_fill (result, fpaddr);
155*1fd5a2e1SPrashanth Swaminathan 	*(__float80 *) addr = result;
156*1fd5a2e1SPrashanth Swaminathan 	break;
157*1fd5a2e1SPrashanth Swaminathan       }
158*1fd5a2e1SPrashanth Swaminathan     default:
159*1fd5a2e1SPrashanth Swaminathan       abort ();
160*1fd5a2e1SPrashanth Swaminathan     }
161*1fd5a2e1SPrashanth Swaminathan }
162*1fd5a2e1SPrashanth Swaminathan 
163*1fd5a2e1SPrashanth Swaminathan /* Is TYPE a struct containing floats, doubles, or extended doubles,
164*1fd5a2e1SPrashanth Swaminathan    all of the same fp type?  If so, return the element type.  Return
165*1fd5a2e1SPrashanth Swaminathan    FFI_TYPE_VOID if not.  */
166*1fd5a2e1SPrashanth Swaminathan 
167*1fd5a2e1SPrashanth Swaminathan static int
hfa_element_type(ffi_type * type,int nested)168*1fd5a2e1SPrashanth Swaminathan hfa_element_type (ffi_type *type, int nested)
169*1fd5a2e1SPrashanth Swaminathan {
170*1fd5a2e1SPrashanth Swaminathan   int element = FFI_TYPE_VOID;
171*1fd5a2e1SPrashanth Swaminathan 
172*1fd5a2e1SPrashanth Swaminathan   switch (type->type)
173*1fd5a2e1SPrashanth Swaminathan     {
174*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
175*1fd5a2e1SPrashanth Swaminathan       /* We want to return VOID for raw floating-point types, but the
176*1fd5a2e1SPrashanth Swaminathan 	 synthetic HFA type if we're nested within an aggregate.  */
177*1fd5a2e1SPrashanth Swaminathan       if (nested)
178*1fd5a2e1SPrashanth Swaminathan 	element = FFI_IA64_TYPE_HFA_FLOAT;
179*1fd5a2e1SPrashanth Swaminathan       break;
180*1fd5a2e1SPrashanth Swaminathan 
181*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
182*1fd5a2e1SPrashanth Swaminathan       /* Similarly.  */
183*1fd5a2e1SPrashanth Swaminathan       if (nested)
184*1fd5a2e1SPrashanth Swaminathan 	element = FFI_IA64_TYPE_HFA_DOUBLE;
185*1fd5a2e1SPrashanth Swaminathan       break;
186*1fd5a2e1SPrashanth Swaminathan 
187*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
188*1fd5a2e1SPrashanth Swaminathan       /* Similarly, except that that HFA is true for double extended,
189*1fd5a2e1SPrashanth Swaminathan 	 but not quad precision.  Both have sizeof == 16, so tell the
190*1fd5a2e1SPrashanth Swaminathan 	 difference based on the precision.  */
191*1fd5a2e1SPrashanth Swaminathan       if (LDBL_MANT_DIG == 64 && nested)
192*1fd5a2e1SPrashanth Swaminathan 	element = FFI_IA64_TYPE_HFA_LDOUBLE;
193*1fd5a2e1SPrashanth Swaminathan       break;
194*1fd5a2e1SPrashanth Swaminathan 
195*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
196*1fd5a2e1SPrashanth Swaminathan       {
197*1fd5a2e1SPrashanth Swaminathan 	ffi_type **ptr = &type->elements[0];
198*1fd5a2e1SPrashanth Swaminathan 
199*1fd5a2e1SPrashanth Swaminathan 	for (ptr = &type->elements[0]; *ptr ; ptr++)
200*1fd5a2e1SPrashanth Swaminathan 	  {
201*1fd5a2e1SPrashanth Swaminathan 	    int sub_element = hfa_element_type (*ptr, 1);
202*1fd5a2e1SPrashanth Swaminathan 	    if (sub_element == FFI_TYPE_VOID)
203*1fd5a2e1SPrashanth Swaminathan 	      return FFI_TYPE_VOID;
204*1fd5a2e1SPrashanth Swaminathan 
205*1fd5a2e1SPrashanth Swaminathan 	    if (element == FFI_TYPE_VOID)
206*1fd5a2e1SPrashanth Swaminathan 	      element = sub_element;
207*1fd5a2e1SPrashanth Swaminathan 	    else if (element != sub_element)
208*1fd5a2e1SPrashanth Swaminathan 	      return FFI_TYPE_VOID;
209*1fd5a2e1SPrashanth Swaminathan 	  }
210*1fd5a2e1SPrashanth Swaminathan       }
211*1fd5a2e1SPrashanth Swaminathan       break;
212*1fd5a2e1SPrashanth Swaminathan 
213*1fd5a2e1SPrashanth Swaminathan     default:
214*1fd5a2e1SPrashanth Swaminathan       return FFI_TYPE_VOID;
215*1fd5a2e1SPrashanth Swaminathan     }
216*1fd5a2e1SPrashanth Swaminathan 
217*1fd5a2e1SPrashanth Swaminathan   return element;
218*1fd5a2e1SPrashanth Swaminathan }
219*1fd5a2e1SPrashanth Swaminathan 
220*1fd5a2e1SPrashanth Swaminathan 
221*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing. */
222*1fd5a2e1SPrashanth Swaminathan 
223*1fd5a2e1SPrashanth Swaminathan static ffi_status
ffi_prep_cif_machdep_core(ffi_cif * cif)224*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_core(ffi_cif *cif)
225*1fd5a2e1SPrashanth Swaminathan {
226*1fd5a2e1SPrashanth Swaminathan   int flags;
227*1fd5a2e1SPrashanth Swaminathan 
228*1fd5a2e1SPrashanth Swaminathan   /* Adjust cif->bytes to include space for the bits of the ia64_args frame
229*1fd5a2e1SPrashanth Swaminathan      that precedes the integer register portion.  The estimate that the
230*1fd5a2e1SPrashanth Swaminathan      generic bits did for the argument space required is good enough for the
231*1fd5a2e1SPrashanth Swaminathan      integer component.  */
232*1fd5a2e1SPrashanth Swaminathan   cif->bytes += offsetof(struct ia64_args, gp_regs[0]);
233*1fd5a2e1SPrashanth Swaminathan   if (cif->bytes < sizeof(struct ia64_args))
234*1fd5a2e1SPrashanth Swaminathan     cif->bytes = sizeof(struct ia64_args);
235*1fd5a2e1SPrashanth Swaminathan 
236*1fd5a2e1SPrashanth Swaminathan   /* Set the return type flag. */
237*1fd5a2e1SPrashanth Swaminathan   flags = cif->rtype->type;
238*1fd5a2e1SPrashanth Swaminathan   switch (cif->rtype->type)
239*1fd5a2e1SPrashanth Swaminathan     {
240*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_LONGDOUBLE:
241*1fd5a2e1SPrashanth Swaminathan       /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision,
242*1fd5a2e1SPrashanth Swaminathan 	 and encode quad precision as a two-word integer structure.  */
243*1fd5a2e1SPrashanth Swaminathan       if (LDBL_MANT_DIG != 64)
244*1fd5a2e1SPrashanth Swaminathan 	flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8);
245*1fd5a2e1SPrashanth Swaminathan       break;
246*1fd5a2e1SPrashanth Swaminathan 
247*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
248*1fd5a2e1SPrashanth Swaminathan       {
249*1fd5a2e1SPrashanth Swaminathan         size_t size = cif->rtype->size;
250*1fd5a2e1SPrashanth Swaminathan   	int hfa_type = hfa_element_type (cif->rtype, 0);
251*1fd5a2e1SPrashanth Swaminathan 
252*1fd5a2e1SPrashanth Swaminathan 	if (hfa_type != FFI_TYPE_VOID)
253*1fd5a2e1SPrashanth Swaminathan 	  {
254*1fd5a2e1SPrashanth Swaminathan 	    size_t nelts = size / hfa_type_size (hfa_type);
255*1fd5a2e1SPrashanth Swaminathan 	    if (nelts <= 8)
256*1fd5a2e1SPrashanth Swaminathan 	      flags = hfa_type | (size << 8);
257*1fd5a2e1SPrashanth Swaminathan 	  }
258*1fd5a2e1SPrashanth Swaminathan 	else
259*1fd5a2e1SPrashanth Swaminathan 	  {
260*1fd5a2e1SPrashanth Swaminathan 	    if (size <= 32)
261*1fd5a2e1SPrashanth Swaminathan 	      flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8);
262*1fd5a2e1SPrashanth Swaminathan 	  }
263*1fd5a2e1SPrashanth Swaminathan       }
264*1fd5a2e1SPrashanth Swaminathan       break;
265*1fd5a2e1SPrashanth Swaminathan 
266*1fd5a2e1SPrashanth Swaminathan     default:
267*1fd5a2e1SPrashanth Swaminathan       break;
268*1fd5a2e1SPrashanth Swaminathan     }
269*1fd5a2e1SPrashanth Swaminathan   cif->flags = flags;
270*1fd5a2e1SPrashanth Swaminathan 
271*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
272*1fd5a2e1SPrashanth Swaminathan }
273*1fd5a2e1SPrashanth Swaminathan 
274*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)275*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep(ffi_cif *cif)
276*1fd5a2e1SPrashanth Swaminathan {
277*1fd5a2e1SPrashanth Swaminathan   cif->nfixedargs = cif->nargs;
278*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_machdep_core(cif);
279*1fd5a2e1SPrashanth Swaminathan }
280*1fd5a2e1SPrashanth Swaminathan 
281*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs MAYBE_UNUSED)282*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_var(ffi_cif *cif,
283*1fd5a2e1SPrashanth Swaminathan 			 unsigned int nfixedargs,
284*1fd5a2e1SPrashanth Swaminathan 			 unsigned int ntotalargs MAYBE_UNUSED)
285*1fd5a2e1SPrashanth Swaminathan {
286*1fd5a2e1SPrashanth Swaminathan   cif->nfixedargs = nfixedargs;
287*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_machdep_core(cif);
288*1fd5a2e1SPrashanth Swaminathan }
289*1fd5a2e1SPrashanth Swaminathan 
290*1fd5a2e1SPrashanth Swaminathan extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
291*1fd5a2e1SPrashanth Swaminathan 
292*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)293*1fd5a2e1SPrashanth Swaminathan ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
294*1fd5a2e1SPrashanth Swaminathan {
295*1fd5a2e1SPrashanth Swaminathan   struct ia64_args *stack;
296*1fd5a2e1SPrashanth Swaminathan   long i, avn, gpcount, fpcount;
297*1fd5a2e1SPrashanth Swaminathan   ffi_type **p_arg;
298*1fd5a2e1SPrashanth Swaminathan 
299*1fd5a2e1SPrashanth Swaminathan   FFI_ASSERT (cif->abi == FFI_UNIX);
300*1fd5a2e1SPrashanth Swaminathan 
301*1fd5a2e1SPrashanth Swaminathan   /* If we have no spot for a return value, make one.  */
302*1fd5a2e1SPrashanth Swaminathan   if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
303*1fd5a2e1SPrashanth Swaminathan     rvalue = alloca (cif->rtype->size);
304*1fd5a2e1SPrashanth Swaminathan 
305*1fd5a2e1SPrashanth Swaminathan   /* Allocate the stack frame.  */
306*1fd5a2e1SPrashanth Swaminathan   stack = alloca (cif->bytes);
307*1fd5a2e1SPrashanth Swaminathan 
308*1fd5a2e1SPrashanth Swaminathan   gpcount = fpcount = 0;
309*1fd5a2e1SPrashanth Swaminathan   avn = cif->nargs;
310*1fd5a2e1SPrashanth Swaminathan   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
311*1fd5a2e1SPrashanth Swaminathan     {
312*1fd5a2e1SPrashanth Swaminathan       switch ((*p_arg)->type)
313*1fd5a2e1SPrashanth Swaminathan 	{
314*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
315*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
316*1fd5a2e1SPrashanth Swaminathan 	  break;
317*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
318*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
319*1fd5a2e1SPrashanth Swaminathan 	  break;
320*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
321*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
322*1fd5a2e1SPrashanth Swaminathan 	  break;
323*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
324*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
325*1fd5a2e1SPrashanth Swaminathan 	  break;
326*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
327*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
328*1fd5a2e1SPrashanth Swaminathan 	  break;
329*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
330*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
331*1fd5a2e1SPrashanth Swaminathan 	  break;
332*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
333*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
334*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
335*1fd5a2e1SPrashanth Swaminathan 	  break;
336*1fd5a2e1SPrashanth Swaminathan 
337*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
338*1fd5a2e1SPrashanth Swaminathan 	  stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
339*1fd5a2e1SPrashanth Swaminathan 	  break;
340*1fd5a2e1SPrashanth Swaminathan 
341*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
342*1fd5a2e1SPrashanth Swaminathan 	  if (gpcount < 8 && fpcount < 8)
343*1fd5a2e1SPrashanth Swaminathan 	    stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
344*1fd5a2e1SPrashanth Swaminathan 	  {
345*1fd5a2e1SPrashanth Swaminathan 	    UINT32 tmp;
346*1fd5a2e1SPrashanth Swaminathan 	    memcpy (&tmp, avalue[i], sizeof (UINT32));
347*1fd5a2e1SPrashanth Swaminathan 	    stack->gp_regs[gpcount++] = tmp;
348*1fd5a2e1SPrashanth Swaminathan 	  }
349*1fd5a2e1SPrashanth Swaminathan 	  break;
350*1fd5a2e1SPrashanth Swaminathan 
351*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
352*1fd5a2e1SPrashanth Swaminathan 	  if (gpcount < 8 && fpcount < 8)
353*1fd5a2e1SPrashanth Swaminathan 	    stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
354*1fd5a2e1SPrashanth Swaminathan 	  memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64));
355*1fd5a2e1SPrashanth Swaminathan 	  break;
356*1fd5a2e1SPrashanth Swaminathan 
357*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
358*1fd5a2e1SPrashanth Swaminathan 	  if (gpcount & 1)
359*1fd5a2e1SPrashanth Swaminathan 	    gpcount++;
360*1fd5a2e1SPrashanth Swaminathan 	  if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
361*1fd5a2e1SPrashanth Swaminathan 	    stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
362*1fd5a2e1SPrashanth Swaminathan 	  memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
363*1fd5a2e1SPrashanth Swaminathan 	  gpcount += 2;
364*1fd5a2e1SPrashanth Swaminathan 	  break;
365*1fd5a2e1SPrashanth Swaminathan 
366*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
367*1fd5a2e1SPrashanth Swaminathan 	  {
368*1fd5a2e1SPrashanth Swaminathan 	    size_t size = (*p_arg)->size;
369*1fd5a2e1SPrashanth Swaminathan 	    size_t align = (*p_arg)->alignment;
370*1fd5a2e1SPrashanth Swaminathan 	    int hfa_type = hfa_element_type (*p_arg, 0);
371*1fd5a2e1SPrashanth Swaminathan 
372*1fd5a2e1SPrashanth Swaminathan 	    FFI_ASSERT (align <= 16);
373*1fd5a2e1SPrashanth Swaminathan 	    if (align == 16 && (gpcount & 1))
374*1fd5a2e1SPrashanth Swaminathan 	      gpcount++;
375*1fd5a2e1SPrashanth Swaminathan 
376*1fd5a2e1SPrashanth Swaminathan 	    if (hfa_type != FFI_TYPE_VOID)
377*1fd5a2e1SPrashanth Swaminathan 	      {
378*1fd5a2e1SPrashanth Swaminathan 		size_t hfa_size = hfa_type_size (hfa_type);
379*1fd5a2e1SPrashanth Swaminathan 		size_t offset = 0;
380*1fd5a2e1SPrashanth Swaminathan 		size_t gp_offset = gpcount * 8;
381*1fd5a2e1SPrashanth Swaminathan 
382*1fd5a2e1SPrashanth Swaminathan 		while (fpcount < 8
383*1fd5a2e1SPrashanth Swaminathan 		       && offset < size
384*1fd5a2e1SPrashanth Swaminathan 		       && gp_offset < 8 * 8)
385*1fd5a2e1SPrashanth Swaminathan 		  {
386*1fd5a2e1SPrashanth Swaminathan 		    hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
387*1fd5a2e1SPrashanth Swaminathan 				   avalue[i] + offset);
388*1fd5a2e1SPrashanth Swaminathan 		    offset += hfa_size;
389*1fd5a2e1SPrashanth Swaminathan 		    gp_offset += hfa_size;
390*1fd5a2e1SPrashanth Swaminathan 		    fpcount += 1;
391*1fd5a2e1SPrashanth Swaminathan 		  }
392*1fd5a2e1SPrashanth Swaminathan 	      }
393*1fd5a2e1SPrashanth Swaminathan 
394*1fd5a2e1SPrashanth Swaminathan 	    memcpy (&stack->gp_regs[gpcount], avalue[i], size);
395*1fd5a2e1SPrashanth Swaminathan 	    gpcount += (size + 7) / 8;
396*1fd5a2e1SPrashanth Swaminathan 	  }
397*1fd5a2e1SPrashanth Swaminathan 	  break;
398*1fd5a2e1SPrashanth Swaminathan 
399*1fd5a2e1SPrashanth Swaminathan 	default:
400*1fd5a2e1SPrashanth Swaminathan 	  abort ();
401*1fd5a2e1SPrashanth Swaminathan 	}
402*1fd5a2e1SPrashanth Swaminathan     }
403*1fd5a2e1SPrashanth Swaminathan 
404*1fd5a2e1SPrashanth Swaminathan   ffi_call_unix (stack, rvalue, fn, cif->flags);
405*1fd5a2e1SPrashanth Swaminathan }
406*1fd5a2e1SPrashanth Swaminathan 
407*1fd5a2e1SPrashanth Swaminathan /* Closures represent a pair consisting of a function pointer, and
408*1fd5a2e1SPrashanth Swaminathan    some user data.  A closure is invoked by reinterpreting the closure
409*1fd5a2e1SPrashanth Swaminathan    as a function pointer, and branching to it.  Thus we can make an
410*1fd5a2e1SPrashanth Swaminathan    interpreted function callable as a C function: We turn the
411*1fd5a2e1SPrashanth Swaminathan    interpreter itself, together with a pointer specifying the
412*1fd5a2e1SPrashanth Swaminathan    interpreted procedure, into a closure.
413*1fd5a2e1SPrashanth Swaminathan 
414*1fd5a2e1SPrashanth Swaminathan    For IA64, function pointer are already pairs consisting of a code
415*1fd5a2e1SPrashanth Swaminathan    pointer, and a gp pointer.  The latter is needed to access global
416*1fd5a2e1SPrashanth Swaminathan    variables.  Here we set up such a pair as the first two words of
417*1fd5a2e1SPrashanth Swaminathan    the closure (in the "trampoline" area), but we replace the gp
418*1fd5a2e1SPrashanth Swaminathan    pointer with a pointer to the closure itself.  We also add the real
419*1fd5a2e1SPrashanth Swaminathan    gp pointer to the closure.  This allows the function entry code to
420*1fd5a2e1SPrashanth Swaminathan    both retrieve the user data, and to restore the correct gp pointer.  */
421*1fd5a2e1SPrashanth Swaminathan 
422*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_unix ();
423*1fd5a2e1SPrashanth Swaminathan 
424*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)425*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
426*1fd5a2e1SPrashanth Swaminathan 		      ffi_cif* cif,
427*1fd5a2e1SPrashanth Swaminathan 		      void (*fun)(ffi_cif*,void*,void**,void*),
428*1fd5a2e1SPrashanth Swaminathan 		      void *user_data,
429*1fd5a2e1SPrashanth Swaminathan 		      void *codeloc)
430*1fd5a2e1SPrashanth Swaminathan {
431*1fd5a2e1SPrashanth Swaminathan   /* The layout of a function descriptor.  A C function pointer really
432*1fd5a2e1SPrashanth Swaminathan      points to one of these.  */
433*1fd5a2e1SPrashanth Swaminathan   struct ia64_fd
434*1fd5a2e1SPrashanth Swaminathan   {
435*1fd5a2e1SPrashanth Swaminathan     UINT64 code_pointer;
436*1fd5a2e1SPrashanth Swaminathan     UINT64 gp;
437*1fd5a2e1SPrashanth Swaminathan   };
438*1fd5a2e1SPrashanth Swaminathan 
439*1fd5a2e1SPrashanth Swaminathan   struct ffi_ia64_trampoline_struct
440*1fd5a2e1SPrashanth Swaminathan   {
441*1fd5a2e1SPrashanth Swaminathan     UINT64 code_pointer;	/* Pointer to ffi_closure_unix.  */
442*1fd5a2e1SPrashanth Swaminathan     UINT64 fake_gp;		/* Pointer to closure, installed as gp.  */
443*1fd5a2e1SPrashanth Swaminathan     UINT64 real_gp;		/* Real gp value.  */
444*1fd5a2e1SPrashanth Swaminathan   };
445*1fd5a2e1SPrashanth Swaminathan 
446*1fd5a2e1SPrashanth Swaminathan   struct ffi_ia64_trampoline_struct *tramp;
447*1fd5a2e1SPrashanth Swaminathan   struct ia64_fd *fd;
448*1fd5a2e1SPrashanth Swaminathan 
449*1fd5a2e1SPrashanth Swaminathan   if (cif->abi != FFI_UNIX)
450*1fd5a2e1SPrashanth Swaminathan     return FFI_BAD_ABI;
451*1fd5a2e1SPrashanth Swaminathan 
452*1fd5a2e1SPrashanth Swaminathan   tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
453*1fd5a2e1SPrashanth Swaminathan   fd = (struct ia64_fd *)(void *)ffi_closure_unix;
454*1fd5a2e1SPrashanth Swaminathan 
455*1fd5a2e1SPrashanth Swaminathan   tramp->code_pointer = fd->code_pointer;
456*1fd5a2e1SPrashanth Swaminathan   tramp->real_gp = fd->gp;
457*1fd5a2e1SPrashanth Swaminathan   tramp->fake_gp = (UINT64)(PTR64)codeloc;
458*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
459*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
460*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
461*1fd5a2e1SPrashanth Swaminathan 
462*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
463*1fd5a2e1SPrashanth Swaminathan }
464*1fd5a2e1SPrashanth Swaminathan 
465*1fd5a2e1SPrashanth Swaminathan 
466*1fd5a2e1SPrashanth Swaminathan UINT64
ffi_closure_unix_inner(ffi_closure * closure,struct ia64_args * stack,void * rvalue,void * r8)467*1fd5a2e1SPrashanth Swaminathan ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
468*1fd5a2e1SPrashanth Swaminathan 			void *rvalue, void *r8)
469*1fd5a2e1SPrashanth Swaminathan {
470*1fd5a2e1SPrashanth Swaminathan   ffi_cif *cif;
471*1fd5a2e1SPrashanth Swaminathan   void **avalue;
472*1fd5a2e1SPrashanth Swaminathan   ffi_type **p_arg;
473*1fd5a2e1SPrashanth Swaminathan   long i, avn, gpcount, fpcount, nfixedargs;
474*1fd5a2e1SPrashanth Swaminathan 
475*1fd5a2e1SPrashanth Swaminathan   cif = closure->cif;
476*1fd5a2e1SPrashanth Swaminathan   avn = cif->nargs;
477*1fd5a2e1SPrashanth Swaminathan   nfixedargs = cif->nfixedargs;
478*1fd5a2e1SPrashanth Swaminathan   avalue = alloca (avn * sizeof (void *));
479*1fd5a2e1SPrashanth Swaminathan 
480*1fd5a2e1SPrashanth Swaminathan   /* If the structure return value is passed in memory get that location
481*1fd5a2e1SPrashanth Swaminathan      from r8 so as to pass the value directly back to the caller.  */
482*1fd5a2e1SPrashanth Swaminathan   if (cif->flags == FFI_TYPE_STRUCT)
483*1fd5a2e1SPrashanth Swaminathan     rvalue = r8;
484*1fd5a2e1SPrashanth Swaminathan 
485*1fd5a2e1SPrashanth Swaminathan   gpcount = fpcount = 0;
486*1fd5a2e1SPrashanth Swaminathan   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
487*1fd5a2e1SPrashanth Swaminathan     {
488*1fd5a2e1SPrashanth Swaminathan       int named = i < nfixedargs;
489*1fd5a2e1SPrashanth Swaminathan       switch ((*p_arg)->type)
490*1fd5a2e1SPrashanth Swaminathan 	{
491*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT8:
492*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT8:
493*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
494*1fd5a2e1SPrashanth Swaminathan 	  break;
495*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT16:
496*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT16:
497*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
498*1fd5a2e1SPrashanth Swaminathan 	  break;
499*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT32:
500*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT32:
501*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
502*1fd5a2e1SPrashanth Swaminathan 	  break;
503*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_SINT64:
504*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_UINT64:
505*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = &stack->gp_regs[gpcount++];
506*1fd5a2e1SPrashanth Swaminathan 	  break;
507*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_POINTER:
508*1fd5a2e1SPrashanth Swaminathan 	  avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
509*1fd5a2e1SPrashanth Swaminathan 	  break;
510*1fd5a2e1SPrashanth Swaminathan 
511*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_FLOAT:
512*1fd5a2e1SPrashanth Swaminathan 	  if (named && gpcount < 8 && fpcount < 8)
513*1fd5a2e1SPrashanth Swaminathan 	    {
514*1fd5a2e1SPrashanth Swaminathan 	      fpreg *addr = &stack->fp_regs[fpcount++];
515*1fd5a2e1SPrashanth Swaminathan 	      float result;
516*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = addr;
517*1fd5a2e1SPrashanth Swaminathan 	      ldf_fill (result, addr);
518*1fd5a2e1SPrashanth Swaminathan 	      *(float *)addr = result;
519*1fd5a2e1SPrashanth Swaminathan 	    }
520*1fd5a2e1SPrashanth Swaminathan 	  else
521*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
522*1fd5a2e1SPrashanth Swaminathan 	  gpcount++;
523*1fd5a2e1SPrashanth Swaminathan 	  break;
524*1fd5a2e1SPrashanth Swaminathan 
525*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_DOUBLE:
526*1fd5a2e1SPrashanth Swaminathan 	  if (named && gpcount < 8 && fpcount < 8)
527*1fd5a2e1SPrashanth Swaminathan 	    {
528*1fd5a2e1SPrashanth Swaminathan 	      fpreg *addr = &stack->fp_regs[fpcount++];
529*1fd5a2e1SPrashanth Swaminathan 	      double result;
530*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = addr;
531*1fd5a2e1SPrashanth Swaminathan 	      ldf_fill (result, addr);
532*1fd5a2e1SPrashanth Swaminathan 	      *(double *)addr = result;
533*1fd5a2e1SPrashanth Swaminathan 	    }
534*1fd5a2e1SPrashanth Swaminathan 	  else
535*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = &stack->gp_regs[gpcount];
536*1fd5a2e1SPrashanth Swaminathan 	  gpcount++;
537*1fd5a2e1SPrashanth Swaminathan 	  break;
538*1fd5a2e1SPrashanth Swaminathan 
539*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_LONGDOUBLE:
540*1fd5a2e1SPrashanth Swaminathan 	  if (gpcount & 1)
541*1fd5a2e1SPrashanth Swaminathan 	    gpcount++;
542*1fd5a2e1SPrashanth Swaminathan 	  if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
543*1fd5a2e1SPrashanth Swaminathan 	    {
544*1fd5a2e1SPrashanth Swaminathan 	      fpreg *addr = &stack->fp_regs[fpcount++];
545*1fd5a2e1SPrashanth Swaminathan 	      __float80 result;
546*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = addr;
547*1fd5a2e1SPrashanth Swaminathan 	      ldf_fill (result, addr);
548*1fd5a2e1SPrashanth Swaminathan 	      *(__float80 *)addr = result;
549*1fd5a2e1SPrashanth Swaminathan 	    }
550*1fd5a2e1SPrashanth Swaminathan 	  else
551*1fd5a2e1SPrashanth Swaminathan 	    avalue[i] = &stack->gp_regs[gpcount];
552*1fd5a2e1SPrashanth Swaminathan 	  gpcount += 2;
553*1fd5a2e1SPrashanth Swaminathan 	  break;
554*1fd5a2e1SPrashanth Swaminathan 
555*1fd5a2e1SPrashanth Swaminathan 	case FFI_TYPE_STRUCT:
556*1fd5a2e1SPrashanth Swaminathan 	  {
557*1fd5a2e1SPrashanth Swaminathan 	    size_t size = (*p_arg)->size;
558*1fd5a2e1SPrashanth Swaminathan 	    size_t align = (*p_arg)->alignment;
559*1fd5a2e1SPrashanth Swaminathan 	    int hfa_type = hfa_element_type (*p_arg, 0);
560*1fd5a2e1SPrashanth Swaminathan 
561*1fd5a2e1SPrashanth Swaminathan 	    FFI_ASSERT (align <= 16);
562*1fd5a2e1SPrashanth Swaminathan 	    if (align == 16 && (gpcount & 1))
563*1fd5a2e1SPrashanth Swaminathan 	      gpcount++;
564*1fd5a2e1SPrashanth Swaminathan 
565*1fd5a2e1SPrashanth Swaminathan 	    if (hfa_type != FFI_TYPE_VOID)
566*1fd5a2e1SPrashanth Swaminathan 	      {
567*1fd5a2e1SPrashanth Swaminathan 		size_t hfa_size = hfa_type_size (hfa_type);
568*1fd5a2e1SPrashanth Swaminathan 		size_t offset = 0;
569*1fd5a2e1SPrashanth Swaminathan 		size_t gp_offset = gpcount * 8;
570*1fd5a2e1SPrashanth Swaminathan 		void *addr = alloca (size);
571*1fd5a2e1SPrashanth Swaminathan 
572*1fd5a2e1SPrashanth Swaminathan 		avalue[i] = addr;
573*1fd5a2e1SPrashanth Swaminathan 
574*1fd5a2e1SPrashanth Swaminathan 		while (fpcount < 8
575*1fd5a2e1SPrashanth Swaminathan 		       && offset < size
576*1fd5a2e1SPrashanth Swaminathan 		       && gp_offset < 8 * 8)
577*1fd5a2e1SPrashanth Swaminathan 		  {
578*1fd5a2e1SPrashanth Swaminathan 		    hfa_type_store (hfa_type, addr + offset,
579*1fd5a2e1SPrashanth Swaminathan 				    &stack->fp_regs[fpcount]);
580*1fd5a2e1SPrashanth Swaminathan 		    offset += hfa_size;
581*1fd5a2e1SPrashanth Swaminathan 		    gp_offset += hfa_size;
582*1fd5a2e1SPrashanth Swaminathan 		    fpcount += 1;
583*1fd5a2e1SPrashanth Swaminathan 		  }
584*1fd5a2e1SPrashanth Swaminathan 
585*1fd5a2e1SPrashanth Swaminathan 		if (offset < size)
586*1fd5a2e1SPrashanth Swaminathan 		  memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
587*1fd5a2e1SPrashanth Swaminathan 			  size - offset);
588*1fd5a2e1SPrashanth Swaminathan 	      }
589*1fd5a2e1SPrashanth Swaminathan 	    else
590*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = &stack->gp_regs[gpcount];
591*1fd5a2e1SPrashanth Swaminathan 
592*1fd5a2e1SPrashanth Swaminathan 	    gpcount += (size + 7) / 8;
593*1fd5a2e1SPrashanth Swaminathan 	  }
594*1fd5a2e1SPrashanth Swaminathan 	  break;
595*1fd5a2e1SPrashanth Swaminathan 
596*1fd5a2e1SPrashanth Swaminathan 	default:
597*1fd5a2e1SPrashanth Swaminathan 	  abort ();
598*1fd5a2e1SPrashanth Swaminathan 	}
599*1fd5a2e1SPrashanth Swaminathan     }
600*1fd5a2e1SPrashanth Swaminathan 
601*1fd5a2e1SPrashanth Swaminathan   closure->fun (cif, rvalue, avalue, closure->user_data);
602*1fd5a2e1SPrashanth Swaminathan 
603*1fd5a2e1SPrashanth Swaminathan   return cif->flags;
604*1fd5a2e1SPrashanth Swaminathan }
605