1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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).
73 X86_64_INTEGERSI_CLASS
,
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
)
96 /* Rule #1: If both classes are equal, this is the resulting class. */
100 /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
102 if (class1
== X86_64_NO_CLASS
)
104 if (class2
== X86_64_NO_CLASS
)
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.
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
;
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
;
157 classes
[0] = X86_64_INTEGER_CLASS
;
159 case typelib_TypeClass_FLOAT
:
160 if ( ( byteOffset
% 8 ) == 0 )
161 classes
[0] = X86_64_SSESF_CLASS
;
163 classes
[0] = X86_64_SSE_CLASS
;
165 case typelib_TypeClass_DOUBLE
:
166 classes
[0] = X86_64_SSEDF_CLASS
;
169 classes[0] = X86_64_X87_CLASS;
170 classes[1] = X86_64_X87UP_CLASS;
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
:
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
);
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
);
211 TYPELIB_DANGER_RELEASE( pTypeDescr
);
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
229 if ( classes
[i
] == X86_64_MEMORY_CLASS
)
232 /* The X86_64_SSEUP_CLASS should be always preceded by
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
;
247 SAL_WARN("bridges", "Unhandled case: pType->eTypeClass == "
248 << pTypeRef
->eTypeClass
);
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
];
261 n
= classify_argument( pTypeRef
, classes
, 0 );
268 for ( n
--; n
>= 0; n
-- )
269 switch ( classes
[n
] )
271 case X86_64_INTEGER_CLASS
:
272 case X86_64_INTEGERSI_CLASS
:
275 case X86_64_SSE_CLASS
:
276 case X86_64_SSESF_CLASS
:
277 case X86_64_SSEDF_CLASS
:
280 case X86_64_NO_CLASS
:
281 case X86_64_SSEUP_CLASS
:
283 case X86_64_X87_CLASS
:
284 case X86_64_X87UP_CLASS
:
289 SAL_WARN("bridges", "Unhandled case: classes[n] == " << classes
[n
]);
295 bool x86_64::return_in_hidden_param( typelib_TypeDescriptionReference
*pTypeRef
) throw ()
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
];
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
++;
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
++ );
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */