Line data Source code
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 : using namespace x86_64;
58 :
59 : /* Register class used for passing given 64bit part of the argument.
60 : These represent classes as documented by the PS ABI, with the exception
61 : of SSESF, SSEDF classes, that are basically SSE class, just gcc will
62 : use SF or DFmode move instead of DImode to avoid reformating penalties.
63 :
64 : Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
65 : whenever possible (upper half does contain padding).
66 : */
67 : enum x86_64_reg_class
68 : {
69 : X86_64_NO_CLASS,
70 : X86_64_INTEGER_CLASS,
71 : X86_64_INTEGERSI_CLASS,
72 : X86_64_SSE_CLASS,
73 : X86_64_SSESF_CLASS,
74 : X86_64_SSEDF_CLASS,
75 : X86_64_SSEUP_CLASS,
76 : X86_64_X87_CLASS,
77 : X86_64_X87UP_CLASS,
78 : X86_64_MEMORY_CLASS
79 : };
80 :
81 : #define MAX_CLASSES 4
82 :
83 : /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
84 : of this code is to classify each 8bytes of incoming argument by the register
85 : class and assign registers accordingly. */
86 :
87 : /* Return the union class of CLASS1 and CLASS2.
88 : See the x86-64 PS ABI for details. */
89 :
90 : static enum x86_64_reg_class
91 6056 : merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
92 : throw ()
93 : {
94 : /* Rule #1: If both classes are equal, this is the resulting class. */
95 6056 : if (class1 == class2)
96 276 : return class1;
97 :
98 : /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
99 : the other class. */
100 5780 : if (class1 == X86_64_NO_CLASS)
101 0 : return class2;
102 5780 : if (class2 == X86_64_NO_CLASS)
103 3520 : return class1;
104 :
105 : /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
106 2260 : if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
107 0 : return X86_64_MEMORY_CLASS;
108 :
109 : /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
110 2260 : if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
111 2260 : || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
112 0 : return X86_64_INTEGERSI_CLASS;
113 2260 : if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
114 36 : || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
115 2224 : return X86_64_INTEGER_CLASS;
116 :
117 : /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */
118 36 : if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
119 36 : || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
120 0 : return X86_64_MEMORY_CLASS;
121 :
122 : /* Rule #6: Otherwise class SSE is used. */
123 36 : return X86_64_SSE_CLASS;
124 : }
125 :
126 : /* Classify the argument of type TYPE and mode MODE.
127 : CLASSES will be filled by the register class used to pass each word
128 : of the operand. The number of words is returned. In case the parameter
129 : should be passed in memory, 0 is returned. As a special case for zero
130 : sized containers, classes[0] will be NO_CLASS and 1 is returned.
131 :
132 : See the x86-64 PS ABI for details.
133 : */
134 : static int
135 568840 : classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) throw ()
136 : {
137 568840 : switch ( pTypeRef->eTypeClass )
138 : {
139 : case typelib_TypeClass_VOID:
140 123937 : classes[0] = X86_64_NO_CLASS;
141 123937 : return 1;
142 : case typelib_TypeClass_CHAR:
143 : case typelib_TypeClass_BOOLEAN:
144 : case typelib_TypeClass_BYTE:
145 : case typelib_TypeClass_SHORT:
146 : case typelib_TypeClass_UNSIGNED_SHORT:
147 : case typelib_TypeClass_LONG:
148 : case typelib_TypeClass_UNSIGNED_LONG:
149 : case typelib_TypeClass_HYPER:
150 : case typelib_TypeClass_UNSIGNED_HYPER:
151 : case typelib_TypeClass_ENUM:
152 109428 : if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
153 106980 : classes[0] = X86_64_INTEGERSI_CLASS;
154 : else
155 2448 : classes[0] = X86_64_INTEGER_CLASS;
156 109428 : return 1;
157 : case typelib_TypeClass_FLOAT:
158 108 : if ( ( byteOffset % 8 ) == 0 )
159 72 : classes[0] = X86_64_SSESF_CLASS;
160 : else
161 36 : classes[0] = X86_64_SSE_CLASS;
162 108 : return 1;
163 : case typelib_TypeClass_DOUBLE:
164 626 : classes[0] = X86_64_SSEDF_CLASS;
165 626 : return 1;
166 : /*case LONGDOUBLE:
167 : classes[0] = X86_64_X87_CLASS;
168 : classes[1] = X86_64_X87UP_CLASS;
169 : return 2;*/
170 : case typelib_TypeClass_STRING:
171 : case typelib_TypeClass_TYPE:
172 : case typelib_TypeClass_ANY:
173 : case typelib_TypeClass_TYPEDEF:
174 : case typelib_TypeClass_SEQUENCE:
175 : case typelib_TypeClass_INTERFACE:
176 319870 : return 0;
177 : case typelib_TypeClass_STRUCT:
178 : case typelib_TypeClass_EXCEPTION:
179 : {
180 14871 : typelib_TypeDescription * pTypeDescr = 0;
181 14871 : TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
182 :
183 14871 : const int UNITS_PER_WORD = 8;
184 14871 : int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
185 : enum x86_64_reg_class subclasses[MAX_CLASSES];
186 :
187 : /* If the struct is larger than 16 bytes, pass it on the stack. */
188 14871 : if ( pTypeDescr->nSize > 16 )
189 : {
190 10325 : TYPELIB_DANGER_RELEASE( pTypeDescr );
191 10325 : return 0;
192 : }
193 :
194 11592 : for ( int i = 0; i < words; i++ )
195 7046 : classes[i] = X86_64_NO_CLASS;
196 :
197 4546 : const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
198 :
199 : /* Merge the fields of structure. */
200 10602 : for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
201 : {
202 7828 : typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
203 7828 : int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
204 :
205 7828 : int num = classify_argument( pTypeInStruct, subclasses, offset );
206 :
207 7828 : if ( num == 0 )
208 : {
209 1772 : TYPELIB_DANGER_RELEASE( pTypeDescr );
210 1772 : return 0;
211 : }
212 :
213 12112 : for ( int i = 0; i < num; i++ )
214 : {
215 6056 : int pos = offset / 8;
216 6056 : classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
217 : }
218 : }
219 :
220 2774 : TYPELIB_DANGER_RELEASE( pTypeDescr );
221 :
222 : /* Final merger cleanup. */
223 7212 : for ( int i = 0; i < words; i++ )
224 : {
225 : /* If one class is MEMORY, everything should be passed in
226 : memory. */
227 4438 : if ( classes[i] == X86_64_MEMORY_CLASS )
228 0 : return 0;
229 :
230 : /* The X86_64_SSEUP_CLASS should be always preceded by
231 : X86_64_SSE_CLASS. */
232 4438 : if ( classes[i] == X86_64_SSEUP_CLASS
233 0 : && ( i == 0 || classes[i - 1] != X86_64_SSE_CLASS ) )
234 0 : classes[i] = X86_64_SSE_CLASS;
235 :
236 : /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */
237 4438 : if ( classes[i] == X86_64_X87UP_CLASS
238 0 : && ( i == 0 || classes[i - 1] != X86_64_X87_CLASS ) )
239 0 : classes[i] = X86_64_SSE_CLASS;
240 : }
241 2774 : return words;
242 : }
243 :
244 : default:
245 : #if OSL_DEBUG_LEVEL > 1
246 : OSL_TRACE( "Unhandled case: pType->eTypeClass == %d", pTypeRef->eTypeClass );
247 : #endif
248 : OSL_ASSERT(false);
249 : }
250 0 : return 0; /* Never reached. */
251 : }
252 :
253 : /* Examine the argument and return set number of register required in each
254 : class. Return 0 iff parameter should be passed in memory. */
255 560146 : bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw ()
256 : {
257 : enum x86_64_reg_class classes[MAX_CLASSES];
258 : int n;
259 :
260 560146 : n = classify_argument( pTypeRef, classes, 0 );
261 :
262 560146 : if ( n == 0 )
263 330195 : return false;
264 :
265 229951 : nUsedGPR = 0;
266 229951 : nUsedSSE = 0;
267 461216 : for ( n--; n >= 0; n-- )
268 231265 : switch ( classes[n] )
269 : {
270 : case X86_64_INTEGER_CLASS:
271 : case X86_64_INTEGERSI_CLASS:
272 105730 : nUsedGPR++;
273 105730 : break;
274 : case X86_64_SSE_CLASS:
275 : case X86_64_SSESF_CLASS:
276 : case X86_64_SSEDF_CLASS:
277 668 : nUsedSSE++;
278 668 : break;
279 : case X86_64_NO_CLASS:
280 : case X86_64_SSEUP_CLASS:
281 124867 : break;
282 : case X86_64_X87_CLASS:
283 : case X86_64_X87UP_CLASS:
284 0 : if ( !bInReturn )
285 0 : return false;
286 0 : break;
287 : default:
288 : #if OSL_DEBUG_LEVEL > 1
289 : OSL_TRACE( "Unhandled case: classes[n] == %d", classes[n] );
290 : #endif
291 : OSL_ASSERT(false);
292 : }
293 229951 : return true;
294 : }
295 :
296 498089 : bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw ()
297 : {
298 : int g, s;
299 :
300 498089 : return !examine_argument( pTypeRef, true, g, s );
301 : }
302 :
303 866 : void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw ()
304 : {
305 : enum x86_64_reg_class classes[MAX_CLASSES];
306 : int n;
307 :
308 866 : n = classify_argument( pTypeRef, classes, 0 );
309 :
310 866 : sal_uInt64 *pStructAlign = reinterpret_cast<sal_uInt64 *>( pStruct );
311 2082 : for ( n--; n >= 0; n-- )
312 1216 : switch ( classes[n] )
313 : {
314 : case X86_64_INTEGER_CLASS:
315 : case X86_64_INTEGERSI_CLASS:
316 1198 : *pStructAlign++ = *pGPR++;
317 1198 : break;
318 : case X86_64_SSE_CLASS:
319 : case X86_64_SSESF_CLASS:
320 : case X86_64_SSEDF_CLASS:
321 18 : *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
322 18 : break;
323 : default:
324 0 : break;
325 : }
326 866 : }
327 :
328 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|