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 "funcargscontext_p.h" 9 : 10 : ASMJIT_BEGIN_NAMESPACE 11 : 12 : //! \cond INTERNAL 13 : //! \addtogroup asmjit_core 14 : //! \{ 15 : 16 54984 : FuncArgsContext::FuncArgsContext() noexcept { 17 274920 : for (RegGroup group : RegGroupVirtValues{}) 18 219936 : _workData[size_t(group)].reset(); 19 54984 : } 20 : 21 54984 : ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args, const RAConstraints* constraints) noexcept { 22 : Arch arch = frame.arch(); 23 : const FuncDetail& func = *args.funcDetail(); 24 : 25 54984 : _archTraits = &ArchTraits::byArch(arch); 26 54984 : _constraints = constraints; 27 54984 : _arch = arch; 28 : 29 : // Initialize `_archRegs`. 30 274920 : for (RegGroup group : RegGroupVirtValues{}) 31 219936 : _workData[group]._archRegs = _constraints->availableRegs(group); 32 : 33 54984 : if (frame.hasPreservedFP()) 34 0 : _workData[size_t(RegGroup::kGp)]._archRegs &= ~Support::bitMask(archTraits().fpRegId()); 35 : 36 : // Extract information from all function arguments/assignments and build Var[] array. 37 : uint32_t varId = 0; 38 934728 : for (uint32_t argIndex = 0; argIndex < Globals::kMaxFuncArgs; argIndex++) { 39 4398720 : for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) { 40 3518976 : const FuncValue& dst_ = args.arg(argIndex, valueIndex); 41 3518976 : if (!dst_.isAssigned()) 42 : continue; 43 : 44 : const FuncValue& src_ = func.arg(argIndex, valueIndex); 45 0 : if (ASMJIT_UNLIKELY(!src_.isAssigned())) 46 : return DebugUtils::errored(kErrorInvalidState); 47 : 48 0 : Var& var = _vars[varId]; 49 : var.init(src_, dst_); 50 : 51 : FuncValue& src = var.cur; 52 : FuncValue& dst = var.out; 53 : 54 : RegGroup dstGroup = RegGroup::kMaxValue; 55 : uint32_t dstId = BaseReg::kIdBad; 56 : WorkData* dstWd = nullptr; 57 : 58 : // Not supported. 59 0 : if (src.isIndirect()) 60 : return DebugUtils::errored(kErrorInvalidAssignment); 61 : 62 0 : if (dst.isReg()) { 63 : RegType dstType = dst.regType(); 64 0 : if (ASMJIT_UNLIKELY(!archTraits().hasRegType(dstType))) 65 : return DebugUtils::errored(kErrorInvalidRegType); 66 : 67 : // Copy TypeId from source if the destination doesn't have it. The RA used by BaseCompiler would never 68 : // leave TypeId undefined, but users of FuncAPI can just assign phys regs without specifying the type. 69 0 : if (!dst.hasTypeId()) 70 : dst.setTypeId(archTraits().regTypeToTypeId(dst.regType())); 71 : 72 : dstGroup = archTraits().regTypeToGroup(dstType); 73 0 : if (ASMJIT_UNLIKELY(dstGroup > RegGroup::kMaxVirt)) 74 : return DebugUtils::errored(kErrorInvalidRegGroup); 75 : 76 : dstWd = &_workData[dstGroup]; 77 : dstId = dst.regId(); 78 0 : if (ASMJIT_UNLIKELY(dstId >= 32 || !Support::bitTest(dstWd->archRegs(), dstId))) 79 : return DebugUtils::errored(kErrorInvalidPhysId); 80 : 81 0 : if (ASMJIT_UNLIKELY(Support::bitTest(dstWd->dstRegs(), dstId))) 82 : return DebugUtils::errored(kErrorOverlappedRegs); 83 : 84 0 : dstWd->_dstRegs |= Support::bitMask(dstId); 85 0 : dstWd->_dstShuf |= Support::bitMask(dstId); 86 0 : dstWd->_usedRegs |= Support::bitMask(dstId); 87 : } 88 : else { 89 0 : if (!dst.hasTypeId()) 90 : dst.setTypeId(src.typeId()); 91 : 92 0 : OperandSignature signature = getSuitableRegForMemToMemMove(arch, dst.typeId(), src.typeId()); 93 0 : if (ASMJIT_UNLIKELY(!signature.isValid())) 94 : return DebugUtils::errored(kErrorInvalidState); 95 0 : _stackDstMask = uint8_t(_stackDstMask | Support::bitMask(signature.regGroup())); 96 : } 97 : 98 0 : if (src.isReg()) { 99 : uint32_t srcId = src.regId(); 100 : RegGroup srcGroup = archTraits().regTypeToGroup(src.regType()); 101 : 102 0 : if (dstGroup == srcGroup) { 103 : ASMJIT_ASSERT(dstWd != nullptr); 104 0 : dstWd->assign(varId, srcId); 105 : 106 : // The best case, register is allocated where it is expected to be. 107 0 : if (dstId == srcId) 108 : var.markDone(); 109 : } 110 : else { 111 0 : if (ASMJIT_UNLIKELY(srcGroup > RegGroup::kMaxVirt)) 112 : return DebugUtils::errored(kErrorInvalidState); 113 : 114 0 : WorkData& srcData = _workData[size_t(srcGroup)]; 115 0 : srcData.assign(varId, srcId); 116 : } 117 : } 118 : else { 119 0 : if (dstWd) 120 0 : dstWd->_numStackArgs++; 121 0 : _hasStackSrc = true; 122 : } 123 : 124 0 : varId++; 125 : } 126 : } 127 : 128 : // Initialize WorkData::workRegs. 129 274920 : for (RegGroup group : RegGroupVirtValues{}) { 130 219936 : _workData[group]._workRegs = 131 219936 : (_workData[group].archRegs() & (frame.dirtyRegs(group) | ~frame.preservedRegs(group))) | _workData[group].dstRegs() | _workData[group].assignedRegs(); 132 : } 133 : 134 : // Create a variable that represents `SARegId` if necessary. 135 54984 : bool saRegRequired = _hasStackSrc && frame.hasDynamicAlignment() && !frame.hasPreservedFP(); 136 : 137 : WorkData& gpRegs = _workData[RegGroup::kGp]; 138 : uint32_t saCurRegId = frame.saRegId(); 139 : uint32_t saOutRegId = args.saRegId(); 140 : 141 54984 : if (saCurRegId != BaseReg::kIdBad) { 142 : // Check if the provided `SARegId` doesn't collide with input registers. 143 27492 : if (ASMJIT_UNLIKELY(gpRegs.isAssigned(saCurRegId))) 144 : return DebugUtils::errored(kErrorOverlappedRegs); 145 : } 146 : 147 54984 : if (saOutRegId != BaseReg::kIdBad) { 148 : // Check if the provided `SARegId` doesn't collide with argument assignments. 149 0 : if (ASMJIT_UNLIKELY(Support::bitTest(gpRegs.dstRegs(), saOutRegId))) 150 : return DebugUtils::errored(kErrorOverlappedRegs); 151 : saRegRequired = true; 152 : } 153 : 154 54984 : if (saRegRequired) { 155 0 : TypeId ptrTypeId = Environment::is32Bit(arch) ? TypeId::kUInt32 : TypeId::kUInt64; 156 0 : RegType ptrRegType = Environment::is32Bit(arch) ? RegType::kGp32 : RegType::kGp64; 157 : 158 0 : _saVarId = uint8_t(varId); 159 0 : _hasPreservedFP = frame.hasPreservedFP(); 160 : 161 0 : Var& var = _vars[varId]; 162 : var.reset(); 163 : 164 0 : if (saCurRegId == BaseReg::kIdBad) { 165 0 : if (saOutRegId != BaseReg::kIdBad && !gpRegs.isAssigned(saOutRegId)) { 166 : saCurRegId = saOutRegId; 167 : } 168 : else { 169 : RegMask availableRegs = gpRegs.availableRegs(); 170 0 : if (!availableRegs) 171 0 : availableRegs = gpRegs.archRegs() & ~gpRegs.workRegs(); 172 : 173 0 : if (ASMJIT_UNLIKELY(!availableRegs)) 174 : return DebugUtils::errored(kErrorNoMorePhysRegs); 175 : 176 : saCurRegId = Support::ctz(availableRegs); 177 : } 178 : } 179 : 180 0 : var.cur.initReg(ptrRegType, saCurRegId, ptrTypeId); 181 0 : gpRegs.assign(varId, saCurRegId); 182 0 : gpRegs._workRegs |= Support::bitMask(saCurRegId); 183 : 184 0 : if (saOutRegId != BaseReg::kIdBad) { 185 0 : var.out.initReg(ptrRegType, saOutRegId, ptrTypeId); 186 0 : gpRegs._dstRegs |= Support::bitMask(saOutRegId); 187 0 : gpRegs._workRegs |= Support::bitMask(saOutRegId); 188 : } 189 : else { 190 : var.markDone(); 191 : } 192 : 193 0 : varId++; 194 : } 195 : 196 54984 : _varCount = varId; 197 : 198 : // Detect register swaps. 199 54984 : for (varId = 0; varId < _varCount; varId++) { 200 : Var& var = _vars[varId]; 201 0 : if (var.cur.isReg() && var.out.isReg()) { 202 : uint32_t srcId = var.cur.regId(); 203 : uint32_t dstId = var.out.regId(); 204 : 205 : RegGroup group = archTraits().regTypeToGroup(var.cur.regType()); 206 0 : if (group != archTraits().regTypeToGroup(var.out.regType())) 207 : continue; 208 : 209 : WorkData& wd = _workData[group]; 210 0 : if (wd.isAssigned(dstId)) { 211 0 : Var& other = _vars[wd._physToVarId[dstId]]; 212 0 : if (archTraits().regTypeToGroup(other.out.regType()) == group && other.out.regId() == srcId) { 213 0 : wd._numSwaps++; 214 0 : _regSwapsMask = uint8_t(_regSwapsMask | Support::bitMask(group)); 215 : } 216 : } 217 : } 218 : } 219 : 220 : return kErrorOk; 221 : } 222 : 223 27492 : ASMJIT_FAVOR_SIZE Error FuncArgsContext::markDstRegsDirty(FuncFrame& frame) noexcept { 224 137460 : for (RegGroup group : RegGroupVirtValues{}) { 225 : WorkData& wd = _workData[group]; 226 109968 : uint32_t regs = wd.usedRegs() | wd._dstShuf; 227 : 228 109968 : wd._workRegs |= regs; 229 : frame.addDirtyRegs(group, regs); 230 : } 231 : 232 27492 : return kErrorOk; 233 : } 234 : 235 27492 : ASMJIT_FAVOR_SIZE Error FuncArgsContext::markScratchRegs(FuncFrame& frame) noexcept { 236 : uint32_t groupMask = 0; 237 : 238 : // Handle stack to stack moves. 239 27492 : groupMask |= _stackDstMask; 240 : 241 : // Handle register swaps. 242 27492 : groupMask |= _regSwapsMask & ~Support::bitMask(RegGroup::kGp); 243 : 244 27492 : if (!groupMask) 245 : return kErrorOk; 246 : 247 : // Selects one dirty register per affected group that can be used as a scratch register. 248 0 : for (RegGroup group : RegGroupVirtValues{}) { 249 0 : if (Support::bitTest(groupMask, group)) { 250 : WorkData& wd = _workData[group]; 251 : 252 : // Initially, pick some clobbered or dirty register. 253 : RegMask workRegs = wd.workRegs(); 254 0 : RegMask regs = workRegs & ~(wd.usedRegs() | wd._dstShuf); 255 : 256 : // If that didn't work out pick some register which is not in 'used'. 257 0 : if (!regs) 258 0 : regs = workRegs & ~wd.usedRegs(); 259 : 260 : // If that didn't work out pick any other register that is allocable. 261 : // This last resort case will, however, result in marking one more 262 : // register dirty. 263 0 : if (!regs) 264 0 : regs = wd.archRegs() & ~workRegs; 265 : 266 : // If that didn't work out we will have to use XORs instead of MOVs. 267 0 : if (!regs) 268 0 : continue; 269 : 270 : RegMask regMask = Support::blsi(regs); 271 0 : wd._workRegs |= regMask; 272 : frame.addDirtyRegs(group, regMask); 273 : } 274 : } 275 : 276 0 : return kErrorOk; 277 : } 278 : 279 27492 : ASMJIT_FAVOR_SIZE Error FuncArgsContext::markStackArgsReg(FuncFrame& frame) noexcept { 280 27492 : if (_saVarId != kVarIdNone) { 281 0 : const Var& var = _vars[_saVarId]; 282 : frame.setSARegId(var.cur.regId()); 283 : } 284 27492 : else if (frame.hasPreservedFP()) { 285 : frame.setSARegId(archTraits().fpRegId()); 286 : } 287 : 288 27492 : return kErrorOk; 289 : } 290 : 291 : //! \} 292 : //! \endcond 293 : 294 : ASMJIT_END_NAMESPACE 295 : 296 : #endif // __PLUMED_HAS_ASMJIT