1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_bridges.hxx" 26 27 // This is an implementation of the parameter-classification rules of the 28 // AArch64 procedure call standard ("Procedure Call Standard for the Arm 64-bit 29 // Architecture", ARM IHI 0055), with the deviations documented in Apple's 30 // "Writing ARM64 Code for Apple Platforms". 31 // 32 // Unlike the System V AMD64 ABI (used by the x86-64 bridge), AAPCS64 does not 33 // split aggregates into per-eightbyte INTEGER/SSE classes. Instead: 34 // * scalars go in one GPR (x) or one FP/SIMD (v) register; 35 // * a Homogeneous Floating-point Aggregate (HFA: <= 4 members, all the same 36 // FP type, recursively) goes in consecutive v registers; 37 // * any other aggregate <= 16 bytes goes in 1-2 GPRs; 38 // * a non-HFA aggregate > 16 bytes is passed indirectly (a pointer to a 39 // caller-allocated copy). 40 // Register fill is "all or nothing": if an aggregate does not fit entirely in 41 // the remaining registers of its bank, it is passed wholly on the stack. 42 // 43 // This is a clean-room implementation from the public specifications; see 44 // ../../../../AAPCS64_BRIDGE_SPEC.md. libffi's aarch64 backend was consulted 45 // only as a behavioural reference; no code is copied. 46 47 #include "abi.hxx" 48 49 #include "bridges/cpp_uno/shared/types.hxx" 50 51 #include <rtl/ustring.hxx> 52 #include <string.h> 53 54 using namespace aarch64; 55 56 namespace { 57 58 // The element type of a Homogeneous Floating-point Aggregate. 59 enum HfaKind 60 { 61 HFA_NONE, // not (yet) an HFA 62 HFA_FLOAT, // all members are FLOAT (4-byte) 63 HFA_DOUBLE // all members are DOUBLE (8-byte) 64 }; 65 66 // Combine the running HFA kind with a newly-seen member kind. Two members 67 // of different FP types, or any non-FP member, break the homogeneity. 68 HfaKind mergeHfa( HfaKind running, HfaKind seen ) 69 { 70 if ( seen == HFA_NONE ) 71 return HFA_NONE; 72 if ( running == HFA_NONE ) 73 return seen; 74 return ( running == seen ) ? running : HFA_NONE; 75 } 76 77 bool isComplexAggregate( typelib_TypeDescriptionReference *pTypeRef ) 78 { 79 typelib_TypeDescription * pTypeDescr = 0; 80 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 81 const typelib_CompoundTypeDescription *pComp = 82 reinterpret_cast<const typelib_CompoundTypeDescription *>( pTypeDescr ); 83 bool complex = pComp->pBaseTypeDescription != 0 && 84 isComplexAggregate( pComp->pBaseTypeDescription->aBase.pWeakRef ); 85 for ( sal_Int32 i = 0; !complex && i < pComp->nMembers; ++i ) 86 { 87 typelib_TypeClass typeClass = pComp->ppTypeRefs[i]->eTypeClass; 88 if ( typeClass == typelib_TypeClass_STRUCT || 89 typeClass == typelib_TypeClass_EXCEPTION ) 90 complex = isComplexAggregate( pComp->ppTypeRefs[i] ); 91 else 92 complex = !bridges::cpp_uno::shared::isSimpleType( typeClass ); 93 } 94 TYPELIB_DANGER_RELEASE( pTypeDescr ); 95 return complex; 96 } 97 98 // Recursively determine whether pTypeRef is (part of) a homogeneous 99 // floating-point aggregate, accumulating the element kind and member count. 100 // 101 // Returns false the moment homogeneity is violated (a non-FP scalar, or a 102 // second distinct FP type, or > 4 elements). A FLOAT/DOUBLE scalar counts as 103 // a 1-element HFA of itself; a struct flattens its members (and base classes). 104 bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind &rKind, int &rCount ) 105 { 106 switch ( pTypeRef->eTypeClass ) 107 { 108 case typelib_TypeClass_FLOAT: 109 rKind = mergeHfa( rKind, HFA_FLOAT ); 110 if ( rKind == HFA_NONE ) return false; 111 return ( ++rCount <= 4 ); 112 113 case typelib_TypeClass_DOUBLE: 114 rKind = mergeHfa( rKind, HFA_DOUBLE ); 115 if ( rKind == HFA_NONE ) return false; 116 return ( ++rCount <= 4 ); 117 118 case typelib_TypeClass_STRUCT: 119 case typelib_TypeClass_EXCEPTION: 120 { 121 typelib_TypeDescription * pTypeDescr = 0; 122 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 123 124 const typelib_CompoundTypeDescription *pComp = 125 reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr ); 126 127 // rCount is cumulative over the whole recursion, so remember where 128 // this aggregate started in order to size-check it below. 129 const int nCountAtEntry = rCount; 130 bool bOk = true; 131 132 // Flatten base class first (its members precede ours in layout). 133 if ( pComp->pBaseTypeDescription ) 134 { 135 bOk = collectHfa( 136 pComp->pBaseTypeDescription->aBase.pWeakRef, rKind, rCount ); 137 } 138 139 for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i ) 140 bOk = collectHfa( pComp->ppTypeRefs[i], rKind, rCount ); 141 142 if ( bOk ) 143 { 144 // Reject anything the elements do not tile exactly: only the 145 // elements contributed by THIS aggregate count towards its size. 146 sal_Int32 elementSize = rKind == HFA_FLOAT ? 4 : 8; 147 bOk = pTypeDescr->nSize == 148 ( rCount - nCountAtEntry ) * elementSize; 149 for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i ) 150 bOk = pComp->pMemberOffsets[i] % elementSize == 0; 151 } 152 153 TYPELIB_DANGER_RELEASE( pTypeDescr ); 154 return bOk; 155 } 156 157 default: 158 // Any non-FP, non-aggregate member breaks homogeneity. 159 rKind = HFA_NONE; 160 return false; 161 } 162 } 163 164 // Classify an aggregate (STRUCT/EXCEPTION). Sets the GPR/FPR counts and 165 // returns true if it is passed in registers, false if it must be passed 166 // indirectly (in memory). 167 bool classifyAggregate( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedFPR ) 168 { 169 // First, the HFA test. 170 HfaKind kind = HFA_NONE; 171 int count = 0; 172 if ( collectHfa( pTypeRef, kind, count ) && kind != HFA_NONE && count >= 1 && count <= 4 ) 173 { 174 nUsedGPR = 0; 175 nUsedFPR = count; // one v register per member 176 return true; 177 } 178 179 // Otherwise classify by size. 180 typelib_TypeDescription * pTypeDescr = 0; 181 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 182 sal_Int32 nSize = pTypeDescr->nSize; 183 TYPELIB_DANGER_RELEASE( pTypeDescr ); 184 185 if ( nSize > 16 ) 186 { 187 // Non-HFA aggregate > 16 bytes => passed indirectly. 188 return false; 189 } 190 191 // Non-HFA aggregate <= 16 bytes => 1 or 2 GPRs (8 bytes each). 192 nUsedGPR = ( nSize > 8 ) ? 2 : 1; 193 nUsedFPR = 0; 194 return true; 195 } 196 197 } // anonymous namespace 198 199 bool aarch64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedFPR ) 200 { 201 nUsedGPR = 0; 202 nUsedFPR = 0; 203 204 switch ( pTypeRef->eTypeClass ) 205 { 206 case typelib_TypeClass_VOID: 207 return true; 208 209 case typelib_TypeClass_CHAR: 210 case typelib_TypeClass_BOOLEAN: 211 case typelib_TypeClass_BYTE: 212 case typelib_TypeClass_SHORT: 213 case typelib_TypeClass_UNSIGNED_SHORT: 214 case typelib_TypeClass_LONG: 215 case typelib_TypeClass_UNSIGNED_LONG: 216 case typelib_TypeClass_HYPER: 217 case typelib_TypeClass_UNSIGNED_HYPER: 218 case typelib_TypeClass_ENUM: 219 nUsedGPR = 1; 220 return true; 221 222 case typelib_TypeClass_FLOAT: 223 case typelib_TypeClass_DOUBLE: 224 nUsedFPR = 1; 225 return true; 226 227 // These UNO types are always handled by the bridge as a pointer/ 228 // reference (one GPR), never passed by value through this classifier. 229 case typelib_TypeClass_STRING: 230 case typelib_TypeClass_TYPE: 231 case typelib_TypeClass_ANY: 232 case typelib_TypeClass_TYPEDEF: 233 case typelib_TypeClass_SEQUENCE: 234 case typelib_TypeClass_INTERFACE: 235 nUsedGPR = 1; 236 return true; 237 238 case typelib_TypeClass_STRUCT: 239 case typelib_TypeClass_EXCEPTION: 240 if ( bInReturn ) 241 return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR ); 242 nUsedGPR = 1; // generated UNO C++ bindings pass aggregates by const reference 243 return true; 244 245 default: 246 #if OSL_DEBUG_LEVEL > 1 247 OSL_TRACE( "Unhandled case: pTypeRef->eTypeClass == %d\n", pTypeRef->eTypeClass ); 248 #endif 249 OSL_ASSERT( 0 ); 250 } 251 return false; 252 } 253 254 bool aarch64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) 255 { 256 switch ( pTypeRef->eTypeClass ) 257 { 258 case typelib_TypeClass_STRING: 259 case typelib_TypeClass_TYPE: 260 case typelib_TypeClass_ANY: 261 case typelib_TypeClass_TYPEDEF: 262 case typelib_TypeClass_UNION: 263 case typelib_TypeClass_ARRAY: 264 case typelib_TypeClass_SEQUENCE: 265 case typelib_TypeClass_INTERFACE: 266 // These are C++ wrapper objects, not pointer-sized scalar values. 267 // Apple's arm64 C++ ABI returns them through the buffer in x8. 268 return true; 269 default: 270 break; 271 } 272 273 if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || 274 pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) 275 { 276 if ( isComplexAggregate( pTypeRef ) ) 277 return true; 278 } 279 280 int g, s; 281 // Returned in registers iff examine_argument() says it fits; otherwise the 282 // caller must pass an indirect-result buffer in x8. 283 return !examine_argument( pTypeRef, true, g, s ); 284 } 285 286 sal_uInt32 aarch64::get_return_kind( typelib_TypeDescriptionReference *pTypeRef ) 287 { 288 if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || 289 pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) 290 { 291 HfaKind kind = HFA_NONE; 292 int count = 0; 293 if ( collectHfa( pTypeRef, kind, count ) && count >= 1 && count <= 4 ) 294 return kind == HFA_FLOAT ? RETURN_KIND_HFA_FLOAT : RETURN_KIND_HFA_DOUBLE; 295 } 296 return pTypeRef->eTypeClass; 297 } 298 299 void aarch64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pFPR, void *pStruct ) 300 { 301 int nUsedGPR = 0; 302 int nUsedFPR = 0; 303 if ( !examine_argument( pTypeRef, true, nUsedGPR, nUsedFPR ) ) 304 { 305 // Should not happen: indirect returns are written through x8 directly, 306 // not scattered here. 307 OSL_ASSERT( 0 ); 308 return; 309 } 310 311 if ( nUsedFPR > 0 ) 312 { 313 // HFA: each member occupies one v register; the members are contiguous 314 // in the struct. Copy element-by-element to honour FLOAT (4-byte) vs 315 // DOUBLE (8-byte) element width. 316 HfaKind kind = HFA_NONE; 317 int count = 0; 318 collectHfa( pTypeRef, kind, count ); 319 if ( kind == HFA_FLOAT ) 320 { 321 float *pDest = reinterpret_cast<float *>( pStruct ); 322 for ( int i = 0; i < nUsedFPR; ++i ) 323 pDest[i] = *reinterpret_cast<const float *>( pFPR + i ); 324 } 325 else // HFA_DOUBLE 326 { 327 double *pDest = reinterpret_cast<double *>( pStruct ); 328 for ( int i = 0; i < nUsedFPR; ++i ) 329 pDest[i] = pFPR[i]; 330 } 331 } 332 else 333 { 334 typelib_TypeDescription * pTypeDescr = 0; 335 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 336 // The registers contain up to 16 bytes, but the destination has the 337 // aggregate's exact size and need not be 64-bit aligned. 338 memcpy( pStruct, pGPR, pTypeDescr->nSize ); 339 TYPELIB_DANGER_RELEASE( pTypeDescr ); 340 } 341 } 342 343 sal_uInt32 aarch64::align_stack_offset( 344 sal_uInt32 offset, typelib_TypeDescriptionReference *pTypeRef ) 345 { 346 typelib_TypeDescription * pTypeDescr = 0; 347 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 348 sal_uInt32 alignment = pTypeDescr->nAlignment; 349 TYPELIB_DANGER_RELEASE( pTypeDescr ); 350 if ( alignment == 0 ) 351 alignment = 1; 352 return (offset + alignment - 1) & ~(alignment - 1); 353 } 354 355 sal_uInt32 aarch64::stack_size( typelib_TypeDescriptionReference *pTypeRef ) 356 { 357 typelib_TypeDescription * pTypeDescr = 0; 358 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 359 sal_uInt32 size = pTypeDescr->nSize; 360 TYPELIB_DANGER_RELEASE( pTypeDescr ); 361 return size; 362 } 363