%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/maglev/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/maglev/maglev-regalloc.h |
// Copyright 2022 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_MAGLEV_MAGLEV_REGALLOC_H_ #define V8_MAGLEV_MAGLEV_REGALLOC_H_ #include "src/codegen/reglist.h" #include "src/compiler/backend/instruction.h" #include "src/maglev/maglev-compilation-info.h" #include "src/maglev/maglev-graph.h" #include "src/maglev/maglev-ir.h" #include "src/maglev/maglev-regalloc-data.h" namespace v8 { namespace internal { namespace maglev { class MaglevCompilationInfo; class MaglevPrintingVisitor; class MergePointRegisterState; // Represents the state of the register frame during register allocation, // including current register values, and the state of each register. // // Register state encodes two orthogonal concepts: // // 1. Used/free registers: Which registers currently hold a valid value, // 2. Blocked/unblocked registers: Which registers can be modified during the // current allocation. // // The combination of these encodes values in different states: // // Free + unblocked: Completely unused registers which can be used for // anything. // Used + unblocked: Live values that can be spilled if there is register // pressure. // Used + blocked: Values that are in a register and are used as an input in // the current allocation. // Free + blocked: Unused registers that are reserved as temporaries, or // inputs that will get clobbered during the execution of the // node being allocated. template <typename RegisterT> class RegisterFrameState { public: static constexpr bool kIsGeneralRegister = std::is_same<Register, RegisterT>(); static constexpr bool kIsDoubleRegister = std::is_same<DoubleRegister, RegisterT>(); static_assert(kIsGeneralRegister || kIsDoubleRegister, "RegisterFrameState should be used only for Register and " "DoubleRegister."); using RegTList = RegListBase<RegisterT>; static constexpr RegTList kAllocatableRegisters = AllocatableRegisters<RegisterT>::kRegisters; static constexpr RegTList kEmptyRegList = {}; RegTList empty() const { return kEmptyRegList; } RegTList free() const { return free_; } RegTList unblocked_free() const { return free_ - blocked_; } RegTList used() const { // Only allocatable registers should be free. DCHECK_EQ(free_, free_ & kAllocatableRegisters); return kAllocatableRegisters ^ free_; } bool UnblockedFreeIsEmpty() const { return unblocked_free().is_empty(); } template <typename Function> void ForEachUsedRegister(Function&& f) const { for (RegisterT reg : used()) { f(reg, GetValue(reg)); } } void RemoveFromFree(RegisterT reg) { free_.clear(reg); } void AddToFree(RegisterT reg) { free_.set(reg); } void AddToFree(RegTList list) { free_ |= list; } void FreeRegistersUsedBy(ValueNode* node) { RegTList list = node->ClearRegisters<RegisterT>(); DCHECK_EQ(free_ & list, kEmptyRegList); free_ |= list; } void SetValue(RegisterT reg, ValueNode* node) { DCHECK(!free_.has(reg)); DCHECK(!blocked_.has(reg)); values_[reg.code()] = node; block(reg); node->AddRegister(reg); } void SetValueWithoutBlocking(RegisterT reg, ValueNode* node) { DCHECK(!free_.has(reg)); DCHECK(!blocked_.has(reg)); values_[reg.code()] = node; node->AddRegister(reg); } ValueNode* GetValue(RegisterT reg) const { DCHECK(!free_.has(reg)); ValueNode* node = values_[reg.code()]; DCHECK_NOT_NULL(node); return node; } #ifdef DEBUG // Like GetValue, but allow reading freed registers as long as they were also // blocked. This allows us to DCHECK expected register state against node // state, even if that node is dead or clobbered by the end of the current // allocation. ValueNode* GetValueMaybeFreeButBlocked(RegisterT reg) const { DCHECK(!free_.has(reg) || blocked_.has(reg)); ValueNode* node = values_[reg.code()]; DCHECK_NOT_NULL(node); return node; } #endif RegTList blocked() const { return blocked_; } void block(RegisterT reg) { blocked_.set(reg); } void unblock(RegisterT reg) { blocked_.clear(reg); } bool is_blocked(RegisterT reg) { return blocked_.has(reg); } void clear_blocked() { blocked_ = kEmptyRegList; } compiler::InstructionOperand TryChooseInputRegister( ValueNode* node, const compiler::InstructionOperand& hint = compiler::InstructionOperand()); compiler::InstructionOperand TryChooseUnblockedInputRegister(ValueNode* node); compiler::AllocatedOperand AllocateRegister( ValueNode* node, const compiler::InstructionOperand& hint = compiler::InstructionOperand()); private: ValueNode* values_[RegisterT::kNumRegisters]; RegTList free_ = kAllocatableRegisters; RegTList blocked_ = kEmptyRegList; }; class StraightForwardRegisterAllocator { public: StraightForwardRegisterAllocator(MaglevCompilationInfo* compilation_info, Graph* graph); ~StraightForwardRegisterAllocator(); private: RegisterFrameState<Register> general_registers_; RegisterFrameState<DoubleRegister> double_registers_; struct SpillSlotInfo { SpillSlotInfo(uint32_t slot_index, NodeIdT freed_at_position, bool double_slot) : slot_index(slot_index), freed_at_position(freed_at_position), double_slot(double_slot) {} uint32_t slot_index; NodeIdT freed_at_position; bool double_slot; }; struct SpillSlots { int top = 0; // Sorted from earliest freed_at_position to latest freed_at_position. std::vector<SpillSlotInfo> free_slots; }; SpillSlots untagged_; SpillSlots tagged_; void ComputePostDominatingHoles(); void AllocateRegisters(); void PrintLiveRegs() const; void UpdateUse(Input* input) { return UpdateUse(input->node(), input); } void UpdateUse(ValueNode* node, InputLocation* input_location); void MarkAsClobbered(ValueNode* node, const compiler::AllocatedOperand& location); void AllocateControlNode(ControlNode* node, BasicBlock* block); void AllocateNode(Node* node); void AllocateNodeResult(ValueNode* node); void AllocateEagerDeopt(const EagerDeoptInfo& deopt_info); void AllocateLazyDeopt(const LazyDeoptInfo& deopt_info); void AssignFixedInput(Input& input); void AssignArbitraryRegisterInput(NodeBase* result_node, Input& input); void AssignAnyInput(Input& input); void AssignInputs(NodeBase* node); template <typename RegisterT> void AssignFixedTemporaries(RegisterFrameState<RegisterT>& registers, NodeBase* node); void AssignFixedTemporaries(NodeBase* node); template <typename RegisterT> void AssignArbitraryTemporaries(RegisterFrameState<RegisterT>& registers, NodeBase* node); void AssignArbitraryTemporaries(NodeBase* node); template <typename RegisterT> void SetLoopPhiRegisterHint(Phi* phi, RegisterT reg); void TryAllocateToInput(Phi* phi); void VerifyInputs(NodeBase* node); void VerifyRegisterState(); void AddMoveBeforeCurrentNode(ValueNode* node, compiler::InstructionOperand source, compiler::AllocatedOperand target); void AllocateSpillSlot(ValueNode* node); void Spill(ValueNode* node); void SpillRegisters(); template <typename RegisterT> void SpillAndClearRegisters(RegisterFrameState<RegisterT>& registers); void SpillAndClearRegisters(); void SaveRegisterSnapshot(NodeBase* node); void FreeRegistersUsedBy(ValueNode* node); template <typename RegisterT> RegisterT FreeUnblockedRegister( RegListBase<RegisterT> reserved = RegListBase<RegisterT>()); template <typename RegisterT> RegisterT PickRegisterToFree(RegListBase<RegisterT> reserved); template <typename RegisterT> RegisterFrameState<RegisterT>& GetRegisterFrameState() { if constexpr (std::is_same<RegisterT, Register>::value) { return general_registers_; } else { return double_registers_; } } template <typename RegisterT> void DropRegisterValueAtEnd(RegisterT reg, bool force_spill = false); bool IsCurrentNodeLastUseOf(ValueNode* node); template <typename RegisterT> void EnsureFreeRegisterAtEnd(const compiler::InstructionOperand& hint = compiler::InstructionOperand()); compiler::AllocatedOperand AllocateRegisterAtEnd(ValueNode* node); template <typename RegisterT> void DropRegisterValue(RegisterFrameState<RegisterT>& registers, RegisterT reg, bool force_spill = false); void DropRegisterValue(Register reg); void DropRegisterValue(DoubleRegister reg); compiler::AllocatedOperand AllocateRegister( ValueNode* node, const compiler::InstructionOperand& hint = compiler::InstructionOperand()); template <typename RegisterT> compiler::AllocatedOperand ForceAllocate( RegisterFrameState<RegisterT>& registers, RegisterT reg, ValueNode* node); compiler::AllocatedOperand ForceAllocate(Register reg, ValueNode* node); compiler::AllocatedOperand ForceAllocate(DoubleRegister reg, ValueNode* node); compiler::AllocatedOperand ForceAllocate(const Input& input, ValueNode* node); template <typename Function> void ForEachMergePointRegisterState( MergePointRegisterState& merge_point_state, Function&& f); void ClearRegisterValues(); void InitializeRegisterValues(MergePointRegisterState& target_state); #ifdef DEBUG bool IsInRegister(MergePointRegisterState& target_state, ValueNode* incoming); bool IsForwardReachable(BasicBlock* start_block, NodeIdT first_id, NodeIdT last_id); #endif template <typename RegisterT> void HoistLoopReloads(BasicBlock* target, RegisterFrameState<RegisterT>& registers); void HoistLoopSpills(BasicBlock* target); void InitializeBranchTargetRegisterValues(ControlNode* source, BasicBlock* target); void InitializeEmptyBlockRegisterValues(ControlNode* source, BasicBlock* target); void InitializeBranchTargetPhis(int predecessor_id, BasicBlock* target); void InitializeConditionalBranchTarget(ConditionalControlNode* source, BasicBlock* target); void MergeRegisterValues(ControlNode* control, BasicBlock* target, int predecessor_id); MaglevGraphLabeller* graph_labeller() const { return compilation_info_->graph_labeller(); } MaglevCompilationInfo* compilation_info_; std::unique_ptr<MaglevPrintingVisitor> printing_visitor_; Graph* graph_; BlockConstIterator block_it_; NodeIterator node_it_; // The current node, whether a Node in the body or the ControlNode. NodeBase* current_node_; }; } // namespace maglev } // namespace internal } // namespace v8 #endif // V8_MAGLEV_MAGLEV_REGALLOC_H_