1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_BACKEND_MID_TIER_REGISTER_ALLOCATOR_H_ 6 #define V8_COMPILER_BACKEND_MID_TIER_REGISTER_ALLOCATOR_H_ 7 8 #include "src/base/compiler-specific.h" 9 #include "src/common/globals.h" 10 #include "src/compiler/backend/instruction.h" 11 #include "src/compiler/backend/register-allocation.h" 12 #include "src/flags/flags.h" 13 #include "src/utils/bit-vector.h" 14 #include "src/zone/zone-containers.h" 15 #include "src/zone/zone.h" 16 17 namespace v8 { 18 namespace internal { 19 20 class TickCounter; 21 22 namespace compiler { 23 24 class BlockState; 25 class VirtualRegisterData; 26 27 // The MidTierRegisterAllocator is a register allocator specifically designed to 28 // perform register allocation as fast as possible while minimizing spill moves. 29 30 class MidTierRegisterAllocationData final : public RegisterAllocationData { 31 public: 32 MidTierRegisterAllocationData(const RegisterConfiguration* config, 33 Zone* allocation_zone, Frame* frame, 34 InstructionSequence* code, 35 TickCounter* tick_counter, 36 const char* debug_name = nullptr); 37 MidTierRegisterAllocationData(const MidTierRegisterAllocationData&) = delete; 38 MidTierRegisterAllocationData& operator=( 39 const MidTierRegisterAllocationData&) = delete; 40 cast(RegisterAllocationData * data)41 static MidTierRegisterAllocationData* cast(RegisterAllocationData* data) { 42 DCHECK_EQ(data->type(), Type::kMidTier); 43 return static_cast<MidTierRegisterAllocationData*>(data); 44 } 45 46 VirtualRegisterData& VirtualRegisterDataFor(int virtual_register); 47 MachineRepresentation RepresentationFor(int virtual_register); 48 49 // Add a gap move between the given operands |from| and |to|. 50 MoveOperands* AddGapMove(int instr_index, Instruction::GapPosition position, 51 const InstructionOperand& from, 52 const InstructionOperand& to); 53 54 // Adds a gap move where both sides are PendingOperand operands. 55 MoveOperands* AddPendingOperandGapMove(int instr_index, 56 Instruction::GapPosition position); 57 58 // Helpers to get a block from an |rpo_number| or |instr_index|. 59 const InstructionBlock* GetBlock(const RpoNumber rpo_number); 60 const InstructionBlock* GetBlock(int instr_index); 61 62 // Returns a bitvector representing all the blocks that are dominated by the 63 // output of the instruction in |block|. 64 const BitVector* GetBlocksDominatedBy(const InstructionBlock* block); 65 66 // List of all instruction indexs that require a reference map. reference_map_instructions()67 ZoneVector<int>& reference_map_instructions() { 68 return reference_map_instructions_; 69 } 70 71 // Returns a bitvector representing the virtual registers that were spilled. spilled_virtual_registers()72 BitVector& spilled_virtual_registers() { return spilled_virtual_registers_; } 73 74 // This zone is for data structures only needed during register allocation 75 // phases. allocation_zone()76 Zone* allocation_zone() const { return allocation_zone_; } 77 78 // This zone is for InstructionOperands and moves that live beyond register 79 // allocation. code_zone()80 Zone* code_zone() const { return code()->zone(); } 81 82 BlockState& block_state(RpoNumber rpo_number); 83 code()84 InstructionSequence* code() const { return code_; } frame()85 Frame* frame() const { return frame_; } debug_name()86 const char* debug_name() const { return debug_name_; } config()87 const RegisterConfiguration* config() const { return config_; } tick_counter()88 TickCounter* tick_counter() { return tick_counter_; } 89 90 private: 91 Zone* const allocation_zone_; 92 Frame* const frame_; 93 InstructionSequence* const code_; 94 const char* const debug_name_; 95 const RegisterConfiguration* const config_; 96 97 ZoneVector<VirtualRegisterData> virtual_register_data_; 98 ZoneVector<BlockState> block_states_; 99 ZoneVector<int> reference_map_instructions_; 100 BitVector spilled_virtual_registers_; 101 102 TickCounter* const tick_counter_; 103 }; 104 105 // Phase 1: Process instruction outputs to determine how each virtual register 106 // is defined. 107 void DefineOutputs(MidTierRegisterAllocationData* data); 108 109 // Phase 2: Allocate registers to instructions. 110 void AllocateRegisters(MidTierRegisterAllocationData* data); 111 112 // Phase 3: assign spilled operands to specific spill slots. 113 void AllocateSpillSlots(MidTierRegisterAllocationData* data); 114 115 // Phase 4: Populate reference maps for spilled references. 116 void PopulateReferenceMaps(MidTierRegisterAllocationData* data); 117 118 } // namespace compiler 119 } // namespace internal 120 } // namespace v8 121 122 #endif // V8_COMPILER_BACKEND_MID_TIER_REGISTER_ALLOCATOR_H_ 123