LCOV - code coverage report
Current view: top level - asmjit - rapass_p.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 130 167 77.8 %
Date: 2026-11-05 10:19:06 Functions: 13 13 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             : #ifndef ASMJIT_CORE_RAPASS_P_H_INCLUDED
       8             : #define ASMJIT_CORE_RAPASS_P_H_INCLUDED
       9             : 
      10             : #include "api-config.h"
      11             : #ifndef ASMJIT_NO_COMPILER
      12             : 
      13             : #include "compiler.h"
      14             : #include "emithelper_p.h"
      15             : #include "raassignment_p.h"
      16             : #include "radefs_p.h"
      17             : #include "rastack_p.h"
      18             : #include "support.h"
      19             : 
      20             : ASMJIT_BEGIN_NAMESPACE
      21             : 
      22             : //! \cond INTERNAL
      23             : //! \addtogroup asmjit_ra
      24             : //! \{
      25             : 
      26             : //! Flags used by \ref RABlock.
      27             : enum class RABlockFlags : uint32_t {
      28             :   //! No flags.
      29             :   kNone = 0,
      30             : 
      31             :   //! Block has been constructed from nodes.
      32             :   kIsConstructed = 0x00000001u,
      33             :   //! Block is reachable (set by `buildCFGViews()`).
      34             :   kIsReachable = 0x00000002u,
      35             :   //! Block is a target (has an associated label or multiple labels).
      36             :   kIsTargetable = 0x00000004u,
      37             :   //! Block has been allocated.
      38             :   kIsAllocated = 0x00000008u,
      39             :   //! Block is a function-exit.
      40             :   kIsFuncExit = 0x00000010u,
      41             : 
      42             :   //! Block has a terminator (jump, conditional jump, ret).
      43             :   kHasTerminator = 0x00000100u,
      44             :   //! Block naturally flows to the next block.
      45             :   kHasConsecutive = 0x00000200u,
      46             :   //! Block has a jump to a jump-table at the end.
      47             :   kHasJumpTable = 0x00000400u,
      48             :   //! Block contains fixed registers (precolored).
      49             :   kHasFixedRegs = 0x00000800u,
      50             :   //! Block contains function calls.
      51             :   kHasFuncCalls = 0x00001000u
      52             : };
      53      266940 : ASMJIT_DEFINE_ENUM_FLAGS(RABlockFlags)
      54             : 
      55             : //! Basic block used by register allocator pass.
      56             : class RABlock {
      57             : public:
      58             :   ASMJIT_NONCOPYABLE(RABlock)
      59             : 
      60             :   typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
      61             :   typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
      62             : 
      63             :   //! \name Constants
      64             :   //! \{
      65             : 
      66             :   enum : uint32_t {
      67             :     //! Unassigned block id.
      68             :     kUnassignedId = 0xFFFFFFFFu
      69             :   };
      70             : 
      71             :   enum LiveType : uint32_t {
      72             :     kLiveIn = 0,
      73             :     kLiveOut = 1,
      74             :     kLiveGen = 2,
      75             :     kLiveKill = 3,
      76             :     kLiveCount = 4
      77             :   };
      78             : 
      79             :   //! \}
      80             : 
      81             :   //! \name Members
      82             :   //! \{
      83             : 
      84             :   //! Register allocator pass.
      85             :   BaseRAPass* _ra;
      86             : 
      87             :   //! Block id (indexed from zero).
      88             :   uint32_t _blockId = kUnassignedId;
      89             :   //! Block flags, see `Flags`.
      90             :   RABlockFlags _flags = RABlockFlags::kNone;
      91             : 
      92             :   //! First `BaseNode` of this block (inclusive).
      93             :   BaseNode* _first = nullptr;
      94             :   //! Last `BaseNode` of this block (inclusive).
      95             :   BaseNode* _last = nullptr;
      96             : 
      97             :   //! Initial position of this block (inclusive).
      98             :   uint32_t _firstPosition = 0;
      99             :   //! End position of this block (exclusive).
     100             :   uint32_t _endPosition = 0;
     101             : 
     102             :   //! Weight of this block (default 0, each loop adds one).
     103             :   uint32_t _weight = 0;
     104             :   //! Post-order view order, used during POV construction.
     105             :   uint32_t _povOrder = 0;
     106             : 
     107             :   //! Basic statistics about registers.
     108             :   RARegsStats _regsStats = RARegsStats();
     109             :   //! Maximum live-count per register group.
     110             :   RALiveCount _maxLiveCount = RALiveCount();
     111             : 
     112             :   //! Timestamp (used by block visitors).
     113             :   mutable uint64_t _timestamp = 0;
     114             :   //! Immediate dominator of this block.
     115             :   RABlock* _idom = nullptr;
     116             : 
     117             :   //! Block predecessors.
     118             :   RABlocks _predecessors {};
     119             :   //! Block successors.
     120             :   RABlocks _successors {};
     121             : 
     122             :   //! Liveness in/out/use/kill.
     123             :   ZoneBitVector _liveBits[kLiveCount] {};
     124             : 
     125             :   //! Shared assignment it or `Globals::kInvalidId` if this block doesn't have shared assignment.
     126             :   //! See \ref RASharedAssignment for more details.
     127             :   uint32_t _sharedAssignmentId = Globals::kInvalidId;
     128             :   //! Scratch registers that cannot be allocated upon block entry.
     129             :   RegMask _entryScratchGpRegs = 0;
     130             :   //! Scratch registers used at exit, by a terminator instruction.
     131             :   RegMask _exitScratchGpRegs = 0;
     132             : 
     133             :   //! Register assignment on entry.
     134             :   PhysToWorkMap* _entryPhysToWorkMap = nullptr;
     135             : 
     136             :   //! \}
     137             : 
     138             :   //! \name Construction & Destruction
     139             :   //! \{
     140             : 
     141       54984 :   inline RABlock(BaseRAPass* ra) noexcept
     142      439872 :     : _ra(ra) {}
     143             : 
     144             :   //! \}
     145             : 
     146             :   //! \name Accessors
     147             :   //! \{
     148             : 
     149             :   inline BaseRAPass* pass() const noexcept { return _ra; }
     150             :   inline ZoneAllocator* allocator() const noexcept;
     151             : 
     152      137460 :   inline uint32_t blockId() const noexcept { return _blockId; }
     153             :   inline RABlockFlags flags() const noexcept { return _flags; }
     154             : 
     155      109968 :   inline bool hasFlag(RABlockFlags flag) const noexcept { return Support::test(_flags, flag); }
     156        9639 :   inline void addFlags(RABlockFlags flags) noexcept { _flags |= flags; }
     157             : 
     158             :   inline bool isAssigned() const noexcept { return _blockId != kUnassignedId; }
     159             : 
     160             :   inline bool isConstructed() const noexcept { return hasFlag(RABlockFlags::kIsConstructed); }
     161             :   inline bool isReachable() const noexcept { return hasFlag(RABlockFlags::kIsReachable); }
     162             :   inline bool isTargetable() const noexcept { return hasFlag(RABlockFlags::kIsTargetable); }
     163             :   inline bool isAllocated() const noexcept { return hasFlag(RABlockFlags::kIsAllocated); }
     164             :   inline bool isFuncExit() const noexcept { return hasFlag(RABlockFlags::kIsFuncExit); }
     165             :   inline bool hasTerminator() const noexcept { return hasFlag(RABlockFlags::kHasTerminator); }
     166             :   inline bool hasConsecutive() const noexcept { return hasFlag(RABlockFlags::kHasConsecutive); }
     167             :   inline bool hasJumpTable() const noexcept { return hasFlag(RABlockFlags::kHasJumpTable); }
     168             : 
     169             :   inline void makeConstructed(const RARegsStats& regStats) noexcept {
     170             :     _flags |= RABlockFlags::kIsConstructed;
     171             :     _regsStats.combineWith(regStats);
     172             :   }
     173             : 
     174             :   inline void makeReachable() noexcept { _flags |= RABlockFlags::kIsReachable; }
     175             :   inline void makeTargetable() noexcept { _flags |= RABlockFlags::kIsTargetable; }
     176             :   inline void makeAllocated() noexcept { _flags |= RABlockFlags::kIsAllocated; }
     177             : 
     178             :   inline const RARegsStats& regsStats() const noexcept { return _regsStats; }
     179             : 
     180             :   inline bool hasPredecessors() const noexcept { return !_predecessors.empty(); }
     181             :   inline bool hasSuccessors() const noexcept { return !_successors.empty(); }
     182             : 
     183       27492 :   inline bool hasSuccessor(RABlock* block) noexcept {
     184       27492 :     if (block->_predecessors.size() < _successors.size())
     185           0 :       return block->_predecessors.contains(this);
     186             :     else
     187       27492 :       return _successors.contains(block);
     188             :   }
     189             : 
     190             :   inline const RABlocks& predecessors() const noexcept { return _predecessors; }
     191           0 :   inline const RABlocks& successors() const noexcept { return _successors; }
     192             : 
     193       82570 :   inline BaseNode* first() const noexcept { return _first; }
     194      164952 :   inline BaseNode* last() const noexcept { return _last; }
     195             : 
     196       82476 :   inline void setFirst(BaseNode* node) noexcept { _first = node; }
     197      219936 :   inline void setLast(BaseNode* node) noexcept { _last = node; }
     198             : 
     199             :   inline uint32_t firstPosition() const noexcept { return _firstPosition; }
     200       54984 :   inline void setFirstPosition(uint32_t position) noexcept { _firstPosition = position; }
     201             : 
     202             :   inline uint32_t endPosition() const noexcept { return _endPosition; }
     203       54984 :   inline void setEndPosition(uint32_t position) noexcept { _endPosition = position; }
     204             : 
     205           0 :   inline uint32_t povOrder() const noexcept { return _povOrder; }
     206             : 
     207             :   inline RegMask entryScratchGpRegs() const noexcept;
     208           0 :   inline RegMask exitScratchGpRegs() const noexcept { return _exitScratchGpRegs; }
     209             : 
     210             :   inline void addEntryScratchGpRegs(RegMask regMask) noexcept { _entryScratchGpRegs |= regMask; }
     211           0 :   inline void addExitScratchGpRegs(RegMask regMask) noexcept { _exitScratchGpRegs |= regMask; }
     212             : 
     213       82476 :   inline bool hasSharedAssignmentId() const noexcept { return _sharedAssignmentId != Globals::kInvalidId; }
     214           0 :   inline uint32_t sharedAssignmentId() const noexcept { return _sharedAssignmentId; }
     215           0 :   inline void setSharedAssignmentId(uint32_t id) noexcept { _sharedAssignmentId = id; }
     216             : 
     217             :   inline uint64_t timestamp() const noexcept { return _timestamp; }
     218           0 :   inline bool hasTimestamp(uint64_t ts) const noexcept { return _timestamp == ts; }
     219           0 :   inline void setTimestamp(uint64_t ts) const noexcept { _timestamp = ts; }
     220             :   inline void resetTimestamp() const noexcept { _timestamp = 0; }
     221             : 
     222           0 :   inline RABlock* consecutive() const noexcept { return hasConsecutive() ? _successors[0] : nullptr; }
     223             : 
     224      109968 :   inline RABlock* iDom() noexcept { return _idom; }
     225           0 :   inline const RABlock* iDom() const noexcept { return _idom; }
     226       27492 :   inline void setIDom(RABlock* block) noexcept { _idom = block; }
     227             : 
     228           0 :   inline ZoneBitVector& liveIn() noexcept { return _liveBits[kLiveIn]; }
     229             :   inline const ZoneBitVector& liveIn() const noexcept { return _liveBits[kLiveIn]; }
     230             : 
     231             :   inline ZoneBitVector& liveOut() noexcept { return _liveBits[kLiveOut]; }
     232       27492 :   inline const ZoneBitVector& liveOut() const noexcept { return _liveBits[kLiveOut]; }
     233             : 
     234             :   inline ZoneBitVector& gen() noexcept { return _liveBits[kLiveGen]; }
     235             :   inline const ZoneBitVector& gen() const noexcept { return _liveBits[kLiveGen]; }
     236             : 
     237             :   inline ZoneBitVector& kill() noexcept { return _liveBits[kLiveKill]; }
     238             :   inline const ZoneBitVector& kill() const noexcept { return _liveBits[kLiveKill]; }
     239             : 
     240       54984 :   inline Error resizeLiveBits(uint32_t size) noexcept {
     241       54984 :     ASMJIT_PROPAGATE(_liveBits[kLiveIn  ].resize(allocator(), size));
     242       54984 :     ASMJIT_PROPAGATE(_liveBits[kLiveOut ].resize(allocator(), size));
     243       54984 :     ASMJIT_PROPAGATE(_liveBits[kLiveGen ].resize(allocator(), size));
     244       54984 :     ASMJIT_PROPAGATE(_liveBits[kLiveKill].resize(allocator(), size));
     245             :     return kErrorOk;
     246             :   }
     247             : 
     248       27492 :   inline bool hasEntryAssignment() const noexcept { return _entryPhysToWorkMap != nullptr; }
     249       27492 :   inline PhysToWorkMap* entryPhysToWorkMap() const noexcept { return _entryPhysToWorkMap; }
     250       54984 :   inline void setEntryAssignment(PhysToWorkMap* physToWorkMap) noexcept { _entryPhysToWorkMap = physToWorkMap; }
     251             : 
     252             :   //! \}
     253             : 
     254             :   //! \name Utilities
     255             :   //! \{
     256             : 
     257             :   //! Adds a successor to this block, and predecessor to `successor`, making connection on both sides.
     258             :   //!
     259             :   //! This API must be used to manage successors and predecessors, never manage it manually.
     260             :   Error appendSuccessor(RABlock* successor) noexcept;
     261             : 
     262             :   //! Similar to `appendSuccessor()`, but does prepend instead append.
     263             :   //!
     264             :   //! This function is used to add a natural flow (always first) to the block.
     265             :   Error prependSuccessor(RABlock* successor) noexcept;
     266             : 
     267             :   //! \}
     268             : };
     269             : 
     270             : //! Register allocator's data associated with each `InstNode`.
     271             : class RAInst {
     272             : public:
     273             :   ASMJIT_NONCOPYABLE(RAInst)
     274             : 
     275             :   //! \name Members
     276             :   //! \{
     277             : 
     278             :   //! Parent block.
     279             :   RABlock* _block;
     280             :   //! Instruction RW flags.
     281             :   InstRWFlags _instRWFlags;
     282             :   //! Aggregated RATiedFlags from all operands & instruction specific flags.
     283             :   RATiedFlags _flags;
     284             :   //! Total count of RATiedReg's.
     285             :   uint32_t _tiedTotal;
     286             :   //! Index of RATiedReg's per register group.
     287             :   RARegIndex _tiedIndex;
     288             :   //! Count of RATiedReg's per register group.
     289             :   RARegCount _tiedCount;
     290             :   //! Number of live, and thus interfering VirtReg's at this point.
     291             :   RALiveCount _liveCount;
     292             :   //! Fixed physical registers used.
     293             :   RARegMask _usedRegs;
     294             :   //! Clobbered registers (by a function call).
     295             :   RARegMask _clobberedRegs;
     296             :   //! Tied registers.
     297             :   RATiedReg _tiedRegs[1];
     298             : 
     299             :   //! \}
     300             : 
     301             :   //! \name Construction & Destruction
     302             :   //! \{
     303             : 
     304      331808 :   inline RAInst(RABlock* block, InstRWFlags instRWFlags, RATiedFlags tiedFlags, uint32_t tiedTotal, const RARegMask& clobberedRegs) noexcept {
     305      331808 :     _block = block;
     306      331808 :     _instRWFlags = instRWFlags;
     307      331808 :     _flags = tiedFlags;
     308      331808 :     _tiedTotal = tiedTotal;
     309             :     _tiedIndex.reset();
     310             :     _tiedCount.reset();
     311             :     _liveCount.reset();
     312             :     _usedRegs.reset();
     313      331808 :     _clobberedRegs = clobberedRegs;
     314      331808 :   }
     315             : 
     316             :   //! \}
     317             : 
     318             :   //! \name Accessors
     319             :   //! \{
     320             : 
     321             :   //! Returns instruction RW flags.
     322             :   inline InstRWFlags instRWFlags() const noexcept { return _instRWFlags; };
     323             :   //! Tests whether the given `flag` is present in instruction RW flags.
     324      331808 :   inline bool hasInstRWFlag(InstRWFlags flag) const noexcept { return Support::test(_instRWFlags, flag); }
     325             :   //! Adds `flags` to instruction RW flags.
     326             :   inline void addInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags |= flags; }
     327             : 
     328             :   //! Returns the instruction flags.
     329             :   inline RATiedFlags flags() const noexcept { return _flags; }
     330             :   //! Tests whether the instruction has flag `flag`.
     331      331808 :   inline bool hasFlag(RATiedFlags flag) const noexcept { return Support::test(_flags, flag); }
     332             :   //! Replaces the existing instruction flags with `flags`.
     333             :   inline void setFlags(RATiedFlags flags) noexcept { _flags = flags; }
     334             :   //! Adds instruction `flags` to this RAInst.
     335             :   inline void addFlags(RATiedFlags flags) noexcept { _flags |= flags; }
     336             :   //! Clears instruction `flags` from  this RAInst.
     337             :   inline void clearFlags(RATiedFlags flags) noexcept { _flags &= ~flags; }
     338             : 
     339             :   //! Tests whether this instruction can be transformed to another instruction if necessary.
     340             :   inline bool isTransformable() const noexcept { return hasFlag(RATiedFlags::kInst_IsTransformable); }
     341             : 
     342             :   //! Returns the associated block with this RAInst.
     343       27492 :   inline RABlock* block() const noexcept { return _block; }
     344             : 
     345             :   //! Returns tied registers (all).
     346     1580727 :   inline RATiedReg* tiedRegs() const noexcept { return const_cast<RATiedReg*>(_tiedRegs); }
     347             :   //! Returns tied registers for a given `group`.
     348     1327232 :   inline RATiedReg* tiedRegs(RegGroup group) const noexcept { return const_cast<RATiedReg*>(_tiedRegs) + _tiedIndex.get(group); }
     349             : 
     350             :   //! Returns count of all tied registers.
     351     1317593 :   inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
     352             :   //! Returns count of tied registers of a given `group`.
     353             :   inline uint32_t tiedCount(RegGroup group) const noexcept { return _tiedCount[group]; }
     354             : 
     355             :   //! Returns `RATiedReg` at the given `index`.
     356             :   inline RATiedReg* tiedAt(uint32_t index) const noexcept {
     357             :     ASMJIT_ASSERT(index < _tiedTotal);
     358      585303 :     return tiedRegs() + index;
     359             :   }
     360             : 
     361             :   //! Returns `RATiedReg` at the given `index` of the given register `group`.
     362             :   inline RATiedReg* tiedOf(RegGroup group, uint32_t index) const noexcept {
     363             :     ASMJIT_ASSERT(index < _tiedCount.get(group));
     364             :     return tiedRegs(group) + index;
     365             :   }
     366             : 
     367             :   inline void setTiedAt(uint32_t index, RATiedReg& tied) noexcept {
     368             :     ASMJIT_ASSERT(index < _tiedTotal);
     369             :     _tiedRegs[index] = tied;
     370             :   }
     371             : 
     372             :   //! \name Static Functions
     373             :   //! \{
     374             : 
     375             :   static inline size_t sizeOf(uint32_t tiedRegCount) noexcept {
     376      331808 :     return sizeof(RAInst) - sizeof(RATiedReg) + tiedRegCount * sizeof(RATiedReg);
     377             :   }
     378             : 
     379             :   //! \}
     380             : };
     381             : 
     382             : //! A helper class that is used to build an array of RATiedReg items that are then copied to `RAInst`.
     383             : class RAInstBuilder {
     384             : public:
     385             :   ASMJIT_NONCOPYABLE(RAInstBuilder)
     386             : 
     387             :   //! \name Members
     388             :   //! \{
     389             : 
     390             :   //! Instruction RW flags.
     391             :   InstRWFlags _instRWFlags;
     392             : 
     393             :   //! Flags combined from all RATiedReg's.
     394             :   RATiedFlags _aggregatedFlags;
     395             :   //! Flags that will be cleared before storing the aggregated flags to `RAInst`.
     396             :   RATiedFlags _forbiddenFlags;
     397             :   RARegCount _count;
     398             :   RARegsStats _stats;
     399             : 
     400             :   RARegMask _used;
     401             :   RARegMask _clobbered;
     402             : 
     403             :   //! Current tied register in `_tiedRegs`.
     404             :   RATiedReg* _cur;
     405             :   //! Array of temporary tied registers.
     406             :   RATiedReg _tiedRegs[128];
     407             : 
     408             :   //! \}
     409             : 
     410             :   //! \name Construction & Destruction
     411             :   //! \{
     412             : 
     413       27492 :   inline RAInstBuilder() noexcept { reset(); }
     414             : 
     415             :   inline void init() noexcept { reset(); }
     416      359300 :   inline void reset() noexcept {
     417      359300 :     _instRWFlags = InstRWFlags::kNone;
     418      359300 :     _aggregatedFlags = RATiedFlags::kNone;
     419      359300 :     _forbiddenFlags = RATiedFlags::kNone;
     420             :     _count.reset();
     421             :     _stats.reset();
     422             :     _used.reset();
     423             :     _clobbered.reset();
     424      359300 :     _cur = _tiedRegs;
     425      359300 :   }
     426             : 
     427             :   //! \}
     428             : 
     429             :   //! \name Accessors
     430             :   //! \{
     431             : 
     432      331808 :   inline InstRWFlags instRWFlags() const noexcept { return _instRWFlags; }
     433             :   inline bool hasInstRWFlag(InstRWFlags flag) const noexcept { return Support::test(_instRWFlags, flag); }
     434           0 :   inline void addInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags |= flags; }
     435             :   inline void clearInstRWFlags(InstRWFlags flags) noexcept { _instRWFlags &= ~flags; }
     436             : 
     437      331808 :   inline RATiedFlags aggregatedFlags() const noexcept { return _aggregatedFlags; }
     438           6 :   inline void addAggregatedFlags(RATiedFlags flags) noexcept { _aggregatedFlags |= flags; }
     439             : 
     440      331808 :   inline RATiedFlags forbiddenFlags() const noexcept { return _forbiddenFlags; }
     441             :   inline void addForbiddenFlags(RATiedFlags flags) noexcept { _forbiddenFlags |= flags; }
     442             : 
     443             :   //! Returns the number of tied registers added to the builder.
     444      636124 :   inline uint32_t tiedRegCount() const noexcept { return uint32_t((size_t)(_cur - _tiedRegs)); }
     445             : 
     446           0 :   inline RATiedReg* begin() noexcept { return _tiedRegs; }
     447           0 :   inline RATiedReg* end() noexcept { return _cur; }
     448             : 
     449             :   inline const RATiedReg* begin() const noexcept { return _tiedRegs; }
     450             :   inline const RATiedReg* end() const noexcept { return _cur; }
     451             : 
     452             :   //! Returns `RATiedReg` at the given `index`.
     453             :   inline RATiedReg* operator[](uint32_t index) noexcept {
     454             :     ASMJIT_ASSERT(index < tiedRegCount());
     455             :     return &_tiedRegs[index];
     456             :   }
     457             : 
     458             :   //! Returns `RATiedReg` at the given `index`. (const).
     459             :   inline const RATiedReg* operator[](uint32_t index) const noexcept {
     460             :     ASMJIT_ASSERT(index < tiedRegCount());
     461             :     return &_tiedRegs[index];
     462             :   }
     463             : 
     464             :   //! \}
     465             : 
     466             :   //! \name Utilities
     467             :   //! \{
     468             : 
     469      673873 :   Error add(
     470             :     RAWorkReg* workReg,
     471             :     RATiedFlags flags,
     472             :     RegMask useRegMask, uint32_t useId, uint32_t useRewriteMask,
     473             :     RegMask outRegMask, uint32_t outId, uint32_t outRewriteMask,
     474             :     uint32_t rmSize = 0,
     475             :     uint32_t consecutiveParent = Globals::kInvalidId) noexcept {
     476             : 
     477             :     RegGroup group = workReg->group();
     478             :     RATiedReg* tiedReg = workReg->tiedReg();
     479             : 
     480      673873 :     if (useId != BaseReg::kIdBad) {
     481             :       _stats.makeFixed(group);
     482       27492 :       _used[group] |= Support::bitMask(useId);
     483             :       flags |= RATiedFlags::kUseFixed;
     484             :     }
     485             : 
     486      673873 :     if (outId != BaseReg::kIdBad) {
     487           0 :       _clobbered[group] |= Support::bitMask(outId);
     488             :       flags |= RATiedFlags::kOutFixed;
     489             :     }
     490             : 
     491             :     _aggregatedFlags |= flags;
     492             :     _stats.makeUsed(group);
     493             : 
     494      673873 :     if (!tiedReg) {
     495             :       // Could happen when the builder is not reset properly after each instruction.
     496             :       ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
     497             : 
     498      594942 :       tiedReg = _cur++;
     499             :       tiedReg->init(workReg->workId(), flags, useRegMask, useId, useRewriteMask, outRegMask, outId, outRewriteMask, rmSize, consecutiveParent);
     500             :       workReg->setTiedReg(tiedReg);
     501             : 
     502             :       _count.add(group);
     503      594942 :       return kErrorOk;
     504             :     }
     505             :     else {
     506       78931 :       if (consecutiveParent != tiedReg->consecutiveParent()) {
     507           0 :         if (tiedReg->consecutiveParent() != Globals::kInvalidId)
     508             :           return DebugUtils::errored(kErrorInvalidState);
     509           0 :         tiedReg->_consecutiveParent = consecutiveParent;
     510             :       }
     511             : 
     512       78931 :       if (useId != BaseReg::kIdBad) {
     513           0 :         if (ASMJIT_UNLIKELY(tiedReg->hasUseId()))
     514             :           return DebugUtils::errored(kErrorOverlappedRegs);
     515             :         tiedReg->setUseId(useId);
     516             :       }
     517             : 
     518       78931 :       if (outId != BaseReg::kIdBad) {
     519           0 :         if (ASMJIT_UNLIKELY(tiedReg->hasOutId()))
     520             :           return DebugUtils::errored(kErrorOverlappedRegs);
     521             :         tiedReg->setOutId(outId);
     522             :       }
     523             : 
     524             :       tiedReg->addRefCount();
     525             :       tiedReg->addFlags(flags);
     526       78931 :       tiedReg->_useRegMask &= useRegMask;
     527       78931 :       tiedReg->_useRewriteMask |= useRewriteMask;
     528       78931 :       tiedReg->_outRegMask &= outRegMask;
     529       78931 :       tiedReg->_outRewriteMask |= outRewriteMask;
     530       78931 :       tiedReg->_rmSize = uint8_t(Support::max<uint32_t>(tiedReg->rmSize(), rmSize));
     531       78931 :       return kErrorOk;
     532             :     }
     533             :   }
     534             : 
     535        9873 :   Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept {
     536             :     ASMJIT_ASSERT(useId != BaseReg::kIdBad);
     537             : 
     538             :     RATiedFlags flags = RATiedFlags::kUse | RATiedFlags::kRead | RATiedFlags::kUseFixed;
     539             :     RegGroup group = workReg->group();
     540             :     RegMask allocable = Support::bitMask(useId);
     541             : 
     542             :     _aggregatedFlags |= flags;
     543        9873 :     _used[group] |= allocable;
     544             :     _stats.makeFixed(group);
     545             :     _stats.makeUsed(group);
     546             : 
     547             :     RATiedReg* tiedReg = workReg->tiedReg();
     548        9873 :     if (!tiedReg) {
     549             :       // Could happen when the builder is not reset properly after each instruction.
     550             :       ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
     551             : 
     552        9873 :       tiedReg = _cur++;
     553             :       tiedReg->init(workReg->workId(), flags, allocable, useId, 0, allocable, BaseReg::kIdBad, 0);
     554             :       workReg->setTiedReg(tiedReg);
     555             : 
     556             :       _count.add(group);
     557        9873 :       return kErrorOk;
     558             :     }
     559             :     else {
     560           0 :       if (tiedReg->hasUseId()) {
     561             :         flags |= RATiedFlags::kDuplicate;
     562           0 :         tiedReg->_useRegMask |= allocable;
     563             :       }
     564             :       else {
     565             :         tiedReg->setUseId(useId);
     566           0 :         tiedReg->_useRegMask &= allocable;
     567             :       }
     568             : 
     569             :       tiedReg->addRefCount();
     570             :       tiedReg->addFlags(flags);
     571           0 :       return kErrorOk;
     572             :     }
     573             :   }
     574             : 
     575        9639 :   Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept {
     576             :     ASMJIT_ASSERT(outId != BaseReg::kIdBad);
     577             : 
     578             :     RATiedFlags flags = RATiedFlags::kOut | RATiedFlags::kWrite | RATiedFlags::kOutFixed;
     579             :     RegGroup group = workReg->group();
     580             :     RegMask outRegs = Support::bitMask(outId);
     581             : 
     582             :     _aggregatedFlags |= flags;
     583        9639 :     _used[group] |= outRegs;
     584             :     _stats.makeFixed(group);
     585             :     _stats.makeUsed(group);
     586             : 
     587             :     RATiedReg* tiedReg = workReg->tiedReg();
     588        9639 :     if (!tiedReg) {
     589             :       // Could happen when the builder is not reset properly after each instruction.
     590             :       ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
     591             : 
     592        9639 :       tiedReg = _cur++;
     593             :       tiedReg->init(workReg->workId(), flags, Support::allOnes<RegMask>(), BaseReg::kIdBad, 0, outRegs, outId, 0);
     594             :       workReg->setTiedReg(tiedReg);
     595             : 
     596             :       _count.add(group);
     597        9639 :       return kErrorOk;
     598             :     }
     599             :     else {
     600           0 :       if (tiedReg->hasOutId())
     601             :         return DebugUtils::errored(kErrorOverlappedRegs);
     602             : 
     603             :       tiedReg->addRefCount();
     604             :       tiedReg->addFlags(flags);
     605             :       tiedReg->setOutId(outId);
     606           0 :       return kErrorOk;
     607             :     }
     608             :   }
     609             : 
     610             :   //! \}
     611             : };
     612             : 
     613             : //! Intersection of multiple register assignments.
     614             : //!
     615             : //! See \ref RAAssignment for more information about register assignments.
     616             : class RASharedAssignment {
     617             : public:
     618             :   typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
     619             :   typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
     620             : 
     621             :   //! \name Members
     622             :   //! \{
     623             : 
     624             :   //! Bit-mask of registers that cannot be used upon a block entry, for each block that has this shared assignment.
     625             :   //! Scratch registers can come from ISA limits (like jecx/loop instructions on x86) or because the registers are
     626             :   //! used by jump/branch instruction that uses registers to perform an indirect jump.
     627             :   RegMask _entryScratchGpRegs = 0;
     628             :   //! Union of all live-in registers.
     629             :   ZoneBitVector _liveIn {};
     630             :   //! Register assignment (PhysToWork).
     631             :   PhysToWorkMap* _physToWorkMap = nullptr;
     632             : 
     633             :   //! \}
     634             : 
     635             :   //! \name Accessors
     636             :   //! \{
     637             : 
     638           0 :   inline bool empty() const noexcept { return _physToWorkMap == nullptr; }
     639             : 
     640           0 :   inline RegMask entryScratchGpRegs() const noexcept { return _entryScratchGpRegs; }
     641           0 :   inline void addEntryScratchGpRegs(RegMask mask) noexcept { _entryScratchGpRegs |= mask; }
     642             : 
     643           0 :   inline const ZoneBitVector& liveIn() const noexcept { return _liveIn; }
     644             : 
     645             :   inline PhysToWorkMap* physToWorkMap() const noexcept { return _physToWorkMap; }
     646           0 :   inline void assignPhysToWorkMap(PhysToWorkMap* physToWorkMap) noexcept { _physToWorkMap = physToWorkMap; }
     647             : 
     648             :   //! \}
     649             : };
     650             : 
     651             : //! Register allocation pass used by `BaseCompiler`.
     652             : class BaseRAPass : public FuncPass {
     653             : public:
     654             :   ASMJIT_NONCOPYABLE(BaseRAPass)
     655             :   typedef FuncPass Base;
     656             : 
     657             :   enum : uint32_t {
     658             :     kCallArgWeight = 80
     659             :   };
     660             : 
     661             :   typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
     662             :   typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
     663             : 
     664             :   //! \name Members
     665             :   //! \{
     666             : 
     667             :   //! Allocator that uses zone passed to `runOnFunction()`.
     668             :   ZoneAllocator _allocator {};
     669             :   //! Emit helper.
     670             :   BaseEmitHelper* _iEmitHelper = nullptr;
     671             : 
     672             :   //! Logger, disabled if null.
     673             :   Logger* _logger = nullptr;
     674             :   //! Format options, copied from Logger, or zeroed if there is no logger.
     675             :   FormatOptions _formatOptions {};
     676             :   //! Diagnostic options, copied from Emitter, or zeroed if there is no logger.
     677             :   DiagnosticOptions _diagnosticOptions {};
     678             : 
     679             :   //! Function being processed.
     680             :   FuncNode* _func = nullptr;
     681             :   //! Stop node.
     682             :   BaseNode* _stop = nullptr;
     683             :   //! Node that is used to insert extra code after the function body.
     684             :   BaseNode* _extraBlock = nullptr;
     685             : 
     686             :   //! Blocks (first block is the entry, always exists).
     687             :   RABlocks _blocks {};
     688             :   //! Function exit blocks (usually one, but can contain more).
     689             :   RABlocks _exits {};
     690             :   //! Post order view (POV).
     691             :   RABlocks _pov {};
     692             : 
     693             :   //! Number of instruction nodes.
     694             :   uint32_t _instructionCount = 0;
     695             :   //! Number of created blocks (internal).
     696             :   uint32_t _createdBlockCount = 0;
     697             : 
     698             :   //! Shared assignment blocks.
     699             :   ZoneVector<RASharedAssignment> _sharedAssignments {};
     700             : 
     701             :   //! Timestamp generator (incremental).
     702             :   mutable uint64_t _lastTimestamp = 0;
     703             : 
     704             :   //! Architecture traits.
     705             :   const ArchTraits* _archTraits = nullptr;
     706             :   //! Index to physical registers in `RAAssignment::PhysToWorkMap`.
     707             :   RARegIndex _physRegIndex = RARegIndex();
     708             :   //! Count of physical registers in `RAAssignment::PhysToWorkMap`.
     709             :   RARegCount _physRegCount = RARegCount();
     710             :   //! Total number of physical registers.
     711             :   uint32_t _physRegTotal = 0;
     712             :   //! Indexes of a possible scratch registers that can be selected if necessary.
     713             :   Support::Array<uint8_t, 2> _scratchRegIndexes {};
     714             : 
     715             :   //! Registers available for allocation.
     716             :   RARegMask _availableRegs = RARegMask();
     717             :   //! Count of physical registers per group.
     718             :   RARegCount _availableRegCount = RARegCount();
     719             :   //! Registers clobbered by the function.
     720             :   RARegMask _clobberedRegs = RARegMask();
     721             : 
     722             :   //! Work registers (registers used by the function).
     723             :   RAWorkRegs _workRegs;
     724             :   //! Work registers per register group.
     725             :   Support::Array<RAWorkRegs, Globals::kNumVirtGroups> _workRegsOfGroup;
     726             : 
     727             :   //! Register allocation strategy per register group.
     728             :   Support::Array<RAStrategy, Globals::kNumVirtGroups> _strategy;
     729             :   //! Global max live-count (from all blocks) per register group.
     730             :   RALiveCount _globalMaxLiveCount = RALiveCount();
     731             :   //! Global live spans per register group.
     732             :   Support::Array<LiveRegSpans*, Globals::kNumVirtGroups> _globalLiveSpans {};
     733             :   //! Temporary stack slot.
     734             :   Operand _temporaryMem = Operand();
     735             : 
     736             :   //! Stack pointer.
     737             :   BaseReg _sp = BaseReg();
     738             :   //! Frame pointer.
     739             :   BaseReg _fp = BaseReg();
     740             :   //! Stack manager.
     741             :   RAStackAllocator _stackAllocator {};
     742             :   //! Function arguments assignment.
     743             :   FuncArgsAssignment _argsAssignment {};
     744             :   //! Some StackArgs have to be assigned to StackSlots.
     745             :   uint32_t _numStackArgsToStackSlots = 0;
     746             : 
     747             :   //! Maximum name-size computed from all WorkRegs.
     748             :   uint32_t _maxWorkRegNameSize = 0;
     749             :   //! Temporary string builder used to format comments.
     750             :   StringTmp<80> _tmpString;
     751             : 
     752             :   //! \}
     753             : 
     754             :   //! \name Construction & Destruction
     755             :   //! \{
     756             : 
     757             :   BaseRAPass() noexcept;
     758             :   virtual ~BaseRAPass() noexcept;
     759             : 
     760             :   //! \}
     761             : 
     762             :   //! \name Accessors
     763             :   //! \{
     764             : 
     765             :   //! Returns \ref Logger passed to \ref runOnFunction().
     766           0 :   inline Logger* logger() const noexcept { return _logger; }
     767             : 
     768             :   //! Returns either a valid logger if the given `option` is set and logging is enabled, or nullptr.
     769      137460 :   inline Logger* getLoggerIf(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option) ? _logger : nullptr; }
     770             : 
     771             :   //! Returns whether the diagnostic `option` is enabled.
     772             :   //!
     773             :   //! \note Returns false if there is no logger (as diagnostics without logging make no sense).
     774      105205 :   inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
     775             : 
     776             :   //! Returns \ref Zone passed to \ref runOnFunction().
     777             :   inline Zone* zone() const noexcept { return _allocator.zone(); }
     778             :   //! Returns \ref ZoneAllocator used by the register allocator.
     779      601218 :   inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); }
     780             : 
     781             :   inline const ZoneVector<RASharedAssignment>& sharedAssignments() const { return _sharedAssignments; }
     782             :   inline uint32_t sharedAssignmentCount() const noexcept { return _sharedAssignments.size(); }
     783             : 
     784             :   //! Returns the current function node.
     785      202083 :   inline FuncNode* func() const noexcept { return _func; }
     786             :   //! Returns the stop of the current function.
     787             :   inline BaseNode* stop() const noexcept { return _stop; }
     788             : 
     789             :   //! Returns an extra block used by the current function being processed.
     790           0 :   inline BaseNode* extraBlock() const noexcept { return _extraBlock; }
     791             :   //! Sets an extra block, see `extraBlock()`.
     792             :   inline void setExtraBlock(BaseNode* node) noexcept { _extraBlock = node; }
     793             : 
     794             :   inline uint32_t endPosition() const noexcept { return _instructionCount * 2; }
     795             : 
     796             :   inline const RARegMask& availableRegs() const noexcept { return _availableRegs; }
     797             :   inline const RARegMask& cloberredRegs() const noexcept { return _clobberedRegs; }
     798             : 
     799             :   //! \}
     800             : 
     801             :   //! \name Utilities
     802             :   //! \{
     803             : 
     804             :   inline void makeUnavailable(RegGroup group, uint32_t regId) noexcept {
     805       27492 :     _availableRegs[group] &= ~Support::bitMask(regId);
     806       27492 :     _availableRegCount[group]--;
     807           0 :   }
     808             : 
     809             :   //! Runs the register allocator for the given `func`.
     810             :   Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) override;
     811             : 
     812             :   //! Performs all allocation steps sequentially, called by `runOnFunction()`.
     813             :   Error onPerformAllSteps() noexcept;
     814             : 
     815             :   //! \}
     816             : 
     817             :   //! \name Events
     818             :   //! \{
     819             : 
     820             :   //! Called by \ref runOnFunction() before the register allocation to initialize
     821             :   //! architecture-specific data and constraints.
     822             :   virtual void onInit() noexcept = 0;
     823             : 
     824             :   //! Called by \ref runOnFunction(` after register allocation to clean everything
     825             :   //! up. Called even if the register allocation failed.
     826             :   virtual void onDone() noexcept = 0;
     827             : 
     828             :   //! \}
     829             : 
     830             :   //! \name CFG - Basic-Block Management
     831             :   //! \{
     832             : 
     833             :   //! Returns the function's entry block.
     834             :   inline RABlock* entryBlock() noexcept {
     835             :     ASMJIT_ASSERT(!_blocks.empty());
     836       82476 :     return _blocks[0];
     837             :   }
     838             : 
     839             :   //! \overload
     840             :   inline const RABlock* entryBlock() const noexcept {
     841             :     ASMJIT_ASSERT(!_blocks.empty());
     842           0 :     return _blocks[0];
     843             :   }
     844             : 
     845             :   //! Returns all basic blocks of this function.
     846             :   inline RABlocks& blocks() noexcept { return _blocks; }
     847             :   //! \overload
     848             :   inline const RABlocks& blocks() const noexcept { return _blocks; }
     849             : 
     850             :   //! Returns the count of basic blocks (returns size of `_blocks` array).
     851             :   inline uint32_t blockCount() const noexcept { return _blocks.size(); }
     852             :   //! Returns the count of reachable basic blocks (returns size of `_pov` array).
     853             :   inline uint32_t reachableBlockCount() const noexcept { return _pov.size(); }
     854             : 
     855             :   //! Tests whether the CFG has dangling blocks - these were created by `newBlock()`, but not added to CFG through
     856             :   //! `addBlocks()`. If `true` is returned and the  CFG is constructed it means that something is missing and it's
     857             :   //! incomplete.
     858             :   //!
     859             :   //! \note This is only used to check if the number of created blocks matches the number of added blocks.
     860       27492 :   inline bool hasDanglingBlocks() const noexcept { return _createdBlockCount != blockCount(); }
     861             : 
     862             :   //! Gest a next timestamp to be used to mark CFG blocks.
     863           0 :   inline uint64_t nextTimestamp() const noexcept { return ++_lastTimestamp; }
     864             : 
     865             :   //! Createss a new `RABlock` instance.
     866             :   //!
     867             :   //! \note New blocks don't have ID assigned until they are added to the block array by calling `addBlock()`.
     868             :   RABlock* newBlock(BaseNode* initialNode = nullptr) noexcept;
     869             : 
     870             :   //! Tries to find a neighboring LabelNode (without going through code) that is already connected with `RABlock`.
     871             :   //! If no label is found then a new RABlock is created and assigned to all possible labels in a backward direction.
     872             :   RABlock* newBlockOrExistingAt(LabelNode* cbLabel, BaseNode** stoppedAt = nullptr) noexcept;
     873             : 
     874             :   //! Adds the given `block` to the block list and assign it a unique block id.
     875             :   Error addBlock(RABlock* block) noexcept;
     876             : 
     877       54984 :   inline Error addExitBlock(RABlock* block) noexcept {
     878       54984 :     block->addFlags(RABlockFlags::kIsFuncExit);
     879       54984 :     return _exits.append(allocator(), block);
     880             :   }
     881             : 
     882             :   ASMJIT_FORCE_INLINE RAInst* newRAInst(RABlock* block, InstRWFlags instRWFlags, RATiedFlags flags, uint32_t tiedRegCount, const RARegMask& clobberedRegs) noexcept {
     883      331808 :     void* p = zone()->alloc(RAInst::sizeOf(tiedRegCount));
     884      331808 :     if (ASMJIT_UNLIKELY(!p))
     885             :       return nullptr;
     886      331808 :     return new(p) RAInst(block, instRWFlags, flags, tiedRegCount, clobberedRegs);
     887             :   }
     888             : 
     889             :   ASMJIT_FORCE_INLINE Error assignRAInst(BaseNode* node, RABlock* block, RAInstBuilder& ib) noexcept {
     890             :     uint32_t tiedRegCount = ib.tiedRegCount();
     891             :     RAInst* raInst = newRAInst(block, ib.instRWFlags(), ib.aggregatedFlags(), tiedRegCount, ib._clobbered);
     892             : 
     893      331808 :     if (ASMJIT_UNLIKELY(!raInst))
     894             :       return DebugUtils::errored(kErrorOutOfMemory);
     895             : 
     896             :     RARegIndex index;
     897             :     RATiedFlags flagsFilter = ~ib.forbiddenFlags();
     898             : 
     899             :     index.buildIndexes(ib._count);
     900      331808 :     raInst->_tiedIndex = index;
     901      331808 :     raInst->_tiedCount = ib._count;
     902             : 
     903      946262 :     for (uint32_t i = 0; i < tiedRegCount; i++) {
     904             :       RATiedReg* tiedReg = ib[i];
     905             :       RAWorkReg* workReg = workRegById(tiedReg->workId());
     906             : 
     907             :       workReg->resetTiedReg();
     908             :       RegGroup group = workReg->group();
     909             : 
     910      614454 :       if (tiedReg->hasUseId()) {
     911             :         block->addFlags(RABlockFlags::kHasFixedRegs);
     912       37365 :         raInst->_usedRegs[group] |= Support::bitMask(tiedReg->useId());
     913             :       }
     914             : 
     915      614454 :       if (tiedReg->hasOutId()) {
     916             :         block->addFlags(RABlockFlags::kHasFixedRegs);
     917             :       }
     918             : 
     919      614454 :       RATiedReg& dst = raInst->_tiedRegs[index[group]++];
     920      614454 :       dst = *tiedReg;
     921             :       dst._flags &= flagsFilter;
     922             : 
     923      614454 :       if (!tiedReg->isDuplicate())
     924      614454 :         dst._useRegMask &= ~ib._used[group];
     925             :     }
     926             : 
     927             :     node->setPassData<RAInst>(raInst);
     928             :     return kErrorOk;
     929             :   }
     930             : 
     931             :   //! \}
     932             : 
     933             :   //! \name CFG - Build CFG
     934             :   //! \{
     935             : 
     936             :   //! Traverse the whole function and do the following:
     937             :   //!
     938             :   //!   1. Construct CFG (represented by `RABlock`) by populating `_blocks` and `_exits`. Blocks describe the control
     939             :   //!      flow of the function and contain some additional information that is used by the register allocator.
     940             :   //!
     941             :   //!   2. Remove unreachable code immediately. This is not strictly necessary for BaseCompiler itself as the register
     942             :   //!      allocator cannot reach such nodes, but keeping instructions that use virtual registers would fail during
     943             :   //!      instruction encoding phase (Assembler).
     944             :   //!
     945             :   //!   3. `RAInst` is created for each `InstNode` or compatible. It contains information that is essential for further
     946             :   //!      analysis and register allocation.
     947             :   //!
     948             :   //! Use `RACFGBuilderT` template that provides the necessary boilerplate.
     949             :   virtual Error buildCFG() noexcept = 0;
     950             : 
     951             :   //! Called after the CFG is built.
     952             :   Error initSharedAssignments(const ZoneVector<uint32_t>& sharedAssignmentsMap) noexcept;
     953             : 
     954             :   //! \}
     955             : 
     956             :   //! \name CFG - Views Order
     957             :   //! \{
     958             : 
     959             :   //! Constructs CFG views (only POV at the moment).
     960             :   Error buildCFGViews() noexcept;
     961             : 
     962             :   //! \}
     963             : 
     964             :   //! \name CFG - Dominators
     965             :   //! \{
     966             : 
     967             :   // Terminology:
     968             :   //   - A node `X` dominates a node `Z` if any path from the entry point to `Z` has to go through `X`.
     969             :   //   - A node `Z` post-dominates a node `X` if any path from `X` to the end of the graph has to go through `Z`.
     970             : 
     971             :   //! Constructs a dominator-tree from CFG.
     972             :   Error buildCFGDominators() noexcept;
     973             : 
     974             :   bool _strictlyDominates(const RABlock* a, const RABlock* b) const noexcept;
     975             :   const RABlock* _nearestCommonDominator(const RABlock* a, const RABlock* b) const noexcept;
     976             : 
     977             :   //! Tests whether the basic block `a` dominates `b` - non-strict, returns true when `a == b`.
     978             :   inline bool dominates(const RABlock* a, const RABlock* b) const noexcept { return a == b ? true : _strictlyDominates(a, b); }
     979             :   //! Tests whether the basic block `a` dominates `b` - strict dominance check, returns false when `a == b`.
     980             :   inline bool strictlyDominates(const RABlock* a, const RABlock* b) const noexcept { return a == b ? false : _strictlyDominates(a, b); }
     981             : 
     982             :   //! Returns a nearest common dominator of `a` and `b`.
     983             :   inline RABlock* nearestCommonDominator(RABlock* a, RABlock* b) const noexcept { return const_cast<RABlock*>(_nearestCommonDominator(a, b)); }
     984             :   //! Returns a nearest common dominator of `a` and `b` (const).
     985             :   inline const RABlock* nearestCommonDominator(const RABlock* a, const RABlock* b) const noexcept { return _nearestCommonDominator(a, b); }
     986             : 
     987             :   //! \}
     988             : 
     989             :   //! \name CFG - Utilities
     990             :   //! \{
     991             : 
     992             :   Error removeUnreachableCode() noexcept;
     993             : 
     994             :   //! Returns `node` or some node after that is ideal for beginning a new block. This function is mostly used after
     995             :   //! a conditional or unconditional jump to select the successor node. In some cases the next node could be a label,
     996             :   //! which means it could have assigned some block already.
     997             :   BaseNode* findSuccessorStartingAt(BaseNode* node) noexcept;
     998             : 
     999             :   //! Returns `true` of the `node` can flow to `target` without reaching code nor data. It's used to eliminate jumps
    1000             :   //! to labels that are next right to them.
    1001             :   bool isNextTo(BaseNode* node, BaseNode* target) noexcept;
    1002             : 
    1003             :   //! \}
    1004             : 
    1005             :   //! \name Virtual Register Management
    1006             :   //! \{
    1007             : 
    1008             :   //! Returns a native size of the general-purpose register of the target architecture.
    1009             :   inline uint32_t registerSize() const noexcept { return _sp.size(); }
    1010             :   inline uint32_t availableRegCount(RegGroup group) const noexcept { return _availableRegCount[group]; }
    1011             : 
    1012     2337051 :   inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _workRegs[workId]; }
    1013             : 
    1014      326298 :   inline RAWorkRegs& workRegs() noexcept { return _workRegs; }
    1015             :   inline RAWorkRegs& workRegs(RegGroup group) noexcept { return _workRegsOfGroup[group]; }
    1016             : 
    1017             :   inline const RAWorkRegs& workRegs() const noexcept { return _workRegs; }
    1018             :   inline const RAWorkRegs& workRegs(RegGroup group) const noexcept { return _workRegsOfGroup[group]; }
    1019             : 
    1020             :   inline uint32_t workRegCount() const noexcept { return _workRegs.size(); }
    1021             :   inline uint32_t workRegCount(RegGroup group) const noexcept { return _workRegsOfGroup[group].size(); }
    1022             : 
    1023       27492 :   inline void _buildPhysIndex() noexcept {
    1024             :     _physRegIndex.buildIndexes(_physRegCount);
    1025       27492 :     _physRegTotal = uint32_t(_physRegIndex[RegGroup::kMaxVirt]) +
    1026       27492 :                     uint32_t(_physRegCount[RegGroup::kMaxVirt]) ;
    1027       27492 :   }
    1028             :   inline uint32_t physRegIndex(RegGroup group) const noexcept { return _physRegIndex[group]; }
    1029       54984 :   inline uint32_t physRegTotal() const noexcept { return _physRegTotal; }
    1030             : 
    1031             :   Error _asWorkReg(VirtReg* vReg, RAWorkReg** out) noexcept;
    1032             : 
    1033             :   //! Creates `RAWorkReg` data for the given `vReg`. The function does nothing
    1034             :   //! if `vReg` already contains link to `RAWorkReg`. Called by `constructBlocks()`.
    1035             :   inline Error asWorkReg(VirtReg* vReg, RAWorkReg** out) noexcept {
    1036      712709 :     *out = vReg->workReg();
    1037      712709 :     return *out ? kErrorOk : _asWorkReg(vReg, out);
    1038             :   }
    1039             : 
    1040             :   ASMJIT_FORCE_INLINE Error virtIndexAsWorkReg(uint32_t vIndex, RAWorkReg** out) noexcept {
    1041             :     const ZoneVector<VirtReg*>& virtRegs = cc()->virtRegs();
    1042      712709 :     if (ASMJIT_UNLIKELY(vIndex >= virtRegs.size()))
    1043             :       return DebugUtils::errored(kErrorInvalidVirtId);
    1044      712709 :     return asWorkReg(virtRegs[vIndex], out);
    1045             :   }
    1046             : 
    1047       71131 :   inline RAStackSlot* getOrCreateStackSlot(RAWorkReg* workReg) noexcept {
    1048             :     RAStackSlot* slot = workReg->stackSlot();
    1049             : 
    1050       71131 :     if (slot)
    1051             :       return slot;
    1052             : 
    1053       30798 :     slot = _stackAllocator.newSlot(_sp.id(), workReg->virtReg()->virtSize(), workReg->virtReg()->alignment(), RAStackSlot::kFlagRegHome);
    1054       30798 :     workReg->_stackSlot = slot;
    1055             :     workReg->markStackUsed();
    1056       30798 :     return slot;
    1057             :   }
    1058             : 
    1059       71131 :   inline BaseMem workRegAsMem(RAWorkReg* workReg) noexcept {
    1060       71131 :     getOrCreateStackSlot(workReg);
    1061             :     return BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
    1062             :                    OperandSignature::fromMemBaseType(_sp.type()) |
    1063             :                    OperandSignature::fromBits(OperandSignature::kMemRegHomeFlag),
    1064       71131 :                    workReg->virtId(), 0, 0);
    1065             :   }
    1066             : 
    1067             :   WorkToPhysMap* newWorkToPhysMap() noexcept;
    1068             :   PhysToWorkMap* newPhysToWorkMap() noexcept;
    1069             : 
    1070       54984 :   inline PhysToWorkMap* clonePhysToWorkMap(const PhysToWorkMap* map) noexcept {
    1071       54984 :     size_t size = PhysToWorkMap::sizeOf(_physRegTotal);
    1072       54984 :     return static_cast<PhysToWorkMap*>(zone()->dupAligned(map, size, sizeof(uint32_t)));
    1073             :   }
    1074             : 
    1075             :   //! \name Liveness Analysis & Statistics
    1076             :   //! \{
    1077             : 
    1078             :   //! 1. Calculates GEN/KILL/IN/OUT of each block.
    1079             :   //! 2. Calculates live spans and basic statistics of each work register.
    1080             :   Error buildLiveness() noexcept;
    1081             : 
    1082             :   //! Assigns argIndex to WorkRegs. Must be called after the liveness analysis
    1083             :   //! finishes as it checks whether the argument is live upon entry.
    1084             :   Error assignArgIndexToWorkRegs() noexcept;
    1085             : 
    1086             :   //! \}
    1087             : 
    1088             :   //! \name Register Allocation - Global
    1089             :   //! \{
    1090             : 
    1091             :   //! Runs a global register allocator.
    1092             :   Error runGlobalAllocator() noexcept;
    1093             : 
    1094             :   //! Initializes data structures used for global live spans.
    1095             :   Error initGlobalLiveSpans() noexcept;
    1096             : 
    1097             :   Error binPack(RegGroup group) noexcept;
    1098             : 
    1099             :   //! \}
    1100             : 
    1101             :   //! \name Register Allocation - Local
    1102             :   //! \{
    1103             : 
    1104             :   //! Runs a local register allocator.
    1105             :   Error runLocalAllocator() noexcept;
    1106             :   Error setBlockEntryAssignment(RABlock* block, const RABlock* fromBlock, const RAAssignment& fromAssignment) noexcept;
    1107             :   Error setSharedAssignment(uint32_t sharedAssignmentId, const RAAssignment& fromAssignment) noexcept;
    1108             : 
    1109             :   //! Called after the RA assignment has been assigned to a block.
    1110             :   //!
    1111             :   //! This cannot change the assignment, but can examine it.
    1112             :   Error blockEntryAssigned(const PhysToWorkMap* physToWorkMap) noexcept;
    1113             : 
    1114             :   //! \}
    1115             : 
    1116             :   //! \name Register Allocation Utilities
    1117             :   //! \{
    1118             : 
    1119             :   Error useTemporaryMem(BaseMem& out, uint32_t size, uint32_t alignment) noexcept;
    1120             : 
    1121             :   //! \}
    1122             : 
    1123             :   //! \name Function Prolog & Epilog
    1124             :   //! \{
    1125             : 
    1126             :   virtual Error updateStackFrame() noexcept;
    1127             :   Error _markStackArgsToKeep() noexcept;
    1128             :   Error _updateStackArgs() noexcept;
    1129             :   Error insertPrologEpilog() noexcept;
    1130             : 
    1131             :   //! \}
    1132             : 
    1133             :   //! \name Instruction Rewriter
    1134             :   //! \{
    1135             : 
    1136             :   Error rewrite() noexcept;
    1137             :   virtual Error _rewrite(BaseNode* first, BaseNode* stop) noexcept = 0;
    1138             : 
    1139             :   //! \}
    1140             : 
    1141             : #ifndef ASMJIT_NO_LOGGING
    1142             :   //! \name Logging
    1143             :   //! \{
    1144             : 
    1145             :   Error annotateCode() noexcept;
    1146             : 
    1147             :   Error _dumpBlockIds(String& sb, const RABlocks& blocks) noexcept;
    1148             :   Error _dumpBlockLiveness(String& sb, const RABlock* block) noexcept;
    1149             :   Error _dumpLiveSpans(String& sb) noexcept;
    1150             : 
    1151             :   //! \}
    1152             : #endif
    1153             : 
    1154             :   //! \name Emit
    1155             :   //! \{
    1156             : 
    1157             :   virtual Error emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept = 0;
    1158             :   virtual Error emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept = 0;
    1159             : 
    1160             :   virtual Error emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept = 0;
    1161             :   virtual Error emitSave(uint32_t workId, uint32_t srcPhysId) noexcept = 0;
    1162             : 
    1163             :   virtual Error emitJump(const Label& label) noexcept = 0;
    1164             :   virtual Error emitPreCall(InvokeNode* invokeNode) noexcept = 0;
    1165             : 
    1166             :   //! \}
    1167             : };
    1168             : 
    1169      274920 : inline ZoneAllocator* RABlock::allocator() const noexcept { return _ra->allocator(); }
    1170             : 
    1171             : inline RegMask RABlock::entryScratchGpRegs() const noexcept {
    1172       27492 :   RegMask regs = _entryScratchGpRegs;
    1173       27492 :   if (hasSharedAssignmentId())
    1174           0 :     regs = _ra->_sharedAssignments[_sharedAssignmentId].entryScratchGpRegs();
    1175             :   return regs;
    1176             : }
    1177             : 
    1178             : //! \}
    1179             : //! \endcond
    1180             : 
    1181             : ASMJIT_END_NAMESPACE
    1182             : 
    1183             : #endif // !ASMJIT_NO_COMPILER
    1184             : #endif // ASMJIT_CORE_RAPASS_P_H_INCLUDED
    1185             : 
    1186             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16