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 |