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