1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2012 Tilera Corp.
3*1fd5a2e1SPrashanth Swaminathan
4*1fd5a2e1SPrashanth Swaminathan TILE Foreign Function Interface
5*1fd5a2e1SPrashanth Swaminathan
6*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
7*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
8*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
9*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
10*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
11*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
12*1fd5a2e1SPrashanth Swaminathan the following conditions:
13*1fd5a2e1SPrashanth Swaminathan
14*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
15*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
16*1fd5a2e1SPrashanth Swaminathan
17*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
25*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
26*1fd5a2e1SPrashanth Swaminathan
27*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
28*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
29*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
30*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
31*1fd5a2e1SPrashanth Swaminathan #include <unistd.h>
32*1fd5a2e1SPrashanth Swaminathan #include <arch/abi.h>
33*1fd5a2e1SPrashanth Swaminathan #include <arch/icache.h>
34*1fd5a2e1SPrashanth Swaminathan #include <arch/opcode.h>
35*1fd5a2e1SPrashanth Swaminathan
36*1fd5a2e1SPrashanth Swaminathan
37*1fd5a2e1SPrashanth Swaminathan /* The first 10 registers are used to pass arguments and return values. */
38*1fd5a2e1SPrashanth Swaminathan #define NUM_ARG_REGS 10
39*1fd5a2e1SPrashanth Swaminathan
40*1fd5a2e1SPrashanth Swaminathan /* Performs a raw function call with the given NUM_ARG_REGS register arguments
41*1fd5a2e1SPrashanth Swaminathan and the specified additional stack arguments (if any). */
42*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_tile(ffi_sarg reg_args[NUM_ARG_REGS],
43*1fd5a2e1SPrashanth Swaminathan const ffi_sarg *stack_args,
44*1fd5a2e1SPrashanth Swaminathan size_t stack_args_bytes,
45*1fd5a2e1SPrashanth Swaminathan void (*fnaddr)(void))
46*1fd5a2e1SPrashanth Swaminathan FFI_HIDDEN;
47*1fd5a2e1SPrashanth Swaminathan
48*1fd5a2e1SPrashanth Swaminathan /* This handles the raw call from the closure stub, cleaning up the
49*1fd5a2e1SPrashanth Swaminathan parameters and delegating to ffi_closure_tile_inner. */
50*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_tile(void) FFI_HIDDEN;
51*1fd5a2e1SPrashanth Swaminathan
52*1fd5a2e1SPrashanth Swaminathan
53*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)54*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep(ffi_cif *cif)
55*1fd5a2e1SPrashanth Swaminathan {
56*1fd5a2e1SPrashanth Swaminathan /* We always allocate room for all registers. Even if we don't
57*1fd5a2e1SPrashanth Swaminathan use them as parameters, they get returned in the same array
58*1fd5a2e1SPrashanth Swaminathan as struct return values so we need to make room. */
59*1fd5a2e1SPrashanth Swaminathan if (cif->bytes < NUM_ARG_REGS * FFI_SIZEOF_ARG)
60*1fd5a2e1SPrashanth Swaminathan cif->bytes = NUM_ARG_REGS * FFI_SIZEOF_ARG;
61*1fd5a2e1SPrashanth Swaminathan
62*1fd5a2e1SPrashanth Swaminathan if (cif->rtype->size > NUM_ARG_REGS * FFI_SIZEOF_ARG)
63*1fd5a2e1SPrashanth Swaminathan cif->flags = FFI_TYPE_STRUCT;
64*1fd5a2e1SPrashanth Swaminathan else
65*1fd5a2e1SPrashanth Swaminathan cif->flags = FFI_TYPE_INT;
66*1fd5a2e1SPrashanth Swaminathan
67*1fd5a2e1SPrashanth Swaminathan /* Nothing to do. */
68*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
69*1fd5a2e1SPrashanth Swaminathan }
70*1fd5a2e1SPrashanth Swaminathan
71*1fd5a2e1SPrashanth Swaminathan
72*1fd5a2e1SPrashanth Swaminathan static long
assign_to_ffi_arg(ffi_sarg * out,void * in,const ffi_type * type,int write_to_reg)73*1fd5a2e1SPrashanth Swaminathan assign_to_ffi_arg(ffi_sarg *out, void *in, const ffi_type *type,
74*1fd5a2e1SPrashanth Swaminathan int write_to_reg)
75*1fd5a2e1SPrashanth Swaminathan {
76*1fd5a2e1SPrashanth Swaminathan switch (type->type)
77*1fd5a2e1SPrashanth Swaminathan {
78*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
79*1fd5a2e1SPrashanth Swaminathan *out = *(SINT8 *)in;
80*1fd5a2e1SPrashanth Swaminathan return 1;
81*1fd5a2e1SPrashanth Swaminathan
82*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
83*1fd5a2e1SPrashanth Swaminathan *out = *(UINT8 *)in;
84*1fd5a2e1SPrashanth Swaminathan return 1;
85*1fd5a2e1SPrashanth Swaminathan
86*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
87*1fd5a2e1SPrashanth Swaminathan *out = *(SINT16 *)in;
88*1fd5a2e1SPrashanth Swaminathan return 1;
89*1fd5a2e1SPrashanth Swaminathan
90*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
91*1fd5a2e1SPrashanth Swaminathan *out = *(UINT16 *)in;
92*1fd5a2e1SPrashanth Swaminathan return 1;
93*1fd5a2e1SPrashanth Swaminathan
94*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
95*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
96*1fd5a2e1SPrashanth Swaminathan #ifndef __LP64__
97*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
98*1fd5a2e1SPrashanth Swaminathan #endif
99*1fd5a2e1SPrashanth Swaminathan /* Note that even unsigned 32-bit quantities are sign extended
100*1fd5a2e1SPrashanth Swaminathan on tilegx when stored in a register. */
101*1fd5a2e1SPrashanth Swaminathan *out = *(SINT32 *)in;
102*1fd5a2e1SPrashanth Swaminathan return 1;
103*1fd5a2e1SPrashanth Swaminathan
104*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
105*1fd5a2e1SPrashanth Swaminathan #ifdef __tilegx__
106*1fd5a2e1SPrashanth Swaminathan if (write_to_reg)
107*1fd5a2e1SPrashanth Swaminathan {
108*1fd5a2e1SPrashanth Swaminathan /* Properly sign extend the value. */
109*1fd5a2e1SPrashanth Swaminathan union { float f; SINT32 s32; } val;
110*1fd5a2e1SPrashanth Swaminathan val.f = *(float *)in;
111*1fd5a2e1SPrashanth Swaminathan *out = val.s32;
112*1fd5a2e1SPrashanth Swaminathan }
113*1fd5a2e1SPrashanth Swaminathan else
114*1fd5a2e1SPrashanth Swaminathan #endif
115*1fd5a2e1SPrashanth Swaminathan {
116*1fd5a2e1SPrashanth Swaminathan *(float *)out = *(float *)in;
117*1fd5a2e1SPrashanth Swaminathan }
118*1fd5a2e1SPrashanth Swaminathan return 1;
119*1fd5a2e1SPrashanth Swaminathan
120*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
121*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
122*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
123*1fd5a2e1SPrashanth Swaminathan #ifdef __LP64__
124*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
125*1fd5a2e1SPrashanth Swaminathan #endif
126*1fd5a2e1SPrashanth Swaminathan *(UINT64 *)out = *(UINT64 *)in;
127*1fd5a2e1SPrashanth Swaminathan return sizeof(UINT64) / FFI_SIZEOF_ARG;
128*1fd5a2e1SPrashanth Swaminathan
129*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
130*1fd5a2e1SPrashanth Swaminathan memcpy(out, in, type->size);
131*1fd5a2e1SPrashanth Swaminathan return (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
132*1fd5a2e1SPrashanth Swaminathan
133*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
134*1fd5a2e1SPrashanth Swaminathan /* Must be a return type. Nothing to do. */
135*1fd5a2e1SPrashanth Swaminathan return 0;
136*1fd5a2e1SPrashanth Swaminathan
137*1fd5a2e1SPrashanth Swaminathan default:
138*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
139*1fd5a2e1SPrashanth Swaminathan return -1;
140*1fd5a2e1SPrashanth Swaminathan }
141*1fd5a2e1SPrashanth Swaminathan }
142*1fd5a2e1SPrashanth Swaminathan
143*1fd5a2e1SPrashanth Swaminathan
144*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)145*1fd5a2e1SPrashanth Swaminathan ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
146*1fd5a2e1SPrashanth Swaminathan {
147*1fd5a2e1SPrashanth Swaminathan ffi_sarg * const arg_mem = alloca(cif->bytes);
148*1fd5a2e1SPrashanth Swaminathan ffi_sarg * const reg_args = arg_mem;
149*1fd5a2e1SPrashanth Swaminathan ffi_sarg * const stack_args = ®_args[NUM_ARG_REGS];
150*1fd5a2e1SPrashanth Swaminathan ffi_sarg *argp = arg_mem;
151*1fd5a2e1SPrashanth Swaminathan ffi_type ** const arg_types = cif->arg_types;
152*1fd5a2e1SPrashanth Swaminathan const long num_args = cif->nargs;
153*1fd5a2e1SPrashanth Swaminathan long i;
154*1fd5a2e1SPrashanth Swaminathan
155*1fd5a2e1SPrashanth Swaminathan if (cif->flags == FFI_TYPE_STRUCT)
156*1fd5a2e1SPrashanth Swaminathan {
157*1fd5a2e1SPrashanth Swaminathan /* Pass a hidden pointer to the return value. We make sure there
158*1fd5a2e1SPrashanth Swaminathan is scratch space for the callee to store the return value even if
159*1fd5a2e1SPrashanth Swaminathan our caller doesn't care about it. */
160*1fd5a2e1SPrashanth Swaminathan *argp++ = (intptr_t)(rvalue ? rvalue : alloca(cif->rtype->size));
161*1fd5a2e1SPrashanth Swaminathan
162*1fd5a2e1SPrashanth Swaminathan /* No more work needed to return anything. */
163*1fd5a2e1SPrashanth Swaminathan rvalue = NULL;
164*1fd5a2e1SPrashanth Swaminathan }
165*1fd5a2e1SPrashanth Swaminathan
166*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < num_args; i++)
167*1fd5a2e1SPrashanth Swaminathan {
168*1fd5a2e1SPrashanth Swaminathan ffi_type *type = arg_types[i];
169*1fd5a2e1SPrashanth Swaminathan void * const arg_in = avalue[i];
170*1fd5a2e1SPrashanth Swaminathan ptrdiff_t arg_word = argp - arg_mem;
171*1fd5a2e1SPrashanth Swaminathan
172*1fd5a2e1SPrashanth Swaminathan #ifndef __tilegx__
173*1fd5a2e1SPrashanth Swaminathan /* Doubleword-aligned values are always in an even-number register
174*1fd5a2e1SPrashanth Swaminathan pair, or doubleword-aligned stack slot if out of registers. */
175*1fd5a2e1SPrashanth Swaminathan long align = arg_word & (type->alignment > FFI_SIZEOF_ARG);
176*1fd5a2e1SPrashanth Swaminathan argp += align;
177*1fd5a2e1SPrashanth Swaminathan arg_word += align;
178*1fd5a2e1SPrashanth Swaminathan #endif
179*1fd5a2e1SPrashanth Swaminathan
180*1fd5a2e1SPrashanth Swaminathan if (type->type == FFI_TYPE_STRUCT)
181*1fd5a2e1SPrashanth Swaminathan {
182*1fd5a2e1SPrashanth Swaminathan const size_t arg_size_in_words =
183*1fd5a2e1SPrashanth Swaminathan (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
184*1fd5a2e1SPrashanth Swaminathan
185*1fd5a2e1SPrashanth Swaminathan if (arg_word < NUM_ARG_REGS &&
186*1fd5a2e1SPrashanth Swaminathan arg_word + arg_size_in_words > NUM_ARG_REGS)
187*1fd5a2e1SPrashanth Swaminathan {
188*1fd5a2e1SPrashanth Swaminathan /* Args are not allowed to span registers and the stack. */
189*1fd5a2e1SPrashanth Swaminathan argp = stack_args;
190*1fd5a2e1SPrashanth Swaminathan }
191*1fd5a2e1SPrashanth Swaminathan
192*1fd5a2e1SPrashanth Swaminathan memcpy(argp, arg_in, type->size);
193*1fd5a2e1SPrashanth Swaminathan argp += arg_size_in_words;
194*1fd5a2e1SPrashanth Swaminathan }
195*1fd5a2e1SPrashanth Swaminathan else
196*1fd5a2e1SPrashanth Swaminathan {
197*1fd5a2e1SPrashanth Swaminathan argp += assign_to_ffi_arg(argp, arg_in, arg_types[i], 1);
198*1fd5a2e1SPrashanth Swaminathan }
199*1fd5a2e1SPrashanth Swaminathan }
200*1fd5a2e1SPrashanth Swaminathan
201*1fd5a2e1SPrashanth Swaminathan /* Actually do the call. */
202*1fd5a2e1SPrashanth Swaminathan ffi_call_tile(reg_args, stack_args,
203*1fd5a2e1SPrashanth Swaminathan cif->bytes - (NUM_ARG_REGS * FFI_SIZEOF_ARG), fn);
204*1fd5a2e1SPrashanth Swaminathan
205*1fd5a2e1SPrashanth Swaminathan if (rvalue != NULL)
206*1fd5a2e1SPrashanth Swaminathan assign_to_ffi_arg(rvalue, reg_args, cif->rtype, 0);
207*1fd5a2e1SPrashanth Swaminathan }
208*1fd5a2e1SPrashanth Swaminathan
209*1fd5a2e1SPrashanth Swaminathan
210*1fd5a2e1SPrashanth Swaminathan /* Template code for closure. */
211*1fd5a2e1SPrashanth Swaminathan extern const UINT64 ffi_template_tramp_tile[] FFI_HIDDEN;
212*1fd5a2e1SPrashanth Swaminathan
213*1fd5a2e1SPrashanth Swaminathan
214*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)215*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
216*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif,
217*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
218*1fd5a2e1SPrashanth Swaminathan void *user_data,
219*1fd5a2e1SPrashanth Swaminathan void *codeloc)
220*1fd5a2e1SPrashanth Swaminathan {
221*1fd5a2e1SPrashanth Swaminathan #ifdef __tilegx__
222*1fd5a2e1SPrashanth Swaminathan /* TILE-Gx */
223*1fd5a2e1SPrashanth Swaminathan SINT64 c;
224*1fd5a2e1SPrashanth Swaminathan SINT64 h;
225*1fd5a2e1SPrashanth Swaminathan int s;
226*1fd5a2e1SPrashanth Swaminathan UINT64 *out;
227*1fd5a2e1SPrashanth Swaminathan
228*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_UNIX)
229*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
230*1fd5a2e1SPrashanth Swaminathan
231*1fd5a2e1SPrashanth Swaminathan out = (UINT64 *)closure->tramp;
232*1fd5a2e1SPrashanth Swaminathan
233*1fd5a2e1SPrashanth Swaminathan c = (intptr_t)closure;
234*1fd5a2e1SPrashanth Swaminathan h = (intptr_t)ffi_closure_tile;
235*1fd5a2e1SPrashanth Swaminathan s = 0;
236*1fd5a2e1SPrashanth Swaminathan
237*1fd5a2e1SPrashanth Swaminathan /* Find the smallest shift count that doesn't lose information
238*1fd5a2e1SPrashanth Swaminathan (i.e. no need to explicitly insert high bits of the address that
239*1fd5a2e1SPrashanth Swaminathan are just the sign extension of the low bits). */
240*1fd5a2e1SPrashanth Swaminathan while ((c >> s) != (SINT16)(c >> s) || (h >> s) != (SINT16)(h >> s))
241*1fd5a2e1SPrashanth Swaminathan s += 16;
242*1fd5a2e1SPrashanth Swaminathan
243*1fd5a2e1SPrashanth Swaminathan #define OPS(a, b, shift) \
244*1fd5a2e1SPrashanth Swaminathan (create_Imm16_X0((a) >> (shift)) | create_Imm16_X1((b) >> (shift)))
245*1fd5a2e1SPrashanth Swaminathan
246*1fd5a2e1SPrashanth Swaminathan /* Emit the moveli. */
247*1fd5a2e1SPrashanth Swaminathan *out++ = ffi_template_tramp_tile[0] | OPS(c, h, s);
248*1fd5a2e1SPrashanth Swaminathan for (s -= 16; s >= 0; s -= 16)
249*1fd5a2e1SPrashanth Swaminathan *out++ = ffi_template_tramp_tile[1] | OPS(c, h, s);
250*1fd5a2e1SPrashanth Swaminathan
251*1fd5a2e1SPrashanth Swaminathan #undef OPS
252*1fd5a2e1SPrashanth Swaminathan
253*1fd5a2e1SPrashanth Swaminathan *out++ = ffi_template_tramp_tile[2];
254*1fd5a2e1SPrashanth Swaminathan
255*1fd5a2e1SPrashanth Swaminathan #else
256*1fd5a2e1SPrashanth Swaminathan /* TILEPro */
257*1fd5a2e1SPrashanth Swaminathan UINT64 *out;
258*1fd5a2e1SPrashanth Swaminathan intptr_t delta;
259*1fd5a2e1SPrashanth Swaminathan
260*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_UNIX)
261*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
262*1fd5a2e1SPrashanth Swaminathan
263*1fd5a2e1SPrashanth Swaminathan out = (UINT64 *)closure->tramp;
264*1fd5a2e1SPrashanth Swaminathan delta = (intptr_t)ffi_closure_tile - (intptr_t)codeloc;
265*1fd5a2e1SPrashanth Swaminathan
266*1fd5a2e1SPrashanth Swaminathan *out++ = ffi_template_tramp_tile[0] | create_JOffLong_X1(delta >> 3);
267*1fd5a2e1SPrashanth Swaminathan #endif
268*1fd5a2e1SPrashanth Swaminathan
269*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
270*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
271*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
272*1fd5a2e1SPrashanth Swaminathan
273*1fd5a2e1SPrashanth Swaminathan invalidate_icache(closure->tramp, (char *)out - closure->tramp,
274*1fd5a2e1SPrashanth Swaminathan getpagesize());
275*1fd5a2e1SPrashanth Swaminathan
276*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
277*1fd5a2e1SPrashanth Swaminathan }
278*1fd5a2e1SPrashanth Swaminathan
279*1fd5a2e1SPrashanth Swaminathan
280*1fd5a2e1SPrashanth Swaminathan /* This is called by the assembly wrapper for closures. This does
281*1fd5a2e1SPrashanth Swaminathan all of the work. On entry reg_args[0] holds the values the registers
282*1fd5a2e1SPrashanth Swaminathan had when the closure was invoked. On return reg_args[1] holds the register
283*1fd5a2e1SPrashanth Swaminathan values to be returned to the caller (many of which may be garbage). */
284*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN
ffi_closure_tile_inner(ffi_closure * closure,ffi_sarg reg_args[2][NUM_ARG_REGS],ffi_sarg * stack_args)285*1fd5a2e1SPrashanth Swaminathan ffi_closure_tile_inner(ffi_closure *closure,
286*1fd5a2e1SPrashanth Swaminathan ffi_sarg reg_args[2][NUM_ARG_REGS],
287*1fd5a2e1SPrashanth Swaminathan ffi_sarg *stack_args)
288*1fd5a2e1SPrashanth Swaminathan {
289*1fd5a2e1SPrashanth Swaminathan ffi_cif * const cif = closure->cif;
290*1fd5a2e1SPrashanth Swaminathan void ** const avalue = alloca(cif->nargs * sizeof(void *));
291*1fd5a2e1SPrashanth Swaminathan void *rvalue;
292*1fd5a2e1SPrashanth Swaminathan ffi_type ** const arg_types = cif->arg_types;
293*1fd5a2e1SPrashanth Swaminathan ffi_sarg * const reg_args_in = reg_args[0];
294*1fd5a2e1SPrashanth Swaminathan ffi_sarg * const reg_args_out = reg_args[1];
295*1fd5a2e1SPrashanth Swaminathan ffi_sarg * argp;
296*1fd5a2e1SPrashanth Swaminathan long i, arg_word, nargs = cif->nargs;
297*1fd5a2e1SPrashanth Swaminathan /* Use a union to guarantee proper alignment for double. */
298*1fd5a2e1SPrashanth Swaminathan union { ffi_sarg arg[NUM_ARG_REGS]; double d; UINT64 u64; } closure_ret;
299*1fd5a2e1SPrashanth Swaminathan
300*1fd5a2e1SPrashanth Swaminathan /* Start out reading register arguments. */
301*1fd5a2e1SPrashanth Swaminathan argp = reg_args_in;
302*1fd5a2e1SPrashanth Swaminathan
303*1fd5a2e1SPrashanth Swaminathan /* Copy the caller's structure return address to that the closure
304*1fd5a2e1SPrashanth Swaminathan returns the data directly to the caller. */
305*1fd5a2e1SPrashanth Swaminathan if (cif->flags == FFI_TYPE_STRUCT)
306*1fd5a2e1SPrashanth Swaminathan {
307*1fd5a2e1SPrashanth Swaminathan /* Return by reference via hidden pointer. */
308*1fd5a2e1SPrashanth Swaminathan rvalue = (void *)(intptr_t)*argp++;
309*1fd5a2e1SPrashanth Swaminathan arg_word = 1;
310*1fd5a2e1SPrashanth Swaminathan }
311*1fd5a2e1SPrashanth Swaminathan else
312*1fd5a2e1SPrashanth Swaminathan {
313*1fd5a2e1SPrashanth Swaminathan /* Return the value in registers. */
314*1fd5a2e1SPrashanth Swaminathan rvalue = &closure_ret;
315*1fd5a2e1SPrashanth Swaminathan arg_word = 0;
316*1fd5a2e1SPrashanth Swaminathan }
317*1fd5a2e1SPrashanth Swaminathan
318*1fd5a2e1SPrashanth Swaminathan /* Grab the addresses of the arguments. */
319*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < nargs; i++)
320*1fd5a2e1SPrashanth Swaminathan {
321*1fd5a2e1SPrashanth Swaminathan ffi_type * const type = arg_types[i];
322*1fd5a2e1SPrashanth Swaminathan const size_t arg_size_in_words =
323*1fd5a2e1SPrashanth Swaminathan (type->size + FFI_SIZEOF_ARG - 1) / FFI_SIZEOF_ARG;
324*1fd5a2e1SPrashanth Swaminathan
325*1fd5a2e1SPrashanth Swaminathan #ifndef __tilegx__
326*1fd5a2e1SPrashanth Swaminathan /* Doubleword-aligned values are always in an even-number register
327*1fd5a2e1SPrashanth Swaminathan pair, or doubleword-aligned stack slot if out of registers. */
328*1fd5a2e1SPrashanth Swaminathan long align = arg_word & (type->alignment > FFI_SIZEOF_ARG);
329*1fd5a2e1SPrashanth Swaminathan argp += align;
330*1fd5a2e1SPrashanth Swaminathan arg_word += align;
331*1fd5a2e1SPrashanth Swaminathan #endif
332*1fd5a2e1SPrashanth Swaminathan
333*1fd5a2e1SPrashanth Swaminathan if (arg_word == NUM_ARG_REGS ||
334*1fd5a2e1SPrashanth Swaminathan (arg_word < NUM_ARG_REGS &&
335*1fd5a2e1SPrashanth Swaminathan arg_word + arg_size_in_words > NUM_ARG_REGS))
336*1fd5a2e1SPrashanth Swaminathan {
337*1fd5a2e1SPrashanth Swaminathan /* Switch to reading arguments from the stack. */
338*1fd5a2e1SPrashanth Swaminathan argp = stack_args;
339*1fd5a2e1SPrashanth Swaminathan arg_word = NUM_ARG_REGS;
340*1fd5a2e1SPrashanth Swaminathan }
341*1fd5a2e1SPrashanth Swaminathan
342*1fd5a2e1SPrashanth Swaminathan avalue[i] = argp;
343*1fd5a2e1SPrashanth Swaminathan argp += arg_size_in_words;
344*1fd5a2e1SPrashanth Swaminathan arg_word += arg_size_in_words;
345*1fd5a2e1SPrashanth Swaminathan }
346*1fd5a2e1SPrashanth Swaminathan
347*1fd5a2e1SPrashanth Swaminathan /* Invoke the closure. */
348*1fd5a2e1SPrashanth Swaminathan closure->fun(cif, rvalue, avalue, closure->user_data);
349*1fd5a2e1SPrashanth Swaminathan
350*1fd5a2e1SPrashanth Swaminathan if (cif->flags != FFI_TYPE_STRUCT)
351*1fd5a2e1SPrashanth Swaminathan {
352*1fd5a2e1SPrashanth Swaminathan /* Canonicalize for register representation. */
353*1fd5a2e1SPrashanth Swaminathan assign_to_ffi_arg(reg_args_out, &closure_ret, cif->rtype, 1);
354*1fd5a2e1SPrashanth Swaminathan }
355*1fd5a2e1SPrashanth Swaminathan }
356