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 
60 using namespace x86_64;
61 
62 namespace {
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  */
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 
93 static enum x86_64_reg_class
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 */
131 static int
132 classify_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. */
224 bool 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 
252 bool 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 
262 x86_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  {
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  {
278  }
280 }
281 
282 void 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: */
void fill_struct(typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pSSE, void *pStruct) noexcept
sal_Int64 n
static int classify_argument(typelib_TypeDescriptionReference *pTypeRef, enum x86_64_reg_class classes[], int byteOffset) noexcept
size_t pos
ReturnKind getReturnKind(typelib_TypeDescriptionReference *type) noexcept
int i
#define O3TL_UNREACHABLE
static enum x86_64_reg_class merge_classes(enum x86_64_reg_class class1, enum x86_64_reg_class class2) noexcept
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
bool examine_argument(typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedSSE) noexcept
ResultType type
bool return_in_hidden_param(typelib_TypeDescriptionReference *pTypeRef) noexcept
Does function that returns this type use a hidden parameter, or registers?
#define MAX_CLASSES