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 "src/compiler/register-allocator-verifier.h" |
7 #include "test/unittests/test-utils.h" | 8 #include "test/unittests/test-utils.h" |
8 #include "testing/gmock/include/gmock/gmock.h" | 9 #include "testing/gmock/include/gmock/gmock.h" |
9 | 10 |
10 namespace v8 { | 11 namespace v8 { |
11 namespace internal { | 12 namespace internal { |
12 namespace compiler { | 13 namespace compiler { |
13 | 14 |
14 typedef BasicBlock::RpoNumber Rpo; | 15 typedef BasicBlock::RpoNumber Rpo; |
15 | 16 |
16 namespace { | 17 namespace { |
(...skipping 13 matching lines...) Expand all Loading... |
30 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); | 31 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); |
31 *loc++ = 0; | 32 *loc++ = 0; |
32 } | 33 } |
33 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) { | 34 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) { |
34 double_register_names_[i] = loc; | 35 double_register_names_[i] = loc; |
35 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; | 36 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; |
36 *loc++ = 0; | 37 *loc++ = 0; |
37 } | 38 } |
38 } | 39 } |
39 | 40 |
40 enum BlockCompletionType { kFallThrough, kBranch, kJump }; | 41 enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump }; |
41 | 42 |
42 struct BlockCompletion { | 43 struct BlockCompletion { |
43 BlockCompletionType type_; | 44 BlockCompletionType type_; |
44 int vreg_; | 45 int vreg_; |
45 int offset_0_; | 46 int offset_0_; |
46 int offset_1_; | 47 int offset_1_; |
47 }; | 48 }; |
48 | 49 |
49 static const int kInvalidJumpOffset = kMinInt; | 50 static const int kInvalidJumpOffset = kMinInt; |
50 | 51 |
(...skipping 19 matching lines...) Expand all Loading... |
70 | 71 |
71 class RegisterAllocatorTest : public TestWithZone { | 72 class RegisterAllocatorTest : public TestWithZone { |
72 public: | 73 public: |
73 static const int kDefaultNRegs = 4; | 74 static const int kDefaultNRegs = 4; |
74 | 75 |
75 RegisterAllocatorTest() | 76 RegisterAllocatorTest() |
76 : num_general_registers_(kDefaultNRegs), | 77 : num_general_registers_(kDefaultNRegs), |
77 num_double_registers_(kDefaultNRegs), | 78 num_double_registers_(kDefaultNRegs), |
78 instruction_blocks_(zone()), | 79 instruction_blocks_(zone()), |
79 current_block_(nullptr), | 80 current_block_(nullptr), |
80 is_last_block_(false) { | 81 is_last_block_(false), |
| 82 block_returns_(false) { |
81 InitializeRegisterNames(); | 83 InitializeRegisterNames(); |
82 } | 84 } |
83 | 85 |
84 void SetNumRegs(int num_general_registers, int num_double_registers) { | 86 void SetNumRegs(int num_general_registers, int num_double_registers) { |
85 CHECK(instruction_blocks_.empty()); | 87 CHECK(instruction_blocks_.empty()); |
86 num_general_registers_ = num_general_registers; | 88 num_general_registers_ = num_general_registers; |
87 num_double_registers_ = num_double_registers; | 89 num_double_registers_ = num_double_registers; |
88 } | 90 } |
89 | 91 |
90 RegisterConfiguration* config() { | 92 RegisterConfiguration* config() { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 } | 137 } |
136 | 138 |
137 void StartLastBlock() { | 139 void StartLastBlock() { |
138 CHECK(!is_last_block_); | 140 CHECK(!is_last_block_); |
139 is_last_block_ = true; | 141 is_last_block_ = true; |
140 NewBlock(); | 142 NewBlock(); |
141 } | 143 } |
142 | 144 |
143 void StartBlock() { | 145 void StartBlock() { |
144 CHECK(!is_last_block_); | 146 CHECK(!is_last_block_); |
| 147 block_returns_ = false; |
145 NewBlock(); | 148 NewBlock(); |
146 } | 149 } |
147 | 150 |
148 void EndBlock(BlockCompletion completion = FallThrough()) { | 151 void EndBlock(BlockCompletion completion = FallThrough()) { |
149 completions_.push_back(completion); | 152 completions_.push_back(completion); |
150 switch (completion.type_) { | 153 switch (completion.type_) { |
| 154 case kBlockEnd: |
| 155 CHECK(false); // unreachable; |
| 156 break; |
151 case kFallThrough: | 157 case kFallThrough: |
152 if (is_last_block_) break; | 158 if (is_last_block_ || block_returns_) { |
153 // TODO(dcarney): we don't emit this after returns. | 159 completions_.back().type_ = kBlockEnd; |
| 160 break; |
| 161 } |
154 EmitFallThrough(); | 162 EmitFallThrough(); |
155 break; | 163 break; |
156 case kJump: | 164 case kJump: |
| 165 CHECK(!block_returns_); |
157 EmitJump(); | 166 EmitJump(); |
158 break; | 167 break; |
159 case kBranch: | 168 case kBranch: |
| 169 CHECK(!block_returns_); |
160 EmitBranch(completion.vreg_); | 170 EmitBranch(completion.vreg_); |
161 break; | 171 break; |
162 } | 172 } |
163 CHECK(current_block_ != nullptr); | 173 CHECK(current_block_ != nullptr); |
164 sequence()->EndBlock(current_block_->rpo_number()); | 174 sequence()->EndBlock(current_block_->rpo_number()); |
165 current_block_ = nullptr; | 175 current_block_ = nullptr; |
166 } | 176 } |
167 | 177 |
168 void Allocate() { | 178 void Allocate() { |
169 CHECK_EQ(nullptr, current_block_); | 179 CHECK_EQ(nullptr, current_block_); |
170 CHECK(is_last_block_); | 180 CHECK(is_last_block_); |
171 WireBlocks(); | 181 WireBlocks(); |
| 182 RegisterAllocatorVerifier verifier(zone(), config(), sequence()); |
172 if (FLAG_trace_alloc || FLAG_trace_turbo) { | 183 if (FLAG_trace_alloc || FLAG_trace_turbo) { |
173 OFStream os(stdout); | 184 OFStream os(stdout); |
174 PrintableInstructionSequence printable = {config(), sequence()}; | 185 PrintableInstructionSequence printable = {config(), sequence()}; |
175 os << "Before: " << std::endl << printable << std::endl; | 186 os << "Before: " << std::endl << printable << std::endl; |
176 } | 187 } |
177 allocator()->Allocate(); | 188 allocator()->Allocate(); |
178 if (FLAG_trace_alloc || FLAG_trace_turbo) { | 189 if (FLAG_trace_alloc || FLAG_trace_turbo) { |
179 OFStream os(stdout); | 190 OFStream os(stdout); |
180 PrintableInstructionSequence printable = {config(), sequence()}; | 191 PrintableInstructionSequence printable = {config(), sequence()}; |
181 os << "After: " << std::endl << printable << std::endl; | 192 os << "After: " << std::endl << printable << std::endl; |
182 } | 193 } |
| 194 verifier.VerifyAssignment(); |
| 195 verifier.VerifyGapMoves(); |
183 } | 196 } |
184 | 197 |
185 int NewReg() { return sequence()->NextVirtualRegister(); } | 198 int NewReg() { return sequence()->NextVirtualRegister(); } |
186 | 199 |
187 int Parameter() { | 200 int Parameter() { |
188 int vreg = NewReg(); | 201 int vreg = NewReg(); |
189 InstructionOperand* outputs[1]{UseRegister(vreg)}; | 202 InstructionOperand* outputs[1]{UseRegister(vreg)}; |
190 Emit(kArchNop, 1, outputs); | 203 Emit(kArchNop, 1, outputs); |
191 return vreg; | 204 return vreg; |
192 } | 205 } |
193 | 206 |
194 Instruction* Return(int vreg) { | 207 Instruction* Return(int vreg) { |
| 208 block_returns_ = true; |
195 InstructionOperand* inputs[1]{UseRegister(vreg)}; | 209 InstructionOperand* inputs[1]{UseRegister(vreg)}; |
196 return Emit(kArchRet, 0, nullptr, 1, inputs); | 210 return Emit(kArchRet, 0, nullptr, 1, inputs); |
197 } | 211 } |
198 | 212 |
199 PhiInstruction* Phi(int vreg) { | 213 PhiInstruction* Phi(int vreg) { |
200 PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg()); | 214 PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg()); |
201 phi->operands().push_back(vreg); | 215 phi->operands().push_back(vreg); |
202 current_block_->AddPhi(phi); | 216 current_block_->AddPhi(phi); |
203 return phi; | 217 return phi; |
204 } | 218 } |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 zone(), block_id, rpo, rpo, loop_header, loop_end, false); | 351 zone(), block_id, rpo, rpo, loop_header, loop_end, false); |
338 instruction_blocks_.push_back(instruction_block); | 352 instruction_blocks_.push_back(instruction_block); |
339 current_block_ = instruction_block; | 353 current_block_ = instruction_block; |
340 sequence()->StartBlock(rpo); | 354 sequence()->StartBlock(rpo); |
341 return instruction_block; | 355 return instruction_block; |
342 } | 356 } |
343 | 357 |
344 void WireBlocks() { | 358 void WireBlocks() { |
345 CHECK(instruction_blocks_.size() == completions_.size()); | 359 CHECK(instruction_blocks_.size() == completions_.size()); |
346 size_t offset = 0; | 360 size_t offset = 0; |
347 size_t size = instruction_blocks_.size(); | |
348 for (const auto& completion : completions_) { | 361 for (const auto& completion : completions_) { |
349 switch (completion.type_) { | 362 switch (completion.type_) { |
350 case kFallThrough: | 363 case kBlockEnd: |
351 if (offset == size - 1) break; | 364 break; |
352 // Fallthrough. | 365 case kFallThrough: // Fallthrough. |
353 case kJump: | 366 case kJump: |
354 WireBlock(offset, completion.offset_0_); | 367 WireBlock(offset, completion.offset_0_); |
355 break; | 368 break; |
356 case kBranch: | 369 case kBranch: |
357 WireBlock(offset, completion.offset_0_); | 370 WireBlock(offset, completion.offset_0_); |
358 WireBlock(offset, completion.offset_1_); | 371 WireBlock(offset, completion.offset_1_); |
359 break; | 372 break; |
360 } | 373 } |
361 ++offset; | 374 ++offset; |
362 } | 375 } |
(...skipping 23 matching lines...) Expand all Loading... |
386 SmartPointer<InstructionSequence> sequence_; | 399 SmartPointer<InstructionSequence> sequence_; |
387 int num_general_registers_; | 400 int num_general_registers_; |
388 int num_double_registers_; | 401 int num_double_registers_; |
389 | 402 |
390 // Block building state. | 403 // Block building state. |
391 InstructionBlocks instruction_blocks_; | 404 InstructionBlocks instruction_blocks_; |
392 Completions completions_; | 405 Completions completions_; |
393 LoopBlocks loop_blocks_; | 406 LoopBlocks loop_blocks_; |
394 InstructionBlock* current_block_; | 407 InstructionBlock* current_block_; |
395 bool is_last_block_; | 408 bool is_last_block_; |
| 409 bool block_returns_; |
396 }; | 410 }; |
397 | 411 |
398 | 412 |
399 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { | 413 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { |
400 StartLastBlock(); | 414 StartLastBlock(); |
401 int a_reg = Parameter(); | 415 int a_reg = Parameter(); |
402 int b_reg = Parameter(); | 416 int b_reg = Parameter(); |
403 int c_reg = NewReg(); | 417 int c_reg = NewReg(); |
404 Instruction* res = EmitRRR(c_reg, a_reg, b_reg); | 418 Instruction* res = EmitRRR(c_reg, a_reg, b_reg); |
405 Return(c_reg); | 419 Return(c_reg); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
504 // Return sum. | 518 // Return sum. |
505 Return(DefineConstant()); | 519 Return(DefineConstant()); |
506 EndBlock(); | 520 EndBlock(); |
507 | 521 |
508 Allocate(); | 522 Allocate(); |
509 } | 523 } |
510 | 524 |
511 } // namespace compiler | 525 } // namespace compiler |
512 } // namespace internal | 526 } // namespace internal |
513 } // namespace v8 | 527 } // namespace v8 |
OLD | NEW |