xref: /AOO41X/main/bridges/source/cpp_uno/s5abi_macosx_x86-64/abi.cxx (revision 6d1ed1ddd0b0ea729254e1711365fd94a5ae4281)
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