LCOV - code coverage report
Current view: top level - asmjit - ralocal_p.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 37 41 90.2 %
Date: 2026-11-05 10:19:06 Functions: 7 8 87.5 %

          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             : #ifndef ASMJIT_CORE_RALOCAL_P_H_INCLUDED
       8             : #define ASMJIT_CORE_RALOCAL_P_H_INCLUDED
       9             : 
      10             : #include "api-config.h"
      11             : #ifndef ASMJIT_NO_COMPILER
      12             : 
      13             : #include "raassignment_p.h"
      14             : #include "radefs_p.h"
      15             : #include "rapass_p.h"
      16             : #include "support.h"
      17             : 
      18             : ASMJIT_BEGIN_NAMESPACE
      19             : 
      20             : //! \cond INTERNAL
      21             : //! \addtogroup asmjit_ra
      22             : //! \{
      23             : 
      24             : //! Local register allocator.
      25             : class RALocalAllocator {
      26             : public:
      27             :   ASMJIT_NONCOPYABLE(RALocalAllocator)
      28             : 
      29             :   typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
      30             :   typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
      31             : 
      32             :   //! Link to `BaseRAPass`.
      33             :   BaseRAPass* _pass;
      34             :   //! Link to `BaseCompiler`.
      35             :   BaseCompiler* _cc;
      36             : 
      37             :   //! Architecture traits.
      38             :   const ArchTraits* _archTraits;
      39             :   //! Registers available to the allocator.
      40             :   RARegMask _availableRegs;
      41             :   //! Registers clobbered by the allocator.
      42             :   RARegMask _clobberedRegs;
      43             : 
      44             :   //! Register assignment (current).
      45             :   RAAssignment _curAssignment;
      46             :   //! Register assignment used temporarily during assignment switches.
      47             :   RAAssignment _tmpAssignment;
      48             : 
      49             :   //! Link to the current `RABlock`.
      50             :   RABlock* _block;
      51             :   //! InstNode.
      52             :   InstNode* _node;
      53             :   //! RA instruction.
      54             :   RAInst* _raInst;
      55             : 
      56             :   //! Count of all TiedReg's.
      57             :   uint32_t _tiedTotal;
      58             :   //! TiedReg's total counter.
      59             :   RARegCount _tiedCount;
      60             : 
      61             :   //! Temporary workToPhysMap that can be used freely by the allocator.
      62             :   WorkToPhysMap* _tmpWorkToPhysMap;
      63             : 
      64             :   //! \name Construction & Destruction
      65             :   //! \{
      66             : 
      67       27492 :   inline RALocalAllocator(BaseRAPass* pass) noexcept
      68       27492 :     : _pass(pass),
      69       27492 :       _cc(pass->cc()),
      70       27492 :       _archTraits(pass->_archTraits),
      71       27492 :       _availableRegs(pass->_availableRegs),
      72      109968 :       _clobberedRegs(),
      73       27492 :       _curAssignment(),
      74       27492 :       _block(nullptr),
      75       27492 :       _node(nullptr),
      76       27492 :       _raInst(nullptr),
      77       27492 :       _tiedTotal(),
      78      137460 :       _tiedCount() {}
      79             : 
      80             :   Error init() noexcept;
      81             : 
      82             :   //! \}
      83             : 
      84             :   //! \name Accessors
      85             :   //! \{
      86             : 
      87      580836 :   inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _pass->workRegById(workId); }
      88             :   inline PhysToWorkMap* physToWorkMap() const noexcept { return _curAssignment.physToWorkMap(); }
      89             :   inline WorkToPhysMap* workToPhysMap() const noexcept { return _curAssignment.workToPhysMap(); }
      90             : 
      91             :   //! Returns the currently processed block.
      92           0 :   inline RABlock* block() const noexcept { return _block; }
      93             :   //! Sets the currently processed block.
      94       54984 :   inline void setBlock(RABlock* block) noexcept { _block = block; }
      95             : 
      96             :   //! Returns the currently processed `InstNode`.
      97             :   inline InstNode* node() const noexcept { return _node; }
      98             :   //! Returns the currently processed `RAInst`.
      99             :   inline RAInst* raInst() const noexcept { return _raInst; }
     100             : 
     101             :   //! Returns all tied regs as `RATiedReg` array.
     102             :   inline RATiedReg* tiedRegs() const noexcept { return _raInst->tiedRegs(); }
     103             :   //! Returns tied registers grouped by the given `group`.
     104     1327232 :   inline RATiedReg* tiedRegs(RegGroup group) const noexcept { return _raInst->tiedRegs(group); }
     105             : 
     106             :   //! Returns count of all TiedRegs used by the instruction.
     107             :   inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
     108             :   //! Returns count of TiedRegs used by the given register `group`.
     109             :   inline uint32_t tiedCount(RegGroup group) const noexcept { return _tiedCount.get(group); }
     110             : 
     111             :   inline bool isGroupUsed(RegGroup group) const noexcept { return _tiedCount[group] != 0; }
     112             : 
     113             :   //! \}
     114             : 
     115             :   //! \name Assignment
     116             :   //! \{
     117             : 
     118             :   Error makeInitialAssignment() noexcept;
     119             : 
     120             :   Error replaceAssignment(const PhysToWorkMap* physToWorkMap) noexcept;
     121             : 
     122             :   //! Switch to the given assignment by reassigning all register and emitting code that reassigns them.
     123             :   //! This is always used to switch to a previously stored assignment.
     124             :   //!
     125             :   //! If `tryMode` is true then the final assignment doesn't have to be exactly same as specified by `dstPhysToWorkMap`
     126             :   //! and `dstWorkToPhysMap`. This mode is only used before conditional jumps that already have assignment to generate
     127             :   //! a code sequence that is always executed regardless of the flow.
     128             :   Error switchToAssignment(PhysToWorkMap* dstPhysToWorkMap, const ZoneBitVector& liveIn, bool dstReadOnly, bool tryMode) noexcept;
     129             : 
     130       27492 :   inline Error spillRegsBeforeEntry(RABlock* block) noexcept {
     131       27492 :     return spillScratchGpRegsBeforeEntry(block->entryScratchGpRegs());
     132             :   }
     133             : 
     134             :   Error spillScratchGpRegsBeforeEntry(uint32_t scratchRegs) noexcept;
     135             : 
     136             :   //! \}
     137             : 
     138             :   //! \name Allocation
     139             :   //! \{
     140             : 
     141             :   Error allocInst(InstNode* node) noexcept;
     142             :   Error spillAfterAllocation(InstNode* node) noexcept;
     143             : 
     144             :   Error allocBranch(InstNode* node, RABlock* target, RABlock* cont) noexcept;
     145             :   Error allocJumpTable(InstNode* node, const RABlocks& targets, RABlock* cont) noexcept;
     146             : 
     147             :   //! \}
     148             : 
     149             :   //! \name Decision Making
     150             :   //! \{
     151             : 
     152             :   enum CostModel : uint32_t {
     153             :     kCostOfFrequency = 1048576,
     154             :     kCostOfDirtyFlag = kCostOfFrequency / 4
     155             :   };
     156             : 
     157             :   inline uint32_t costByFrequency(float freq) const noexcept {
     158      117536 :     return uint32_t(int32_t(freq * float(kCostOfFrequency)));
     159             :   }
     160             : 
     161      117536 :   inline uint32_t calculateSpillCost(RegGroup group, uint32_t workId, uint32_t assignedId) const noexcept {
     162             :     RAWorkReg* workReg = workRegById(workId);
     163             :     uint32_t cost = costByFrequency(workReg->liveStats().freq());
     164             : 
     165      117536 :     if (_curAssignment.isPhysDirty(group, assignedId))
     166      117536 :       cost += kCostOfDirtyFlag;
     167             : 
     168      117536 :     return cost;
     169             :   }
     170             : 
     171             :   //! Decides on register assignment.
     172             :   uint32_t decideOnAssignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept;
     173             : 
     174             :   //! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated in a physical register that have
     175             :   //! to be used by another WorkReg.
     176             :   //!
     177             :   //! The function must return either `RAAssignment::kPhysNone`, which means that the WorkReg of `workId` should be
     178             :   //! spilled, or a valid physical register ID, which means that the register should be moved to that physical register
     179             :   //! instead.
     180             :   uint32_t decideOnReassignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept;
     181             : 
     182             :   //! Decides on best spill given a register mask `spillableRegs`
     183             :   uint32_t decideOnSpillFor(RegGroup group, uint32_t workId, RegMask spillableRegs, uint32_t* spillWorkId) const noexcept;
     184             : 
     185             :   //! \}
     186             : 
     187             :   //! \name Emit
     188             :   //! \{
     189             : 
     190             :   //! Emits a move between a destination and source register, and fixes the
     191             :   //! register assignment.
     192        1785 :   inline Error onMoveReg(RegGroup group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
     193        1785 :     if (dstPhysId == srcPhysId) return kErrorOk;
     194        1785 :     _curAssignment.reassign(group, workId, dstPhysId, srcPhysId);
     195        1785 :     return _pass->emitMove(workId, dstPhysId, srcPhysId);
     196             :   }
     197             : 
     198             :   //! Emits a swap between two physical registers and fixes their assignment.
     199             :   //!
     200             :   //! \note Target must support this operation otherwise this would ASSERT.
     201           0 :   inline Error onSwapReg(RegGroup group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
     202           0 :     _curAssignment.swap(group, aWorkId, aPhysId, bWorkId, bPhysId);
     203           0 :     return _pass->emitSwap(aWorkId, aPhysId, bWorkId, bPhysId);
     204             :   }
     205             : 
     206             :   //! Emits a load from [VirtReg/WorkReg]'s spill slot to a physical register
     207             :   //! and makes it assigned and clean.
     208       17638 :   inline Error onLoadReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
     209       17638 :     _curAssignment.assign(group, workId, physId, RAAssignment::kClean);
     210       17638 :     return _pass->emitLoad(workId, physId);
     211             :   }
     212             : 
     213             :   //! Emits a save a physical register to a [VirtReg/WorkReg]'s spill slot,
     214             :   //! keeps it assigned, and makes it clean.
     215       30798 :   inline Error onSaveReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
     216             :     ASMJIT_ASSERT(_curAssignment.workToPhysId(group, workId) == physId);
     217             :     ASMJIT_ASSERT(_curAssignment.physToWorkId(group, physId) == workId);
     218             : 
     219             :     _curAssignment.makeClean(group, workId, physId);
     220       30798 :     return _pass->emitSave(workId, physId);
     221             :   }
     222             : 
     223             :   //! Assigns a register, the content of it is undefined at this point.
     224             :   inline Error onAssignReg(RegGroup group, uint32_t workId, uint32_t physId, bool dirty) noexcept {
     225      276738 :     _curAssignment.assign(group, workId, physId, dirty);
     226             :     return kErrorOk;
     227             :   }
     228             : 
     229             :   //! Spills a variable/register, saves the content to the memory-home if modified.
     230       35846 :   inline Error onSpillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
     231       35846 :     if (_curAssignment.isPhysDirty(group, physId))
     232       30798 :       ASMJIT_PROPAGATE(onSaveReg(group, workId, physId));
     233       35846 :     return onKillReg(group, workId, physId);
     234             :   }
     235             : 
     236             :   inline Error onDirtyReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
     237             :     _curAssignment.makeDirty(group, workId, physId);
     238             :     return kErrorOk;
     239             :   }
     240             : 
     241             :   inline Error onKillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
     242      294376 :     _curAssignment.unassign(group, workId, physId);
     243             :     return kErrorOk;
     244             :   }
     245             : 
     246             :   //! \}
     247             : };
     248             : 
     249             : //! \}
     250             : //! \endcond
     251             : 
     252             : ASMJIT_END_NAMESPACE
     253             : 
     254             : #endif // !ASMJIT_NO_COMPILER
     255             : #endif // ASMJIT_CORE_RALOCAL_P_H_INCLUDED
     256             : 
     257             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16