1809f4227SJim Jagielski /**************************************************************
2809f4227SJim Jagielski *
3809f4227SJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one
4809f4227SJim Jagielski * or more contributor license agreements. See the NOTICE file
5809f4227SJim Jagielski * distributed with this work for additional information
6809f4227SJim Jagielski * regarding copyright ownership. The ASF licenses this file
7809f4227SJim Jagielski * to you under the Apache License, Version 2.0 (the
8809f4227SJim Jagielski * "License"); you may not use this file except in compliance
9809f4227SJim Jagielski * with the License. You may obtain a copy of the License at
10809f4227SJim Jagielski *
11809f4227SJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0
12809f4227SJim Jagielski *
13809f4227SJim Jagielski * Unless required by applicable law or agreed to in writing,
14809f4227SJim Jagielski * software distributed under the License is distributed on an
15809f4227SJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16809f4227SJim Jagielski * KIND, either express or implied. See the License for the
17809f4227SJim Jagielski * specific language governing permissions and limitations
18809f4227SJim Jagielski * under the License.
19809f4227SJim Jagielski *
20809f4227SJim Jagielski *************************************************************/
21809f4227SJim Jagielski
22809f4227SJim Jagielski
23809f4227SJim Jagielski
24809f4227SJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25809f4227SJim Jagielski #include "precompiled_bridges.hxx"
26809f4227SJim Jagielski
27809f4227SJim Jagielski // This is an implementation of the x86-64 ABI as described in 'System V
28809f4227SJim Jagielski // Application Binary Interface, AMD64 Architecture Processor Supplement'
29809f4227SJim Jagielski // (http://www.x86-64.org/documentation/abi-0.95.pdf)
30809f4227SJim Jagielski //
31809f4227SJim Jagielski // The code in this file is a modification of src/x86/ffi64.c from libffi
32809f4227SJim Jagielski // (http://sources.redhat.com/libffi/) which is under the following license:
33809f4227SJim Jagielski
34809f4227SJim Jagielski /* -----------------------------------------------------------------------
35809f4227SJim Jagielski ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
36809f4227SJim Jagielski
37809f4227SJim Jagielski x86-64 Foreign Function Interface
38809f4227SJim Jagielski
39809f4227SJim Jagielski Permission is hereby granted, free of charge, to any person obtaining
40809f4227SJim Jagielski a copy of this software and associated documentation files (the
41809f4227SJim Jagielski ``Software''), to deal in the Software without restriction, including
42809f4227SJim Jagielski without limitation the rights to use, copy, modify, merge, publish,
43809f4227SJim Jagielski distribute, sublicense, and/or sell copies of the Software, and to
44809f4227SJim Jagielski permit persons to whom the Software is furnished to do so, subject to
45809f4227SJim Jagielski the following conditions:
46809f4227SJim Jagielski
47809f4227SJim Jagielski The above copyright notice and this permission notice shall be included
48809f4227SJim Jagielski in all copies or substantial portions of the Software.
49809f4227SJim Jagielski
50809f4227SJim Jagielski THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
51809f4227SJim Jagielski OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
52809f4227SJim Jagielski MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
53809f4227SJim Jagielski IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
54809f4227SJim Jagielski OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
55809f4227SJim Jagielski ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
56809f4227SJim Jagielski OTHER DEALINGS IN THE SOFTWARE.
57809f4227SJim Jagielski ----------------------------------------------------------------------- */
58809f4227SJim Jagielski
59809f4227SJim Jagielski #include "abi.hxx"
60809f4227SJim Jagielski
61809f4227SJim Jagielski #include <rtl/ustring.hxx>
62809f4227SJim Jagielski
63809f4227SJim Jagielski using namespace x86_64;
64809f4227SJim Jagielski
65809f4227SJim Jagielski typedef struct
66809f4227SJim Jagielski {
67809f4227SJim Jagielski /* Registers for argument passing. */
68809f4227SJim Jagielski long gpr[MAX_GPR_REGS];
69809f4227SJim Jagielski __int128_t sse[MAX_SSE_REGS];
70809f4227SJim Jagielski
71809f4227SJim Jagielski /* Stack space for arguments. */
72809f4227SJim Jagielski char argspace[0];
73809f4227SJim Jagielski } stackLayout;
74809f4227SJim Jagielski
75809f4227SJim Jagielski /* Register class used for passing given 64bit part of the argument.
76809f4227SJim Jagielski These represent classes as documented by the PS ABI, with the exception
77809f4227SJim Jagielski of SSESF, SSEDF classes, that are basically SSE class, just gcc will
78*cbe561cdSJohn Bampton use SF or DFmode move instead of DImode to avoid reformatting penalties.
79809f4227SJim Jagielski
80809f4227SJim Jagielski Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
81809f4227SJim Jagielski whenever possible (upper half does contain padding).
82809f4227SJim Jagielski */
83809f4227SJim Jagielski enum x86_64_reg_class
84809f4227SJim Jagielski {
85809f4227SJim Jagielski X86_64_NO_CLASS,
86809f4227SJim Jagielski X86_64_INTEGER_CLASS,
87809f4227SJim Jagielski X86_64_INTEGERSI_CLASS,
88809f4227SJim Jagielski X86_64_SSE_CLASS,
89809f4227SJim Jagielski X86_64_SSESF_CLASS,
90809f4227SJim Jagielski X86_64_SSEDF_CLASS,
91809f4227SJim Jagielski X86_64_SSEUP_CLASS,
92809f4227SJim Jagielski X86_64_X87_CLASS,
93809f4227SJim Jagielski X86_64_X87UP_CLASS,
94809f4227SJim Jagielski X86_64_MEMORY_CLASS
95809f4227SJim Jagielski };
96809f4227SJim Jagielski
97809f4227SJim Jagielski #define MAX_CLASSES 4
98809f4227SJim Jagielski
99809f4227SJim Jagielski /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
100809f4227SJim Jagielski of this code is to classify each 8bytes of incoming argument by the register
101809f4227SJim Jagielski class and assign registers accordingly. */
102809f4227SJim Jagielski
103809f4227SJim Jagielski /* Return the union class of CLASS1 and CLASS2.
104809f4227SJim Jagielski See the x86-64 PS ABI for details. */
105809f4227SJim Jagielski
106809f4227SJim Jagielski static enum x86_64_reg_class
merge_classes(enum x86_64_reg_class class1,enum x86_64_reg_class class2)107809f4227SJim Jagielski merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
108809f4227SJim Jagielski {
109809f4227SJim Jagielski /* Rule #1: If both classes are equal, this is the resulting class. */
110809f4227SJim Jagielski if (class1 == class2)
111809f4227SJim Jagielski return class1;
112809f4227SJim Jagielski
113809f4227SJim Jagielski /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
114809f4227SJim Jagielski the other class. */
115809f4227SJim Jagielski if (class1 == X86_64_NO_CLASS)
116809f4227SJim Jagielski return class2;
117809f4227SJim Jagielski if (class2 == X86_64_NO_CLASS)
118809f4227SJim Jagielski return class1;
119809f4227SJim Jagielski
120809f4227SJim Jagielski /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
121809f4227SJim Jagielski if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
122809f4227SJim Jagielski return X86_64_MEMORY_CLASS;
123809f4227SJim Jagielski
124809f4227SJim Jagielski /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
125809f4227SJim Jagielski if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
126809f4227SJim Jagielski || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
127809f4227SJim Jagielski return X86_64_INTEGERSI_CLASS;
128809f4227SJim Jagielski if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
129809f4227SJim Jagielski || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
130809f4227SJim Jagielski return X86_64_INTEGER_CLASS;
131809f4227SJim Jagielski
132809f4227SJim Jagielski /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */
133809f4227SJim Jagielski if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
134809f4227SJim Jagielski || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
135809f4227SJim Jagielski return X86_64_MEMORY_CLASS;
136809f4227SJim Jagielski
137809f4227SJim Jagielski /* Rule #6: Otherwise class SSE is used. */
138809f4227SJim Jagielski return X86_64_SSE_CLASS;
139809f4227SJim Jagielski }
140809f4227SJim Jagielski
141809f4227SJim Jagielski /* Classify the argument of type TYPE and mode MODE.
142809f4227SJim Jagielski CLASSES will be filled by the register class used to pass each word
143809f4227SJim Jagielski of the operand. The number of words is returned. In case the parameter
144809f4227SJim Jagielski should be passed in memory, 0 is returned. As a special case for zero
145809f4227SJim Jagielski sized containers, classes[0] will be NO_CLASS and 1 is returned.
146809f4227SJim Jagielski
147809f4227SJim Jagielski See the x86-64 PS ABI for details.
148809f4227SJim Jagielski */
149809f4227SJim Jagielski static int
classify_argument(typelib_TypeDescriptionReference * pTypeRef,enum x86_64_reg_class classes[],int byteOffset)150809f4227SJim Jagielski classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset )
151809f4227SJim Jagielski {
152809f4227SJim Jagielski switch ( pTypeRef->eTypeClass )
153809f4227SJim Jagielski {
154809f4227SJim Jagielski case typelib_TypeClass_VOID:
155809f4227SJim Jagielski classes[0] = X86_64_NO_CLASS;
156809f4227SJim Jagielski return 1;
157809f4227SJim Jagielski case typelib_TypeClass_CHAR:
158809f4227SJim Jagielski case typelib_TypeClass_BOOLEAN:
159809f4227SJim Jagielski case typelib_TypeClass_BYTE:
160809f4227SJim Jagielski case typelib_TypeClass_SHORT:
161809f4227SJim Jagielski case typelib_TypeClass_UNSIGNED_SHORT:
162809f4227SJim Jagielski case typelib_TypeClass_LONG:
163809f4227SJim Jagielski case typelib_TypeClass_UNSIGNED_LONG:
164809f4227SJim Jagielski case typelib_TypeClass_HYPER:
165809f4227SJim Jagielski case typelib_TypeClass_UNSIGNED_HYPER:
166809f4227SJim Jagielski case typelib_TypeClass_ENUM:
167809f4227SJim Jagielski if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
168809f4227SJim Jagielski classes[0] = X86_64_INTEGERSI_CLASS;
169809f4227SJim Jagielski else
170809f4227SJim Jagielski classes[0] = X86_64_INTEGER_CLASS;
171809f4227SJim Jagielski return 1;
172809f4227SJim Jagielski case typelib_TypeClass_FLOAT:
173809f4227SJim Jagielski if ( ( byteOffset % 8 ) == 0 )
174809f4227SJim Jagielski classes[0] = X86_64_SSESF_CLASS;
175809f4227SJim Jagielski else
176809f4227SJim Jagielski classes[0] = X86_64_SSE_CLASS;
177809f4227SJim Jagielski return 1;
178809f4227SJim Jagielski case typelib_TypeClass_DOUBLE:
179809f4227SJim Jagielski classes[0] = X86_64_SSEDF_CLASS;
180809f4227SJim Jagielski return 1;
181809f4227SJim Jagielski /*case LONGDOUBLE:
182809f4227SJim Jagielski classes[0] = X86_64_X87_CLASS;
183809f4227SJim Jagielski classes[1] = X86_64_X87UP_CLASS;
184809f4227SJim Jagielski return 2;*/
185809f4227SJim Jagielski case typelib_TypeClass_STRING:
186809f4227SJim Jagielski case typelib_TypeClass_TYPE:
187809f4227SJim Jagielski case typelib_TypeClass_ANY:
188809f4227SJim Jagielski case typelib_TypeClass_TYPEDEF:
189809f4227SJim Jagielski case typelib_TypeClass_UNION:
190809f4227SJim Jagielski case typelib_TypeClass_SEQUENCE:
191809f4227SJim Jagielski case typelib_TypeClass_ARRAY:
192809f4227SJim Jagielski case typelib_TypeClass_INTERFACE:
193809f4227SJim Jagielski return 0;
194809f4227SJim Jagielski case typelib_TypeClass_STRUCT:
195809f4227SJim Jagielski case typelib_TypeClass_EXCEPTION:
196809f4227SJim Jagielski {
197809f4227SJim Jagielski typelib_TypeDescription * pTypeDescr = 0;
198809f4227SJim Jagielski TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
199809f4227SJim Jagielski
200809f4227SJim Jagielski const int UNITS_PER_WORD = 8;
201809f4227SJim Jagielski int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
202809f4227SJim Jagielski enum x86_64_reg_class subclasses[MAX_CLASSES];
203809f4227SJim Jagielski
204809f4227SJim Jagielski /* If the struct is larger than 16 bytes, pass it on the stack. */
205809f4227SJim Jagielski if ( pTypeDescr->nSize > 16 )
206809f4227SJim Jagielski {
207809f4227SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
208809f4227SJim Jagielski return 0;
209809f4227SJim Jagielski }
210809f4227SJim Jagielski
211809f4227SJim Jagielski for ( int i = 0; i < words; i++ )
212809f4227SJim Jagielski classes[i] = X86_64_NO_CLASS;
213809f4227SJim Jagielski
214809f4227SJim Jagielski const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
215809f4227SJim Jagielski
216809f4227SJim Jagielski /* Merge the fields of structure. */
217809f4227SJim Jagielski for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
218809f4227SJim Jagielski {
219809f4227SJim Jagielski typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
220809f4227SJim Jagielski int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
221809f4227SJim Jagielski
222809f4227SJim Jagielski int num = classify_argument( pTypeInStruct, subclasses, offset );
223809f4227SJim Jagielski
224809f4227SJim Jagielski if ( num == 0 )
225809f4227SJim Jagielski {
226809f4227SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
227809f4227SJim Jagielski return 0;
228809f4227SJim Jagielski }
229809f4227SJim Jagielski
230809f4227SJim Jagielski for ( int i = 0; i < num; i++ )
231809f4227SJim Jagielski {
232809f4227SJim Jagielski int pos = offset / 8;
233809f4227SJim Jagielski classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
234809f4227SJim Jagielski }
235809f4227SJim Jagielski }
236809f4227SJim Jagielski
237809f4227SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
238809f4227SJim Jagielski
239809f4227SJim Jagielski /* Final merger cleanup. */
240809f4227SJim Jagielski for ( int i = 0; i < words; i++ )
241809f4227SJim Jagielski {
242809f4227SJim Jagielski /* If one class is MEMORY, everything should be passed in
243809f4227SJim Jagielski memory. */
244809f4227SJim Jagielski if ( classes[i] == X86_64_MEMORY_CLASS )
245809f4227SJim Jagielski return 0;
246809f4227SJim Jagielski
247809f4227SJim Jagielski /* The X86_64_SSEUP_CLASS should be always preceded by
248809f4227SJim Jagielski X86_64_SSE_CLASS. */
249809f4227SJim Jagielski if ( classes[i] == X86_64_SSEUP_CLASS
250809f4227SJim Jagielski && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
251809f4227SJim Jagielski classes[i] = X86_64_SSE_CLASS;
252809f4227SJim Jagielski
253809f4227SJim Jagielski /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
254809f4227SJim Jagielski if ( classes[i] == X86_64_X87UP_CLASS
255809f4227SJim Jagielski && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
256809f4227SJim Jagielski classes[i] = X86_64_SSE_CLASS;
257809f4227SJim Jagielski }
258809f4227SJim Jagielski return words;
259809f4227SJim Jagielski }
260809f4227SJim Jagielski
261809f4227SJim Jagielski default:
262809f4227SJim Jagielski #if OSL_DEBUG_LEVEL > 1
263809f4227SJim Jagielski OSL_TRACE( "Unhandled case: pType->eTypeClass == %d\n", pTypeRef->eTypeClass );
264809f4227SJim Jagielski #endif
265809f4227SJim Jagielski OSL_ASSERT(0);
266809f4227SJim Jagielski }
267809f4227SJim Jagielski return 0; /* Never reached. */
268809f4227SJim Jagielski }
269809f4227SJim Jagielski
270809f4227SJim Jagielski /* Examine the argument and return set number of register required in each
271809f4227SJim Jagielski class. Return 0 iff parameter should be passed in memory. */
examine_argument(typelib_TypeDescriptionReference * pTypeRef,bool bInReturn,int & nUsedGPR,int & nUsedSSE)272809f4227SJim Jagielski bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE )
273809f4227SJim Jagielski {
274809f4227SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
275809f4227SJim Jagielski int n;
276809f4227SJim Jagielski
277809f4227SJim Jagielski n = classify_argument( pTypeRef, classes, 0 );
278809f4227SJim Jagielski
279809f4227SJim Jagielski if ( n == 0 )
280809f4227SJim Jagielski return false;
281809f4227SJim Jagielski
282809f4227SJim Jagielski nUsedGPR = 0;
283809f4227SJim Jagielski nUsedSSE = 0;
284809f4227SJim Jagielski for ( n--; n >= 0; n-- )
285809f4227SJim Jagielski switch ( classes[n] )
286809f4227SJim Jagielski {
287809f4227SJim Jagielski case X86_64_INTEGER_CLASS:
288809f4227SJim Jagielski case X86_64_INTEGERSI_CLASS:
289809f4227SJim Jagielski nUsedGPR++;
290809f4227SJim Jagielski break;
291809f4227SJim Jagielski case X86_64_SSE_CLASS:
292809f4227SJim Jagielski case X86_64_SSESF_CLASS:
293809f4227SJim Jagielski case X86_64_SSEDF_CLASS:
294809f4227SJim Jagielski nUsedSSE++;
295809f4227SJim Jagielski break;
296809f4227SJim Jagielski case X86_64_NO_CLASS:
297809f4227SJim Jagielski case X86_64_SSEUP_CLASS:
298809f4227SJim Jagielski break;
299809f4227SJim Jagielski case X86_64_X87_CLASS:
300809f4227SJim Jagielski case X86_64_X87UP_CLASS:
301809f4227SJim Jagielski if ( !bInReturn )
302809f4227SJim Jagielski return false;
303809f4227SJim Jagielski break;
304809f4227SJim Jagielski default:
305809f4227SJim Jagielski #if OSL_DEBUG_LEVEL > 1
306809f4227SJim Jagielski OSL_TRACE( "Unhandled case: classes[n] == %d\n", classes[n] );
307809f4227SJim Jagielski #endif
308809f4227SJim Jagielski OSL_ASSERT(0);
309809f4227SJim Jagielski }
310809f4227SJim Jagielski return true;
311809f4227SJim Jagielski }
312809f4227SJim Jagielski
return_in_hidden_param(typelib_TypeDescriptionReference * pTypeRef)313809f4227SJim Jagielski bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
314809f4227SJim Jagielski {
315809f4227SJim Jagielski int g, s;
316809f4227SJim Jagielski
317809f4227SJim Jagielski return examine_argument( pTypeRef, true, g, s ) == 0;
318809f4227SJim Jagielski }
319809f4227SJim Jagielski
fill_struct(typelib_TypeDescriptionReference * pTypeRef,const sal_uInt64 * pGPR,const double * pSSE,void * pStruct)320809f4227SJim Jagielski void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct )
321809f4227SJim Jagielski {
322809f4227SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
323809f4227SJim Jagielski int n;
324809f4227SJim Jagielski
325809f4227SJim Jagielski n = classify_argument( pTypeRef, classes, 0 );
326809f4227SJim Jagielski
327ecf1c5e9SJim Jagielski sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
328809f4227SJim Jagielski for ( n--; n >= 0; n-- )
329809f4227SJim Jagielski switch ( classes[n] )
330809f4227SJim Jagielski {
331809f4227SJim Jagielski case X86_64_INTEGER_CLASS:
332809f4227SJim Jagielski case X86_64_INTEGERSI_CLASS:
333809f4227SJim Jagielski *pStructAlign++ = *pGPR++;
334809f4227SJim Jagielski break;
335809f4227SJim Jagielski case X86_64_SSE_CLASS:
336809f4227SJim Jagielski case X86_64_SSESF_CLASS:
337809f4227SJim Jagielski case X86_64_SSEDF_CLASS:
338809f4227SJim Jagielski *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
339809f4227SJim Jagielski break;
340809f4227SJim Jagielski default:
341809f4227SJim Jagielski break;
342809f4227SJim Jagielski }
343809f4227SJim Jagielski }
344809f4227SJim Jagielski
345809f4227SJim Jagielski #if 0
346809f4227SJim Jagielski
347809f4227SJim Jagielski /* Functions to load floats and double to an SSE register placeholder. */
348809f4227SJim Jagielski extern void float2sse (float, __int128_t *);
349809f4227SJim Jagielski extern void double2sse (double, __int128_t *);
350809f4227SJim Jagielski extern void floatfloat2sse (void *, __int128_t *);
351809f4227SJim Jagielski
352809f4227SJim Jagielski /* Functions to put the floats and doubles back. */
353809f4227SJim Jagielski extern float sse2float (__int128_t *);
354809f4227SJim Jagielski extern double sse2double (__int128_t *);
355809f4227SJim Jagielski extern void sse2floatfloat(__int128_t *, void *);
356809f4227SJim Jagielski
357809f4227SJim Jagielski /*@-exportheader@*/
358809f4227SJim Jagielski void
359809f4227SJim Jagielski ffi_prep_args (stackLayout *stack, extended_cif *ecif)
360809f4227SJim Jagielski /*@=exportheader@*/
361809f4227SJim Jagielski {
362809f4227SJim Jagielski int gprcount, ssecount, i, g, s;
363809f4227SJim Jagielski void **p_argv;
364809f4227SJim Jagielski void *argp = &stack->argspace;
365809f4227SJim Jagielski ffi_type **p_arg;
366809f4227SJim Jagielski
367809f4227SJim Jagielski /* First check if the return value should be passed in memory. If so,
368809f4227SJim Jagielski pass the pointer as the first argument. */
369809f4227SJim Jagielski gprcount = ssecount = 0;
370809f4227SJim Jagielski if (ecif->cif->rtype->type != FFI_TYPE_VOID
371809f4227SJim Jagielski && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
372809f4227SJim Jagielski (void *)stack->gpr[gprcount++] = ecif->rvalue;
373809f4227SJim Jagielski
374809f4227SJim Jagielski for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
375809f4227SJim Jagielski i!=0; i--, p_arg++, p_argv++)
376809f4227SJim Jagielski {
377809f4227SJim Jagielski int in_register = 0;
378809f4227SJim Jagielski
379809f4227SJim Jagielski switch ((*p_arg)->type)
380809f4227SJim Jagielski {
381809f4227SJim Jagielski case FFI_TYPE_SINT8:
382809f4227SJim Jagielski case FFI_TYPE_SINT16:
383809f4227SJim Jagielski case FFI_TYPE_SINT32:
384809f4227SJim Jagielski case FFI_TYPE_SINT64:
385809f4227SJim Jagielski case FFI_TYPE_UINT8:
386809f4227SJim Jagielski case FFI_TYPE_UINT16:
387809f4227SJim Jagielski case FFI_TYPE_UINT32:
388809f4227SJim Jagielski case FFI_TYPE_UINT64:
389809f4227SJim Jagielski case FFI_TYPE_POINTER:
390809f4227SJim Jagielski if (gprcount < MAX_GPR_REGS)
391809f4227SJim Jagielski {
392809f4227SJim Jagielski stack->gpr[gprcount] = 0;
393809f4227SJim Jagielski stack->gpr[gprcount++] = *(long long *)(*p_argv);
394809f4227SJim Jagielski in_register = 1;
395809f4227SJim Jagielski }
396809f4227SJim Jagielski break;
397809f4227SJim Jagielski
398809f4227SJim Jagielski case FFI_TYPE_FLOAT:
399809f4227SJim Jagielski if (ssecount < MAX_SSE_REGS)
400809f4227SJim Jagielski {
401809f4227SJim Jagielski float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
402809f4227SJim Jagielski in_register = 1;
403809f4227SJim Jagielski }
404809f4227SJim Jagielski break;
405809f4227SJim Jagielski
406809f4227SJim Jagielski case FFI_TYPE_DOUBLE:
407809f4227SJim Jagielski if (ssecount < MAX_SSE_REGS)
408809f4227SJim Jagielski {
409809f4227SJim Jagielski double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
410809f4227SJim Jagielski in_register = 1;
411809f4227SJim Jagielski }
412809f4227SJim Jagielski break;
413809f4227SJim Jagielski }
414809f4227SJim Jagielski
415809f4227SJim Jagielski if (in_register)
416809f4227SJim Jagielski continue;
417809f4227SJim Jagielski
418809f4227SJim Jagielski /* Either all places in registers where filled, or this is a
419809f4227SJim Jagielski type that potentially goes into a memory slot. */
420809f4227SJim Jagielski if (examine_argument (*p_arg, 0, &g, &s) == 0
421809f4227SJim Jagielski || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
422809f4227SJim Jagielski {
423809f4227SJim Jagielski /* Pass this argument in memory. */
424809f4227SJim Jagielski argp = (void *)ALIGN(argp, (*p_arg)->alignment);
425809f4227SJim Jagielski memcpy (argp, *p_argv, (*p_arg)->size);
426809f4227SJim Jagielski argp += (*p_arg)->size;
427809f4227SJim Jagielski }
428809f4227SJim Jagielski else
429809f4227SJim Jagielski {
430809f4227SJim Jagielski /* All easy cases are eliminated. Now fire the big guns. */
431809f4227SJim Jagielski
432809f4227SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
433809f4227SJim Jagielski int j, num;
434809f4227SJim Jagielski void *a;
435809f4227SJim Jagielski
436809f4227SJim Jagielski num = classify_argument (*p_arg, classes, 0);
437809f4227SJim Jagielski for (j=0, a=*p_argv; j<num; j++, a+=8)
438809f4227SJim Jagielski {
439809f4227SJim Jagielski switch (classes[j])
440809f4227SJim Jagielski {
441809f4227SJim Jagielski case X86_64_INTEGER_CLASS:
442809f4227SJim Jagielski case X86_64_INTEGERSI_CLASS:
443809f4227SJim Jagielski stack->gpr[gprcount++] = *(long long *)a;
444809f4227SJim Jagielski break;
445809f4227SJim Jagielski case X86_64_SSE_CLASS:
446809f4227SJim Jagielski floatfloat2sse (a, &stack->sse[ssecount++]);
447809f4227SJim Jagielski break;
448809f4227SJim Jagielski case X86_64_SSESF_CLASS:
449809f4227SJim Jagielski float2sse (*(float *)a, &stack->sse[ssecount++]);
450809f4227SJim Jagielski break;
451809f4227SJim Jagielski case X86_64_SSEDF_CLASS:
452809f4227SJim Jagielski double2sse (*(double *)a, &stack->sse[ssecount++]);
453809f4227SJim Jagielski break;
454809f4227SJim Jagielski default:
455809f4227SJim Jagielski abort();
456809f4227SJim Jagielski }
457809f4227SJim Jagielski }
458809f4227SJim Jagielski }
459809f4227SJim Jagielski }
460809f4227SJim Jagielski }
461809f4227SJim Jagielski
462809f4227SJim Jagielski /* Perform machine dependent cif processing. */
463809f4227SJim Jagielski ffi_status
464809f4227SJim Jagielski ffi_prep_cif_machdep (ffi_cif *cif)
465809f4227SJim Jagielski {
466809f4227SJim Jagielski int gprcount, ssecount, i, g, s;
467809f4227SJim Jagielski
468809f4227SJim Jagielski gprcount = ssecount = 0;
469809f4227SJim Jagielski
470809f4227SJim Jagielski /* Reset the byte count. We handle this size estimation here. */
471809f4227SJim Jagielski cif->bytes = 0;
472809f4227SJim Jagielski
473809f4227SJim Jagielski /* If the return value should be passed in memory, pass the pointer
474809f4227SJim Jagielski as the first argument. The actual memory isn't allocated here. */
475809f4227SJim Jagielski if (cif->rtype->type != FFI_TYPE_VOID
476809f4227SJim Jagielski && examine_argument (cif->rtype, 1, &g, &s) == 0)
477809f4227SJim Jagielski gprcount = 1;
478809f4227SJim Jagielski
479809f4227SJim Jagielski /* Go over all arguments and determine the way they should be passed.
480809f4227SJim Jagielski If it's in a register and there is space for it, let that be so. If
481809f4227SJim Jagielski not, add it's size to the stack byte count. */
482809f4227SJim Jagielski for (i=0; i<cif->nargs; i++)
483809f4227SJim Jagielski {
484809f4227SJim Jagielski if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
485809f4227SJim Jagielski || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
486809f4227SJim Jagielski {
487809f4227SJim Jagielski /* This is passed in memory. First align to the basic type. */
488809f4227SJim Jagielski cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
489809f4227SJim Jagielski
490809f4227SJim Jagielski /* Stack arguments are *always* at least 8 byte aligned. */
491809f4227SJim Jagielski cif->bytes = ALIGN(cif->bytes, 8);
492809f4227SJim Jagielski
493809f4227SJim Jagielski /* Now add the size of this argument. */
494809f4227SJim Jagielski cif->bytes += cif->arg_types[i]->size;
495809f4227SJim Jagielski }
496809f4227SJim Jagielski else
497809f4227SJim Jagielski {
498809f4227SJim Jagielski gprcount += g;
499809f4227SJim Jagielski ssecount += s;
500809f4227SJim Jagielski }
501809f4227SJim Jagielski }
502809f4227SJim Jagielski
503809f4227SJim Jagielski /* Set the flag for the closures return. */
504809f4227SJim Jagielski switch (cif->rtype->type)
505809f4227SJim Jagielski {
506809f4227SJim Jagielski case FFI_TYPE_VOID:
507809f4227SJim Jagielski case FFI_TYPE_STRUCT:
508809f4227SJim Jagielski case FFI_TYPE_SINT64:
509809f4227SJim Jagielski case FFI_TYPE_FLOAT:
510809f4227SJim Jagielski case FFI_TYPE_DOUBLE:
511809f4227SJim Jagielski case FFI_TYPE_LONGDOUBLE:
512809f4227SJim Jagielski cif->flags = (unsigned) cif->rtype->type;
513809f4227SJim Jagielski break;
514809f4227SJim Jagielski
515809f4227SJim Jagielski case FFI_TYPE_UINT64:
516809f4227SJim Jagielski cif->flags = FFI_TYPE_SINT64;
517809f4227SJim Jagielski break;
518809f4227SJim Jagielski
519809f4227SJim Jagielski default:
520809f4227SJim Jagielski cif->flags = FFI_TYPE_INT;
521809f4227SJim Jagielski break;
522809f4227SJim Jagielski }
523809f4227SJim Jagielski
524809f4227SJim Jagielski return FFI_OK;
525809f4227SJim Jagielski }
526809f4227SJim Jagielski
527809f4227SJim Jagielski typedef struct
528809f4227SJim Jagielski {
529809f4227SJim Jagielski long gpr[2];
530809f4227SJim Jagielski __int128_t sse[2];
531809f4227SJim Jagielski long double st0;
532809f4227SJim Jagielski } return_value;
533809f4227SJim Jagielski
534809f4227SJim Jagielski //#endif
535809f4227SJim Jagielski
536809f4227SJim Jagielski void
537809f4227SJim Jagielski ffi_fill_return_value (return_value *rv, extended_cif *ecif)
538809f4227SJim Jagielski {
539809f4227SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
540809f4227SJim Jagielski int i = 0, num;
541809f4227SJim Jagielski long *gpr = rv->gpr;
542809f4227SJim Jagielski __int128_t *sse = rv->sse;
543809f4227SJim Jagielski signed char sc;
544809f4227SJim Jagielski signed short ss;
545809f4227SJim Jagielski
546809f4227SJim Jagielski /* This is needed because of the way x86-64 handles signed short
547809f4227SJim Jagielski integers. */
548809f4227SJim Jagielski switch (ecif->cif->rtype->type)
549809f4227SJim Jagielski {
550809f4227SJim Jagielski case FFI_TYPE_SINT8:
551809f4227SJim Jagielski sc = *(signed char *)gpr;
552809f4227SJim Jagielski *(long long *)ecif->rvalue = (long long)sc;
553809f4227SJim Jagielski return;
554809f4227SJim Jagielski case FFI_TYPE_SINT16:
555809f4227SJim Jagielski ss = *(signed short *)gpr;
556809f4227SJim Jagielski *(long long *)ecif->rvalue = (long long)ss;
557809f4227SJim Jagielski return;
558809f4227SJim Jagielski default:
559809f4227SJim Jagielski /* Just continue. */
560809f4227SJim Jagielski ;
561809f4227SJim Jagielski }
562809f4227SJim Jagielski
563809f4227SJim Jagielski num = classify_argument (ecif->cif->rtype, classes, 0);
564809f4227SJim Jagielski
565809f4227SJim Jagielski if (num == 0)
566809f4227SJim Jagielski /* Return in memory. */
567809f4227SJim Jagielski ecif->rvalue = (void *) rv->gpr[0];
568809f4227SJim Jagielski else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
569809f4227SJim Jagielski classes[1] == X86_64_X87UP_CLASS)
570809f4227SJim Jagielski /* This is a long double (this is easiest to handle this way instead
571809f4227SJim Jagielski of an eightbyte at a time as in the loop below. */
572809f4227SJim Jagielski *((long double *)ecif->rvalue) = rv->st0;
573809f4227SJim Jagielski else
574809f4227SJim Jagielski {
575809f4227SJim Jagielski void *a;
576809f4227SJim Jagielski
577809f4227SJim Jagielski for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
578809f4227SJim Jagielski {
579809f4227SJim Jagielski switch (classes[i])
580809f4227SJim Jagielski {
581809f4227SJim Jagielski case X86_64_INTEGER_CLASS:
582809f4227SJim Jagielski case X86_64_INTEGERSI_CLASS:
583809f4227SJim Jagielski *(long long *)a = *gpr;
584809f4227SJim Jagielski gpr++;
585809f4227SJim Jagielski break;
586809f4227SJim Jagielski case X86_64_SSE_CLASS:
587809f4227SJim Jagielski sse2floatfloat (sse++, a);
588809f4227SJim Jagielski break;
589809f4227SJim Jagielski case X86_64_SSESF_CLASS:
590809f4227SJim Jagielski *(float *)a = sse2float (sse++);
591809f4227SJim Jagielski break;
592809f4227SJim Jagielski case X86_64_SSEDF_CLASS:
593809f4227SJim Jagielski *(double *)a = sse2double (sse++);
594809f4227SJim Jagielski break;
595809f4227SJim Jagielski default:
596809f4227SJim Jagielski abort();
597809f4227SJim Jagielski }
598809f4227SJim Jagielski }
599809f4227SJim Jagielski }
600809f4227SJim Jagielski }
601809f4227SJim Jagielski
602809f4227SJim Jagielski //#if 0
603809f4227SJim Jagielski
604809f4227SJim Jagielski /*@-declundef@*/
605809f4227SJim Jagielski /*@-exportheader@*/
606809f4227SJim Jagielski extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
607809f4227SJim Jagielski void (*) (return_value *, extended_cif *),
608809f4227SJim Jagielski /*@out@*/ extended_cif *,
609809f4227SJim Jagielski unsigned, /*@out@*/ unsigned *, void (*fn)());
610809f4227SJim Jagielski /*@=declundef@*/
611809f4227SJim Jagielski /*@=exportheader@*/
612809f4227SJim Jagielski
613809f4227SJim Jagielski void ffi_call(/*@dependent@*/ ffi_cif *cif,
614809f4227SJim Jagielski void (*fn)(),
615809f4227SJim Jagielski /*@out@*/ void *rvalue,
616809f4227SJim Jagielski /*@dependent@*/ void **avalue)
617809f4227SJim Jagielski {
618809f4227SJim Jagielski extended_cif ecif;
619809f4227SJim Jagielski int dummy;
620809f4227SJim Jagielski
621809f4227SJim Jagielski ecif.cif = cif;
622809f4227SJim Jagielski ecif.avalue = avalue;
623809f4227SJim Jagielski
624809f4227SJim Jagielski /* If the return value is a struct and we don't have a return */
625809f4227SJim Jagielski /* value address then we need to make one */
626809f4227SJim Jagielski
627809f4227SJim Jagielski if ((rvalue == NULL) &&
628809f4227SJim Jagielski (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
629809f4227SJim Jagielski {
630809f4227SJim Jagielski /*@-sysunrecog@*/
631809f4227SJim Jagielski ecif.rvalue = alloca(cif->rtype->size);
632809f4227SJim Jagielski /*@=sysunrecog@*/
633809f4227SJim Jagielski }
634809f4227SJim Jagielski else
635809f4227SJim Jagielski ecif.rvalue = rvalue;
636809f4227SJim Jagielski
637809f4227SJim Jagielski /* Stack must always be 16byte aligned. Make it so. */
638809f4227SJim Jagielski cif->bytes = ALIGN(cif->bytes, 16);
639809f4227SJim Jagielski
640809f4227SJim Jagielski switch (cif->abi)
641809f4227SJim Jagielski {
642809f4227SJim Jagielski case FFI_SYSV:
643809f4227SJim Jagielski /* Calling 32bit code from 64bit is not possible */
644809f4227SJim Jagielski FFI_ASSERT(0);
645809f4227SJim Jagielski break;
646809f4227SJim Jagielski
647809f4227SJim Jagielski case FFI_UNIX64:
648809f4227SJim Jagielski /*@-usedef@*/
649809f4227SJim Jagielski ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
650809f4227SJim Jagielski cif->bytes, ecif.rvalue, fn);
651809f4227SJim Jagielski /*@=usedef@*/
652809f4227SJim Jagielski break;
653809f4227SJim Jagielski
654809f4227SJim Jagielski default:
655809f4227SJim Jagielski FFI_ASSERT(0);
656809f4227SJim Jagielski break;
657809f4227SJim Jagielski }
658809f4227SJim Jagielski }
659809f4227SJim Jagielski
660809f4227SJim Jagielski extern void ffi_closure_UNIX64(void);
661809f4227SJim Jagielski
662809f4227SJim Jagielski ffi_status
663809f4227SJim Jagielski ffi_prep_closure (ffi_closure* closure,
664809f4227SJim Jagielski ffi_cif* cif,
665809f4227SJim Jagielski void (*fun)(ffi_cif*, void*, void**, void*),
666809f4227SJim Jagielski void *user_data)
667809f4227SJim Jagielski {
668809f4227SJim Jagielski volatile unsigned short *tramp;
669809f4227SJim Jagielski
670809f4227SJim Jagielski /* FFI_ASSERT (cif->abi == FFI_OSF); */
671809f4227SJim Jagielski
672809f4227SJim Jagielski tramp = (volatile unsigned short *) &closure->tramp[0];
673809f4227SJim Jagielski tramp[0] = 0xbb49; /* mov <code>, %r11 */
674809f4227SJim Jagielski tramp[5] = 0xba49; /* mov <data>, %r10 */
675809f4227SJim Jagielski tramp[10] = 0xff49; /* jmp *%r11 */
676809f4227SJim Jagielski tramp[11] = 0x00e3;
677809f4227SJim Jagielski *(void * volatile *) &tramp[1] = ffi_closure_UNIX64;
678809f4227SJim Jagielski *(void * volatile *) &tramp[6] = closure;
679809f4227SJim Jagielski
680809f4227SJim Jagielski closure->cif = cif;
681809f4227SJim Jagielski closure->fun = fun;
682809f4227SJim Jagielski closure->user_data = user_data;
683809f4227SJim Jagielski
684809f4227SJim Jagielski return FFI_OK;
685809f4227SJim Jagielski }
686809f4227SJim Jagielski
687809f4227SJim Jagielski int
688809f4227SJim Jagielski ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
689809f4227SJim Jagielski {
690809f4227SJim Jagielski ffi_cif *cif;
691809f4227SJim Jagielski void **avalue;
692809f4227SJim Jagielski ffi_type **arg_types;
693809f4227SJim Jagielski long i, avn, argn;
694809f4227SJim Jagielski
695809f4227SJim Jagielski cif = closure->cif;
696809f4227SJim Jagielski avalue = alloca(cif->nargs * sizeof(void *));
697809f4227SJim Jagielski
698809f4227SJim Jagielski argn = 0;
699809f4227SJim Jagielski
700809f4227SJim Jagielski i = 0;
701809f4227SJim Jagielski avn = cif->nargs;
702809f4227SJim Jagielski arg_types = cif->arg_types;
703809f4227SJim Jagielski
704809f4227SJim Jagielski /* Grab the addresses of the arguments from the stack frame. */
705809f4227SJim Jagielski while (i < avn)
706809f4227SJim Jagielski {
707809f4227SJim Jagielski switch (arg_types[i]->type)
708809f4227SJim Jagielski {
709809f4227SJim Jagielski case FFI_TYPE_SINT8:
710809f4227SJim Jagielski case FFI_TYPE_UINT8:
711809f4227SJim Jagielski case FFI_TYPE_SINT16:
712809f4227SJim Jagielski case FFI_TYPE_UINT16:
713809f4227SJim Jagielski case FFI_TYPE_SINT32:
714809f4227SJim Jagielski case FFI_TYPE_UINT32:
715809f4227SJim Jagielski case FFI_TYPE_SINT64:
716809f4227SJim Jagielski case FFI_TYPE_UINT64:
717809f4227SJim Jagielski case FFI_TYPE_POINTER:
718809f4227SJim Jagielski {
719809f4227SJim Jagielski if (l->gp_offset > 48-8)
720809f4227SJim Jagielski {
721809f4227SJim Jagielski avalue[i] = l->overflow_arg_area;
722809f4227SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
723809f4227SJim Jagielski }
724809f4227SJim Jagielski else
725809f4227SJim Jagielski {
726809f4227SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->gp_offset;
727809f4227SJim Jagielski l->gp_offset += 8;
728809f4227SJim Jagielski }
729809f4227SJim Jagielski }
730809f4227SJim Jagielski break;
731809f4227SJim Jagielski
732809f4227SJim Jagielski case FFI_TYPE_STRUCT:
733809f4227SJim Jagielski /* FIXME */
734809f4227SJim Jagielski FFI_ASSERT(0);
735809f4227SJim Jagielski break;
736809f4227SJim Jagielski
737809f4227SJim Jagielski case FFI_TYPE_DOUBLE:
738809f4227SJim Jagielski {
739809f4227SJim Jagielski if (l->fp_offset > 176-16)
740809f4227SJim Jagielski {
741809f4227SJim Jagielski avalue[i] = l->overflow_arg_area;
742809f4227SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
743809f4227SJim Jagielski }
744809f4227SJim Jagielski else
745809f4227SJim Jagielski {
746809f4227SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->fp_offset;
747809f4227SJim Jagielski l->fp_offset += 16;
748809f4227SJim Jagielski }
749809f4227SJim Jagielski }
750809f4227SJim Jagielski #if DEBUG_FFI
751809f4227SJim Jagielski fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
752809f4227SJim Jagielski #endif
753809f4227SJim Jagielski break;
754809f4227SJim Jagielski
755809f4227SJim Jagielski case FFI_TYPE_FLOAT:
756809f4227SJim Jagielski {
757809f4227SJim Jagielski if (l->fp_offset > 176-16)
758809f4227SJim Jagielski {
759809f4227SJim Jagielski avalue[i] = l->overflow_arg_area;
760809f4227SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
761809f4227SJim Jagielski }
762809f4227SJim Jagielski else
763809f4227SJim Jagielski {
764809f4227SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->fp_offset;
765809f4227SJim Jagielski l->fp_offset += 16;
766809f4227SJim Jagielski }
767809f4227SJim Jagielski }
768809f4227SJim Jagielski #if DEBUG_FFI
769809f4227SJim Jagielski fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
770809f4227SJim Jagielski #endif
771809f4227SJim Jagielski break;
772809f4227SJim Jagielski
773809f4227SJim Jagielski default:
774809f4227SJim Jagielski FFI_ASSERT(0);
775809f4227SJim Jagielski }
776809f4227SJim Jagielski
777809f4227SJim Jagielski argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
778809f4227SJim Jagielski i++;
779809f4227SJim Jagielski }
780809f4227SJim Jagielski
781809f4227SJim Jagielski /* Invoke the closure. */
782809f4227SJim Jagielski (closure->fun) (cif, rp, avalue, closure->user_data);
783809f4227SJim Jagielski
784809f4227SJim Jagielski /* FIXME: Structs not supported. */
785809f4227SJim Jagielski FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);
786809f4227SJim Jagielski
787809f4227SJim Jagielski /* Tell ffi_closure_UNIX64 how to perform return type promotions. */
788809f4227SJim Jagielski
789809f4227SJim Jagielski return cif->rtype->type;
790809f4227SJim Jagielski }
791809f4227SJim Jagielski
792809f4227SJim Jagielski #endif
793