OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/base/utils/random-number-generator.h" |
| 6 #include "src/compiler/register-allocator.h" |
| 7 #include "test/unittests/test-utils.h" |
| 8 #include "testing/gmock/include/gmock/gmock.h" |
| 9 |
| 10 namespace v8 { |
| 11 namespace internal { |
| 12 namespace compiler { |
| 13 |
| 14 typedef BasicBlock::RpoNumber Rpo; |
| 15 |
| 16 namespace { |
| 17 |
| 18 static const char* general_register_names_[kMaxGeneralRegisters]; |
| 19 static const char* double_register_names_[kMaxDoubleRegisters]; |
| 20 static char register_names_[10 * (kMaxGeneralRegisters + kMaxDoubleRegisters)]; |
| 21 |
| 22 |
| 23 static const char* GeneralRegisterName(int allocation_index) { |
| 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 |
| 32 |
| 33 static void InitializeRegisterNames() { |
| 34 char* loc = register_names_; |
| 35 for (int i = 0; i < kMaxGeneralRegisters; ++i) { |
| 36 general_register_names_[i] = loc; |
| 37 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); |
| 38 *loc++ = 0; |
| 39 } |
| 40 for (int i = 0; i < kMaxDoubleRegisters; ++i) { |
| 41 double_register_names_[i] = loc; |
| 42 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; |
| 43 *loc++ = 0; |
| 44 } |
| 45 } |
| 46 |
| 47 } // namespace |
| 48 |
| 49 |
| 50 // TODO(dcarney): fake opcodes. |
| 51 // TODO(dcarney): fix printing of sequence w.r.t fake opcodes and registers. |
| 52 class RegisterAllocatorTest : public TestWithZone { |
| 53 public: |
| 54 static const int kDefaultNRegs = 4; |
| 55 |
| 56 RegisterAllocatorTest() |
| 57 : basic_blocks_(zone()), |
| 58 instruction_blocks_(zone()), |
| 59 current_block_(NULL) { |
| 60 InitializeRegisterNames(); |
| 61 config_.num_general_registers_ = kDefaultNRegs; |
| 62 config_.num_double_registers_ = kDefaultNRegs; |
| 63 config_.num_aliased_double_registers_ = kDefaultNRegs; |
| 64 config_.GeneralRegisterName = GeneralRegisterName; |
| 65 config_.DoubleRegisterName = DoubleRegisterName; |
| 66 } |
| 67 |
| 68 Frame* frame() { |
| 69 if (frame_.is_empty()) { |
| 70 frame_.Reset(new Frame()); |
| 71 } |
| 72 return frame_.get(); |
| 73 } |
| 74 |
| 75 InstructionSequence* sequence() { |
| 76 if (sequence_.is_empty()) { |
| 77 sequence_.Reset(new InstructionSequence(zone(), &instruction_blocks_)); |
| 78 } |
| 79 return sequence_.get(); |
| 80 } |
| 81 |
| 82 RegisterAllocator* allocator() { |
| 83 if (allocator_.is_empty()) { |
| 84 allocator_.Reset( |
| 85 new RegisterAllocator(config_, zone(), frame(), sequence())); |
| 86 } |
| 87 return allocator_.get(); |
| 88 } |
| 89 |
| 90 InstructionBlock* StartBlock(Rpo loop_header = Rpo::Invalid(), |
| 91 Rpo loop_end = Rpo::Invalid()) { |
| 92 CHECK(current_block_ == NULL); |
| 93 BasicBlock::Id block_id = |
| 94 BasicBlock::Id::FromSize(instruction_blocks_.size()); |
| 95 BasicBlock* basic_block = new (zone()) BasicBlock(zone(), block_id); |
| 96 basic_block->set_rpo_number(block_id.ToInt()); |
| 97 basic_block->set_ao_number(block_id.ToInt()); |
| 98 if (loop_header.IsValid()) { |
| 99 basic_block->set_loop_depth(1); |
| 100 basic_block->set_loop_header(basic_blocks_[loop_header.ToSize()]); |
| 101 basic_block->set_loop_end(loop_end.ToInt()); |
| 102 } |
| 103 InstructionBlock* instruction_block = |
| 104 new (zone()) InstructionBlock(zone(), basic_block); |
| 105 basic_blocks_.push_back(basic_block); |
| 106 instruction_blocks_.push_back(instruction_block); |
| 107 current_block_ = instruction_block; |
| 108 sequence()->StartBlock(basic_block); |
| 109 return instruction_block; |
| 110 } |
| 111 |
| 112 void EndBlock() { |
| 113 CHECK(current_block_ != NULL); |
| 114 sequence()->EndBlock(basic_blocks_[current_block_->rpo_number().ToSize()]); |
| 115 current_block_ = NULL; |
| 116 } |
| 117 |
| 118 void Allocate() { |
| 119 if (FLAG_trace_alloc) { |
| 120 OFStream os(stdout); |
| 121 os << "Before: " << std::endl << *sequence() << std::endl; |
| 122 } |
| 123 allocator()->Allocate(); |
| 124 if (FLAG_trace_alloc) { |
| 125 OFStream os(stdout); |
| 126 os << "After: " << std::endl << *sequence() << std::endl; |
| 127 } |
| 128 } |
| 129 |
| 130 int NewReg() { return sequence()->NextVirtualRegister(); } |
| 131 |
| 132 int Parameter() { |
| 133 // TODO(dcarney): assert parameters before other instructions. |
| 134 int vreg = NewReg(); |
| 135 InstructionOperand* outputs[1]{ |
| 136 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)}; |
| 137 sequence()->AddInstruction( |
| 138 Instruction::New(zone(), kArchNop, 1, outputs, 0, NULL, 0, NULL)); |
| 139 return vreg; |
| 140 } |
| 141 |
| 142 void Return(int vreg) { |
| 143 InstructionOperand* inputs[1]{ |
| 144 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)}; |
| 145 sequence()->AddInstruction( |
| 146 Instruction::New(zone(), kArchNop, 0, NULL, 1, inputs, 0, NULL)); |
| 147 } |
| 148 |
| 149 Instruction* Emit(int output_vreg, int input_vreg_0, int input_vreg_1) { |
| 150 InstructionOperand* outputs[1]{ |
| 151 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, output_vreg)}; |
| 152 InstructionOperand* inputs[2]{ |
| 153 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, input_vreg_0), |
| 154 Unallocated(UnallocatedOperand::MUST_HAVE_REGISTER, input_vreg_1)}; |
| 155 Instruction* instruction = |
| 156 Instruction::New(zone(), kArchNop, 1, outputs, 2, inputs, 0, NULL); |
| 157 sequence()->AddInstruction(instruction); |
| 158 return instruction; |
| 159 } |
| 160 |
| 161 private: |
| 162 InstructionOperand* Unallocated(UnallocatedOperand::ExtendedPolicy policy, |
| 163 int vreg) { |
| 164 UnallocatedOperand* op = |
| 165 new (zone()) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER); |
| 166 op->set_virtual_register(vreg); |
| 167 return op; |
| 168 } |
| 169 |
| 170 RegisterAllocator::Config config_; |
| 171 ZoneVector<BasicBlock*> basic_blocks_; |
| 172 InstructionBlocks instruction_blocks_; |
| 173 InstructionBlock* current_block_; |
| 174 SmartPointer<Frame> frame_; |
| 175 SmartPointer<RegisterAllocator> allocator_; |
| 176 SmartPointer<InstructionSequence> sequence_; |
| 177 }; |
| 178 |
| 179 |
| 180 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { |
| 181 StartBlock(); |
| 182 int a_reg = Parameter(); |
| 183 int b_reg = Parameter(); |
| 184 int c_reg = NewReg(); |
| 185 Instruction* res = Emit(c_reg, a_reg, b_reg); |
| 186 Return(c_reg); |
| 187 EndBlock(); |
| 188 |
| 189 Allocate(); |
| 190 |
| 191 ASSERT_TRUE(res->OutputAt(0)->IsRegister()); |
| 192 } |
| 193 |
| 194 } // namespace compiler |
| 195 } // namespace internal |
| 196 } // namespace v8 |
OLD | NEW |