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