diff options
Diffstat (limited to '3rdparty/asmjit/src/asmjit/core/ralocal_p.h')
-rw-r--r-- | 3rdparty/asmjit/src/asmjit/core/ralocal_p.h | 167 |
1 files changed, 66 insertions, 101 deletions
diff --git a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h index c944aad2bb4..63fd1b78aba 100644 --- a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h +++ b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h @@ -1,25 +1,7 @@ -// AsmJit - Machine code generation for C++ +// This file is part of AsmJit project <https://asmjit.com> // -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib #ifndef ASMJIT_CORE_RALOCAL_P_H_INCLUDED #define ASMJIT_CORE_RALOCAL_P_H_INCLUDED @@ -38,10 +20,6 @@ ASMJIT_BEGIN_NAMESPACE //! \addtogroup asmjit_ra //! \{ -// ============================================================================ -// [asmjit::RALocalAllocator] -// ============================================================================ - //! Local register allocator. class RALocalAllocator { public: @@ -50,50 +28,46 @@ public: typedef RAAssignment::PhysToWorkMap PhysToWorkMap; typedef RAAssignment::WorkToPhysMap WorkToPhysMap; - //! Link to `RAPass`. - RAPass* _pass; + //! Link to `BaseRAPass`. + BaseRAPass* _pass {}; //! Link to `BaseCompiler`. - BaseCompiler* _cc; + BaseCompiler* _cc {}; //! Architecture traits. - RAArchTraits _archTraits; + const ArchTraits* _archTraits {}; //! Registers available to the allocator. - RARegMask _availableRegs; + RARegMask _availableRegs {}; //! Registers clobbered by the allocator. - RARegMask _clobberedRegs; + RARegMask _clobberedRegs {}; //! Register assignment (current). - RAAssignment _curAssignment; + RAAssignment _curAssignment {}; //! Register assignment used temporarily during assignment switches. - RAAssignment _tmpAssignment; + RAAssignment _tmpAssignment {}; //! Link to the current `RABlock`. - RABlock* _block; + RABlock* _block {}; //! InstNode. - InstNode* _node; + InstNode* _node {}; //! RA instruction. - RAInst* _raInst; + RAInst* _raInst {}; //! Count of all TiedReg's. - uint32_t _tiedTotal; + uint32_t _tiedTotal {}; //! TiedReg's total counter. - RARegCount _tiedCount; + RARegCount _tiedCount {}; + + //! Temporary workToPhysMap that can be used freely by the allocator. + WorkToPhysMap* _tmpWorkToPhysMap {}; //! \name Construction & Destruction //! \{ - inline RALocalAllocator(RAPass* pass) noexcept + inline explicit RALocalAllocator(BaseRAPass* pass) noexcept : _pass(pass), _cc(pass->cc()), _archTraits(pass->_archTraits), - _availableRegs(pass->_availableRegs), - _clobberedRegs(), - _curAssignment(), - _block(nullptr), - _node(nullptr), - _raInst(nullptr), - _tiedTotal(), - _tiedCount() {} + _availableRegs(pass->_availableRegs) {} Error init() noexcept; @@ -102,31 +76,31 @@ public: //! \name Accessors //! \{ - inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _pass->workRegById(workId); } - inline PhysToWorkMap* physToWorkMap() const noexcept { return _curAssignment.physToWorkMap(); } - inline WorkToPhysMap* workToPhysMap() const noexcept { return _curAssignment.workToPhysMap(); } + ASMJIT_INLINE_NODEBUG RAWorkReg* workRegById(uint32_t workId) const noexcept { return _pass->workRegById(workId); } + ASMJIT_INLINE_NODEBUG PhysToWorkMap* physToWorkMap() const noexcept { return _curAssignment.physToWorkMap(); } + ASMJIT_INLINE_NODEBUG WorkToPhysMap* workToPhysMap() const noexcept { return _curAssignment.workToPhysMap(); } //! Returns the currently processed block. - inline RABlock* block() const noexcept { return _block; } + ASMJIT_INLINE_NODEBUG RABlock* block() const noexcept { return _block; } //! Sets the currently processed block. - inline void setBlock(RABlock* block) noexcept { _block = block; } + ASMJIT_INLINE_NODEBUG void setBlock(RABlock* block) noexcept { _block = block; } //! Returns the currently processed `InstNode`. - inline InstNode* node() const noexcept { return _node; } + ASMJIT_INLINE_NODEBUG InstNode* node() const noexcept { return _node; } //! Returns the currently processed `RAInst`. - inline RAInst* raInst() const noexcept { return _raInst; } + ASMJIT_INLINE_NODEBUG RAInst* raInst() const noexcept { return _raInst; } //! Returns all tied regs as `RATiedReg` array. - inline RATiedReg* tiedRegs() const noexcept { return _raInst->tiedRegs(); } + ASMJIT_INLINE_NODEBUG RATiedReg* tiedRegs() const noexcept { return _raInst->tiedRegs(); } //! Returns tied registers grouped by the given `group`. - inline RATiedReg* tiedRegs(uint32_t group) const noexcept { return _raInst->tiedRegs(group); } + ASMJIT_INLINE_NODEBUG RATiedReg* tiedRegs(RegGroup group) const noexcept { return _raInst->tiedRegs(group); } //! Returns count of all TiedRegs used by the instruction. - inline uint32_t tiedCount() const noexcept { return _tiedTotal; } + ASMJIT_INLINE_NODEBUG uint32_t tiedCount() const noexcept { return _tiedTotal; } //! Returns count of TiedRegs used by the given register `group`. - inline uint32_t tiedCount(uint32_t group) const noexcept { return _tiedCount.get(group); } + ASMJIT_INLINE_NODEBUG uint32_t tiedCount(RegGroup group) const noexcept { return _tiedCount.get(group); } - inline bool isGroupUsed(uint32_t group) const noexcept { return _tiedCount[group] != 0; } + ASMJIT_INLINE_NODEBUG bool isGroupUsed(RegGroup group) const noexcept { return _tiedCount[group] != 0; } //! \} @@ -135,30 +109,21 @@ public: Error makeInitialAssignment() noexcept; - Error replaceAssignment( - const PhysToWorkMap* physToWorkMap, - const WorkToPhysMap* workToPhysMap) noexcept; + Error replaceAssignment(const PhysToWorkMap* physToWorkMap) noexcept; - //! Switch to the given assignment by reassigning all register and emitting - //! code that reassigns them. This is always used to switch to a previously - //! stored assignment. + //! Switch to the given assignment by reassigning all register and emitting code that reassigns them. + //! This is always used to switch to a previously stored assignment. //! - //! If `tryMode` is true then the final assignment doesn't have to be exactly - //! same as specified by `dstPhysToWorkMap` and `dstWorkToPhysMap`. This mode - //! is only used before conditional jumps that already have assignment to - //! generate a code sequence that is always executed regardless of the flow. - Error switchToAssignment( - PhysToWorkMap* dstPhysToWorkMap, - WorkToPhysMap* dstWorkToPhysMap, - const ZoneBitVector& liveIn, - bool dstReadOnly, - bool tryMode) noexcept; - - inline Error spillRegsBeforeEntry(RABlock* block) noexcept { - return spillGpScratchRegsBeforeEntry(block->entryScratchGpRegs()); + //! If `tryMode` is true then the final assignment doesn't have to be exactly same as specified by `dstPhysToWorkMap` + //! and `dstWorkToPhysMap`. This mode is only used before conditional jumps that already have assignment to generate + //! a code sequence that is always executed regardless of the flow. + Error switchToAssignment(PhysToWorkMap* dstPhysToWorkMap, const ZoneBitVector& liveIn, bool dstReadOnly, bool tryMode) noexcept; + + ASMJIT_INLINE_NODEBUG Error spillRegsBeforeEntry(RABlock* block) noexcept { + return spillScratchGpRegsBeforeEntry(block->entryScratchGpRegs()); } - Error spillGpScratchRegsBeforeEntry(uint32_t scratchRegs) noexcept; + Error spillScratchGpRegsBeforeEntry(uint32_t scratchRegs) noexcept; //! \} @@ -181,11 +146,11 @@ public: kCostOfDirtyFlag = kCostOfFrequency / 4 }; - inline uint32_t costByFrequency(float freq) const noexcept { + ASMJIT_INLINE_NODEBUG uint32_t costByFrequency(float freq) const noexcept { return uint32_t(int32_t(freq * float(kCostOfFrequency))); } - inline uint32_t calculateSpillCost(uint32_t group, uint32_t workId, uint32_t assignedId) const noexcept { + inline uint32_t calculateSpillCost(RegGroup group, uint32_t workId, uint32_t assignedId) const noexcept { RAWorkReg* workReg = workRegById(workId); uint32_t cost = costByFrequency(workReg->liveStats().freq()); @@ -196,18 +161,18 @@ public: } //! Decides on register assignment. - uint32_t decideOnAssignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; + uint32_t decideOnAssignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept; - //! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated - //! in a physical register that have to be used by another WorkReg. + //! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated in a physical register that have + //! to be used by another WorkReg. //! - //! The function must return either `RAAssignment::kPhysNone`, which means that - //! the WorkReg of `workId` should be spilled, or a valid physical register ID, - //! which means that the register should be moved to that physical register instead. - uint32_t decideOnReassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; + //! The function must return either `RAAssignment::kPhysNone`, which means that the WorkReg of `workId` should be + //! spilled, or a valid physical register ID, which means that the register should be moved to that physical register + //! instead. + uint32_t decideOnReassignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept; //! Decides on best spill given a register mask `spillableRegs` - uint32_t decideOnSpillFor(uint32_t group, uint32_t workId, uint32_t spillableRegs, uint32_t* spillWorkId) const noexcept; + uint32_t decideOnSpillFor(RegGroup group, uint32_t workId, RegMask spillableRegs, uint32_t* spillWorkId) const noexcept; //! \} @@ -216,56 +181,56 @@ public: //! Emits a move between a destination and source register, and fixes the //! register assignment. - inline Error onMoveReg(uint32_t group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept { + inline Error onMoveReg(RegGroup group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept { if (dstPhysId == srcPhysId) return kErrorOk; _curAssignment.reassign(group, workId, dstPhysId, srcPhysId); - return _pass->onEmitMove(workId, dstPhysId, srcPhysId); + return _pass->emitMove(workId, dstPhysId, srcPhysId); } //! Emits a swap between two physical registers and fixes their assignment. //! //! \note Target must support this operation otherwise this would ASSERT. - inline Error onSwapReg(uint32_t group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept { + inline Error onSwapReg(RegGroup group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept { _curAssignment.swap(group, aWorkId, aPhysId, bWorkId, bPhysId); - return _pass->onEmitSwap(aWorkId, aPhysId, bWorkId, bPhysId); + return _pass->emitSwap(aWorkId, aPhysId, bWorkId, bPhysId); } //! Emits a load from [VirtReg/WorkReg]'s spill slot to a physical register //! and makes it assigned and clean. - inline Error onLoadReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + inline Error onLoadReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept { _curAssignment.assign(group, workId, physId, RAAssignment::kClean); - return _pass->onEmitLoad(workId, physId); + return _pass->emitLoad(workId, physId); } //! Emits a save a physical register to a [VirtReg/WorkReg]'s spill slot, //! keeps it assigned, and makes it clean. - inline Error onSaveReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + inline Error onSaveReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept { ASMJIT_ASSERT(_curAssignment.workToPhysId(group, workId) == physId); ASMJIT_ASSERT(_curAssignment.physToWorkId(group, physId) == workId); _curAssignment.makeClean(group, workId, physId); - return _pass->onEmitSave(workId, physId); + return _pass->emitSave(workId, physId); } //! Assigns a register, the content of it is undefined at this point. - inline Error onAssignReg(uint32_t group, uint32_t workId, uint32_t physId, uint32_t dirty) noexcept { + inline Error onAssignReg(RegGroup group, uint32_t workId, uint32_t physId, bool dirty) noexcept { _curAssignment.assign(group, workId, physId, dirty); return kErrorOk; } //! Spills a variable/register, saves the content to the memory-home if modified. - inline Error onSpillReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + inline Error onSpillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept { if (_curAssignment.isPhysDirty(group, physId)) ASMJIT_PROPAGATE(onSaveReg(group, workId, physId)); return onKillReg(group, workId, physId); } - inline Error onDirtyReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + inline Error onDirtyReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept { _curAssignment.makeDirty(group, workId, physId); return kErrorOk; } - inline Error onKillReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept { + inline Error onKillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept { _curAssignment.unassign(group, workId, physId); return kErrorOk; } |