bump product version to 6.3.0.0.beta1
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_linux_x86-64 / abi.cxx
blob3da3adac5fc3973f72798930745755148ba2d1dc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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)
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:
28 /* -----------------------------------------------------------------------
29 ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de>
31 x86-64 Foreign Function Interface
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:
41 The above copyright notice and this permission notice shall be included
42 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
53 #include <sal/config.h>
55 #include "abi.hxx"
57 #include <sal/log.hxx>
59 using namespace x86_64;
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.
66 Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
67 whenever possible (upper half does contain padding).
69 enum x86_64_reg_class
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
83 #define MAX_CLASSES 4
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. */
89 /* Return the union class of CLASS1 and CLASS2.
90 See the x86-64 PS ABI for details. */
92 static enum x86_64_reg_class
93 merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
94 throw ()
96 /* Rule #1: If both classes are equal, this is the resulting class. */
97 if (class1 == class2)
98 return class1;
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;
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;
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;
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;
124 /* Rule #6: Otherwise class SSE is used. */
125 return X86_64_SSE_CLASS;
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.
134 See the x86-64 PS ABI for details.
136 static int
137 classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) throw ()
139 switch ( pTypeRef->eTypeClass )
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:
182 typelib_TypeDescription * pTypeDescr = nullptr;
183 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
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];
189 /* If the struct is larger than 16 bytes, pass it on the stack. */
190 if ( pTypeDescr->nSize > 16 )
192 TYPELIB_DANGER_RELEASE( pTypeDescr );
193 return 0;
196 for ( int i = 0; i < words; i++ )
197 classes[i] = X86_64_NO_CLASS;
199 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
201 /* Merge the fields of structure. */
202 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
204 typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
205 int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
207 int num = classify_argument( pTypeInStruct, subclasses, offset );
209 if ( num == 0 )
211 TYPELIB_DANGER_RELEASE( pTypeDescr );
212 return 0;
215 for ( int i = 0; i < num; i++ )
217 int pos = offset / 8;
218 classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
222 TYPELIB_DANGER_RELEASE( pTypeDescr );
224 /* Final merger cleanup. */
225 for ( int i = 0; i < words; i++ )
227 /* If one class is MEMORY, everything should be passed in
228 memory. */
229 if ( classes[i] == X86_64_MEMORY_CLASS )
230 return 0;
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;
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;
243 return words;
246 default:
247 SAL_WARN("bridges", "Unhandled case: pType->eTypeClass == "
248 << pTypeRef->eTypeClass);
249 assert(false);
251 return 0; /* Never reached. */
254 /* Examine the argument and return set number of register required in each
255 class. Return 0 iff parameter should be passed in memory. */
256 bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedSSE ) throw ()
258 enum x86_64_reg_class classes[MAX_CLASSES];
259 int n;
261 n = classify_argument( pTypeRef, classes, 0 );
263 if ( n == 0 )
264 return false;
266 nUsedGPR = 0;
267 nUsedSSE = 0;
268 for ( n--; n >= 0; n-- )
269 switch ( classes[n] )
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);
292 return true;
295 bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) throw ()
297 int g, s;
299 return !examine_argument( pTypeRef, true, g, s );
302 void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) throw ()
304 enum x86_64_reg_class classes[MAX_CLASSES];
305 int n;
307 n = classify_argument( pTypeRef, classes, 0 );
309 sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
310 for ( n--; n >= 0; n-- )
311 switch ( classes[n] )
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;
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */