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 <rtl/ustring.hxx> 50 51 using namespace aarch64; 52 53 namespace { 54 55 // The element type of a Homogeneous Floating-point Aggregate. 56 enum HfaKind 57 { 58 HFA_NONE, // not (yet) an HFA 59 HFA_FLOAT, // all members are FLOAT (4-byte) 60 HFA_DOUBLE // all members are DOUBLE (8-byte) 61 }; 62 63 // Combine the running HFA kind with a newly-seen member kind. Two members 64 // of different FP types, or any non-FP member, break the homogeneity. 65 HfaKind mergeHfa( HfaKind running, HfaKind seen ) 66 { 67 if ( seen == HFA_NONE ) 68 return HFA_NONE; 69 if ( running == HFA_NONE ) 70 return seen; 71 return ( running == seen ) ? running : HFA_NONE; 72 } 73 74 // Recursively determine whether pTypeRef is (part of) a homogeneous 75 // floating-point aggregate, accumulating the element kind and member count. 76 // 77 // Returns false the moment homogeneity is violated (a non-FP scalar, or a 78 // second distinct FP type, or > 4 elements). A FLOAT/DOUBLE scalar counts as 79 // a 1-element HFA of itself; a struct flattens its members (and base classes). 80 bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind &rKind, int &rCount ) 81 { 82 switch ( pTypeRef->eTypeClass ) 83 { 84 case typelib_TypeClass_FLOAT: 85 rKind = mergeHfa( rKind, HFA_FLOAT ); 86 if ( rKind == HFA_NONE ) return false; 87 return ( ++rCount <= 4 ); 88 89 case typelib_TypeClass_DOUBLE: 90 rKind = mergeHfa( rKind, HFA_DOUBLE ); 91 if ( rKind == HFA_NONE ) return false; 92 return ( ++rCount <= 4 ); 93 94 case typelib_TypeClass_STRUCT: 95 case typelib_TypeClass_EXCEPTION: 96 { 97 typelib_TypeDescription * pTypeDescr = 0; 98 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 99 100 const typelib_CompoundTypeDescription *pComp = 101 reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr ); 102 103 bool bOk = true; 104 105 // Flatten base class first (its members precede ours in layout). 106 if ( pComp->pBaseTypeDescription ) 107 { 108 bOk = collectHfa( 109 pComp->pBaseTypeDescription->aBase.pWeakRef, rKind, rCount ); 110 } 111 112 for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i ) 113 bOk = collectHfa( pComp->ppTypeRefs[i], rKind, rCount ); 114 115 TYPELIB_DANGER_RELEASE( pTypeDescr ); 116 return bOk; 117 } 118 119 default: 120 // Any non-FP, non-aggregate member breaks homogeneity. 121 rKind = HFA_NONE; 122 return false; 123 } 124 } 125 126 // Classify an aggregate (STRUCT/EXCEPTION). Sets the GPR/FPR counts and 127 // returns true if it is passed in registers, false if it must be passed 128 // indirectly (in memory). 129 bool classifyAggregate( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, int &nUsedFPR ) 130 { 131 // First, the HFA test. 132 HfaKind kind = HFA_NONE; 133 int count = 0; 134 if ( collectHfa( pTypeRef, kind, count ) && kind != HFA_NONE && count >= 1 && count <= 4 ) 135 { 136 nUsedGPR = 0; 137 nUsedFPR = count; // one v register per member 138 return true; 139 } 140 141 // Otherwise classify by size. 142 typelib_TypeDescription * pTypeDescr = 0; 143 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 144 sal_Int32 nSize = pTypeDescr->nSize; 145 TYPELIB_DANGER_RELEASE( pTypeDescr ); 146 147 if ( nSize > 16 ) 148 { 149 // Non-HFA aggregate > 16 bytes => passed indirectly. 150 return false; 151 } 152 153 // Non-HFA aggregate <= 16 bytes => 1 or 2 GPRs (8 bytes each). 154 nUsedGPR = ( nSize > 8 ) ? 2 : 1; 155 nUsedFPR = 0; 156 return true; 157 } 158 159 } // anonymous namespace 160 161 bool aarch64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool /*bInReturn*/, int &nUsedGPR, int &nUsedFPR ) 162 { 163 nUsedGPR = 0; 164 nUsedFPR = 0; 165 166 switch ( pTypeRef->eTypeClass ) 167 { 168 case typelib_TypeClass_VOID: 169 return true; 170 171 case typelib_TypeClass_CHAR: 172 case typelib_TypeClass_BOOLEAN: 173 case typelib_TypeClass_BYTE: 174 case typelib_TypeClass_SHORT: 175 case typelib_TypeClass_UNSIGNED_SHORT: 176 case typelib_TypeClass_LONG: 177 case typelib_TypeClass_UNSIGNED_LONG: 178 case typelib_TypeClass_HYPER: 179 case typelib_TypeClass_UNSIGNED_HYPER: 180 case typelib_TypeClass_ENUM: 181 nUsedGPR = 1; 182 return true; 183 184 case typelib_TypeClass_FLOAT: 185 case typelib_TypeClass_DOUBLE: 186 nUsedFPR = 1; 187 return true; 188 189 // These UNO types are always handled by the bridge as a pointer/ 190 // reference (one GPR), never passed by value through this classifier. 191 case typelib_TypeClass_STRING: 192 case typelib_TypeClass_TYPE: 193 case typelib_TypeClass_ANY: 194 case typelib_TypeClass_TYPEDEF: 195 case typelib_TypeClass_SEQUENCE: 196 case typelib_TypeClass_INTERFACE: 197 nUsedGPR = 1; 198 return true; 199 200 case typelib_TypeClass_STRUCT: 201 case typelib_TypeClass_EXCEPTION: 202 return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR ); 203 204 default: 205 #if OSL_DEBUG_LEVEL > 1 206 OSL_TRACE( "Unhandled case: pTypeRef->eTypeClass == %d\n", pTypeRef->eTypeClass ); 207 #endif 208 OSL_ASSERT( 0 ); 209 } 210 return false; 211 } 212 213 bool aarch64::return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) 214 { 215 int g, s; 216 // Returned in registers iff examine_argument() says it fits; otherwise the 217 // caller must pass an indirect-result buffer in x8. 218 return !examine_argument( pTypeRef, true, g, s ); 219 } 220 221 void aarch64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64 *pGPR, const double *pFPR, void *pStruct ) 222 { 223 int nUsedGPR = 0; 224 int nUsedFPR = 0; 225 if ( !examine_argument( pTypeRef, true, nUsedGPR, nUsedFPR ) ) 226 { 227 // Should not happen: indirect returns are written through x8 directly, 228 // not scattered here. 229 OSL_ASSERT( 0 ); 230 return; 231 } 232 233 if ( nUsedFPR > 0 ) 234 { 235 // HFA: each member occupies one v register; the members are contiguous 236 // in the struct. Copy element-by-element to honour FLOAT (4-byte) vs 237 // DOUBLE (8-byte) element width. 238 HfaKind kind = HFA_NONE; 239 int count = 0; 240 collectHfa( pTypeRef, kind, count ); 241 if ( kind == HFA_FLOAT ) 242 { 243 float *pDest = reinterpret_cast<float *>( pStruct ); 244 for ( int i = 0; i < nUsedFPR; ++i ) 245 pDest[i] = static_cast<float>( pFPR[i] ); 246 } 247 else // HFA_DOUBLE 248 { 249 double *pDest = reinterpret_cast<double *>( pStruct ); 250 for ( int i = 0; i < nUsedFPR; ++i ) 251 pDest[i] = pFPR[i]; 252 } 253 } 254 else 255 { 256 // Non-HFA aggregate <= 16 bytes: raw copy of the 1-2 GPRs. 257 sal_uInt64 *pDest = reinterpret_cast<sal_uInt64 *>( pStruct ); 258 for ( int i = 0; i < nUsedGPR; ++i ) 259 pDest[i] = pGPR[i]; 260 } 261 } 262