1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 // This is an implementation of the x86-64 ABI as described in 'System V
22 // Application Binary Interface, AMD64 Architecture Processor Supplement'
23 // (http://www.x86-64.org/documentation/abi-0.95.pdf)
24 //
25 // The code in this file is a modification of src/x86/ffi64.c from libffi
26 // (http://sources.redhat.com/libffi/) which is under the following license:
27 
28 /* -----------------------------------------------------------------------
29    ffi.c - Copyright (c) 2002  Bo Thorsen <bo@suse.de>
30 
31    x86-64 Foreign Function Interface
32 
33    Permission is hereby granted, free of charge, to any person obtaining
34    a copy of this software and associated documentation files (the
35    ``Software''), to deal in the Software without restriction, including
36    without limitation the rights to use, copy, modify, merge, publish,
37    distribute, sublicense, and/or sell copies of the Software, and to
38    permit persons to whom the Software is furnished to do so, subject to
39    the following conditions:
40 
41    The above copyright notice and this permission notice shall be included
42    in all copies or substantial portions of the Software.
43 
44    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
45    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
47    IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
48    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
49    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
50    OTHER DEALINGS IN THE SOFTWARE.
51    ----------------------------------------------------------------------- */
52 
53 #include <sal/config.h>
54 
55 #include "abi.hxx"
56 
57 #include <sal/log.hxx>
58 
59 using namespace x86_64;
60 
61 /* Register class used for passing given 64bit part of the argument.
62    These represent classes as documented by the PS ABI, with the exception
63    of SSESF, SSEDF classes, that are basically SSE class, just gcc will
64    use SF or DFmode move instead of DImode to avoid reformatting penalties.
65 
66    Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
67    whenever possible (upper half does contain padding).
68  */
69 enum x86_64_reg_class
70 {
71     X86_64_NO_CLASS,
72     X86_64_INTEGER_CLASS,
73     X86_64_INTEGERSI_CLASS,
74     X86_64_SSE_CLASS,
75     X86_64_SSESF_CLASS,
76     X86_64_SSEDF_CLASS,
77     X86_64_SSEUP_CLASS,
78     X86_64_X87_CLASS,
79     X86_64_X87UP_CLASS,
80     X86_64_MEMORY_CLASS
81 };
82 
83 #define MAX_CLASSES 4
84 
85 /* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
86    of this code is to classify each 8bytes of incoming argument by the register
87    class and assign registers accordingly.  */
88 
89 /* Return the union class of CLASS1 and CLASS2.
90    See the x86-64 PS ABI for details.  */
91 
92 static enum x86_64_reg_class
merge_classes(enum x86_64_reg_class class1,enum x86_64_reg_class class2)93 merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
94     throw ()
95 {
96     /* Rule #1: If both classes are equal, this is the resulting class.  */
97     if (class1 == class2)
98         return class1;
99 
100     /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
101        the other class.  */
102     if (class1 == X86_64_NO_CLASS)
103         return class2;
104     if (class2 == X86_64_NO_CLASS)
105         return class1;
106 
107     /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
108     if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
109         return X86_64_MEMORY_CLASS;
110 
111     /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
112     if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
113             || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
114         return X86_64_INTEGERSI_CLASS;
115     if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
116             || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
117         return X86_64_INTEGER_CLASS;
118 
119     /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
120     if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
121             || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
122         return X86_64_MEMORY_CLASS;
123 
124     /* Rule #6: Otherwise class SSE is used.  */
125     return X86_64_SSE_CLASS;
126 }
127 
128 /* Classify the argument of type TYPE and mode MODE.
129    CLASSES will be filled by the register class used to pass each word
130    of the operand.  The number of words is returned.  In case the parameter
131    should be passed in memory, 0 is returned. As a special case for zero
132    sized containers, classes[0] will be NO_CLASS and 1 is returned.
133 
134    See the x86-64 PS ABI for details.
135 */
136 static int
classify_argument(typelib_TypeDescriptionReference * pTypeRef,enum x86_64_reg_class classes[],int byteOffset)137 classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) throw ()
138 {
139     switch ( pTypeRef->eTypeClass )
140     {
141         case typelib_TypeClass_VOID:
142             classes[0] = X86_64_NO_CLASS;
143             return 1;
144         case typelib_TypeClass_CHAR:
145         case typelib_TypeClass_BOOLEAN:
146         case typelib_TypeClass_BYTE:
147         case typelib_TypeClass_SHORT:
148         case typelib_TypeClass_UNSIGNED_SHORT:
149         case typelib_TypeClass_LONG:
150         case typelib_TypeClass_UNSIGNED_LONG:
151         case typelib_TypeClass_HYPER:
152         case typelib_TypeClass_UNSIGNED_HYPER:
153         case typelib_TypeClass_ENUM:
154             if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
155                 classes[0] = X86_64_INTEGERSI_CLASS;
156             else
157                 classes[0] = X86_64_INTEGER_CLASS;
158             return 1;
159         case typelib_TypeClass_FLOAT:
160             if ( ( byteOffset % 8 ) == 0 )
161                 classes[0] = X86_64_SSESF_CLASS;
162             else
163                 classes[0] = X86_64_SSE_CLASS;
164             return 1;
165         case typelib_TypeClass_DOUBLE:
166             classes[0] = X86_64_SSEDF_CLASS;
167             return 1;
168         /*case LONGDOUBLE:
169             classes[0] = X86_64_X87_CLASS;
170             classes[1] = X86_64_X87UP_CLASS;
171             return 2;*/
172         case typelib_TypeClass_STRING:
173         case typelib_TypeClass_TYPE:
174         case typelib_TypeClass_ANY:
175         case typelib_TypeClass_TYPEDEF:
176         case typelib_TypeClass_SEQUENCE:
177         case typelib_TypeClass_INTERFACE:
178             return 0;
179         case typelib_TypeClass_STRUCT:
180         case typelib_TypeClass_EXCEPTION:
181             {
182                 typelib_TypeDescription * pTypeDescr = nullptr;
183                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
184 
185                 const int UNITS_PER_WORD = 8;
186                 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
187                 enum x86_64_reg_class subclasses[MAX_CLASSES];
188 
189                 /* If the struct is larger than 16 bytes, pass it on the stack.  */
190                 if ( pTypeDescr->nSize > 16 )
191                 {
192                     TYPELIB_DANGER_RELEASE( pTypeDescr );
193                     return 0;
194                 }
195 
196                 for ( int i = 0; i < words; i++ )
197                     classes[i] = X86_64_NO_CLASS;
198 
199                 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
200 
201                 /* Merge the fields of structure.  */
202                 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
203                 {
204                     typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
205                     int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
206 
207                     int num = classify_argument( pTypeInStruct, subclasses, offset );
208 
209                     if ( num == 0 )
210                     {
211                         TYPELIB_DANGER_RELEASE( pTypeDescr );
212                         return 0;
213                     }
214 
215                     for ( int i = 0; i < num; i++ )
216                     {
217                         int pos = offset / 8;
218                         classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
219                     }
220                 }
221 
222                 TYPELIB_DANGER_RELEASE( pTypeDescr );
223 
224                 /* Final merger cleanup.  */
225                 for ( int i = 0; i < words; i++ )
226                 {
227                     /* If one class is MEMORY, everything should be passed in
228                        memory.  */
229                     if ( classes[i] == X86_64_MEMORY_CLASS )
230                         return 0;
231 
232                     /* The X86_64_SSEUP_CLASS should be always preceded by
233                        X86_64_SSE_CLASS.  */
234                     if ( classes[i] == X86_64_SSEUP_CLASS
235                             && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
236                         classes[i] = X86_64_SSE_CLASS;
237 
238                     /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
239                     if ( classes[i] == X86_64_X87UP_CLASS
240                             && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
241                         classes[i] = X86_64_SSE_CLASS;
242                 }
243                 return words;
244             }
245 
246         default:
247             SAL_WARN("bridges", "Unhandled case: pType->eTypeClass == "
248                     << pTypeRef->eTypeClass);
249             assert(false);
250     }
251     return 0; /* Never reached.  */
252 }
253 
254 /* Examine the argument and return set number of register required in each
255    class.  Return 0 iff parameter should be passed in memory.  */
examine_argument(typelib_TypeDescriptionReference * pTypeRef,bool bInReturn,int & nUsedGPR,int & nUsedSSE)256 bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw ()
257 {
258     enum x86_64_reg_class classes[MAX_CLASSES];
259     int n;
260 
261     n = classify_argument( pTypeRef, classes, 0 );
262 
263     if ( n == 0 )
264         return false;
265 
266     nUsedGPR = 0;
267     nUsedSSE = 0;
268     for ( n--; n >= 0; n-- )
269         switch ( classes[n] )
270         {
271             case X86_64_INTEGER_CLASS:
272             case X86_64_INTEGERSI_CLASS:
273                 nUsedGPR++;
274                 break;
275             case X86_64_SSE_CLASS:
276             case X86_64_SSESF_CLASS:
277             case X86_64_SSEDF_CLASS:
278                 nUsedSSE++;
279                 break;
280             case X86_64_NO_CLASS:
281             case X86_64_SSEUP_CLASS:
282                 break;
283             case X86_64_X87_CLASS:
284             case X86_64_X87UP_CLASS:
285                 if ( !bInReturn )
286                     return false;
287                 break;
288             default:
289             SAL_WARN("bridges", "Unhandled case: classes[n] == " << classes[n]);
290             assert(false);
291         }
292     return true;
293 }
294 
return_in_hidden_param(typelib_TypeDescriptionReference * pTypeRef)295 bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw ()
296 {
297     int g, s;
298 
299     return !examine_argument( pTypeRef, true, g, s );
300 }
301 
fill_struct(typelib_TypeDescriptionReference * pTypeRef,const sal_uInt64 * pGPR,const double * pSSE,void * pStruct)302 void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw ()
303 {
304     enum x86_64_reg_class classes[MAX_CLASSES];
305     int n;
306 
307     n = classify_argument( pTypeRef, classes, 0 );
308 
309     sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
310     for ( n--; n >= 0; n-- )
311         switch ( classes[n] )
312         {
313             case X86_64_INTEGER_CLASS:
314             case X86_64_INTEGERSI_CLASS:
315                 *pStructAlign++ = *pGPR++;
316                 break;
317             case X86_64_SSE_CLASS:
318             case X86_64_SSESF_CLASS:
319             case X86_64_SSEDF_CLASS:
320                 *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
321                 break;
322             default:
323                 break;
324         }
325 }
326 
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
328