LCOV - code coverage report
Current view: top level - asmjit - funcargscontext.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 38 104 36.5 %
Date: 2026-11-05 10:19:06 Functions: 5 5 100.0 %

          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

Generated by: LCOV version 1.16