1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi64.c - Copyright (c) 2011, 2018 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 2013 The Written Word, Inc.
4*1fd5a2e1SPrashanth Swaminathan Copyright (c) 2008, 2010 Red Hat, Inc.
5*1fd5a2e1SPrashanth Swaminathan Copyright (c) 2002, 2007 Bo Thorsen <[email protected]>
6*1fd5a2e1SPrashanth Swaminathan
7*1fd5a2e1SPrashanth Swaminathan x86-64 Foreign Function Interface
8*1fd5a2e1SPrashanth Swaminathan
9*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
10*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
11*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
12*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
13*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
14*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
15*1fd5a2e1SPrashanth Swaminathan the following conditions:
16*1fd5a2e1SPrashanth Swaminathan
17*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
18*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
19*1fd5a2e1SPrashanth Swaminathan
20*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
21*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
28*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
29*1fd5a2e1SPrashanth Swaminathan
30*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
31*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
32*1fd5a2e1SPrashanth Swaminathan
33*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
34*1fd5a2e1SPrashanth Swaminathan #include <stdarg.h>
35*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
36*1fd5a2e1SPrashanth Swaminathan #include "internal64.h"
37*1fd5a2e1SPrashanth Swaminathan
38*1fd5a2e1SPrashanth Swaminathan #ifdef __x86_64__
39*1fd5a2e1SPrashanth Swaminathan
40*1fd5a2e1SPrashanth Swaminathan #define MAX_GPR_REGS 6
41*1fd5a2e1SPrashanth Swaminathan #define MAX_SSE_REGS 8
42*1fd5a2e1SPrashanth Swaminathan
43*1fd5a2e1SPrashanth Swaminathan #if defined(__INTEL_COMPILER)
44*1fd5a2e1SPrashanth Swaminathan #include "xmmintrin.h"
45*1fd5a2e1SPrashanth Swaminathan #define UINT128 __m128
46*1fd5a2e1SPrashanth Swaminathan #else
47*1fd5a2e1SPrashanth Swaminathan #if defined(__SUNPRO_C)
48*1fd5a2e1SPrashanth Swaminathan #include <sunmedia_types.h>
49*1fd5a2e1SPrashanth Swaminathan #define UINT128 __m128i
50*1fd5a2e1SPrashanth Swaminathan #else
51*1fd5a2e1SPrashanth Swaminathan #define UINT128 __int128_t
52*1fd5a2e1SPrashanth Swaminathan #endif
53*1fd5a2e1SPrashanth Swaminathan #endif
54*1fd5a2e1SPrashanth Swaminathan
55*1fd5a2e1SPrashanth Swaminathan union big_int_union
56*1fd5a2e1SPrashanth Swaminathan {
57*1fd5a2e1SPrashanth Swaminathan UINT32 i32;
58*1fd5a2e1SPrashanth Swaminathan UINT64 i64;
59*1fd5a2e1SPrashanth Swaminathan UINT128 i128;
60*1fd5a2e1SPrashanth Swaminathan };
61*1fd5a2e1SPrashanth Swaminathan
62*1fd5a2e1SPrashanth Swaminathan struct register_args
63*1fd5a2e1SPrashanth Swaminathan {
64*1fd5a2e1SPrashanth Swaminathan /* Registers for argument passing. */
65*1fd5a2e1SPrashanth Swaminathan UINT64 gpr[MAX_GPR_REGS];
66*1fd5a2e1SPrashanth Swaminathan union big_int_union sse[MAX_SSE_REGS];
67*1fd5a2e1SPrashanth Swaminathan UINT64 rax; /* ssecount */
68*1fd5a2e1SPrashanth Swaminathan UINT64 r10; /* static chain */
69*1fd5a2e1SPrashanth Swaminathan };
70*1fd5a2e1SPrashanth Swaminathan
71*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
72*1fd5a2e1SPrashanth Swaminathan void *raddr, void (*fnaddr)(void)) FFI_HIDDEN;
73*1fd5a2e1SPrashanth Swaminathan
74*1fd5a2e1SPrashanth Swaminathan /* All reference to register classes here is identical to the code in
75*1fd5a2e1SPrashanth Swaminathan gcc/config/i386/i386.c. Do *not* change one without the other. */
76*1fd5a2e1SPrashanth Swaminathan
77*1fd5a2e1SPrashanth Swaminathan /* Register class used for passing given 64bit part of the argument.
78*1fd5a2e1SPrashanth Swaminathan These represent classes as documented by the PS ABI, with the
79*1fd5a2e1SPrashanth Swaminathan exception of SSESF, SSEDF classes, that are basically SSE class,
80*1fd5a2e1SPrashanth Swaminathan just gcc will use SF or DFmode move instead of DImode to avoid
81*1fd5a2e1SPrashanth Swaminathan reformatting penalties.
82*1fd5a2e1SPrashanth Swaminathan
83*1fd5a2e1SPrashanth Swaminathan Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
84*1fd5a2e1SPrashanth Swaminathan whenever possible (upper half does contain padding). */
85*1fd5a2e1SPrashanth Swaminathan enum x86_64_reg_class
86*1fd5a2e1SPrashanth Swaminathan {
87*1fd5a2e1SPrashanth Swaminathan X86_64_NO_CLASS,
88*1fd5a2e1SPrashanth Swaminathan X86_64_INTEGER_CLASS,
89*1fd5a2e1SPrashanth Swaminathan X86_64_INTEGERSI_CLASS,
90*1fd5a2e1SPrashanth Swaminathan X86_64_SSE_CLASS,
91*1fd5a2e1SPrashanth Swaminathan X86_64_SSESF_CLASS,
92*1fd5a2e1SPrashanth Swaminathan X86_64_SSEDF_CLASS,
93*1fd5a2e1SPrashanth Swaminathan X86_64_SSEUP_CLASS,
94*1fd5a2e1SPrashanth Swaminathan X86_64_X87_CLASS,
95*1fd5a2e1SPrashanth Swaminathan X86_64_X87UP_CLASS,
96*1fd5a2e1SPrashanth Swaminathan X86_64_COMPLEX_X87_CLASS,
97*1fd5a2e1SPrashanth Swaminathan X86_64_MEMORY_CLASS
98*1fd5a2e1SPrashanth Swaminathan };
99*1fd5a2e1SPrashanth Swaminathan
100*1fd5a2e1SPrashanth Swaminathan #define MAX_CLASSES 4
101*1fd5a2e1SPrashanth Swaminathan
102*1fd5a2e1SPrashanth Swaminathan #define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
103*1fd5a2e1SPrashanth Swaminathan
104*1fd5a2e1SPrashanth Swaminathan /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
105*1fd5a2e1SPrashanth Swaminathan of this code is to classify each 8bytes of incoming argument by the register
106*1fd5a2e1SPrashanth Swaminathan class and assign registers accordingly. */
107*1fd5a2e1SPrashanth Swaminathan
108*1fd5a2e1SPrashanth Swaminathan /* Return the union class of CLASS1 and CLASS2.
109*1fd5a2e1SPrashanth Swaminathan See the x86-64 PS ABI for details. */
110*1fd5a2e1SPrashanth Swaminathan
111*1fd5a2e1SPrashanth Swaminathan static enum x86_64_reg_class
merge_classes(enum x86_64_reg_class class1,enum x86_64_reg_class class2)112*1fd5a2e1SPrashanth Swaminathan merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
113*1fd5a2e1SPrashanth Swaminathan {
114*1fd5a2e1SPrashanth Swaminathan /* Rule #1: If both classes are equal, this is the resulting class. */
115*1fd5a2e1SPrashanth Swaminathan if (class1 == class2)
116*1fd5a2e1SPrashanth Swaminathan return class1;
117*1fd5a2e1SPrashanth Swaminathan
118*1fd5a2e1SPrashanth Swaminathan /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
119*1fd5a2e1SPrashanth Swaminathan the other class. */
120*1fd5a2e1SPrashanth Swaminathan if (class1 == X86_64_NO_CLASS)
121*1fd5a2e1SPrashanth Swaminathan return class2;
122*1fd5a2e1SPrashanth Swaminathan if (class2 == X86_64_NO_CLASS)
123*1fd5a2e1SPrashanth Swaminathan return class1;
124*1fd5a2e1SPrashanth Swaminathan
125*1fd5a2e1SPrashanth Swaminathan /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
126*1fd5a2e1SPrashanth Swaminathan if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
127*1fd5a2e1SPrashanth Swaminathan return X86_64_MEMORY_CLASS;
128*1fd5a2e1SPrashanth Swaminathan
129*1fd5a2e1SPrashanth Swaminathan /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
130*1fd5a2e1SPrashanth Swaminathan if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
131*1fd5a2e1SPrashanth Swaminathan || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
132*1fd5a2e1SPrashanth Swaminathan return X86_64_INTEGERSI_CLASS;
133*1fd5a2e1SPrashanth Swaminathan if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
134*1fd5a2e1SPrashanth Swaminathan || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
135*1fd5a2e1SPrashanth Swaminathan return X86_64_INTEGER_CLASS;
136*1fd5a2e1SPrashanth Swaminathan
137*1fd5a2e1SPrashanth Swaminathan /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
138*1fd5a2e1SPrashanth Swaminathan MEMORY is used. */
139*1fd5a2e1SPrashanth Swaminathan if (class1 == X86_64_X87_CLASS
140*1fd5a2e1SPrashanth Swaminathan || class1 == X86_64_X87UP_CLASS
141*1fd5a2e1SPrashanth Swaminathan || class1 == X86_64_COMPLEX_X87_CLASS
142*1fd5a2e1SPrashanth Swaminathan || class2 == X86_64_X87_CLASS
143*1fd5a2e1SPrashanth Swaminathan || class2 == X86_64_X87UP_CLASS
144*1fd5a2e1SPrashanth Swaminathan || class2 == X86_64_COMPLEX_X87_CLASS)
145*1fd5a2e1SPrashanth Swaminathan return X86_64_MEMORY_CLASS;
146*1fd5a2e1SPrashanth Swaminathan
147*1fd5a2e1SPrashanth Swaminathan /* Rule #6: Otherwise class SSE is used. */
148*1fd5a2e1SPrashanth Swaminathan return X86_64_SSE_CLASS;
149*1fd5a2e1SPrashanth Swaminathan }
150*1fd5a2e1SPrashanth Swaminathan
151*1fd5a2e1SPrashanth Swaminathan /* Classify the argument of type TYPE and mode MODE.
152*1fd5a2e1SPrashanth Swaminathan CLASSES will be filled by the register class used to pass each word
153*1fd5a2e1SPrashanth Swaminathan of the operand. The number of words is returned. In case the parameter
154*1fd5a2e1SPrashanth Swaminathan should be passed in memory, 0 is returned. As a special case for zero
155*1fd5a2e1SPrashanth Swaminathan sized containers, classes[0] will be NO_CLASS and 1 is returned.
156*1fd5a2e1SPrashanth Swaminathan
157*1fd5a2e1SPrashanth Swaminathan See the x86-64 PS ABI for details.
158*1fd5a2e1SPrashanth Swaminathan */
159*1fd5a2e1SPrashanth Swaminathan static size_t
classify_argument(ffi_type * type,enum x86_64_reg_class classes[],size_t byte_offset)160*1fd5a2e1SPrashanth Swaminathan classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
161*1fd5a2e1SPrashanth Swaminathan size_t byte_offset)
162*1fd5a2e1SPrashanth Swaminathan {
163*1fd5a2e1SPrashanth Swaminathan switch (type->type)
164*1fd5a2e1SPrashanth Swaminathan {
165*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
166*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
167*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
168*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
169*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
170*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
171*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
172*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
173*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
174*1fd5a2e1SPrashanth Swaminathan do_integer:
175*1fd5a2e1SPrashanth Swaminathan {
176*1fd5a2e1SPrashanth Swaminathan size_t size = byte_offset + type->size;
177*1fd5a2e1SPrashanth Swaminathan
178*1fd5a2e1SPrashanth Swaminathan if (size <= 4)
179*1fd5a2e1SPrashanth Swaminathan {
180*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_INTEGERSI_CLASS;
181*1fd5a2e1SPrashanth Swaminathan return 1;
182*1fd5a2e1SPrashanth Swaminathan }
183*1fd5a2e1SPrashanth Swaminathan else if (size <= 8)
184*1fd5a2e1SPrashanth Swaminathan {
185*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_INTEGER_CLASS;
186*1fd5a2e1SPrashanth Swaminathan return 1;
187*1fd5a2e1SPrashanth Swaminathan }
188*1fd5a2e1SPrashanth Swaminathan else if (size <= 12)
189*1fd5a2e1SPrashanth Swaminathan {
190*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_INTEGER_CLASS;
191*1fd5a2e1SPrashanth Swaminathan classes[1] = X86_64_INTEGERSI_CLASS;
192*1fd5a2e1SPrashanth Swaminathan return 2;
193*1fd5a2e1SPrashanth Swaminathan }
194*1fd5a2e1SPrashanth Swaminathan else if (size <= 16)
195*1fd5a2e1SPrashanth Swaminathan {
196*1fd5a2e1SPrashanth Swaminathan classes[0] = classes[1] = X86_64_INTEGER_CLASS;
197*1fd5a2e1SPrashanth Swaminathan return 2;
198*1fd5a2e1SPrashanth Swaminathan }
199*1fd5a2e1SPrashanth Swaminathan else
200*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (0);
201*1fd5a2e1SPrashanth Swaminathan }
202*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
203*1fd5a2e1SPrashanth Swaminathan if (!(byte_offset % 8))
204*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_SSESF_CLASS;
205*1fd5a2e1SPrashanth Swaminathan else
206*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_SSE_CLASS;
207*1fd5a2e1SPrashanth Swaminathan return 1;
208*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
209*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_SSEDF_CLASS;
210*1fd5a2e1SPrashanth Swaminathan return 1;
211*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
212*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
213*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_X87_CLASS;
214*1fd5a2e1SPrashanth Swaminathan classes[1] = X86_64_X87UP_CLASS;
215*1fd5a2e1SPrashanth Swaminathan return 2;
216*1fd5a2e1SPrashanth Swaminathan #endif
217*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
218*1fd5a2e1SPrashanth Swaminathan {
219*1fd5a2e1SPrashanth Swaminathan const size_t UNITS_PER_WORD = 8;
220*1fd5a2e1SPrashanth Swaminathan size_t words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
221*1fd5a2e1SPrashanth Swaminathan ffi_type **ptr;
222*1fd5a2e1SPrashanth Swaminathan unsigned int i;
223*1fd5a2e1SPrashanth Swaminathan enum x86_64_reg_class subclasses[MAX_CLASSES];
224*1fd5a2e1SPrashanth Swaminathan
225*1fd5a2e1SPrashanth Swaminathan /* If the struct is larger than 32 bytes, pass it on the stack. */
226*1fd5a2e1SPrashanth Swaminathan if (type->size > 32)
227*1fd5a2e1SPrashanth Swaminathan return 0;
228*1fd5a2e1SPrashanth Swaminathan
229*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < words; i++)
230*1fd5a2e1SPrashanth Swaminathan classes[i] = X86_64_NO_CLASS;
231*1fd5a2e1SPrashanth Swaminathan
232*1fd5a2e1SPrashanth Swaminathan /* Zero sized arrays or structures are NO_CLASS. We return 0 to
233*1fd5a2e1SPrashanth Swaminathan signalize memory class, so handle it as special case. */
234*1fd5a2e1SPrashanth Swaminathan if (!words)
235*1fd5a2e1SPrashanth Swaminathan {
236*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
237*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_NO_CLASS;
238*1fd5a2e1SPrashanth Swaminathan return 1;
239*1fd5a2e1SPrashanth Swaminathan }
240*1fd5a2e1SPrashanth Swaminathan
241*1fd5a2e1SPrashanth Swaminathan /* Merge the fields of structure. */
242*1fd5a2e1SPrashanth Swaminathan for (ptr = type->elements; *ptr != NULL; ptr++)
243*1fd5a2e1SPrashanth Swaminathan {
244*1fd5a2e1SPrashanth Swaminathan size_t num;
245*1fd5a2e1SPrashanth Swaminathan
246*1fd5a2e1SPrashanth Swaminathan byte_offset = FFI_ALIGN (byte_offset, (*ptr)->alignment);
247*1fd5a2e1SPrashanth Swaminathan
248*1fd5a2e1SPrashanth Swaminathan num = classify_argument (*ptr, subclasses, byte_offset % 8);
249*1fd5a2e1SPrashanth Swaminathan if (num == 0)
250*1fd5a2e1SPrashanth Swaminathan return 0;
251*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < num; i++)
252*1fd5a2e1SPrashanth Swaminathan {
253*1fd5a2e1SPrashanth Swaminathan size_t pos = byte_offset / 8;
254*1fd5a2e1SPrashanth Swaminathan classes[i + pos] =
255*1fd5a2e1SPrashanth Swaminathan merge_classes (subclasses[i], classes[i + pos]);
256*1fd5a2e1SPrashanth Swaminathan }
257*1fd5a2e1SPrashanth Swaminathan
258*1fd5a2e1SPrashanth Swaminathan byte_offset += (*ptr)->size;
259*1fd5a2e1SPrashanth Swaminathan }
260*1fd5a2e1SPrashanth Swaminathan
261*1fd5a2e1SPrashanth Swaminathan if (words > 2)
262*1fd5a2e1SPrashanth Swaminathan {
263*1fd5a2e1SPrashanth Swaminathan /* When size > 16 bytes, if the first one isn't
264*1fd5a2e1SPrashanth Swaminathan X86_64_SSE_CLASS or any other ones aren't
265*1fd5a2e1SPrashanth Swaminathan X86_64_SSEUP_CLASS, everything should be passed in
266*1fd5a2e1SPrashanth Swaminathan memory. */
267*1fd5a2e1SPrashanth Swaminathan if (classes[0] != X86_64_SSE_CLASS)
268*1fd5a2e1SPrashanth Swaminathan return 0;
269*1fd5a2e1SPrashanth Swaminathan
270*1fd5a2e1SPrashanth Swaminathan for (i = 1; i < words; i++)
271*1fd5a2e1SPrashanth Swaminathan if (classes[i] != X86_64_SSEUP_CLASS)
272*1fd5a2e1SPrashanth Swaminathan return 0;
273*1fd5a2e1SPrashanth Swaminathan }
274*1fd5a2e1SPrashanth Swaminathan
275*1fd5a2e1SPrashanth Swaminathan /* Final merger cleanup. */
276*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < words; i++)
277*1fd5a2e1SPrashanth Swaminathan {
278*1fd5a2e1SPrashanth Swaminathan /* If one class is MEMORY, everything should be passed in
279*1fd5a2e1SPrashanth Swaminathan memory. */
280*1fd5a2e1SPrashanth Swaminathan if (classes[i] == X86_64_MEMORY_CLASS)
281*1fd5a2e1SPrashanth Swaminathan return 0;
282*1fd5a2e1SPrashanth Swaminathan
283*1fd5a2e1SPrashanth Swaminathan /* The X86_64_SSEUP_CLASS should be always preceded by
284*1fd5a2e1SPrashanth Swaminathan X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
285*1fd5a2e1SPrashanth Swaminathan if (i > 1 && classes[i] == X86_64_SSEUP_CLASS
286*1fd5a2e1SPrashanth Swaminathan && classes[i - 1] != X86_64_SSE_CLASS
287*1fd5a2e1SPrashanth Swaminathan && classes[i - 1] != X86_64_SSEUP_CLASS)
288*1fd5a2e1SPrashanth Swaminathan {
289*1fd5a2e1SPrashanth Swaminathan /* The first one should never be X86_64_SSEUP_CLASS. */
290*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (i != 0);
291*1fd5a2e1SPrashanth Swaminathan classes[i] = X86_64_SSE_CLASS;
292*1fd5a2e1SPrashanth Swaminathan }
293*1fd5a2e1SPrashanth Swaminathan
294*1fd5a2e1SPrashanth Swaminathan /* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
295*1fd5a2e1SPrashanth Swaminathan everything should be passed in memory. */
296*1fd5a2e1SPrashanth Swaminathan if (i > 1 && classes[i] == X86_64_X87UP_CLASS
297*1fd5a2e1SPrashanth Swaminathan && (classes[i - 1] != X86_64_X87_CLASS))
298*1fd5a2e1SPrashanth Swaminathan {
299*1fd5a2e1SPrashanth Swaminathan /* The first one should never be X86_64_X87UP_CLASS. */
300*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (i != 0);
301*1fd5a2e1SPrashanth Swaminathan return 0;
302*1fd5a2e1SPrashanth Swaminathan }
303*1fd5a2e1SPrashanth Swaminathan }
304*1fd5a2e1SPrashanth Swaminathan return words;
305*1fd5a2e1SPrashanth Swaminathan }
306*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
307*1fd5a2e1SPrashanth Swaminathan {
308*1fd5a2e1SPrashanth Swaminathan ffi_type *inner = type->elements[0];
309*1fd5a2e1SPrashanth Swaminathan switch (inner->type)
310*1fd5a2e1SPrashanth Swaminathan {
311*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
312*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
313*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
314*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
315*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
316*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
317*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
318*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
319*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
320*1fd5a2e1SPrashanth Swaminathan goto do_integer;
321*1fd5a2e1SPrashanth Swaminathan
322*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
323*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_SSE_CLASS;
324*1fd5a2e1SPrashanth Swaminathan if (byte_offset % 8)
325*1fd5a2e1SPrashanth Swaminathan {
326*1fd5a2e1SPrashanth Swaminathan classes[1] = X86_64_SSESF_CLASS;
327*1fd5a2e1SPrashanth Swaminathan return 2;
328*1fd5a2e1SPrashanth Swaminathan }
329*1fd5a2e1SPrashanth Swaminathan return 1;
330*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
331*1fd5a2e1SPrashanth Swaminathan classes[0] = classes[1] = X86_64_SSEDF_CLASS;
332*1fd5a2e1SPrashanth Swaminathan return 2;
333*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
334*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
335*1fd5a2e1SPrashanth Swaminathan classes[0] = X86_64_COMPLEX_X87_CLASS;
336*1fd5a2e1SPrashanth Swaminathan return 1;
337*1fd5a2e1SPrashanth Swaminathan #endif
338*1fd5a2e1SPrashanth Swaminathan }
339*1fd5a2e1SPrashanth Swaminathan }
340*1fd5a2e1SPrashanth Swaminathan }
341*1fd5a2e1SPrashanth Swaminathan abort();
342*1fd5a2e1SPrashanth Swaminathan }
343*1fd5a2e1SPrashanth Swaminathan
344*1fd5a2e1SPrashanth Swaminathan /* Examine the argument and return set number of register required in each
345*1fd5a2e1SPrashanth Swaminathan class. Return zero iff parameter should be passed in memory, otherwise
346*1fd5a2e1SPrashanth Swaminathan the number of registers. */
347*1fd5a2e1SPrashanth Swaminathan
348*1fd5a2e1SPrashanth Swaminathan static size_t
examine_argument(ffi_type * type,enum x86_64_reg_class classes[MAX_CLASSES],_Bool in_return,int * pngpr,int * pnsse)349*1fd5a2e1SPrashanth Swaminathan examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
350*1fd5a2e1SPrashanth Swaminathan _Bool in_return, int *pngpr, int *pnsse)
351*1fd5a2e1SPrashanth Swaminathan {
352*1fd5a2e1SPrashanth Swaminathan size_t n;
353*1fd5a2e1SPrashanth Swaminathan unsigned int i;
354*1fd5a2e1SPrashanth Swaminathan int ngpr, nsse;
355*1fd5a2e1SPrashanth Swaminathan
356*1fd5a2e1SPrashanth Swaminathan n = classify_argument (type, classes, 0);
357*1fd5a2e1SPrashanth Swaminathan if (n == 0)
358*1fd5a2e1SPrashanth Swaminathan return 0;
359*1fd5a2e1SPrashanth Swaminathan
360*1fd5a2e1SPrashanth Swaminathan ngpr = nsse = 0;
361*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < n; ++i)
362*1fd5a2e1SPrashanth Swaminathan switch (classes[i])
363*1fd5a2e1SPrashanth Swaminathan {
364*1fd5a2e1SPrashanth Swaminathan case X86_64_INTEGER_CLASS:
365*1fd5a2e1SPrashanth Swaminathan case X86_64_INTEGERSI_CLASS:
366*1fd5a2e1SPrashanth Swaminathan ngpr++;
367*1fd5a2e1SPrashanth Swaminathan break;
368*1fd5a2e1SPrashanth Swaminathan case X86_64_SSE_CLASS:
369*1fd5a2e1SPrashanth Swaminathan case X86_64_SSESF_CLASS:
370*1fd5a2e1SPrashanth Swaminathan case X86_64_SSEDF_CLASS:
371*1fd5a2e1SPrashanth Swaminathan nsse++;
372*1fd5a2e1SPrashanth Swaminathan break;
373*1fd5a2e1SPrashanth Swaminathan case X86_64_NO_CLASS:
374*1fd5a2e1SPrashanth Swaminathan case X86_64_SSEUP_CLASS:
375*1fd5a2e1SPrashanth Swaminathan break;
376*1fd5a2e1SPrashanth Swaminathan case X86_64_X87_CLASS:
377*1fd5a2e1SPrashanth Swaminathan case X86_64_X87UP_CLASS:
378*1fd5a2e1SPrashanth Swaminathan case X86_64_COMPLEX_X87_CLASS:
379*1fd5a2e1SPrashanth Swaminathan return in_return != 0;
380*1fd5a2e1SPrashanth Swaminathan default:
381*1fd5a2e1SPrashanth Swaminathan abort ();
382*1fd5a2e1SPrashanth Swaminathan }
383*1fd5a2e1SPrashanth Swaminathan
384*1fd5a2e1SPrashanth Swaminathan *pngpr = ngpr;
385*1fd5a2e1SPrashanth Swaminathan *pnsse = nsse;
386*1fd5a2e1SPrashanth Swaminathan
387*1fd5a2e1SPrashanth Swaminathan return n;
388*1fd5a2e1SPrashanth Swaminathan }
389*1fd5a2e1SPrashanth Swaminathan
390*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing. */
391*1fd5a2e1SPrashanth Swaminathan
392*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
393*1fd5a2e1SPrashanth Swaminathan extern ffi_status
394*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_efi64(ffi_cif *cif);
395*1fd5a2e1SPrashanth Swaminathan #endif
396*1fd5a2e1SPrashanth Swaminathan
397*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)398*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif *cif)
399*1fd5a2e1SPrashanth Swaminathan {
400*1fd5a2e1SPrashanth Swaminathan int gprcount, ssecount, i, avn, ngpr, nsse;
401*1fd5a2e1SPrashanth Swaminathan unsigned flags;
402*1fd5a2e1SPrashanth Swaminathan enum x86_64_reg_class classes[MAX_CLASSES];
403*1fd5a2e1SPrashanth Swaminathan size_t bytes, n, rtype_size;
404*1fd5a2e1SPrashanth Swaminathan ffi_type *rtype;
405*1fd5a2e1SPrashanth Swaminathan
406*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
407*1fd5a2e1SPrashanth Swaminathan if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
408*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_machdep_efi64(cif);
409*1fd5a2e1SPrashanth Swaminathan #endif
410*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_UNIX64)
411*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
412*1fd5a2e1SPrashanth Swaminathan
413*1fd5a2e1SPrashanth Swaminathan gprcount = ssecount = 0;
414*1fd5a2e1SPrashanth Swaminathan
415*1fd5a2e1SPrashanth Swaminathan rtype = cif->rtype;
416*1fd5a2e1SPrashanth Swaminathan rtype_size = rtype->size;
417*1fd5a2e1SPrashanth Swaminathan switch (rtype->type)
418*1fd5a2e1SPrashanth Swaminathan {
419*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
420*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_VOID;
421*1fd5a2e1SPrashanth Swaminathan break;
422*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
423*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_UINT8;
424*1fd5a2e1SPrashanth Swaminathan break;
425*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
426*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_SINT8;
427*1fd5a2e1SPrashanth Swaminathan break;
428*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
429*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_UINT16;
430*1fd5a2e1SPrashanth Swaminathan break;
431*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
432*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_SINT16;
433*1fd5a2e1SPrashanth Swaminathan break;
434*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
435*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_UINT32;
436*1fd5a2e1SPrashanth Swaminathan break;
437*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
438*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
439*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_SINT32;
440*1fd5a2e1SPrashanth Swaminathan break;
441*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
442*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
443*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_INT64;
444*1fd5a2e1SPrashanth Swaminathan break;
445*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
446*1fd5a2e1SPrashanth Swaminathan flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
447*1fd5a2e1SPrashanth Swaminathan break;
448*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
449*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_XMM32;
450*1fd5a2e1SPrashanth Swaminathan break;
451*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
452*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_XMM64;
453*1fd5a2e1SPrashanth Swaminathan break;
454*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
455*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
456*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_X87;
457*1fd5a2e1SPrashanth Swaminathan break;
458*1fd5a2e1SPrashanth Swaminathan #endif
459*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
460*1fd5a2e1SPrashanth Swaminathan n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
461*1fd5a2e1SPrashanth Swaminathan if (n == 0)
462*1fd5a2e1SPrashanth Swaminathan {
463*1fd5a2e1SPrashanth Swaminathan /* The return value is passed in memory. A pointer to that
464*1fd5a2e1SPrashanth Swaminathan memory is the first argument. Allocate a register for it. */
465*1fd5a2e1SPrashanth Swaminathan gprcount++;
466*1fd5a2e1SPrashanth Swaminathan /* We don't have to do anything in asm for the return. */
467*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_VOID | UNIX64_FLAG_RET_IN_MEM;
468*1fd5a2e1SPrashanth Swaminathan }
469*1fd5a2e1SPrashanth Swaminathan else
470*1fd5a2e1SPrashanth Swaminathan {
471*1fd5a2e1SPrashanth Swaminathan _Bool sse0 = SSE_CLASS_P (classes[0]);
472*1fd5a2e1SPrashanth Swaminathan
473*1fd5a2e1SPrashanth Swaminathan if (rtype_size == 4 && sse0)
474*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_XMM32;
475*1fd5a2e1SPrashanth Swaminathan else if (rtype_size == 8)
476*1fd5a2e1SPrashanth Swaminathan flags = sse0 ? UNIX64_RET_XMM64 : UNIX64_RET_INT64;
477*1fd5a2e1SPrashanth Swaminathan else
478*1fd5a2e1SPrashanth Swaminathan {
479*1fd5a2e1SPrashanth Swaminathan _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
480*1fd5a2e1SPrashanth Swaminathan if (sse0 && sse1)
481*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_XMM0_XMM1;
482*1fd5a2e1SPrashanth Swaminathan else if (sse0)
483*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_XMM0_RAX;
484*1fd5a2e1SPrashanth Swaminathan else if (sse1)
485*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_RAX_XMM0;
486*1fd5a2e1SPrashanth Swaminathan else
487*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_RAX_RDX;
488*1fd5a2e1SPrashanth Swaminathan flags |= rtype_size << UNIX64_SIZE_SHIFT;
489*1fd5a2e1SPrashanth Swaminathan }
490*1fd5a2e1SPrashanth Swaminathan }
491*1fd5a2e1SPrashanth Swaminathan break;
492*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_COMPLEX:
493*1fd5a2e1SPrashanth Swaminathan switch (rtype->elements[0]->type)
494*1fd5a2e1SPrashanth Swaminathan {
495*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
496*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
497*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
498*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
499*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
500*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
501*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
502*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
503*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
504*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_RAX_RDX | ((unsigned) rtype_size << UNIX64_SIZE_SHIFT);
505*1fd5a2e1SPrashanth Swaminathan break;
506*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
507*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_XMM64;
508*1fd5a2e1SPrashanth Swaminathan break;
509*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
510*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_ST_XMM0_XMM1 | (16 << UNIX64_SIZE_SHIFT);
511*1fd5a2e1SPrashanth Swaminathan break;
512*1fd5a2e1SPrashanth Swaminathan #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
513*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_LONGDOUBLE:
514*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_X87_2;
515*1fd5a2e1SPrashanth Swaminathan break;
516*1fd5a2e1SPrashanth Swaminathan #endif
517*1fd5a2e1SPrashanth Swaminathan default:
518*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
519*1fd5a2e1SPrashanth Swaminathan }
520*1fd5a2e1SPrashanth Swaminathan break;
521*1fd5a2e1SPrashanth Swaminathan default:
522*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_TYPEDEF;
523*1fd5a2e1SPrashanth Swaminathan }
524*1fd5a2e1SPrashanth Swaminathan
525*1fd5a2e1SPrashanth Swaminathan /* Go over all arguments and determine the way they should be passed.
526*1fd5a2e1SPrashanth Swaminathan If it's in a register and there is space for it, let that be so. If
527*1fd5a2e1SPrashanth Swaminathan not, add it's size to the stack byte count. */
528*1fd5a2e1SPrashanth Swaminathan for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
529*1fd5a2e1SPrashanth Swaminathan {
530*1fd5a2e1SPrashanth Swaminathan if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
531*1fd5a2e1SPrashanth Swaminathan || gprcount + ngpr > MAX_GPR_REGS
532*1fd5a2e1SPrashanth Swaminathan || ssecount + nsse > MAX_SSE_REGS)
533*1fd5a2e1SPrashanth Swaminathan {
534*1fd5a2e1SPrashanth Swaminathan long align = cif->arg_types[i]->alignment;
535*1fd5a2e1SPrashanth Swaminathan
536*1fd5a2e1SPrashanth Swaminathan if (align < 8)
537*1fd5a2e1SPrashanth Swaminathan align = 8;
538*1fd5a2e1SPrashanth Swaminathan
539*1fd5a2e1SPrashanth Swaminathan bytes = FFI_ALIGN (bytes, align);
540*1fd5a2e1SPrashanth Swaminathan bytes += cif->arg_types[i]->size;
541*1fd5a2e1SPrashanth Swaminathan }
542*1fd5a2e1SPrashanth Swaminathan else
543*1fd5a2e1SPrashanth Swaminathan {
544*1fd5a2e1SPrashanth Swaminathan gprcount += ngpr;
545*1fd5a2e1SPrashanth Swaminathan ssecount += nsse;
546*1fd5a2e1SPrashanth Swaminathan }
547*1fd5a2e1SPrashanth Swaminathan }
548*1fd5a2e1SPrashanth Swaminathan if (ssecount)
549*1fd5a2e1SPrashanth Swaminathan flags |= UNIX64_FLAG_XMM_ARGS;
550*1fd5a2e1SPrashanth Swaminathan
551*1fd5a2e1SPrashanth Swaminathan cif->flags = flags;
552*1fd5a2e1SPrashanth Swaminathan cif->bytes = (unsigned) FFI_ALIGN (bytes, 8);
553*1fd5a2e1SPrashanth Swaminathan
554*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
555*1fd5a2e1SPrashanth Swaminathan }
556*1fd5a2e1SPrashanth Swaminathan
557*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)558*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
559*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
560*1fd5a2e1SPrashanth Swaminathan {
561*1fd5a2e1SPrashanth Swaminathan enum x86_64_reg_class classes[MAX_CLASSES];
562*1fd5a2e1SPrashanth Swaminathan char *stack, *argp;
563*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types;
564*1fd5a2e1SPrashanth Swaminathan int gprcount, ssecount, ngpr, nsse, i, avn, flags;
565*1fd5a2e1SPrashanth Swaminathan struct register_args *reg_args;
566*1fd5a2e1SPrashanth Swaminathan
567*1fd5a2e1SPrashanth Swaminathan /* Can't call 32-bit mode from 64-bit mode. */
568*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (cif->abi == FFI_UNIX64);
569*1fd5a2e1SPrashanth Swaminathan
570*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return value
571*1fd5a2e1SPrashanth Swaminathan address then we need to make one. Otherwise we can ignore it. */
572*1fd5a2e1SPrashanth Swaminathan flags = cif->flags;
573*1fd5a2e1SPrashanth Swaminathan if (rvalue == NULL)
574*1fd5a2e1SPrashanth Swaminathan {
575*1fd5a2e1SPrashanth Swaminathan if (flags & UNIX64_FLAG_RET_IN_MEM)
576*1fd5a2e1SPrashanth Swaminathan rvalue = alloca (cif->rtype->size);
577*1fd5a2e1SPrashanth Swaminathan else
578*1fd5a2e1SPrashanth Swaminathan flags = UNIX64_RET_VOID;
579*1fd5a2e1SPrashanth Swaminathan }
580*1fd5a2e1SPrashanth Swaminathan
581*1fd5a2e1SPrashanth Swaminathan /* Allocate the space for the arguments, plus 4 words of temp space. */
582*1fd5a2e1SPrashanth Swaminathan stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
583*1fd5a2e1SPrashanth Swaminathan reg_args = (struct register_args *) stack;
584*1fd5a2e1SPrashanth Swaminathan argp = stack + sizeof (struct register_args);
585*1fd5a2e1SPrashanth Swaminathan
586*1fd5a2e1SPrashanth Swaminathan reg_args->r10 = (uintptr_t) closure;
587*1fd5a2e1SPrashanth Swaminathan
588*1fd5a2e1SPrashanth Swaminathan gprcount = ssecount = 0;
589*1fd5a2e1SPrashanth Swaminathan
590*1fd5a2e1SPrashanth Swaminathan /* If the return value is passed in memory, add the pointer as the
591*1fd5a2e1SPrashanth Swaminathan first integer argument. */
592*1fd5a2e1SPrashanth Swaminathan if (flags & UNIX64_FLAG_RET_IN_MEM)
593*1fd5a2e1SPrashanth Swaminathan reg_args->gpr[gprcount++] = (unsigned long) rvalue;
594*1fd5a2e1SPrashanth Swaminathan
595*1fd5a2e1SPrashanth Swaminathan avn = cif->nargs;
596*1fd5a2e1SPrashanth Swaminathan arg_types = cif->arg_types;
597*1fd5a2e1SPrashanth Swaminathan
598*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < avn; ++i)
599*1fd5a2e1SPrashanth Swaminathan {
600*1fd5a2e1SPrashanth Swaminathan size_t n, size = arg_types[i]->size;
601*1fd5a2e1SPrashanth Swaminathan
602*1fd5a2e1SPrashanth Swaminathan n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
603*1fd5a2e1SPrashanth Swaminathan if (n == 0
604*1fd5a2e1SPrashanth Swaminathan || gprcount + ngpr > MAX_GPR_REGS
605*1fd5a2e1SPrashanth Swaminathan || ssecount + nsse > MAX_SSE_REGS)
606*1fd5a2e1SPrashanth Swaminathan {
607*1fd5a2e1SPrashanth Swaminathan long align = arg_types[i]->alignment;
608*1fd5a2e1SPrashanth Swaminathan
609*1fd5a2e1SPrashanth Swaminathan /* Stack arguments are *always* at least 8 byte aligned. */
610*1fd5a2e1SPrashanth Swaminathan if (align < 8)
611*1fd5a2e1SPrashanth Swaminathan align = 8;
612*1fd5a2e1SPrashanth Swaminathan
613*1fd5a2e1SPrashanth Swaminathan /* Pass this argument in memory. */
614*1fd5a2e1SPrashanth Swaminathan argp = (void *) FFI_ALIGN (argp, align);
615*1fd5a2e1SPrashanth Swaminathan memcpy (argp, avalue[i], size);
616*1fd5a2e1SPrashanth Swaminathan argp += size;
617*1fd5a2e1SPrashanth Swaminathan }
618*1fd5a2e1SPrashanth Swaminathan else
619*1fd5a2e1SPrashanth Swaminathan {
620*1fd5a2e1SPrashanth Swaminathan /* The argument is passed entirely in registers. */
621*1fd5a2e1SPrashanth Swaminathan char *a = (char *) avalue[i];
622*1fd5a2e1SPrashanth Swaminathan unsigned int j;
623*1fd5a2e1SPrashanth Swaminathan
624*1fd5a2e1SPrashanth Swaminathan for (j = 0; j < n; j++, a += 8, size -= 8)
625*1fd5a2e1SPrashanth Swaminathan {
626*1fd5a2e1SPrashanth Swaminathan switch (classes[j])
627*1fd5a2e1SPrashanth Swaminathan {
628*1fd5a2e1SPrashanth Swaminathan case X86_64_NO_CLASS:
629*1fd5a2e1SPrashanth Swaminathan case X86_64_SSEUP_CLASS:
630*1fd5a2e1SPrashanth Swaminathan break;
631*1fd5a2e1SPrashanth Swaminathan case X86_64_INTEGER_CLASS:
632*1fd5a2e1SPrashanth Swaminathan case X86_64_INTEGERSI_CLASS:
633*1fd5a2e1SPrashanth Swaminathan /* Sign-extend integer arguments passed in general
634*1fd5a2e1SPrashanth Swaminathan purpose registers, to cope with the fact that
635*1fd5a2e1SPrashanth Swaminathan LLVM incorrectly assumes that this will be done
636*1fd5a2e1SPrashanth Swaminathan (the x86-64 PS ABI does not specify this). */
637*1fd5a2e1SPrashanth Swaminathan switch (arg_types[i]->type)
638*1fd5a2e1SPrashanth Swaminathan {
639*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
640*1fd5a2e1SPrashanth Swaminathan reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
641*1fd5a2e1SPrashanth Swaminathan break;
642*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
643*1fd5a2e1SPrashanth Swaminathan reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
644*1fd5a2e1SPrashanth Swaminathan break;
645*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
646*1fd5a2e1SPrashanth Swaminathan reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
647*1fd5a2e1SPrashanth Swaminathan break;
648*1fd5a2e1SPrashanth Swaminathan default:
649*1fd5a2e1SPrashanth Swaminathan reg_args->gpr[gprcount] = 0;
650*1fd5a2e1SPrashanth Swaminathan memcpy (®_args->gpr[gprcount], a, size);
651*1fd5a2e1SPrashanth Swaminathan }
652*1fd5a2e1SPrashanth Swaminathan gprcount++;
653*1fd5a2e1SPrashanth Swaminathan break;
654*1fd5a2e1SPrashanth Swaminathan case X86_64_SSE_CLASS:
655*1fd5a2e1SPrashanth Swaminathan case X86_64_SSEDF_CLASS:
656*1fd5a2e1SPrashanth Swaminathan memcpy (®_args->sse[ssecount++].i64, a, sizeof(UINT64));
657*1fd5a2e1SPrashanth Swaminathan break;
658*1fd5a2e1SPrashanth Swaminathan case X86_64_SSESF_CLASS:
659*1fd5a2e1SPrashanth Swaminathan memcpy (®_args->sse[ssecount++].i32, a, sizeof(UINT32));
660*1fd5a2e1SPrashanth Swaminathan break;
661*1fd5a2e1SPrashanth Swaminathan default:
662*1fd5a2e1SPrashanth Swaminathan abort();
663*1fd5a2e1SPrashanth Swaminathan }
664*1fd5a2e1SPrashanth Swaminathan }
665*1fd5a2e1SPrashanth Swaminathan }
666*1fd5a2e1SPrashanth Swaminathan }
667*1fd5a2e1SPrashanth Swaminathan reg_args->rax = ssecount;
668*1fd5a2e1SPrashanth Swaminathan
669*1fd5a2e1SPrashanth Swaminathan ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
670*1fd5a2e1SPrashanth Swaminathan flags, rvalue, fn);
671*1fd5a2e1SPrashanth Swaminathan }
672*1fd5a2e1SPrashanth Swaminathan
673*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
674*1fd5a2e1SPrashanth Swaminathan extern void
675*1fd5a2e1SPrashanth Swaminathan ffi_call_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
676*1fd5a2e1SPrashanth Swaminathan #endif
677*1fd5a2e1SPrashanth Swaminathan
678*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)679*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
680*1fd5a2e1SPrashanth Swaminathan {
681*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
682*1fd5a2e1SPrashanth Swaminathan if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
683*1fd5a2e1SPrashanth Swaminathan {
684*1fd5a2e1SPrashanth Swaminathan ffi_call_efi64(cif, fn, rvalue, avalue);
685*1fd5a2e1SPrashanth Swaminathan return;
686*1fd5a2e1SPrashanth Swaminathan }
687*1fd5a2e1SPrashanth Swaminathan #endif
688*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, NULL);
689*1fd5a2e1SPrashanth Swaminathan }
690*1fd5a2e1SPrashanth Swaminathan
691*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
692*1fd5a2e1SPrashanth Swaminathan extern void
693*1fd5a2e1SPrashanth Swaminathan ffi_call_go_efi64(ffi_cif *cif, void (*fn)(void), void *rvalue,
694*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure);
695*1fd5a2e1SPrashanth Swaminathan #endif
696*1fd5a2e1SPrashanth Swaminathan
697*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)698*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
699*1fd5a2e1SPrashanth Swaminathan void **avalue, void *closure)
700*1fd5a2e1SPrashanth Swaminathan {
701*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
702*1fd5a2e1SPrashanth Swaminathan if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
703*1fd5a2e1SPrashanth Swaminathan {
704*1fd5a2e1SPrashanth Swaminathan ffi_call_go_efi64(cif, fn, rvalue, avalue, closure);
705*1fd5a2e1SPrashanth Swaminathan return;
706*1fd5a2e1SPrashanth Swaminathan }
707*1fd5a2e1SPrashanth Swaminathan #endif
708*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, closure);
709*1fd5a2e1SPrashanth Swaminathan }
710*1fd5a2e1SPrashanth Swaminathan
711*1fd5a2e1SPrashanth Swaminathan
712*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_unix64(void) FFI_HIDDEN;
713*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_unix64_sse(void) FFI_HIDDEN;
714*1fd5a2e1SPrashanth Swaminathan
715*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
716*1fd5a2e1SPrashanth Swaminathan extern ffi_status
717*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc_efi64(ffi_closure* closure,
718*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
719*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
720*1fd5a2e1SPrashanth Swaminathan void *user_data,
721*1fd5a2e1SPrashanth Swaminathan void *codeloc);
722*1fd5a2e1SPrashanth Swaminathan #endif
723*1fd5a2e1SPrashanth Swaminathan
724*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)725*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
726*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
727*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
728*1fd5a2e1SPrashanth Swaminathan void *user_data,
729*1fd5a2e1SPrashanth Swaminathan void *codeloc)
730*1fd5a2e1SPrashanth Swaminathan {
731*1fd5a2e1SPrashanth Swaminathan static const unsigned char trampoline[16] = {
732*1fd5a2e1SPrashanth Swaminathan /* leaq -0x7(%rip),%r10 # 0x0 */
733*1fd5a2e1SPrashanth Swaminathan 0x4c, 0x8d, 0x15, 0xf9, 0xff, 0xff, 0xff,
734*1fd5a2e1SPrashanth Swaminathan /* jmpq *0x3(%rip) # 0x10 */
735*1fd5a2e1SPrashanth Swaminathan 0xff, 0x25, 0x03, 0x00, 0x00, 0x00,
736*1fd5a2e1SPrashanth Swaminathan /* nopl (%rax) */
737*1fd5a2e1SPrashanth Swaminathan 0x0f, 0x1f, 0x00
738*1fd5a2e1SPrashanth Swaminathan };
739*1fd5a2e1SPrashanth Swaminathan void (*dest)(void);
740*1fd5a2e1SPrashanth Swaminathan char *tramp = closure->tramp;
741*1fd5a2e1SPrashanth Swaminathan
742*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
743*1fd5a2e1SPrashanth Swaminathan if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
744*1fd5a2e1SPrashanth Swaminathan return ffi_prep_closure_loc_efi64(closure, cif, fun, user_data, codeloc);
745*1fd5a2e1SPrashanth Swaminathan #endif
746*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_UNIX64)
747*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
748*1fd5a2e1SPrashanth Swaminathan
749*1fd5a2e1SPrashanth Swaminathan if (cif->flags & UNIX64_FLAG_XMM_ARGS)
750*1fd5a2e1SPrashanth Swaminathan dest = ffi_closure_unix64_sse;
751*1fd5a2e1SPrashanth Swaminathan else
752*1fd5a2e1SPrashanth Swaminathan dest = ffi_closure_unix64;
753*1fd5a2e1SPrashanth Swaminathan
754*1fd5a2e1SPrashanth Swaminathan memcpy (tramp, trampoline, sizeof(trampoline));
755*1fd5a2e1SPrashanth Swaminathan *(UINT64 *)(tramp + 16) = (uintptr_t)dest;
756*1fd5a2e1SPrashanth Swaminathan
757*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
758*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
759*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
760*1fd5a2e1SPrashanth Swaminathan
761*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
762*1fd5a2e1SPrashanth Swaminathan }
763*1fd5a2e1SPrashanth Swaminathan
764*1fd5a2e1SPrashanth Swaminathan int FFI_HIDDEN
ffi_closure_unix64_inner(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,struct register_args * reg_args,char * argp)765*1fd5a2e1SPrashanth Swaminathan ffi_closure_unix64_inner(ffi_cif *cif,
766*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
767*1fd5a2e1SPrashanth Swaminathan void *user_data,
768*1fd5a2e1SPrashanth Swaminathan void *rvalue,
769*1fd5a2e1SPrashanth Swaminathan struct register_args *reg_args,
770*1fd5a2e1SPrashanth Swaminathan char *argp)
771*1fd5a2e1SPrashanth Swaminathan {
772*1fd5a2e1SPrashanth Swaminathan void **avalue;
773*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types;
774*1fd5a2e1SPrashanth Swaminathan long i, avn;
775*1fd5a2e1SPrashanth Swaminathan int gprcount, ssecount, ngpr, nsse;
776*1fd5a2e1SPrashanth Swaminathan int flags;
777*1fd5a2e1SPrashanth Swaminathan
778*1fd5a2e1SPrashanth Swaminathan avn = cif->nargs;
779*1fd5a2e1SPrashanth Swaminathan flags = cif->flags;
780*1fd5a2e1SPrashanth Swaminathan avalue = alloca(avn * sizeof(void *));
781*1fd5a2e1SPrashanth Swaminathan gprcount = ssecount = 0;
782*1fd5a2e1SPrashanth Swaminathan
783*1fd5a2e1SPrashanth Swaminathan if (flags & UNIX64_FLAG_RET_IN_MEM)
784*1fd5a2e1SPrashanth Swaminathan {
785*1fd5a2e1SPrashanth Swaminathan /* On return, %rax will contain the address that was passed
786*1fd5a2e1SPrashanth Swaminathan by the caller in %rdi. */
787*1fd5a2e1SPrashanth Swaminathan void *r = (void *)(uintptr_t)reg_args->gpr[gprcount++];
788*1fd5a2e1SPrashanth Swaminathan *(void **)rvalue = r;
789*1fd5a2e1SPrashanth Swaminathan rvalue = r;
790*1fd5a2e1SPrashanth Swaminathan flags = (sizeof(void *) == 4 ? UNIX64_RET_UINT32 : UNIX64_RET_INT64);
791*1fd5a2e1SPrashanth Swaminathan }
792*1fd5a2e1SPrashanth Swaminathan
793*1fd5a2e1SPrashanth Swaminathan arg_types = cif->arg_types;
794*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < avn; ++i)
795*1fd5a2e1SPrashanth Swaminathan {
796*1fd5a2e1SPrashanth Swaminathan enum x86_64_reg_class classes[MAX_CLASSES];
797*1fd5a2e1SPrashanth Swaminathan size_t n;
798*1fd5a2e1SPrashanth Swaminathan
799*1fd5a2e1SPrashanth Swaminathan n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
800*1fd5a2e1SPrashanth Swaminathan if (n == 0
801*1fd5a2e1SPrashanth Swaminathan || gprcount + ngpr > MAX_GPR_REGS
802*1fd5a2e1SPrashanth Swaminathan || ssecount + nsse > MAX_SSE_REGS)
803*1fd5a2e1SPrashanth Swaminathan {
804*1fd5a2e1SPrashanth Swaminathan long align = arg_types[i]->alignment;
805*1fd5a2e1SPrashanth Swaminathan
806*1fd5a2e1SPrashanth Swaminathan /* Stack arguments are *always* at least 8 byte aligned. */
807*1fd5a2e1SPrashanth Swaminathan if (align < 8)
808*1fd5a2e1SPrashanth Swaminathan align = 8;
809*1fd5a2e1SPrashanth Swaminathan
810*1fd5a2e1SPrashanth Swaminathan /* Pass this argument in memory. */
811*1fd5a2e1SPrashanth Swaminathan argp = (void *) FFI_ALIGN (argp, align);
812*1fd5a2e1SPrashanth Swaminathan avalue[i] = argp;
813*1fd5a2e1SPrashanth Swaminathan argp += arg_types[i]->size;
814*1fd5a2e1SPrashanth Swaminathan }
815*1fd5a2e1SPrashanth Swaminathan /* If the argument is in a single register, or two consecutive
816*1fd5a2e1SPrashanth Swaminathan integer registers, then we can use that address directly. */
817*1fd5a2e1SPrashanth Swaminathan else if (n == 1
818*1fd5a2e1SPrashanth Swaminathan || (n == 2 && !(SSE_CLASS_P (classes[0])
819*1fd5a2e1SPrashanth Swaminathan || SSE_CLASS_P (classes[1]))))
820*1fd5a2e1SPrashanth Swaminathan {
821*1fd5a2e1SPrashanth Swaminathan /* The argument is in a single register. */
822*1fd5a2e1SPrashanth Swaminathan if (SSE_CLASS_P (classes[0]))
823*1fd5a2e1SPrashanth Swaminathan {
824*1fd5a2e1SPrashanth Swaminathan avalue[i] = ®_args->sse[ssecount];
825*1fd5a2e1SPrashanth Swaminathan ssecount += n;
826*1fd5a2e1SPrashanth Swaminathan }
827*1fd5a2e1SPrashanth Swaminathan else
828*1fd5a2e1SPrashanth Swaminathan {
829*1fd5a2e1SPrashanth Swaminathan avalue[i] = ®_args->gpr[gprcount];
830*1fd5a2e1SPrashanth Swaminathan gprcount += n;
831*1fd5a2e1SPrashanth Swaminathan }
832*1fd5a2e1SPrashanth Swaminathan }
833*1fd5a2e1SPrashanth Swaminathan /* Otherwise, allocate space to make them consecutive. */
834*1fd5a2e1SPrashanth Swaminathan else
835*1fd5a2e1SPrashanth Swaminathan {
836*1fd5a2e1SPrashanth Swaminathan char *a = alloca (16);
837*1fd5a2e1SPrashanth Swaminathan unsigned int j;
838*1fd5a2e1SPrashanth Swaminathan
839*1fd5a2e1SPrashanth Swaminathan avalue[i] = a;
840*1fd5a2e1SPrashanth Swaminathan for (j = 0; j < n; j++, a += 8)
841*1fd5a2e1SPrashanth Swaminathan {
842*1fd5a2e1SPrashanth Swaminathan if (SSE_CLASS_P (classes[j]))
843*1fd5a2e1SPrashanth Swaminathan memcpy (a, ®_args->sse[ssecount++], 8);
844*1fd5a2e1SPrashanth Swaminathan else
845*1fd5a2e1SPrashanth Swaminathan memcpy (a, ®_args->gpr[gprcount++], 8);
846*1fd5a2e1SPrashanth Swaminathan }
847*1fd5a2e1SPrashanth Swaminathan }
848*1fd5a2e1SPrashanth Swaminathan }
849*1fd5a2e1SPrashanth Swaminathan
850*1fd5a2e1SPrashanth Swaminathan /* Invoke the closure. */
851*1fd5a2e1SPrashanth Swaminathan fun (cif, rvalue, avalue, user_data);
852*1fd5a2e1SPrashanth Swaminathan
853*1fd5a2e1SPrashanth Swaminathan /* Tell assembly how to perform return type promotions. */
854*1fd5a2e1SPrashanth Swaminathan return flags;
855*1fd5a2e1SPrashanth Swaminathan }
856*1fd5a2e1SPrashanth Swaminathan
857*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_unix64(void) FFI_HIDDEN;
858*1fd5a2e1SPrashanth Swaminathan extern void ffi_go_closure_unix64_sse(void) FFI_HIDDEN;
859*1fd5a2e1SPrashanth Swaminathan
860*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
861*1fd5a2e1SPrashanth Swaminathan extern ffi_status
862*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure_efi64(ffi_go_closure* closure, ffi_cif* cif,
863*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*));
864*1fd5a2e1SPrashanth Swaminathan #endif
865*1fd5a2e1SPrashanth Swaminathan
866*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))867*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
868*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*))
869*1fd5a2e1SPrashanth Swaminathan {
870*1fd5a2e1SPrashanth Swaminathan #ifndef __ILP32__
871*1fd5a2e1SPrashanth Swaminathan if (cif->abi == FFI_EFI64 || cif->abi == FFI_GNUW64)
872*1fd5a2e1SPrashanth Swaminathan return ffi_prep_go_closure_efi64(closure, cif, fun);
873*1fd5a2e1SPrashanth Swaminathan #endif
874*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_UNIX64)
875*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
876*1fd5a2e1SPrashanth Swaminathan
877*1fd5a2e1SPrashanth Swaminathan closure->tramp = (cif->flags & UNIX64_FLAG_XMM_ARGS
878*1fd5a2e1SPrashanth Swaminathan ? ffi_go_closure_unix64_sse
879*1fd5a2e1SPrashanth Swaminathan : ffi_go_closure_unix64);
880*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
881*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
882*1fd5a2e1SPrashanth Swaminathan
883*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
884*1fd5a2e1SPrashanth Swaminathan }
885*1fd5a2e1SPrashanth Swaminathan
886*1fd5a2e1SPrashanth Swaminathan #endif /* __x86_64__ */
887