xref: /aosp_15_r20/external/libffi/src/x86/ffi64.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
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 (&reg_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 (&reg_args->sse[ssecount++].i64, a, sizeof(UINT64));
657*1fd5a2e1SPrashanth Swaminathan 		  break;
658*1fd5a2e1SPrashanth Swaminathan 		case X86_64_SSESF_CLASS:
659*1fd5a2e1SPrashanth Swaminathan 		  memcpy (&reg_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] = &reg_args->sse[ssecount];
825*1fd5a2e1SPrashanth Swaminathan 	      ssecount += n;
826*1fd5a2e1SPrashanth Swaminathan 	    }
827*1fd5a2e1SPrashanth Swaminathan 	  else
828*1fd5a2e1SPrashanth Swaminathan 	    {
829*1fd5a2e1SPrashanth Swaminathan 	      avalue[i] = &reg_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, &reg_args->sse[ssecount++], 8);
844*1fd5a2e1SPrashanth Swaminathan 	      else
845*1fd5a2e1SPrashanth Swaminathan 		memcpy (a, &reg_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