LibreOffice Module bridges (master) 1
gcc3_linux_x86-64/abi.cxx
Go to the documentation of this file.
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 <o3tl/unreachable.hxx>
58#include <sal/log.hxx>
59
60using namespace x86_64;
61
62namespace {
63
64/* Register class used for passing given 64bit part of the argument.
65 These represent classes as documented by the PS ABI, with the exception
66 of SSESF, SSEDF classes, that are basically SSE class, just gcc will
67 use SF or DFmode move instead of DImode to avoid reformatting penalties.
68
69 Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
70 whenever possible (upper half does contain padding).
71 */
72enum x86_64_reg_class
73{
74 X86_64_NO_CLASS,
75 X86_64_INTEGER_CLASS,
76 X86_64_INTEGERSI_CLASS,
77 X86_64_SSE_CLASS,
78 X86_64_SSESF_CLASS,
79 X86_64_MEMORY_CLASS
80};
81
82}
83
84#define MAX_CLASSES 4
85
86/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
87 of this code is to classify each 8bytes of incoming argument by the register
88 class and assign registers accordingly. */
89
90/* Return the union class of CLASS1 and CLASS2.
91 See the x86-64 PS ABI for details. */
92
93static enum x86_64_reg_class
94merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
95 noexcept
96{
97 /* Rule #1: If both classes are equal, this is the resulting class. */
98 if (class1 == class2)
99 return class1;
100
101 /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
102 the other class. */
103 if (class1 == X86_64_NO_CLASS)
104 return class2;
105 if (class2 == X86_64_NO_CLASS)
106 return class1;
107
108 /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
109 if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
110 return X86_64_MEMORY_CLASS;
111
112 /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
113 if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
114 || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
115 return X86_64_INTEGERSI_CLASS;
116 if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
117 || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
118 return X86_64_INTEGER_CLASS;
119
120 /* Rule #6: Otherwise class SSE is used. */
121 return X86_64_SSE_CLASS;
122}
123
124/* Classify a parameter/return type.
125 CLASSES will be filled by the register class used to pass each word
126 of the operand. The number of words is returned. In case the operand
127 should be passed in memory, 0 is returned.
128
129 See the x86-64 PS ABI for details.
130*/
131static int
132classify_argument( typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset ) noexcept
133{
134 switch ( pTypeRef->eTypeClass )
135 {
136 case typelib_TypeClass_CHAR:
137 case typelib_TypeClass_BOOLEAN:
138 case typelib_TypeClass_BYTE:
139 case typelib_TypeClass_SHORT:
140 case typelib_TypeClass_UNSIGNED_SHORT:
141 case typelib_TypeClass_LONG:
142 case typelib_TypeClass_UNSIGNED_LONG:
143 case typelib_TypeClass_HYPER:
144 case typelib_TypeClass_UNSIGNED_HYPER:
145 case typelib_TypeClass_ENUM:
146 if ( ( byteOffset % 8 + pTypeRef->pType->nSize ) <= 4 )
147 classes[0] = X86_64_INTEGERSI_CLASS;
148 else
149 classes[0] = X86_64_INTEGER_CLASS;
150 return 1;
151 case typelib_TypeClass_FLOAT:
152 if ( ( byteOffset % 8 ) == 0 )
153 classes[0] = X86_64_SSESF_CLASS;
154 else
155 classes[0] = X86_64_SSE_CLASS;
156 return 1;
157 case typelib_TypeClass_DOUBLE:
158 classes[0] = X86_64_SSE_CLASS;
159 return 1;
160 case typelib_TypeClass_STRING:
161 case typelib_TypeClass_TYPE:
162 case typelib_TypeClass_ANY:
163 case typelib_TypeClass_SEQUENCE:
164 case typelib_TypeClass_INTERFACE:
165 return 0;
166 case typelib_TypeClass_STRUCT:
167 {
168 typelib_TypeDescription * pTypeDescr = nullptr;
169 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
170
171 const int UNITS_PER_WORD = 8;
172 int words = ( pTypeDescr->nSize + UNITS_PER_WORD - 1 ) / UNITS_PER_WORD;
173 enum x86_64_reg_class subclasses[MAX_CLASSES];
174
175 /* If the struct is larger than 16 bytes, pass it on the stack. */
176 if ( pTypeDescr->nSize > 16 )
177 {
178 TYPELIB_DANGER_RELEASE( pTypeDescr );
179 return 0;
180 }
181
182 for ( int i = 0; i < words; i++ )
183 classes[i] = X86_64_NO_CLASS;
184
185 const typelib_CompoundTypeDescription *pStruct = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
186
187 /* Merge the fields of structure. */
188 for ( sal_Int32 nMember = 0; nMember < pStruct->nMembers; ++nMember )
189 {
190 typelib_TypeDescriptionReference *pTypeInStruct = pStruct->ppTypeRefs[ nMember ];
191 int offset = byteOffset + pStruct->pMemberOffsets[ nMember ];
192
193 int num = classify_argument( pTypeInStruct, subclasses, offset );
194
195 if ( num == 0 )
196 {
197 TYPELIB_DANGER_RELEASE( pTypeDescr );
198 return 0;
199 }
200
201 for ( int i = 0; i < num; i++ )
202 {
203 int pos = offset / 8;
204 classes[i + pos] = merge_classes( subclasses[i], classes[i + pos] );
205 if (classes[i + pos] == X86_64_MEMORY_CLASS) {
206 TYPELIB_DANGER_RELEASE( pTypeDescr );
207 return 0;
208 }
209 }
210 }
211
212 TYPELIB_DANGER_RELEASE( pTypeDescr );
213
214 return words;
215 }
216
217 default:
219 }
220}
221
222/* Examine the argument and return set number of register required in each
223 class. Return 0 iff parameter should be passed in memory. */
224bool x86_64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE ) noexcept
225{
226 enum x86_64_reg_class classes[MAX_CLASSES];
227 // coverity[uninit_use_in_call : FALSE]
228 int n = classify_argument( pTypeRef, classes, 0 );
229
230 if ( n == 0 )
231 return false;
232
233 nUsedGPR = 0;
234 nUsedSSE = 0;
235 for ( n--; n >= 0; n-- )
236 switch ( classes[n] )
237 {
238 case X86_64_INTEGER_CLASS:
239 case X86_64_INTEGERSI_CLASS:
240 nUsedGPR++;
241 break;
242 case X86_64_SSE_CLASS:
243 case X86_64_SSESF_CLASS:
244 nUsedSSE++;
245 break;
246 default:
248 }
249 return true;
250}
251
252bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) noexcept
253{
254 if (pTypeRef->eTypeClass == typelib_TypeClass_VOID) {
255 return false;
256 }
257 enum x86_64_reg_class classes[MAX_CLASSES];
258 // coverity[uninit_use_in_call : FALSE]
259 return classify_argument(pTypeRef, classes, 0) == 0;
260}
261
262x86_64::ReturnKind x86_64::getReturnKind(typelib_TypeDescriptionReference * type) noexcept {
263 x86_64_reg_class classes[MAX_CLASSES];
264 // coverity[uninit_use_in_call : FALSE]
265 auto const n = classify_argument(type, classes, 0);
266 if (n == 0) {
267 return ReturnKind::Memory;
268 }
269 if (n == 2 && (classes[0] == X86_64_SSE_CLASS || classes[0] == X86_64_SSESF_CLASS)
270 && (classes[1] == X86_64_INTEGER_CLASS || classes[1] == X86_64_INTEGERSI_CLASS))
271 {
272 return ReturnKind::RegistersFpInt;
273 }
274 if (n == 2 && (classes[0] == X86_64_INTEGER_CLASS || classes[0] == X86_64_INTEGERSI_CLASS)
275 && (classes[1] == X86_64_SSE_CLASS || classes[1] == X86_64_SSESF_CLASS))
276 {
277 return ReturnKind::RegistersIntFp;
278 }
279 return ReturnKind::RegistersGeneral;
280}
281
282void x86_64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct ) noexcept
283{
284 enum x86_64_reg_class classes[MAX_CLASSES];
285 // coverity[uninit_use_in_call : FALSE]
286 int n = classify_argument( pTypeRef, classes, 0 );
287
288 sal_uInt64 *pStructAlign = static_cast<sal_uInt64 *>( pStruct );
289 for ( int i = 0; i != n; ++i )
290 switch ( classes[i] )
291 {
292 case X86_64_INTEGER_CLASS:
293 case X86_64_INTEGERSI_CLASS:
294 *pStructAlign++ = *pGPR++;
295 break;
296 case X86_64_SSE_CLASS:
297 case X86_64_SSESF_CLASS:
298 *pStructAlign++ = *reinterpret_cast<const sal_uInt64 *>( pSSE++ );
299 break;
300 default:
302 }
303}
304
305/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static int classify_argument(typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset) noexcept
static enum x86_64_reg_class merge_classes(enum x86_64_reg_class class1, enum x86_64_reg_class class2) noexcept
#define MAX_CLASSES
sal_Int64 n
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
int i
bool examine_argument(typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE) noexcept
bool return_in_hidden_param(typelib_TypeDescriptionReference *pTypeRef) noexcept
Does function that returns this type use a hidden parameter, or registers?
void fill_struct(typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct) noexcept
ReturnKind getReturnKind(typelib_TypeDescriptionReference *type) noexcept
ResultType type
#define O3TL_UNREACHABLE
size_t pos