| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/utils/random-number-generator.h" | 5 #include "src/base/utils/random-number-generator.h" |
| 6 #include "src/compiler/register-allocator.h" | 6 #include "src/compiler/register-allocator.h" |
| 7 #include "test/unittests/test-utils.h" | 7 #include "test/unittests/test-utils.h" |
| 8 #include "testing/gmock/include/gmock/gmock.h" | 8 #include "testing/gmock/include/gmock/gmock.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace compiler { | 12 namespace compiler { |
| 13 | 13 |
| 14 typedef BasicBlock::RpoNumber Rpo; | 14 typedef BasicBlock::RpoNumber Rpo; |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 | 17 |
| 18 static const char* general_register_names_[kMaxGeneralRegisters]; | 18 static const char* |
| 19 static const char* double_register_names_[kMaxDoubleRegisters]; | 19 general_register_names_[RegisterConfiguration::kMaxGeneralRegisters]; |
| 20 static char register_names_[10 * (kMaxGeneralRegisters + kMaxDoubleRegisters)]; | 20 static const char* |
| 21 | 21 double_register_names_[RegisterConfiguration::kMaxDoubleRegisters]; |
| 22 | 22 static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters + |
| 23 static const char* GeneralRegisterName(int allocation_index) { | 23 RegisterConfiguration::kMaxDoubleRegisters)]; |
| 24 return general_register_names_[allocation_index]; | |
| 25 } | |
| 26 | |
| 27 | |
| 28 static const char* DoubleRegisterName(int allocation_index) { | |
| 29 return double_register_names_[allocation_index]; | |
| 30 } | |
| 31 | 24 |
| 32 | 25 |
| 33 static void InitializeRegisterNames() { | 26 static void InitializeRegisterNames() { |
| 34 char* loc = register_names_; | 27 char* loc = register_names_; |
| 35 for (int i = 0; i < kMaxGeneralRegisters; ++i) { | 28 for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) { |
| 36 general_register_names_[i] = loc; | 29 general_register_names_[i] = loc; |
| 37 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); | 30 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); |
| 38 *loc++ = 0; | 31 *loc++ = 0; |
| 39 } | 32 } |
| 40 for (int i = 0; i < kMaxDoubleRegisters; ++i) { | 33 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) { |
| 41 double_register_names_[i] = loc; | 34 double_register_names_[i] = loc; |
| 42 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; | 35 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; |
| 43 *loc++ = 0; | 36 *loc++ = 0; |
| 44 } | 37 } |
| 45 } | 38 } |
| 46 | 39 |
| 47 } // namespace | 40 } // namespace |
| 48 | 41 |
| 49 | 42 |
| 50 // TODO(dcarney): fake opcodes. | 43 // TODO(dcarney): fake opcodes. |
| 51 // TODO(dcarney): fix printing of sequence w.r.t fake opcodes and registers. | 44 // TODO(dcarney): fix printing of sequence w.r.t fake opcodes and registers. |
| 52 class RegisterAllocatorTest : public TestWithZone { | 45 class RegisterAllocatorTest : public TestWithZone { |
| 53 public: | 46 public: |
| 54 static const int kDefaultNRegs = 4; | 47 static const int kDefaultNRegs = 4; |
| 55 | 48 |
| 56 RegisterAllocatorTest() | 49 RegisterAllocatorTest() |
| 57 : basic_blocks_(zone()), | 50 : num_general_registers_(kDefaultNRegs), |
| 51 num_double_registers_(kDefaultNRegs), |
| 52 basic_blocks_(zone()), |
| 58 instruction_blocks_(zone()), | 53 instruction_blocks_(zone()), |
| 59 current_block_(NULL) { | 54 current_block_(NULL) { |
| 60 InitializeRegisterNames(); | 55 InitializeRegisterNames(); |
| 61 config_.num_general_registers_ = kDefaultNRegs; | 56 } |
| 62 config_.num_double_registers_ = kDefaultNRegs; | 57 |
| 63 config_.num_aliased_double_registers_ = kDefaultNRegs; | 58 RegisterConfiguration* config() { |
| 64 config_.GeneralRegisterName = GeneralRegisterName; | 59 if (config_.is_empty()) { |
| 65 config_.DoubleRegisterName = DoubleRegisterName; | 60 config_.Reset(new RegisterConfiguration( |
| 61 num_general_registers_, num_double_registers_, num_double_registers_, |
| 62 general_register_names_, double_register_names_)); |
| 63 } |
| 64 return config_.get(); |
| 66 } | 65 } |
| 67 | 66 |
| 68 Frame* frame() { | 67 Frame* frame() { |
| 69 if (frame_.is_empty()) { | 68 if (frame_.is_empty()) { |
| 70 frame_.Reset(new Frame()); | 69 frame_.Reset(new Frame()); |
| 71 } | 70 } |
| 72 return frame_.get(); | 71 return frame_.get(); |
| 73 } | 72 } |
| 74 | 73 |
| 75 InstructionSequence* sequence() { | 74 InstructionSequence* sequence() { |
| 76 if (sequence_.is_empty()) { | 75 if (sequence_.is_empty()) { |
| 77 sequence_.Reset(new InstructionSequence(zone(), &instruction_blocks_)); | 76 sequence_.Reset(new InstructionSequence(zone(), &instruction_blocks_)); |
| 78 } | 77 } |
| 79 return sequence_.get(); | 78 return sequence_.get(); |
| 80 } | 79 } |
| 81 | 80 |
| 82 RegisterAllocator* allocator() { | 81 RegisterAllocator* allocator() { |
| 83 if (allocator_.is_empty()) { | 82 if (allocator_.is_empty()) { |
| 84 allocator_.Reset( | 83 allocator_.Reset( |
| 85 new RegisterAllocator(config_, zone(), frame(), sequence())); | 84 new RegisterAllocator(config(), zone(), frame(), sequence())); |
| 86 } | 85 } |
| 87 return allocator_.get(); | 86 return allocator_.get(); |
| 88 } | 87 } |
| 89 | 88 |
| 90 InstructionBlock* StartBlock(Rpo loop_header = Rpo::Invalid(), | 89 InstructionBlock* StartBlock(Rpo loop_header = Rpo::Invalid(), |
| 91 Rpo loop_end = Rpo::Invalid()) { | 90 Rpo loop_end = Rpo::Invalid()) { |
| 92 CHECK(current_block_ == NULL); | 91 CHECK(current_block_ == NULL); |
| 93 BasicBlock::Id block_id = | 92 BasicBlock::Id block_id = |
| 94 BasicBlock::Id::FromSize(instruction_blocks_.size()); | 93 BasicBlock::Id::FromSize(instruction_blocks_.size()); |
| 95 BasicBlock* basic_block = new (zone()) BasicBlock(zone(), block_id); | 94 BasicBlock* basic_block = new (zone()) BasicBlock(zone(), block_id); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 111 | 110 |
| 112 void EndBlock() { | 111 void EndBlock() { |
| 113 CHECK(current_block_ != NULL); | 112 CHECK(current_block_ != NULL); |
| 114 sequence()->EndBlock(basic_blocks_[current_block_->rpo_number().ToSize()]); | 113 sequence()->EndBlock(basic_blocks_[current_block_->rpo_number().ToSize()]); |
| 115 current_block_ = NULL; | 114 current_block_ = NULL; |
| 116 } | 115 } |
| 117 | 116 |
| 118 void Allocate() { | 117 void Allocate() { |
| 119 if (FLAG_trace_alloc) { | 118 if (FLAG_trace_alloc) { |
| 120 OFStream os(stdout); | 119 OFStream os(stdout); |
| 121 os << "Before: " << std::endl << *sequence() << std::endl; | 120 PrintableInstructionSequence printable = {config(), sequence()}; |
| 121 os << "Before: " << std::endl << printable << std::endl; |
| 122 } | 122 } |
| 123 allocator()->Allocate(); | 123 allocator()->Allocate(); |
| 124 if (FLAG_trace_alloc) { | 124 if (FLAG_trace_alloc) { |
| 125 OFStream os(stdout); | 125 OFStream os(stdout); |
| 126 os << "After: " << std::endl << *sequence() << std::endl; | 126 PrintableInstructionSequence printable = {config(), sequence()}; |
| 127 os << "After: " << std::endl << printable << std::endl; |
| 127 } | 128 } |
| 128 } | 129 } |
| 129 | 130 |
| 130 int NewReg() { return sequence()->NextVirtualRegister(); } | 131 int NewReg() { return sequence()->NextVirtualRegister(); } |
| 131 | 132 |
| 132 int Parameter() { | 133 int Parameter() { |
| 133 // TODO(dcarney): assert parameters before other instructions. | 134 // TODO(dcarney): assert parameters before other instructions. |
| 134 int vreg = NewReg(); | 135 int vreg = NewReg(); |
| 135 InstructionOperand* outputs[1]{ | 136 InstructionOperand* outputs[1]{ |
| 136 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)}; | 137 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)}; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 160 | 161 |
| 161 private: | 162 private: |
| 162 InstructionOperand* Unallocated(UnallocatedOperand::ExtendedPolicy policy, | 163 InstructionOperand* Unallocated(UnallocatedOperand::ExtendedPolicy policy, |
| 163 int vreg) { | 164 int vreg) { |
| 164 UnallocatedOperand* op = | 165 UnallocatedOperand* op = |
| 165 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER); | 166 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER); |
| 166 op->set_virtual_register(vreg); | 167 op->set_virtual_register(vreg); |
| 167 return op; | 168 return op; |
| 168 } | 169 } |
| 169 | 170 |
| 170 RegisterAllocator::Config config_; | 171 int num_general_registers_; |
| 172 int num_double_registers_; |
| 173 SmartPointer<RegisterConfiguration> config_; |
| 171 ZoneVector<BasicBlock*> basic_blocks_; | 174 ZoneVector<BasicBlock*> basic_blocks_; |
| 172 InstructionBlocks instruction_blocks_; | 175 InstructionBlocks instruction_blocks_; |
| 173 InstructionBlock* current_block_; | 176 InstructionBlock* current_block_; |
| 174 SmartPointer<Frame> frame_; | 177 SmartPointer<Frame> frame_; |
| 175 SmartPointer<RegisterAllocator> allocator_; | 178 SmartPointer<RegisterAllocator> allocator_; |
| 176 SmartPointer<InstructionSequence> sequence_; | 179 SmartPointer<InstructionSequence> sequence_; |
| 177 }; | 180 }; |
| 178 | 181 |
| 179 | 182 |
| 180 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { | 183 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { |
| 181 StartBlock(); | 184 StartBlock(); |
| 182 int a_reg = Parameter(); | 185 int a_reg = Parameter(); |
| 183 int b_reg = Parameter(); | 186 int b_reg = Parameter(); |
| 184 int c_reg = NewReg(); | 187 int c_reg = NewReg(); |
| 185 Instruction* res = Emit(c_reg, a_reg, b_reg); | 188 Instruction* res = Emit(c_reg, a_reg, b_reg); |
| 186 Return(c_reg); | 189 Return(c_reg); |
| 187 EndBlock(); | 190 EndBlock(); |
| 188 | 191 |
| 189 Allocate(); | 192 Allocate(); |
| 190 | 193 |
| 191 ASSERT_TRUE(res->OutputAt(0)->IsRegister()); | 194 ASSERT_TRUE(res->OutputAt(0)->IsRegister()); |
| 192 } | 195 } |
| 193 | 196 |
| 194 } // namespace compiler | 197 } // namespace compiler |
| 195 } // namespace internal | 198 } // namespace internal |
| 196 } // namespace v8 | 199 } // namespace v8 |
| OLD | NEW |