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