1b682cb18SJim Jagielski /**************************************************************
2b682cb18SJim Jagielski *
3b682cb18SJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one
4b682cb18SJim Jagielski * or more contributor license agreements. See the NOTICE file
5b682cb18SJim Jagielski * distributed with this work for additional information
6b682cb18SJim Jagielski * regarding copyright ownership. The ASF licenses this file
7b682cb18SJim Jagielski * to you under the Apache License, Version 2.0 (the
8b682cb18SJim Jagielski * "License"); you may not use this file except in compliance
9b682cb18SJim Jagielski * with the License. You may obtain a copy of the License at
10b682cb18SJim Jagielski *
11b682cb18SJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0
12b682cb18SJim Jagielski *
13b682cb18SJim Jagielski * Unless required by applicable law or agreed to in writing,
14b682cb18SJim Jagielski * software distributed under the License is distributed on an
15b682cb18SJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16b682cb18SJim Jagielski * KIND, either express or implied. See the License for the
17b682cb18SJim Jagielski * specific language governing permissions and limitations
18b682cb18SJim Jagielski * under the License.
19b682cb18SJim Jagielski *
20b682cb18SJim Jagielski *************************************************************/
21b682cb18SJim Jagielski
22b682cb18SJim Jagielski
23b682cb18SJim Jagielski
24b682cb18SJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25b682cb18SJim Jagielski #include "precompiled_bridges.hxx"
26b682cb18SJim Jagielski
27b682cb18SJim Jagielski // This is an implementation of the x86-64 ABI as described in 'System V
28b682cb18SJim Jagielski // Application Binary Interface, AMD64 Architecture Processor Supplement'
29b682cb18SJim Jagielski // (http://www.x86-64.org/documentation/abi-0.95.pdf)
30b682cb18SJim Jagielski //
31b682cb18SJim Jagielski // The code in this file is a modification of src/x86/ffi64.c from libffi
32b682cb18SJim Jagielski // (http://sources.redhat.com/libffi/) which is under the following license:
33b682cb18SJim Jagielski
34b682cb18SJim Jagielski /* -----------------------------------------------------------------------
35b682cb18SJim Jagielski ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
36b682cb18SJim Jagielski
37b682cb18SJim Jagielski x86-64 Foreign Function Interface
38b682cb18SJim Jagielski
39b682cb18SJim Jagielski Permission is hereby granted, free of charge, to any person obtaining
40b682cb18SJim Jagielski a copy of this software and associated documentation files (the
41b682cb18SJim Jagielski ``Software''), to deal in the Software without restriction, including
42b682cb18SJim Jagielski without limitation the rights to use, copy, modify, merge, publish,
43b682cb18SJim Jagielski distribute, sublicense, and/or sell copies of the Software, and to
44b682cb18SJim Jagielski permit persons to whom the Software is furnished to do so, subject to
45b682cb18SJim Jagielski the following conditions:
46b682cb18SJim Jagielski
47b682cb18SJim Jagielski The above copyright notice and this permission notice shall be included
48b682cb18SJim Jagielski in all copies or substantial portions of the Software.
49b682cb18SJim Jagielski
50b682cb18SJim Jagielski THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
51b682cb18SJim Jagielski OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
52b682cb18SJim Jagielski MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
53b682cb18SJim Jagielski IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
54b682cb18SJim Jagielski OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
55b682cb18SJim Jagielski ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
56b682cb18SJim Jagielski OTHER DEALINGS IN THE SOFTWARE.
57b682cb18SJim Jagielski ----------------------------------------------------------------------- */
58b682cb18SJim Jagielski
59b682cb18SJim Jagielski #include "abi.hxx"
60b682cb18SJim Jagielski
61b682cb18SJim Jagielski #include <rtl/ustring.hxx>
62b682cb18SJim Jagielski
63b682cb18SJim Jagielski using namespace x86_64;
64b682cb18SJim Jagielski
65b682cb18SJim Jagielski typedef struct
66b682cb18SJim Jagielski {
67b682cb18SJim Jagielski /* Registers for argument passing. */
68b682cb18SJim Jagielski long gpr[MAX_GPR_REGS];
69b682cb18SJim Jagielski __int128_t sse[MAX_SSE_REGS];
70b682cb18SJim Jagielski
71b682cb18SJim Jagielski /* Stack space for arguments. */
72b682cb18SJim Jagielski char argspace[0];
73b682cb18SJim Jagielski } stackLayout;
74b682cb18SJim Jagielski
75b682cb18SJim Jagielski /* Register class used for passing given 64bit part of the argument.
76b682cb18SJim Jagielski These represent classes as documented by the PS ABI, with the exception
77b682cb18SJim Jagielski of SSESF, SSEDF classes, that are basically SSE class, just gcc will
78*06fb39a1SJohn Bampton use SF or DFmode move instead of DImode to avoid reformatting penalties.
79b682cb18SJim Jagielski
80b682cb18SJim Jagielski Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
81b682cb18SJim Jagielski whenever possible (upper half does contain padding).
82b682cb18SJim Jagielski */
83b682cb18SJim Jagielski enum x86_64_reg_class
84b682cb18SJim Jagielski {
85b682cb18SJim Jagielski X86_64_NO_CLASS,
86b682cb18SJim Jagielski X86_64_INTEGER_CLASS,
87b682cb18SJim Jagielski X86_64_INTEGERSI_CLASS,
88b682cb18SJim Jagielski X86_64_SSE_CLASS,
89b682cb18SJim Jagielski X86_64_SSESF_CLASS,
90b682cb18SJim Jagielski X86_64_SSEDF_CLASS,
91b682cb18SJim Jagielski X86_64_SSEUP_CLASS,
92b682cb18SJim Jagielski X86_64_X87_CLASS,
93b682cb18SJim Jagielski X86_64_X87UP_CLASS,
94b682cb18SJim Jagielski X86_64_MEMORY_CLASS
95b682cb18SJim Jagielski };
96b682cb18SJim Jagielski
97b682cb18SJim Jagielski #define MAX_CLASSES 4
98b682cb18SJim Jagielski
99b682cb18SJim Jagielski /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
100b682cb18SJim Jagielski of this code is to classify each 8bytes of incoming argument by the register
101b682cb18SJim Jagielski class and assign registers accordingly. */
102b682cb18SJim Jagielski
103b682cb18SJim Jagielski /* Return the union class of CLASS1 and CLASS2.
104b682cb18SJim Jagielski See the x86-64 PS ABI for details. */
105b682cb18SJim Jagielski
106b682cb18SJim Jagielski static enum x86_64_reg_class
merge_classes(enum x86_64_reg_class class1,enum x86_64_reg_class class2)107b682cb18SJim Jagielski merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
108b682cb18SJim Jagielski {
109b682cb18SJim Jagielski /* Rule #1: If both classes are equal, this is the resulting class. */
110b682cb18SJim Jagielski if (class1 == class2)
111b682cb18SJim Jagielski return class1;
112b682cb18SJim Jagielski
113b682cb18SJim Jagielski /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
114b682cb18SJim Jagielski the other class. */
115b682cb18SJim Jagielski if (class1 == X86_64_NO_CLASS)
116b682cb18SJim Jagielski return class2;
117b682cb18SJim Jagielski if (class2 == X86_64_NO_CLASS)
118b682cb18SJim Jagielski return class1;
119b682cb18SJim Jagielski
120b682cb18SJim Jagielski /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
121b682cb18SJim Jagielski if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
122b682cb18SJim Jagielski return X86_64_MEMORY_CLASS;
123b682cb18SJim Jagielski
124b682cb18SJim Jagielski /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
125b682cb18SJim Jagielski if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
126b682cb18SJim Jagielski || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
127b682cb18SJim Jagielski return X86_64_INTEGERSI_CLASS;
128b682cb18SJim Jagielski if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
129b682cb18SJim Jagielski || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
130b682cb18SJim Jagielski return X86_64_INTEGER_CLASS;
131b682cb18SJim Jagielski
132b682cb18SJim Jagielski /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */
133b682cb18SJim Jagielski if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
134b682cb18SJim Jagielski || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
135b682cb18SJim Jagielski return X86_64_MEMORY_CLASS;
136b682cb18SJim Jagielski
137b682cb18SJim Jagielski /* Rule #6: Otherwise class SSE is used. */
138b682cb18SJim Jagielski return X86_64_SSE_CLASS;
139b682cb18SJim Jagielski }
140b682cb18SJim Jagielski
141b682cb18SJim Jagielski /* Classify the argument of type TYPE and mode MODE.
142b682cb18SJim Jagielski CLASSES will be filled by the register class used to pass each word
143b682cb18SJim Jagielski of the operand. The number of words is returned. In case the parameter
144b682cb18SJim Jagielski should be passed in memory, 0 is returned. As a special case for zero
145b682cb18SJim Jagielski sized containers, classes[0] will be NO_CLASS and 1 is returned.
146b682cb18SJim Jagielski
147b682cb18SJim Jagielski See the x86-64 PS ABI for details.
148b682cb18SJim Jagielski */
149b682cb18SJim Jagielski static int
classify_argument(typelib_TypeDescriptionReference * pTypeRef,enum x86_64_reg_class classes[],int byteOffset)150b682cb18SJim Jagielski classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset )
151b682cb18SJim Jagielski {
152b682cb18SJim Jagielski switch ( pTypeRef->eTypeClass )
153b682cb18SJim Jagielski {
154b682cb18SJim Jagielski case typelib_TypeClass_VOID:
155b682cb18SJim Jagielski classes[0] = X86_64_NO_CLASS;
156b682cb18SJim Jagielski return 1;
157b682cb18SJim Jagielski case typelib_TypeClass_CHAR:
158b682cb18SJim Jagielski case typelib_TypeClass_BOOLEAN:
159b682cb18SJim Jagielski case typelib_TypeClass_BYTE:
160b682cb18SJim Jagielski case typelib_TypeClass_SHORT:
161b682cb18SJim Jagielski case typelib_TypeClass_UNSIGNED_SHORT:
162b682cb18SJim Jagielski case typelib_TypeClass_LONG:
163b682cb18SJim Jagielski case typelib_TypeClass_UNSIGNED_LONG:
164b682cb18SJim Jagielski case typelib_TypeClass_HYPER:
165b682cb18SJim Jagielski case typelib_TypeClass_UNSIGNED_HYPER:
166b682cb18SJim Jagielski case typelib_TypeClass_ENUM:
167b682cb18SJim Jagielski if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
168b682cb18SJim Jagielski classes[0] = X86_64_INTEGERSI_CLASS;
169b682cb18SJim Jagielski else
170b682cb18SJim Jagielski classes[0] = X86_64_INTEGER_CLASS;
171b682cb18SJim Jagielski return 1;
172b682cb18SJim Jagielski case typelib_TypeClass_FLOAT:
173b682cb18SJim Jagielski if ( ( byteOffset % 8 ) == 0 )
174b682cb18SJim Jagielski classes[0] = X86_64_SSESF_CLASS;
175b682cb18SJim Jagielski else
176b682cb18SJim Jagielski classes[0] = X86_64_SSE_CLASS;
177b682cb18SJim Jagielski return 1;
178b682cb18SJim Jagielski case typelib_TypeClass_DOUBLE:
179b682cb18SJim Jagielski classes[0] = X86_64_SSEDF_CLASS;
180b682cb18SJim Jagielski return 1;
181b682cb18SJim Jagielski /*case LONGDOUBLE:
182b682cb18SJim Jagielski classes[0] = X86_64_X87_CLASS;
183b682cb18SJim Jagielski classes[1] = X86_64_X87UP_CLASS;
184b682cb18SJim Jagielski return 2;*/
185b682cb18SJim Jagielski case typelib_TypeClass_STRING:
186b682cb18SJim Jagielski case typelib_TypeClass_TYPE:
187b682cb18SJim Jagielski case typelib_TypeClass_ANY:
188b682cb18SJim Jagielski case typelib_TypeClass_TYPEDEF:
189b682cb18SJim Jagielski case typelib_TypeClass_UNION:
190b682cb18SJim Jagielski case typelib_TypeClass_SEQUENCE:
191b682cb18SJim Jagielski case typelib_TypeClass_ARRAY:
192b682cb18SJim Jagielski case typelib_TypeClass_INTERFACE:
193b682cb18SJim Jagielski return 0;
194b682cb18SJim Jagielski case typelib_TypeClass_STRUCT:
195b682cb18SJim Jagielski case typelib_TypeClass_EXCEPTION:
196b682cb18SJim Jagielski {
197b682cb18SJim Jagielski typelib_TypeDescription * pTypeDescr = 0;
198b682cb18SJim Jagielski TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
199b682cb18SJim Jagielski
200b682cb18SJim Jagielski const int UNITS_PER_WORD = 8;
201b682cb18SJim Jagielski int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
202b682cb18SJim Jagielski enum x86_64_reg_class subclasses[MAX_CLASSES];
203b682cb18SJim Jagielski
204b682cb18SJim Jagielski /* If the struct is larger than 16 bytes, pass it on the stack. */
205b682cb18SJim Jagielski if ( pTypeDescr->nSize > 16 )
206b682cb18SJim Jagielski {
207b682cb18SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
208b682cb18SJim Jagielski return 0;
209b682cb18SJim Jagielski }
210b682cb18SJim Jagielski
211b682cb18SJim Jagielski for ( int i = 0; i < words; i++ )
212b682cb18SJim Jagielski classes[i] = X86_64_NO_CLASS;
213b682cb18SJim Jagielski
214b682cb18SJim Jagielski const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
215b682cb18SJim Jagielski
216b682cb18SJim Jagielski /* Merge the fields of structure. */
217b682cb18SJim Jagielski for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
218b682cb18SJim Jagielski {
219b682cb18SJim Jagielski typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
220b682cb18SJim Jagielski int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
221b682cb18SJim Jagielski
222b682cb18SJim Jagielski int num = classify_argument( pTypeInStruct, subclasses, offset );
223b682cb18SJim Jagielski
224b682cb18SJim Jagielski if ( num == 0 )
225b682cb18SJim Jagielski {
226b682cb18SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
227b682cb18SJim Jagielski return 0;
228b682cb18SJim Jagielski }
229b682cb18SJim Jagielski
230b682cb18SJim Jagielski for ( int i = 0; i < num; i++ )
231b682cb18SJim Jagielski {
232b682cb18SJim Jagielski int pos = offset / 8;
233b682cb18SJim Jagielski classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
234b682cb18SJim Jagielski }
235b682cb18SJim Jagielski }
236b682cb18SJim Jagielski
237b682cb18SJim Jagielski TYPELIB_DANGER_RELEASE( pTypeDescr );
238b682cb18SJim Jagielski
239b682cb18SJim Jagielski /* Final merger cleanup. */
240b682cb18SJim Jagielski for ( int i = 0; i < words; i++ )
241b682cb18SJim Jagielski {
242b682cb18SJim Jagielski /* If one class is MEMORY, everything should be passed in
243b682cb18SJim Jagielski memory. */
244b682cb18SJim Jagielski if ( classes[i] == X86_64_MEMORY_CLASS )
245b682cb18SJim Jagielski return 0;
246b682cb18SJim Jagielski
247b682cb18SJim Jagielski /* The X86_64_SSEUP_CLASS should be always preceded by
248b682cb18SJim Jagielski X86_64_SSE_CLASS. */
249b682cb18SJim Jagielski if ( classes[i] == X86_64_SSEUP_CLASS
250b682cb18SJim Jagielski && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
251b682cb18SJim Jagielski classes[i] = X86_64_SSE_CLASS;
252b682cb18SJim Jagielski
253b682cb18SJim Jagielski /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
254b682cb18SJim Jagielski if ( classes[i] == X86_64_X87UP_CLASS
255b682cb18SJim Jagielski && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
256b682cb18SJim Jagielski classes[i] = X86_64_SSE_CLASS;
257b682cb18SJim Jagielski }
258b682cb18SJim Jagielski return words;
259b682cb18SJim Jagielski }
260b682cb18SJim Jagielski
261b682cb18SJim Jagielski default:
262b682cb18SJim Jagielski #if OSL_DEBUG_LEVEL > 1
263b682cb18SJim Jagielski OSL_TRACE( "Unhandled case: pType->eTypeClass == %d\n", pTypeRef->eTypeClass );
264b682cb18SJim Jagielski #endif
265b682cb18SJim Jagielski OSL_ASSERT(0);
266b682cb18SJim Jagielski }
267b682cb18SJim Jagielski return 0; /* Never reached. */
268b682cb18SJim Jagielski }
269b682cb18SJim Jagielski
270b682cb18SJim Jagielski /* Examine the argument and return set number of register required in each
271b682cb18SJim Jagielski class. Return 0 iff parameter should be passed in memory. */
examine_argument(typelib_TypeDescriptionReference * pTypeRef,bool bInReturn,int & nUsedGPR,int & nUsedSSE)272b682cb18SJim Jagielski bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE )
273b682cb18SJim Jagielski {
274b682cb18SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
275b682cb18SJim Jagielski int n;
276b682cb18SJim Jagielski
277b682cb18SJim Jagielski n = classify_argument( pTypeRef, classes, 0 );
278b682cb18SJim Jagielski
279b682cb18SJim Jagielski if ( n == 0 )
280b682cb18SJim Jagielski return false;
281b682cb18SJim Jagielski
282b682cb18SJim Jagielski nUsedGPR = 0;
283b682cb18SJim Jagielski nUsedSSE = 0;
284b682cb18SJim Jagielski for ( n--; n >= 0; n-- )
285b682cb18SJim Jagielski switch ( classes[n] )
286b682cb18SJim Jagielski {
287b682cb18SJim Jagielski case X86_64_INTEGER_CLASS:
288b682cb18SJim Jagielski case X86_64_INTEGERSI_CLASS:
289b682cb18SJim Jagielski nUsedGPR++;
290b682cb18SJim Jagielski break;
291b682cb18SJim Jagielski case X86_64_SSE_CLASS:
292b682cb18SJim Jagielski case X86_64_SSESF_CLASS:
293b682cb18SJim Jagielski case X86_64_SSEDF_CLASS:
294b682cb18SJim Jagielski nUsedSSE++;
295b682cb18SJim Jagielski break;
296b682cb18SJim Jagielski case X86_64_NO_CLASS:
297b682cb18SJim Jagielski case X86_64_SSEUP_CLASS:
298b682cb18SJim Jagielski break;
299b682cb18SJim Jagielski case X86_64_X87_CLASS:
300b682cb18SJim Jagielski case X86_64_X87UP_CLASS:
301b682cb18SJim Jagielski if ( !bInReturn )
302b682cb18SJim Jagielski return false;
303b682cb18SJim Jagielski break;
304b682cb18SJim Jagielski default:
305b682cb18SJim Jagielski #if OSL_DEBUG_LEVEL > 1
306b682cb18SJim Jagielski OSL_TRACE( "Unhandled case: classes[n] == %d\n", classes[n] );
307b682cb18SJim Jagielski #endif
308b682cb18SJim Jagielski OSL_ASSERT(0);
309b682cb18SJim Jagielski }
310b682cb18SJim Jagielski return true;
311b682cb18SJim Jagielski }
312b682cb18SJim Jagielski
return_in_hidden_param(typelib_TypeDescriptionReference * pTypeRef)313b682cb18SJim Jagielski bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
314b682cb18SJim Jagielski {
315b682cb18SJim Jagielski int g, s;
316b682cb18SJim Jagielski
317b682cb18SJim Jagielski return examine_argument( pTypeRef, true, g, s ) == 0;
318b682cb18SJim Jagielski }
319b682cb18SJim Jagielski
fill_struct(typelib_TypeDescriptionReference * pTypeRef,const sal_uInt64 * pGPR,const double * pSSE,void * pStruct)320b682cb18SJim Jagielski void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct )
321b682cb18SJim Jagielski {
322b682cb18SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
323b682cb18SJim Jagielski int n;
324b682cb18SJim Jagielski
325b682cb18SJim Jagielski n = classify_argument( pTypeRef, classes, 0 );
326b682cb18SJim Jagielski
327dfec5905SJim Jagielski sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
328b682cb18SJim Jagielski for ( n--; n >= 0; n-- )
329b682cb18SJim Jagielski switch ( classes[n] )
330b682cb18SJim Jagielski {
331b682cb18SJim Jagielski case X86_64_INTEGER_CLASS:
332b682cb18SJim Jagielski case X86_64_INTEGERSI_CLASS:
333b682cb18SJim Jagielski *pStructAlign++ = *pGPR++;
334b682cb18SJim Jagielski break;
335b682cb18SJim Jagielski case X86_64_SSE_CLASS:
336b682cb18SJim Jagielski case X86_64_SSESF_CLASS:
337b682cb18SJim Jagielski case X86_64_SSEDF_CLASS:
338b682cb18SJim Jagielski *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
339b682cb18SJim Jagielski break;
340b682cb18SJim Jagielski default:
341b682cb18SJim Jagielski break;
342b682cb18SJim Jagielski }
343b682cb18SJim Jagielski }
344b682cb18SJim Jagielski
345b682cb18SJim Jagielski #if 0
346b682cb18SJim Jagielski
347b682cb18SJim Jagielski /* Functions to load floats and double to an SSE register placeholder. */
348b682cb18SJim Jagielski extern void float2sse (float, __int128_t *);
349b682cb18SJim Jagielski extern void double2sse (double, __int128_t *);
350b682cb18SJim Jagielski extern void floatfloat2sse (void *, __int128_t *);
351b682cb18SJim Jagielski
352b682cb18SJim Jagielski /* Functions to put the floats and doubles back. */
353b682cb18SJim Jagielski extern float sse2float (__int128_t *);
354b682cb18SJim Jagielski extern double sse2double (__int128_t *);
355b682cb18SJim Jagielski extern void sse2floatfloat(__int128_t *, void *);
356b682cb18SJim Jagielski
357b682cb18SJim Jagielski /*@-exportheader@*/
358b682cb18SJim Jagielski void
359b682cb18SJim Jagielski ffi_prep_args (stackLayout *stack, extended_cif *ecif)
360b682cb18SJim Jagielski /*@=exportheader@*/
361b682cb18SJim Jagielski {
362b682cb18SJim Jagielski int gprcount, ssecount, i, g, s;
363b682cb18SJim Jagielski void **p_argv;
364b682cb18SJim Jagielski void *argp = &stack->argspace;
365b682cb18SJim Jagielski ffi_type **p_arg;
366b682cb18SJim Jagielski
367b682cb18SJim Jagielski /* First check if the return value should be passed in memory. If so,
368b682cb18SJim Jagielski pass the pointer as the first argument. */
369b682cb18SJim Jagielski gprcount = ssecount = 0;
370b682cb18SJim Jagielski if (ecif->cif->rtype->type != FFI_TYPE_VOID
371b682cb18SJim Jagielski && examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
372b682cb18SJim Jagielski (void *)stack->gpr[gprcount++] = ecif->rvalue;
373b682cb18SJim Jagielski
374b682cb18SJim Jagielski for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
375b682cb18SJim Jagielski i!=0; i--, p_arg++, p_argv++)
376b682cb18SJim Jagielski {
377b682cb18SJim Jagielski int in_register = 0;
378b682cb18SJim Jagielski
379b682cb18SJim Jagielski switch ((*p_arg)->type)
380b682cb18SJim Jagielski {
381b682cb18SJim Jagielski case FFI_TYPE_SINT8:
382b682cb18SJim Jagielski case FFI_TYPE_SINT16:
383b682cb18SJim Jagielski case FFI_TYPE_SINT32:
384b682cb18SJim Jagielski case FFI_TYPE_SINT64:
385b682cb18SJim Jagielski case FFI_TYPE_UINT8:
386b682cb18SJim Jagielski case FFI_TYPE_UINT16:
387b682cb18SJim Jagielski case FFI_TYPE_UINT32:
388b682cb18SJim Jagielski case FFI_TYPE_UINT64:
389b682cb18SJim Jagielski case FFI_TYPE_POINTER:
390b682cb18SJim Jagielski if (gprcount < MAX_GPR_REGS)
391b682cb18SJim Jagielski {
392b682cb18SJim Jagielski stack->gpr[gprcount] = 0;
393b682cb18SJim Jagielski stack->gpr[gprcount++] = *(long long *)(*p_argv);
394b682cb18SJim Jagielski in_register = 1;
395b682cb18SJim Jagielski }
396b682cb18SJim Jagielski break;
397b682cb18SJim Jagielski
398b682cb18SJim Jagielski case FFI_TYPE_FLOAT:
399b682cb18SJim Jagielski if (ssecount < MAX_SSE_REGS)
400b682cb18SJim Jagielski {
401b682cb18SJim Jagielski float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
402b682cb18SJim Jagielski in_register = 1;
403b682cb18SJim Jagielski }
404b682cb18SJim Jagielski break;
405b682cb18SJim Jagielski
406b682cb18SJim Jagielski case FFI_TYPE_DOUBLE:
407b682cb18SJim Jagielski if (ssecount < MAX_SSE_REGS)
408b682cb18SJim Jagielski {
409b682cb18SJim Jagielski double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
410b682cb18SJim Jagielski in_register = 1;
411b682cb18SJim Jagielski }
412b682cb18SJim Jagielski break;
413b682cb18SJim Jagielski }
414b682cb18SJim Jagielski
415b682cb18SJim Jagielski if (in_register)
416b682cb18SJim Jagielski continue;
417b682cb18SJim Jagielski
418b682cb18SJim Jagielski /* Either all places in registers where filled, or this is a
419b682cb18SJim Jagielski type that potentially goes into a memory slot. */
420b682cb18SJim Jagielski if (examine_argument (*p_arg, 0, &g, &s) == 0
421b682cb18SJim Jagielski || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
422b682cb18SJim Jagielski {
423b682cb18SJim Jagielski /* Pass this argument in memory. */
424b682cb18SJim Jagielski argp = (void *)ALIGN(argp, (*p_arg)->alignment);
425b682cb18SJim Jagielski memcpy (argp, *p_argv, (*p_arg)->size);
426b682cb18SJim Jagielski argp += (*p_arg)->size;
427b682cb18SJim Jagielski }
428b682cb18SJim Jagielski else
429b682cb18SJim Jagielski {
430b682cb18SJim Jagielski /* All easy cases are eliminated. Now fire the big guns. */
431b682cb18SJim Jagielski
432b682cb18SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
433b682cb18SJim Jagielski int j, num;
434b682cb18SJim Jagielski void *a;
435b682cb18SJim Jagielski
436b682cb18SJim Jagielski num = classify_argument (*p_arg, classes, 0);
437b682cb18SJim Jagielski for (j=0, a=*p_argv; j<num; j++, a+=8)
438b682cb18SJim Jagielski {
439b682cb18SJim Jagielski switch (classes[j])
440b682cb18SJim Jagielski {
441b682cb18SJim Jagielski case X86_64_INTEGER_CLASS:
442b682cb18SJim Jagielski case X86_64_INTEGERSI_CLASS:
443b682cb18SJim Jagielski stack->gpr[gprcount++] = *(long long *)a;
444b682cb18SJim Jagielski break;
445b682cb18SJim Jagielski case X86_64_SSE_CLASS:
446b682cb18SJim Jagielski floatfloat2sse (a, &stack->sse[ssecount++]);
447b682cb18SJim Jagielski break;
448b682cb18SJim Jagielski case X86_64_SSESF_CLASS:
449b682cb18SJim Jagielski float2sse (*(float *)a, &stack->sse[ssecount++]);
450b682cb18SJim Jagielski break;
451b682cb18SJim Jagielski case X86_64_SSEDF_CLASS:
452b682cb18SJim Jagielski double2sse (*(double *)a, &stack->sse[ssecount++]);
453b682cb18SJim Jagielski break;
454b682cb18SJim Jagielski default:
455b682cb18SJim Jagielski abort();
456b682cb18SJim Jagielski }
457b682cb18SJim Jagielski }
458b682cb18SJim Jagielski }
459b682cb18SJim Jagielski }
460b682cb18SJim Jagielski }
461b682cb18SJim Jagielski
462b682cb18SJim Jagielski /* Perform machine dependent cif processing. */
463b682cb18SJim Jagielski ffi_status
464b682cb18SJim Jagielski ffi_prep_cif_machdep (ffi_cif *cif)
465b682cb18SJim Jagielski {
466b682cb18SJim Jagielski int gprcount, ssecount, i, g, s;
467b682cb18SJim Jagielski
468b682cb18SJim Jagielski gprcount = ssecount = 0;
469b682cb18SJim Jagielski
470b682cb18SJim Jagielski /* Reset the byte count. We handle this size estimation here. */
471b682cb18SJim Jagielski cif->bytes = 0;
472b682cb18SJim Jagielski
473b682cb18SJim Jagielski /* If the return value should be passed in memory, pass the pointer
474b682cb18SJim Jagielski as the first argument. The actual memory isn't allocated here. */
475b682cb18SJim Jagielski if (cif->rtype->type != FFI_TYPE_VOID
476b682cb18SJim Jagielski && examine_argument (cif->rtype, 1, &g, &s) == 0)
477b682cb18SJim Jagielski gprcount = 1;
478b682cb18SJim Jagielski
479b682cb18SJim Jagielski /* Go over all arguments and determine the way they should be passed.
480b682cb18SJim Jagielski If it's in a register and there is space for it, let that be so. If
481b682cb18SJim Jagielski not, add it's size to the stack byte count. */
482b682cb18SJim Jagielski for (i=0; i<cif->nargs; i++)
483b682cb18SJim Jagielski {
484b682cb18SJim Jagielski if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0
485b682cb18SJim Jagielski || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
486b682cb18SJim Jagielski {
487b682cb18SJim Jagielski /* This is passed in memory. First align to the basic type. */
488b682cb18SJim Jagielski cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
489b682cb18SJim Jagielski
490b682cb18SJim Jagielski /* Stack arguments are *always* at least 8 byte aligned. */
491b682cb18SJim Jagielski cif->bytes = ALIGN(cif->bytes, 8);
492b682cb18SJim Jagielski
493b682cb18SJim Jagielski /* Now add the size of this argument. */
494b682cb18SJim Jagielski cif->bytes += cif->arg_types[i]->size;
495b682cb18SJim Jagielski }
496b682cb18SJim Jagielski else
497b682cb18SJim Jagielski {
498b682cb18SJim Jagielski gprcount += g;
499b682cb18SJim Jagielski ssecount += s;
500b682cb18SJim Jagielski }
501b682cb18SJim Jagielski }
502b682cb18SJim Jagielski
503b682cb18SJim Jagielski /* Set the flag for the closures return. */
504b682cb18SJim Jagielski switch (cif->rtype->type)
505b682cb18SJim Jagielski {
506b682cb18SJim Jagielski case FFI_TYPE_VOID:
507b682cb18SJim Jagielski case FFI_TYPE_STRUCT:
508b682cb18SJim Jagielski case FFI_TYPE_SINT64:
509b682cb18SJim Jagielski case FFI_TYPE_FLOAT:
510b682cb18SJim Jagielski case FFI_TYPE_DOUBLE:
511b682cb18SJim Jagielski case FFI_TYPE_LONGDOUBLE:
512b682cb18SJim Jagielski cif->flags = (unsigned) cif->rtype->type;
513b682cb18SJim Jagielski break;
514b682cb18SJim Jagielski
515b682cb18SJim Jagielski case FFI_TYPE_UINT64:
516b682cb18SJim Jagielski cif->flags = FFI_TYPE_SINT64;
517b682cb18SJim Jagielski break;
518b682cb18SJim Jagielski
519b682cb18SJim Jagielski default:
520b682cb18SJim Jagielski cif->flags = FFI_TYPE_INT;
521b682cb18SJim Jagielski break;
522b682cb18SJim Jagielski }
523b682cb18SJim Jagielski
524b682cb18SJim Jagielski return FFI_OK;
525b682cb18SJim Jagielski }
526b682cb18SJim Jagielski
527b682cb18SJim Jagielski typedef struct
528b682cb18SJim Jagielski {
529b682cb18SJim Jagielski long gpr[2];
530b682cb18SJim Jagielski __int128_t sse[2];
531b682cb18SJim Jagielski long double st0;
532b682cb18SJim Jagielski } return_value;
533b682cb18SJim Jagielski
534b682cb18SJim Jagielski //#endif
535b682cb18SJim Jagielski
536b682cb18SJim Jagielski void
537b682cb18SJim Jagielski ffi_fill_return_value (return_value *rv, extended_cif *ecif)
538b682cb18SJim Jagielski {
539b682cb18SJim Jagielski enum x86_64_reg_class classes[MAX_CLASSES];
540b682cb18SJim Jagielski int i = 0, num;
541b682cb18SJim Jagielski long *gpr = rv->gpr;
542b682cb18SJim Jagielski __int128_t *sse = rv->sse;
543b682cb18SJim Jagielski signed char sc;
544b682cb18SJim Jagielski signed short ss;
545b682cb18SJim Jagielski
546b682cb18SJim Jagielski /* This is needed because of the way x86-64 handles signed short
547b682cb18SJim Jagielski integers. */
548b682cb18SJim Jagielski switch (ecif->cif->rtype->type)
549b682cb18SJim Jagielski {
550b682cb18SJim Jagielski case FFI_TYPE_SINT8:
551b682cb18SJim Jagielski sc = *(signed char *)gpr;
552b682cb18SJim Jagielski *(long long *)ecif->rvalue = (long long)sc;
553b682cb18SJim Jagielski return;
554b682cb18SJim Jagielski case FFI_TYPE_SINT16:
555b682cb18SJim Jagielski ss = *(signed short *)gpr;
556b682cb18SJim Jagielski *(long long *)ecif->rvalue = (long long)ss;
557b682cb18SJim Jagielski return;
558b682cb18SJim Jagielski default:
559b682cb18SJim Jagielski /* Just continue. */
560b682cb18SJim Jagielski ;
561b682cb18SJim Jagielski }
562b682cb18SJim Jagielski
563b682cb18SJim Jagielski num = classify_argument (ecif->cif->rtype, classes, 0);
564b682cb18SJim Jagielski
565b682cb18SJim Jagielski if (num == 0)
566b682cb18SJim Jagielski /* Return in memory. */
567b682cb18SJim Jagielski ecif->rvalue = (void *) rv->gpr[0];
568b682cb18SJim Jagielski else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
569b682cb18SJim Jagielski classes[1] == X86_64_X87UP_CLASS)
570b682cb18SJim Jagielski /* This is a long double (this is easiest to handle this way instead
571b682cb18SJim Jagielski of an eightbyte at a time as in the loop below. */
572b682cb18SJim Jagielski *((long double *)ecif->rvalue) = rv->st0;
573b682cb18SJim Jagielski else
574b682cb18SJim Jagielski {
575b682cb18SJim Jagielski void *a;
576b682cb18SJim Jagielski
577b682cb18SJim Jagielski for (i=0, a=ecif->rvalue; i<num; i++, a+=8)
578b682cb18SJim Jagielski {
579b682cb18SJim Jagielski switch (classes[i])
580b682cb18SJim Jagielski {
581b682cb18SJim Jagielski case X86_64_INTEGER_CLASS:
582b682cb18SJim Jagielski case X86_64_INTEGERSI_CLASS:
583b682cb18SJim Jagielski *(long long *)a = *gpr;
584b682cb18SJim Jagielski gpr++;
585b682cb18SJim Jagielski break;
586b682cb18SJim Jagielski case X86_64_SSE_CLASS:
587b682cb18SJim Jagielski sse2floatfloat (sse++, a);
588b682cb18SJim Jagielski break;
589b682cb18SJim Jagielski case X86_64_SSESF_CLASS:
590b682cb18SJim Jagielski *(float *)a = sse2float (sse++);
591b682cb18SJim Jagielski break;
592b682cb18SJim Jagielski case X86_64_SSEDF_CLASS:
593b682cb18SJim Jagielski *(double *)a = sse2double (sse++);
594b682cb18SJim Jagielski break;
595b682cb18SJim Jagielski default:
596b682cb18SJim Jagielski abort();
597b682cb18SJim Jagielski }
598b682cb18SJim Jagielski }
599b682cb18SJim Jagielski }
600b682cb18SJim Jagielski }
601b682cb18SJim Jagielski
602b682cb18SJim Jagielski //#if 0
603b682cb18SJim Jagielski
604b682cb18SJim Jagielski /*@-declundef@*/
605b682cb18SJim Jagielski /*@-exportheader@*/
606b682cb18SJim Jagielski extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
607b682cb18SJim Jagielski void (*) (return_value *, extended_cif *),
608b682cb18SJim Jagielski /*@out@*/ extended_cif *,
609b682cb18SJim Jagielski unsigned, /*@out@*/ unsigned *, void (*fn)());
610b682cb18SJim Jagielski /*@=declundef@*/
611b682cb18SJim Jagielski /*@=exportheader@*/
612b682cb18SJim Jagielski
613b682cb18SJim Jagielski void ffi_call(/*@dependent@*/ ffi_cif *cif,
614b682cb18SJim Jagielski void (*fn)(),
615b682cb18SJim Jagielski /*@out@*/ void *rvalue,
616b682cb18SJim Jagielski /*@dependent@*/ void **avalue)
617b682cb18SJim Jagielski {
618b682cb18SJim Jagielski extended_cif ecif;
619b682cb18SJim Jagielski int dummy;
620b682cb18SJim Jagielski
621b682cb18SJim Jagielski ecif.cif = cif;
622b682cb18SJim Jagielski ecif.avalue = avalue;
623b682cb18SJim Jagielski
624b682cb18SJim Jagielski /* If the return value is a struct and we don't have a return */
625b682cb18SJim Jagielski /* value address then we need to make one */
626b682cb18SJim Jagielski
627b682cb18SJim Jagielski if ((rvalue == NULL) &&
628b682cb18SJim Jagielski (examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
629b682cb18SJim Jagielski {
630b682cb18SJim Jagielski /*@-sysunrecog@*/
631b682cb18SJim Jagielski ecif.rvalue = alloca(cif->rtype->size);
632b682cb18SJim Jagielski /*@=sysunrecog@*/
633b682cb18SJim Jagielski }
634b682cb18SJim Jagielski else
635b682cb18SJim Jagielski ecif.rvalue = rvalue;
636b682cb18SJim Jagielski
637b682cb18SJim Jagielski /* Stack must always be 16byte aligned. Make it so. */
638b682cb18SJim Jagielski cif->bytes = ALIGN(cif->bytes, 16);
639b682cb18SJim Jagielski
640b682cb18SJim Jagielski switch (cif->abi)
641b682cb18SJim Jagielski {
642b682cb18SJim Jagielski case FFI_SYSV:
643b682cb18SJim Jagielski /* Calling 32bit code from 64bit is not possible */
644b682cb18SJim Jagielski FFI_ASSERT(0);
645b682cb18SJim Jagielski break;
646b682cb18SJim Jagielski
647b682cb18SJim Jagielski case FFI_UNIX64:
648b682cb18SJim Jagielski /*@-usedef@*/
649b682cb18SJim Jagielski ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
650b682cb18SJim Jagielski cif->bytes, ecif.rvalue, fn);
651b682cb18SJim Jagielski /*@=usedef@*/
652b682cb18SJim Jagielski break;
653b682cb18SJim Jagielski
654b682cb18SJim Jagielski default:
655b682cb18SJim Jagielski FFI_ASSERT(0);
656b682cb18SJim Jagielski break;
657b682cb18SJim Jagielski }
658b682cb18SJim Jagielski }
659b682cb18SJim Jagielski
660b682cb18SJim Jagielski extern void ffi_closure_UNIX64(void);
661b682cb18SJim Jagielski
662b682cb18SJim Jagielski ffi_status
663b682cb18SJim Jagielski ffi_prep_closure (ffi_closure* closure,
664b682cb18SJim Jagielski ffi_cif* cif,
665b682cb18SJim Jagielski void (*fun)(ffi_cif*, void*, void**, void*),
666b682cb18SJim Jagielski void *user_data)
667b682cb18SJim Jagielski {
668b682cb18SJim Jagielski volatile unsigned short *tramp;
669b682cb18SJim Jagielski
670b682cb18SJim Jagielski /* FFI_ASSERT (cif->abi == FFI_OSF); */
671b682cb18SJim Jagielski
672b682cb18SJim Jagielski tramp = (volatile unsigned short *) &closure->tramp[0];
673b682cb18SJim Jagielski tramp[0] = 0xbb49; /* mov <code>, %r11 */
674b682cb18SJim Jagielski tramp[5] = 0xba49; /* mov <data>, %r10 */
675b682cb18SJim Jagielski tramp[10] = 0xff49; /* jmp *%r11 */
676b682cb18SJim Jagielski tramp[11] = 0x00e3;
677b682cb18SJim Jagielski *(void * volatile *) &tramp[1] = ffi_closure_UNIX64;
678b682cb18SJim Jagielski *(void * volatile *) &tramp[6] = closure;
679b682cb18SJim Jagielski
680b682cb18SJim Jagielski closure->cif = cif;
681b682cb18SJim Jagielski closure->fun = fun;
682b682cb18SJim Jagielski closure->user_data = user_data;
683b682cb18SJim Jagielski
684b682cb18SJim Jagielski return FFI_OK;
685b682cb18SJim Jagielski }
686b682cb18SJim Jagielski
687b682cb18SJim Jagielski int
688b682cb18SJim Jagielski ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp)
689b682cb18SJim Jagielski {
690b682cb18SJim Jagielski ffi_cif *cif;
691b682cb18SJim Jagielski void **avalue;
692b682cb18SJim Jagielski ffi_type **arg_types;
693b682cb18SJim Jagielski long i, avn, argn;
694b682cb18SJim Jagielski
695b682cb18SJim Jagielski cif = closure->cif;
696b682cb18SJim Jagielski avalue = alloca(cif->nargs * sizeof(void *));
697b682cb18SJim Jagielski
698b682cb18SJim Jagielski argn = 0;
699b682cb18SJim Jagielski
700b682cb18SJim Jagielski i = 0;
701b682cb18SJim Jagielski avn = cif->nargs;
702b682cb18SJim Jagielski arg_types = cif->arg_types;
703b682cb18SJim Jagielski
704b682cb18SJim Jagielski /* Grab the addresses of the arguments from the stack frame. */
705b682cb18SJim Jagielski while (i < avn)
706b682cb18SJim Jagielski {
707b682cb18SJim Jagielski switch (arg_types[i]->type)
708b682cb18SJim Jagielski {
709b682cb18SJim Jagielski case FFI_TYPE_SINT8:
710b682cb18SJim Jagielski case FFI_TYPE_UINT8:
711b682cb18SJim Jagielski case FFI_TYPE_SINT16:
712b682cb18SJim Jagielski case FFI_TYPE_UINT16:
713b682cb18SJim Jagielski case FFI_TYPE_SINT32:
714b682cb18SJim Jagielski case FFI_TYPE_UINT32:
715b682cb18SJim Jagielski case FFI_TYPE_SINT64:
716b682cb18SJim Jagielski case FFI_TYPE_UINT64:
717b682cb18SJim Jagielski case FFI_TYPE_POINTER:
718b682cb18SJim Jagielski {
719b682cb18SJim Jagielski if (l->gp_offset > 48-8)
720b682cb18SJim Jagielski {
721b682cb18SJim Jagielski avalue[i] = l->overflow_arg_area;
722b682cb18SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
723b682cb18SJim Jagielski }
724b682cb18SJim Jagielski else
725b682cb18SJim Jagielski {
726b682cb18SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->gp_offset;
727b682cb18SJim Jagielski l->gp_offset += 8;
728b682cb18SJim Jagielski }
729b682cb18SJim Jagielski }
730b682cb18SJim Jagielski break;
731b682cb18SJim Jagielski
732b682cb18SJim Jagielski case FFI_TYPE_STRUCT:
733b682cb18SJim Jagielski /* FIXME */
734b682cb18SJim Jagielski FFI_ASSERT(0);
735b682cb18SJim Jagielski break;
736b682cb18SJim Jagielski
737b682cb18SJim Jagielski case FFI_TYPE_DOUBLE:
738b682cb18SJim Jagielski {
739b682cb18SJim Jagielski if (l->fp_offset > 176-16)
740b682cb18SJim Jagielski {
741b682cb18SJim Jagielski avalue[i] = l->overflow_arg_area;
742b682cb18SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
743b682cb18SJim Jagielski }
744b682cb18SJim Jagielski else
745b682cb18SJim Jagielski {
746b682cb18SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->fp_offset;
747b682cb18SJim Jagielski l->fp_offset += 16;
748b682cb18SJim Jagielski }
749b682cb18SJim Jagielski }
750b682cb18SJim Jagielski #if DEBUG_FFI
751b682cb18SJim Jagielski fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
752b682cb18SJim Jagielski #endif
753b682cb18SJim Jagielski break;
754b682cb18SJim Jagielski
755b682cb18SJim Jagielski case FFI_TYPE_FLOAT:
756b682cb18SJim Jagielski {
757b682cb18SJim Jagielski if (l->fp_offset > 176-16)
758b682cb18SJim Jagielski {
759b682cb18SJim Jagielski avalue[i] = l->overflow_arg_area;
760b682cb18SJim Jagielski l->overflow_arg_area = (char *)l->overflow_arg_area + 8;
761b682cb18SJim Jagielski }
762b682cb18SJim Jagielski else
763b682cb18SJim Jagielski {
764b682cb18SJim Jagielski avalue[i] = (char *)l->reg_save_area + l->fp_offset;
765b682cb18SJim Jagielski l->fp_offset += 16;
766b682cb18SJim Jagielski }
767b682cb18SJim Jagielski }
768b682cb18SJim Jagielski #if DEBUG_FFI
769b682cb18SJim Jagielski fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);
770b682cb18SJim Jagielski #endif
771b682cb18SJim Jagielski break;
772b682cb18SJim Jagielski
773b682cb18SJim Jagielski default:
774b682cb18SJim Jagielski FFI_ASSERT(0);
775b682cb18SJim Jagielski }
776b682cb18SJim Jagielski
777b682cb18SJim Jagielski argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG;
778b682cb18SJim Jagielski i++;
779b682cb18SJim Jagielski }
780b682cb18SJim Jagielski
781b682cb18SJim Jagielski /* Invoke the closure. */
782b682cb18SJim Jagielski (closure->fun) (cif, rp, avalue, closure->user_data);
783b682cb18SJim Jagielski
784b682cb18SJim Jagielski /* FIXME: Structs not supported. */
785b682cb18SJim Jagielski FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT);
786b682cb18SJim Jagielski
787b682cb18SJim Jagielski /* Tell ffi_closure_UNIX64 how to perform return type promotions. */
788b682cb18SJim Jagielski
789b682cb18SJim Jagielski return cif->rtype->type;
790b682cb18SJim Jagielski }
791b682cb18SJim Jagielski
792b682cb18SJim Jagielski #endif
793