Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT 2 : // This file is part of AsmJit project <https://asmjit.com> 3 : // 4 : // See asmjit.h or LICENSE.md for license and copyright information 5 : // SPDX-License-Identifier: Zlib 6 : 7 : #include "api-build_p.h" 8 : #include "archtraits.h" 9 : #include "func.h" 10 : #include "operand.h" 11 : #include "type.h" 12 : #include "funcargscontext_p.h" 13 : 14 : #if !defined(ASMJIT_NO_X86) 15 : #include "x86func_p.h" 16 : #endif 17 : 18 : #if !defined(ASMJIT_NO_AARCH64) 19 : #include "a64func_p.h" 20 : #endif 21 : 22 : ASMJIT_BEGIN_NAMESPACE 23 : 24 : // CallConv - Init & Reset 25 : // ======================= 26 : 27 37131 : ASMJIT_FAVOR_SIZE Error CallConv::init(CallConvId ccId, const Environment& environment) noexcept { 28 37131 : reset(); 29 : 30 : #if !defined(ASMJIT_NO_X86) 31 37131 : if (environment.isFamilyX86()) 32 37131 : return x86::FuncInternal::initCallConv(*this, ccId, environment); 33 : #endif 34 : 35 : #if !defined(ASMJIT_NO_AARCH64) 36 0 : if (environment.isFamilyAArch64()) 37 0 : return a64::FuncInternal::initCallConv(*this, ccId, environment); 38 : #endif 39 : 40 : return DebugUtils::errored(kErrorInvalidArgument); 41 : } 42 : 43 : // FuncDetail - Init / Reset 44 : // ========================= 45 : 46 37131 : ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept { 47 : CallConvId ccId = signature.callConvId(); 48 : uint32_t argCount = signature.argCount(); 49 : 50 37131 : if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs)) 51 : return DebugUtils::errored(kErrorInvalidArgument); 52 : 53 37131 : CallConv& cc = _callConv; 54 37131 : ASMJIT_PROPAGATE(cc.init(ccId, environment)); 55 : 56 : uint32_t registerSize = Environment::registerSizeFromArch(cc.arch()); 57 : uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize); 58 : 59 : const TypeId* signatureArgs = signature.args(); 60 47004 : for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { 61 : FuncValuePack& argPack = _args[argIndex]; 62 9873 : argPack[0].initTypeId(TypeUtils::deabstract(signatureArgs[argIndex], deabstractDelta)); 63 : } 64 : 65 37131 : _argCount = uint8_t(argCount); 66 37131 : _vaIndex = uint8_t(signature.vaIndex()); 67 : 68 : TypeId ret = signature.ret(); 69 37131 : if (ret != TypeId::kVoid) 70 37131 : _rets[0].initTypeId(TypeUtils::deabstract(ret, deabstractDelta)); 71 : 72 : #if !defined(ASMJIT_NO_X86) 73 37131 : if (environment.isFamilyX86()) 74 37131 : return x86::FuncInternal::initFuncDetail(*this, signature, registerSize); 75 : #endif 76 : 77 : #if !defined(ASMJIT_NO_AARCH64) 78 0 : if (environment.isFamilyAArch64()) 79 0 : return a64::FuncInternal::initFuncDetail(*this, signature, registerSize); 80 : #endif 81 : 82 : // We should never bubble here as if `cc.init()` succeeded then there has to be an implementation for the current 83 : // architecture. However, stay safe. 84 : return DebugUtils::errored(kErrorInvalidArgument); 85 : } 86 : 87 : // FuncFrame - Init 88 : // ================ 89 : 90 27492 : ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { 91 : Arch arch = func.callConv().arch(); 92 27492 : if (!Environment::isValidArch(arch)) 93 : return DebugUtils::errored(kErrorInvalidArch); 94 : 95 : const ArchTraits& archTraits = ArchTraits::byArch(arch); 96 : 97 : // Initializing FuncFrame means making a copy of some properties of `func`. Properties like `_localStackSize` will 98 : // be set by the user before the frame is finalized. 99 27492 : reset(); 100 : 101 27492 : _arch = arch; 102 27492 : _spRegId = uint8_t(archTraits.spRegId()); 103 27492 : _saRegId = uint8_t(BaseReg::kIdBad); 104 : 105 : uint32_t naturalStackAlignment = func.callConv().naturalStackAlignment(); 106 : uint32_t minDynamicAlignment = Support::max<uint32_t>(naturalStackAlignment, 16); 107 : 108 27492 : if (minDynamicAlignment == naturalStackAlignment) 109 27492 : minDynamicAlignment <<= 1; 110 : 111 27492 : _naturalStackAlignment = uint8_t(naturalStackAlignment); 112 27492 : _minDynamicAlignment = uint8_t(minDynamicAlignment); 113 27492 : _redZoneSize = uint8_t(func.redZoneSize()); 114 27492 : _spillZoneSize = uint8_t(func.spillZoneSize()); 115 27492 : _finalStackAlignment = uint8_t(_naturalStackAlignment); 116 : 117 27492 : if (func.hasFlag(CallConvFlags::kCalleePopsStack)) { 118 0 : _calleeStackCleanup = uint16_t(func.argStackSize()); 119 : } 120 : 121 : // Initial masks of dirty and preserved registers. 122 137460 : for (RegGroup group : RegGroupVirtValues{}) { 123 109968 : _dirtyRegs[group] = func.usedRegs(group); 124 109968 : _preservedRegs[group] = func.preservedRegs(group); 125 : } 126 : 127 : // Exclude stack pointer - this register is never included in saved GP regs. 128 27492 : _preservedRegs[RegGroup::kGp] &= ~Support::bitMask(archTraits.spRegId()); 129 : 130 : // The size and alignment of save/restore area of registers for each virtual register group 131 27492 : _saveRestoreRegSize = func.callConv()._saveRestoreRegSize; 132 27492 : _saveRestoreAlignment = func.callConv()._saveRestoreAlignment; 133 : 134 27492 : return kErrorOk; 135 : } 136 : 137 : // FuncFrame - Finalize 138 : // ==================== 139 : 140 27492 : ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { 141 27492 : if (!Environment::isValidArch(arch())) 142 : return DebugUtils::errored(kErrorInvalidArch); 143 : 144 : const ArchTraits& archTraits = ArchTraits::byArch(arch()); 145 : 146 27492 : uint32_t registerSize = _saveRestoreRegSize[RegGroup::kGp]; 147 27492 : uint32_t vectorSize = _saveRestoreRegSize[RegGroup::kVec]; 148 27492 : uint32_t returnAddressSize = archTraits.hasLinkReg() ? 0u : registerSize; 149 : 150 : // The final stack alignment must be updated accordingly to call and local stack alignments. 151 27492 : uint32_t stackAlignment = _finalStackAlignment; 152 : ASMJIT_ASSERT(stackAlignment == Support::max(_naturalStackAlignment, 153 : _callStackAlignment, 154 : _localStackAlignment)); 155 : 156 : bool hasFP = hasPreservedFP(); 157 : bool hasDA = hasDynamicAlignment(); 158 : 159 : uint32_t kSp = archTraits.spRegId(); 160 : uint32_t kFp = archTraits.fpRegId(); 161 : uint32_t kLr = archTraits.linkRegId(); 162 : 163 : // Make frame pointer dirty if the function uses it. 164 27492 : if (hasFP) { 165 0 : _dirtyRegs[RegGroup::kGp] |= Support::bitMask(kFp); 166 : 167 : // Currently required by ARM, if this works differently across architectures we would have to generalize most 168 : // likely in CallConv. 169 0 : if (kLr != BaseReg::kIdBad) 170 0 : _dirtyRegs[RegGroup::kGp] |= Support::bitMask(kLr); 171 : } 172 : 173 : // These two are identical if the function doesn't align its stack dynamically. 174 27492 : uint32_t saRegId = _saRegId; 175 27492 : if (saRegId == BaseReg::kIdBad) 176 : saRegId = kSp; 177 : 178 : // Fix stack arguments base-register from SP to FP in case it was not picked before and the function performs 179 : // dynamic stack alignment. 180 27492 : if (hasDA && saRegId == kSp) 181 : saRegId = kFp; 182 : 183 : // Mark as dirty any register but SP if used as SA pointer. 184 27492 : if (saRegId != kSp) 185 0 : _dirtyRegs[RegGroup::kGp] |= Support::bitMask(saRegId); 186 : 187 27492 : _spRegId = uint8_t(kSp); 188 27492 : _saRegId = uint8_t(saRegId); 189 : 190 : // Setup stack size used to save preserved registers. 191 27492 : uint32_t saveRestoreSizes[2] {}; 192 137460 : for (RegGroup group : RegGroupVirtValues{}) 193 109968 : saveRestoreSizes[size_t(!archTraits.hasInstPushPop(group))] 194 109968 : += Support::alignUp(Support::popcnt(savedRegs(group)) * saveRestoreRegSize(group), saveRestoreAlignment(group)); 195 : 196 27492 : _pushPopSaveSize = uint16_t(saveRestoreSizes[0]); 197 27492 : _extraRegSaveSize = uint16_t(saveRestoreSizes[1]); 198 : 199 : uint32_t v = 0; // The beginning of the stack frame relative to SP after prolog. 200 : v += callStackSize(); // Count 'callStackSize' <- This is used to call functions. 201 : v = Support::alignUp(v, stackAlignment); // Align to function's stack alignment. 202 : 203 27492 : _localStackOffset = v; // Store 'localStackOffset' <- Function's local stack starts here. 204 27492 : v += localStackSize(); // Count 'localStackSize' <- Function's local stack ends here. 205 : 206 : // If the function's stack must be aligned, calculate the alignment necessary to store vector registers, and set 207 : // `FuncAttributes::kAlignedVecSR` to inform PEI that it can use instructions that perform aligned stores/loads. 208 27492 : if (stackAlignment >= vectorSize && _extraRegSaveSize) { 209 : addAttributes(FuncAttributes::kAlignedVecSR); 210 : v = Support::alignUp(v, vectorSize); // Align 'extraRegSaveOffset'. 211 : } 212 : 213 27492 : _extraRegSaveOffset = v; // Store 'extraRegSaveOffset' <- Non-GP save/restore starts here. 214 27492 : v += _extraRegSaveSize; // Count 'extraRegSaveSize' <- Non-GP save/restore ends here. 215 : 216 : // Calculate if dynamic alignment (DA) slot (stored as offset relative to SP) is required and its offset. 217 27492 : if (hasDA && !hasFP) { 218 0 : _daOffset = v; // Store 'daOffset' <- DA pointer would be stored here. 219 0 : v += registerSize; // Count 'daOffset'. 220 : } 221 : else { 222 27492 : _daOffset = FuncFrame::kTagInvalidOffset; 223 : } 224 : 225 : // Link Register 226 : // ------------- 227 : // 228 : // The stack is aligned after the function call as the return address is stored in a link register. Some 229 : // architectures may require to always have aligned stack after PUSH/POP operation, which is represented 230 : // by ArchTraits::stackAlignmentConstraint(). 231 : // 232 : // No Link Register (X86/X64) 233 : // -------------------------- 234 : // 235 : // The return address should be stored after GP save/restore regs. It has the same size as `registerSize` 236 : // (basically the native register/pointer size). We don't adjust it now as `v` now contains the exact size 237 : // that the function requires to adjust (call frame + stack frame, vec stack size). The stack (if we consider 238 : // this size) is misaligned now, as it's always aligned before the function call - when `call()` is executed 239 : // it pushes the current EIP|RIP onto the stack, and misaligns it by 12 or 8 bytes (depending on the 240 : // architecture). So count number of bytes needed to align it up to the function's CallFrame (the beginning). 241 27492 : if (v || hasFuncCalls() || !returnAddressSize) 242 4990 : v += Support::alignUpDiff(v + pushPopSaveSize() + returnAddressSize, stackAlignment); 243 : 244 27492 : _pushPopSaveOffset = v; // Store 'pushPopSaveOffset' <- Function's push/pop save/restore starts here. 245 27492 : _stackAdjustment = v; // Store 'stackAdjustment' <- SA used by 'add SP, SA' and 'sub SP, SA'. 246 27492 : v += _pushPopSaveSize; // Count 'pushPopSaveSize' <- Function's push/pop save/restore ends here. 247 27492 : _finalStackSize = v; // Store 'finalStackSize' <- Final stack used by the function. 248 : 249 27492 : if (!archTraits.hasLinkReg()) 250 27492 : v += registerSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. 251 : 252 : // If the function performs dynamic stack alignment then the stack-adjustment must be aligned. 253 27492 : if (hasDA) 254 0 : _stackAdjustment = Support::alignUp(_stackAdjustment, stackAlignment); 255 : 256 : // Calculate where the function arguments start relative to SP. 257 27492 : _saOffsetFromSP = hasDA ? FuncFrame::kTagInvalidOffset : v; 258 : 259 : // Calculate where the function arguments start relative to FP or user-provided register. 260 27492 : _saOffsetFromSA = hasFP ? returnAddressSize + registerSize // Return address + frame pointer. 261 : : returnAddressSize + _pushPopSaveSize; // Return address + all push/pop regs. 262 : 263 27492 : return kErrorOk; 264 : } 265 : 266 : // FuncArgsAssignment - UpdateFuncFrame 267 : // ==================================== 268 : 269 27492 : ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept { 270 : Arch arch = frame.arch(); 271 : const FuncDetail* func = funcDetail(); 272 : 273 27492 : if (!func) 274 : return DebugUtils::errored(kErrorInvalidState); 275 : 276 27492 : RAConstraints constraints; 277 27492 : ASMJIT_PROPAGATE(constraints.init(arch)); 278 : 279 27492 : FuncArgsContext ctx; 280 27492 : ASMJIT_PROPAGATE(ctx.initWorkData(frame, *this, &constraints)); 281 27492 : ASMJIT_PROPAGATE(ctx.markDstRegsDirty(frame)); 282 27492 : ASMJIT_PROPAGATE(ctx.markScratchRegs(frame)); 283 27492 : ASMJIT_PROPAGATE(ctx.markStackArgsReg(frame)); 284 : return kErrorOk; 285 : } 286 : 287 : ASMJIT_END_NAMESPACE 288 : 289 : #endif // __PLUMED_HAS_ASMJIT