Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(303)

Side by Side Diff: test/unittests/compiler/register-allocator-unittest.cc

Issue 700753003: [turbofan] add some registerallocator unittests (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "src/compiler/register-allocator-verifier.h"
8 #include "test/unittests/test-utils.h" 8 #include "test/unittests/test-utils.h"
9 #include "testing/gmock/include/gmock/gmock.h" 9 #include "testing/gmock/include/gmock/gmock.h"
10 10
11 namespace v8 { 11 namespace v8 {
12 namespace internal { 12 namespace internal {
13 namespace compiler { 13 namespace compiler {
14 14
15 typedef BasicBlock::RpoNumber Rpo; 15 typedef BasicBlock::RpoNumber Rpo;
16 16
17 namespace {
18
19 static const char* 17 static const char*
20 general_register_names_[RegisterConfiguration::kMaxGeneralRegisters]; 18 general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
21 static const char* 19 static const char*
22 double_register_names_[RegisterConfiguration::kMaxDoubleRegisters]; 20 double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
23 static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters + 21 static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
24 RegisterConfiguration::kMaxDoubleRegisters)]; 22 RegisterConfiguration::kMaxDoubleRegisters)];
25 23
26
27 static void InitializeRegisterNames() { 24 static void InitializeRegisterNames() {
28 char* loc = register_names_; 25 char* loc = register_names_;
29 for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) { 26 for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
30 general_register_names_[i] = loc; 27 general_register_names_[i] = loc;
31 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i); 28 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
32 *loc++ = 0; 29 *loc++ = 0;
33 } 30 }
34 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) { 31 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
35 double_register_names_[i] = loc; 32 double_register_names_[i] = loc;
36 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1; 33 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
37 *loc++ = 0; 34 *loc++ = 0;
38 } 35 }
39 } 36 }
40 37
41 enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
42
43 struct BlockCompletion {
44 BlockCompletionType type_;
45 int vreg_;
46 int offset_0_;
47 int offset_1_;
48 };
49
50 static const int kInvalidJumpOffset = kMinInt;
51
52 BlockCompletion FallThrough() {
53 BlockCompletion completion = {kFallThrough, -1, 1, kInvalidJumpOffset};
54 return completion;
55 }
56
57
58 BlockCompletion Jump(int offset) {
59 BlockCompletion completion = {kJump, -1, offset, kInvalidJumpOffset};
60 return completion;
61 }
62
63
64 BlockCompletion Branch(int vreg, int left_offset, int right_offset) {
65 BlockCompletion completion = {kBranch, vreg, left_offset, right_offset};
66 return completion;
67 }
68
69 } // namespace
70
71 38
72 class RegisterAllocatorTest : public TestWithZone { 39 class RegisterAllocatorTest : public TestWithZone {
73 public: 40 public:
74 static const int kDefaultNRegs = 4; 41 static const int kDefaultNRegs = 4;
42 static const int kNoValue = kMinInt;
43
44 struct VReg {
45 VReg() : value_(kNoValue) {}
46 VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {} // NOLINT
47 explicit VReg(int value) : value_(value) {}
48 int value_;
49 };
50
51 enum TestOperandType {
52 kInvalid,
53 kSameAsFirst,
54 kRegister,
55 kFixedRegister,
56 kSlot,
57 kFixedSlot,
58 kImmediate,
59 kNone
60 };
61
62 struct TestOperand {
63 TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
64 TestOperand(TestOperandType type, int imm)
65 : type_(type), vreg_(), value_(imm) {}
66 TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
67 : type_(type), vreg_(vreg), value_(value) {}
68
69 TestOperandType type_;
70 VReg vreg_;
71 int value_;
72 };
73
74 static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
75
76 static TestOperand Reg(VReg vreg, int index = kNoValue) {
77 TestOperandType type = kRegister;
78 if (index != kNoValue) type = kFixedRegister;
79 return TestOperand(type, vreg, index);
80 }
81
82 static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
83
84 static TestOperand Slot(VReg vreg, int index = kNoValue) {
85 TestOperandType type = kSlot;
86 if (index != kNoValue) type = kFixedSlot;
87 return TestOperand(type, vreg, index);
88 }
89
90 static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
91
92 static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
93
94 static TestOperand Use() { return Use(VReg()); }
95
96 enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
97
98 struct BlockCompletion {
99 BlockCompletionType type_;
100 TestOperand op_;
101 int offset_0_;
102 int offset_1_;
103 };
104
105 static BlockCompletion FallThrough() {
106 BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
107 return completion;
108 }
109
110 static BlockCompletion Jump(int offset) {
111 BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
112 return completion;
113 }
114
115 static BlockCompletion Branch(TestOperand op, int left_offset,
116 int right_offset) {
117 BlockCompletion completion = {kBranch, op, left_offset, right_offset};
118 return completion;
119 }
120
121 static BlockCompletion Last() {
122 BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
123 return completion;
124 }
75 125
76 RegisterAllocatorTest() 126 RegisterAllocatorTest()
77 : num_general_registers_(kDefaultNRegs), 127 : num_general_registers_(kDefaultNRegs),
78 num_double_registers_(kDefaultNRegs), 128 num_double_registers_(kDefaultNRegs),
79 instruction_blocks_(zone()), 129 instruction_blocks_(zone()),
130 current_instruction_index_(-1),
80 current_block_(nullptr), 131 current_block_(nullptr),
81 is_last_block_(false),
82 block_returns_(false) { 132 block_returns_(false) {
83 InitializeRegisterNames(); 133 InitializeRegisterNames();
84 } 134 }
85 135
86 void SetNumRegs(int num_general_registers, int num_double_registers) { 136 void SetNumRegs(int num_general_registers, int num_double_registers) {
137 CHECK(config_.is_empty());
138 CHECK(instructions_.empty());
87 CHECK(instruction_blocks_.empty()); 139 CHECK(instruction_blocks_.empty());
88 num_general_registers_ = num_general_registers; 140 num_general_registers_ = num_general_registers;
89 num_double_registers_ = num_double_registers; 141 num_double_registers_ = num_double_registers;
90 } 142 }
91 143
92 RegisterConfiguration* config() { 144 RegisterConfiguration* config() {
93 if (config_.is_empty()) { 145 if (config_.is_empty()) {
94 config_.Reset(new RegisterConfiguration( 146 config_.Reset(new RegisterConfiguration(
95 num_general_registers_, num_double_registers_, num_double_registers_, 147 num_general_registers_, num_double_registers_, num_double_registers_,
96 general_register_names_, double_register_names_)); 148 general_register_names_, double_register_names_));
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 loop_blocks_.push_back(loop_data); 181 loop_blocks_.push_back(loop_data);
130 } 182 }
131 183
132 void EndLoop() { 184 void EndLoop() {
133 CHECK(current_block_ == nullptr); 185 CHECK(current_block_ == nullptr);
134 CHECK(!loop_blocks_.empty()); 186 CHECK(!loop_blocks_.empty());
135 CHECK_EQ(0, loop_blocks_.back().expected_blocks_); 187 CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
136 loop_blocks_.pop_back(); 188 loop_blocks_.pop_back();
137 } 189 }
138 190
139 void StartLastBlock() {
140 CHECK(!is_last_block_);
141 is_last_block_ = true;
142 NewBlock();
143 }
144
145 void StartBlock() { 191 void StartBlock() {
146 CHECK(!is_last_block_);
147 block_returns_ = false; 192 block_returns_ = false;
148 NewBlock(); 193 NewBlock();
149 } 194 }
150 195
151 void EndBlock(BlockCompletion completion = FallThrough()) { 196 int EndBlock(BlockCompletion completion = FallThrough()) {
152 completions_.push_back(completion); 197 int instruction_index = kMinInt;
198 if (block_returns_) {
199 CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
200 completion.type_ = kBlockEnd;
201 }
153 switch (completion.type_) { 202 switch (completion.type_) {
154 case kBlockEnd: 203 case kBlockEnd:
155 CHECK(false); // unreachable;
156 break; 204 break;
157 case kFallThrough: 205 case kFallThrough:
158 if (is_last_block_ || block_returns_) { 206 instruction_index = EmitFallThrough();
159 completions_.back().type_ = kBlockEnd;
160 break;
161 }
162 EmitFallThrough();
163 break; 207 break;
164 case kJump: 208 case kJump:
165 CHECK(!block_returns_); 209 CHECK(!block_returns_);
166 EmitJump(); 210 instruction_index = EmitJump();
167 break; 211 break;
168 case kBranch: 212 case kBranch:
169 CHECK(!block_returns_); 213 CHECK(!block_returns_);
170 EmitBranch(completion.vreg_); 214 instruction_index = EmitBranch(completion.op_);
171 break; 215 break;
172 } 216 }
217 completions_.push_back(completion);
173 CHECK(current_block_ != nullptr); 218 CHECK(current_block_ != nullptr);
174 sequence()->EndBlock(current_block_->rpo_number()); 219 sequence()->EndBlock(current_block_->rpo_number());
175 current_block_ = nullptr; 220 current_block_ = nullptr;
221 return instruction_index;
176 } 222 }
177 223
178 void Allocate() { 224 void Allocate() {
179 CHECK_EQ(nullptr, current_block_); 225 CHECK_EQ(nullptr, current_block_);
180 CHECK(is_last_block_);
181 WireBlocks(); 226 WireBlocks();
182 RegisterAllocatorVerifier verifier(zone(), config(), sequence()); 227 RegisterAllocatorVerifier verifier(zone(), config(), sequence());
183 if (FLAG_trace_alloc || FLAG_trace_turbo) { 228 if (FLAG_trace_alloc || FLAG_trace_turbo) {
184 OFStream os(stdout); 229 OFStream os(stdout);
185 PrintableInstructionSequence printable = {config(), sequence()}; 230 PrintableInstructionSequence printable = {config(), sequence()};
186 os << "Before: " << std::endl << printable << std::endl; 231 os << "Before: " << std::endl << printable << std::endl;
187 } 232 }
188 allocator()->Allocate(); 233 allocator()->Allocate();
189 if (FLAG_trace_alloc || FLAG_trace_turbo) { 234 if (FLAG_trace_alloc || FLAG_trace_turbo) {
190 OFStream os(stdout); 235 OFStream os(stdout);
191 PrintableInstructionSequence printable = {config(), sequence()}; 236 PrintableInstructionSequence printable = {config(), sequence()};
192 os << "After: " << std::endl << printable << std::endl; 237 os << "After: " << std::endl << printable << std::endl;
193 } 238 }
194 verifier.VerifyAssignment(); 239 verifier.VerifyAssignment();
195 verifier.VerifyGapMoves(); 240 verifier.VerifyGapMoves();
196 } 241 }
197 242
198 int NewReg() { return sequence()->NextVirtualRegister(); } 243 TestOperand Imm(int32_t imm = 0) {
244 int index = sequence()->AddImmediate(Constant(imm));
245 return TestOperand(kImmediate, index);
246 }
199 247
200 int Parameter() { 248 VReg Parameter(TestOperand output_op = Reg()) {
201 int vreg = NewReg(); 249 VReg vreg = NewReg();
202 InstructionOperand* outputs[1]{UseRegister(vreg)}; 250 InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
203 Emit(kArchNop, 1, outputs); 251 Emit(vreg.value_, kArchNop, 1, outputs);
204 return vreg; 252 return vreg;
205 } 253 }
206 254
207 Instruction* Return(int vreg) { 255 int Return(TestOperand input_op_0) {
208 block_returns_ = true; 256 block_returns_ = true;
209 InstructionOperand* inputs[1]{UseRegister(vreg)}; 257 InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
210 return Emit(kArchRet, 0, nullptr, 1, inputs); 258 return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
211 } 259 }
212 260
213 PhiInstruction* Phi(int vreg) { 261 int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
214 PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg()); 262
215 phi->operands().push_back(vreg); 263 PhiInstruction* Phi(VReg incoming_vreg) {
264 PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg().value_);
265 phi->operands().push_back(incoming_vreg.value_);
216 current_block_->AddPhi(phi); 266 current_block_->AddPhi(phi);
217 return phi; 267 return phi;
218 } 268 }
219 269
220 int DefineConstant(int32_t imm = 0) { 270 PhiInstruction* Phi(VReg incoming_vreg_0, VReg incoming_vreg_1) {
221 int virtual_register = NewReg(); 271 auto phi = Phi(incoming_vreg_0);
222 sequence()->AddConstant(virtual_register, Constant(imm)); 272 Extend(phi, incoming_vreg_1);
223 InstructionOperand* outputs[1]{ 273 return phi;
224 ConstantOperand::Create(virtual_register, zone())};
225 Emit(kArchNop, 1, outputs);
226 return virtual_register;
227 } 274 }
228 275
229 ImmediateOperand* Immediate(int32_t imm = 0) { 276 static void Extend(PhiInstruction* phi, VReg vreg) {
230 int index = sequence()->AddImmediate(Constant(imm)); 277 phi->operands().push_back(vreg.value_);
231 return ImmediateOperand::Create(index, zone());
232 } 278 }
233 279
234 Instruction* EmitFRI(int output_vreg, int input_vreg_0) { 280 VReg DefineConstant(int32_t imm = 0) {
235 InstructionOperand* outputs[1]{DefineSameAsFirst(output_vreg)}; 281 VReg vreg = NewReg();
236 InstructionOperand* inputs[2]{UseRegister(input_vreg_0), Immediate()}; 282 sequence()->AddConstant(vreg.value_, Constant(imm));
237 return Emit(kArchNop, 1, outputs, 2, inputs); 283 InstructionOperand* outputs[1]{
284 ConstantOperand::Create(vreg.value_, zone())};
285 Emit(vreg.value_, kArchNop, 1, outputs);
286 return vreg;
238 } 287 }
239 288
240 Instruction* EmitFRU(int output_vreg, int input_vreg_0, int input_vreg_1) { 289 VReg EmitOII(TestOperand output_op, TestOperand input_op_0,
241 InstructionOperand* outputs[1]{DefineSameAsFirst(output_vreg)}; 290 TestOperand input_op_1) {
242 InstructionOperand* inputs[2]{UseRegister(input_vreg_0), Use(input_vreg_1)}; 291 VReg output_vreg = NewReg();
243 return Emit(kArchNop, 1, outputs, 2, inputs); 292 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
293 InstructionOperand* inputs[2]{ConvertInputOp(input_op_0),
294 ConvertInputOp(input_op_1)};
295 Emit(output_vreg.value_, kArchNop, 1, outputs, 2, inputs);
296 return output_vreg;
244 } 297 }
245 298
246 Instruction* EmitRRR(int output_vreg, int input_vreg_0, int input_vreg_1) { 299 VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs) {
247 InstructionOperand* outputs[1]{UseRegister(output_vreg)}; 300 VReg output_vreg = NewReg();
248 InstructionOperand* inputs[2]{UseRegister(input_vreg_0), 301 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
249 UseRegister(input_vreg_1)}; 302 InstructionOperand** mapped_inputs =
250 return Emit(kArchNop, 1, outputs, 2, inputs); 303 zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
304 for (size_t i = 0; i < input_size; ++i) {
305 mapped_inputs[i] = ConvertInputOp(inputs[i]);
306 }
307 Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
308 mapped_inputs);
309 return output_vreg;
310 }
311
312 // Get defining instruction vreg or value returned at instruction creation
313 // time when there is no return value.
314 const Instruction* GetInstruction(int instruction_index) {
315 auto it = instructions_.find(instruction_index);
316 CHECK(it != instructions_.end());
317 return it->second;
251 } 318 }
252 319
253 private: 320 private:
254 InstructionOperand* Unallocated(int vreg, 321 VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
255 UnallocatedOperand::ExtendedPolicy policy) { 322 int NewIndex() { return current_instruction_index_--; }
256 UnallocatedOperand* op = new (zone()) UnallocatedOperand(policy); 323
257 op->set_virtual_register(vreg); 324 static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
258 return op; 325
326 int EmitBranch(TestOperand input_op) {
327 InstructionOperand* inputs[4]{ConvertInputOp(input_op),
328 ConvertInputOp(Imm()), ConvertInputOp(Imm()),
329 ConvertInputOp(Imm())};
330 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
331 FlagsConditionField::encode(kEqual);
332 auto instruction =
333 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
334 return AddInstruction(NewIndex(), instruction);
259 } 335 }
260 336
261 InstructionOperand* Unallocated(int vreg, 337 int EmitFallThrough() {
262 UnallocatedOperand::ExtendedPolicy policy, 338 auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
263 UnallocatedOperand::Lifetime lifetime) { 339 return AddInstruction(NewIndex(), instruction);
264 UnallocatedOperand* op = new (zone()) UnallocatedOperand(policy, lifetime);
265 op->set_virtual_register(vreg);
266 return op;
267 } 340 }
268 341
269 InstructionOperand* UseRegister(int vreg) { 342 int EmitJump() {
270 return Unallocated(vreg, UnallocatedOperand::MUST_HAVE_REGISTER); 343 InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
271 } 344 auto instruction =
272
273 InstructionOperand* DefineSameAsFirst(int vreg) {
274 return Unallocated(vreg, UnallocatedOperand::SAME_AS_FIRST_INPUT);
275 }
276
277 InstructionOperand* Use(int vreg) {
278 return Unallocated(vreg, UnallocatedOperand::NONE,
279 UnallocatedOperand::USED_AT_START);
280 }
281
282 void EmitBranch(int vreg) {
283 InstructionOperand* inputs[4]{UseRegister(vreg), Immediate(), Immediate(),
284 Immediate()};
285 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
286 FlagsConditionField::encode(kEqual);
287 Instruction* instruction =
288 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
289 sequence()->AddInstruction(instruction);
290 }
291
292 void EmitFallThrough() {
293 Instruction* instruction =
294 NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
295 sequence()->AddInstruction(instruction);
296 }
297
298 void EmitJump() {
299 InstructionOperand* inputs[1]{Immediate()};
300 Instruction* instruction =
301 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl(); 345 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
302 sequence()->AddInstruction(instruction); 346 return AddInstruction(NewIndex(), instruction);
303 } 347 }
304 348
305 Instruction* NewInstruction(InstructionCode code, size_t outputs_size, 349 Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
306 InstructionOperand** outputs, 350 InstructionOperand** outputs,
307 size_t inputs_size = 0, 351 size_t inputs_size = 0,
308 InstructionOperand* *inputs = nullptr, 352 InstructionOperand* *inputs = nullptr,
309 size_t temps_size = 0, 353 size_t temps_size = 0,
310 InstructionOperand* *temps = nullptr) { 354 InstructionOperand* *temps = nullptr) {
311 CHECK_NE(nullptr, current_block_); 355 CHECK_NE(nullptr, current_block_);
312 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size, 356 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
313 inputs, temps_size, temps); 357 inputs, temps_size, temps);
314 } 358 }
315 359
316 Instruction* Emit(InstructionCode code, size_t outputs_size, 360 InstructionOperand* Unallocated(TestOperand op,
317 InstructionOperand** outputs, size_t inputs_size = 0, 361 UnallocatedOperand::ExtendedPolicy policy) {
318 InstructionOperand* *inputs = nullptr, 362 auto unallocated = new (zone()) UnallocatedOperand(policy);
319 size_t temps_size = 0, 363 unallocated->set_virtual_register(op.vreg_.value_);
320 InstructionOperand* *temps = nullptr) { 364 return unallocated;
321 Instruction* instruction = NewInstruction( 365 }
322 code, outputs_size, outputs, inputs_size, inputs, temps_size, temps); 366
323 sequence()->AddInstruction(instruction); 367 InstructionOperand* Unallocated(TestOperand op,
324 return instruction; 368 UnallocatedOperand::ExtendedPolicy policy,
369 UnallocatedOperand::Lifetime lifetime) {
370 auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
371 unallocated->set_virtual_register(op.vreg_.value_);
372 return unallocated;
373 }
374
375 InstructionOperand* Unallocated(TestOperand op,
376 UnallocatedOperand::ExtendedPolicy policy,
377 int index) {
378 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
379 unallocated->set_virtual_register(op.vreg_.value_);
380 return unallocated;
381 }
382
383 InstructionOperand* Unallocated(TestOperand op,
384 UnallocatedOperand::BasicPolicy policy,
385 int index) {
386 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
387 unallocated->set_virtual_register(op.vreg_.value_);
388 return unallocated;
389 }
390
391 InstructionOperand* ConvertInputOp(TestOperand op) {
392 if (op.type_ == kImmediate) {
393 CHECK_EQ(op.vreg_.value_, kNoValue);
394 return ImmediateOperand::Create(op.value_, zone());
395 }
396 CHECK_NE(op.vreg_.value_, kNoValue);
397 switch (op.type_) {
398 case kNone:
399 return Unallocated(op, UnallocatedOperand::NONE,
400 UnallocatedOperand::USED_AT_START);
401 case kRegister:
402 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
403 UnallocatedOperand::USED_AT_START);
404 case kFixedRegister:
405 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
406 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
407 default:
408 break;
409 }
410 CHECK(false);
411 return NULL;
412 }
413
414 InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op) {
415 CHECK_EQ(op.vreg_.value_, kNoValue);
416 op.vreg_ = vreg;
417 switch (op.type_) {
418 case kSameAsFirst:
419 return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
420 case kRegister:
421 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
422 case kFixedSlot:
423 return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
424 case kFixedRegister:
425 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
426 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
427 default:
428 break;
429 }
430 CHECK(false);
431 return NULL;
325 } 432 }
326 433
327 InstructionBlock* NewBlock() { 434 InstructionBlock* NewBlock() {
328 CHECK(current_block_ == nullptr); 435 CHECK(current_block_ == nullptr);
329 BasicBlock::Id block_id = 436 auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
330 BasicBlock::Id::FromSize(instruction_blocks_.size());
331 Rpo rpo = Rpo::FromInt(block_id.ToInt()); 437 Rpo rpo = Rpo::FromInt(block_id.ToInt());
332 Rpo loop_header = Rpo::Invalid(); 438 Rpo loop_header = Rpo::Invalid();
333 Rpo loop_end = Rpo::Invalid(); 439 Rpo loop_end = Rpo::Invalid();
334 if (!loop_blocks_.empty()) { 440 if (!loop_blocks_.empty()) {
335 auto& loop_data = loop_blocks_.back(); 441 auto& loop_data = loop_blocks_.back();
336 // This is a loop header. 442 // This is a loop header.
337 if (!loop_data.loop_header_.IsValid()) { 443 if (!loop_data.loop_header_.IsValid()) {
338 loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_); 444 loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
339 loop_data.expected_blocks_--; 445 loop_data.expected_blocks_--;
340 loop_data.loop_header_ = rpo; 446 loop_data.loop_header_ = rpo;
341 } else { 447 } else {
342 // This is a loop body. 448 // This is a loop body.
343 CHECK_NE(0, loop_data.expected_blocks_); 449 CHECK_NE(0, loop_data.expected_blocks_);
344 // TODO(dcarney): handle nested loops. 450 // TODO(dcarney): handle nested loops.
345 loop_data.expected_blocks_--; 451 loop_data.expected_blocks_--;
346 loop_header = loop_data.loop_header_; 452 loop_header = loop_data.loop_header_;
347 } 453 }
348 } 454 }
349 // Construct instruction block. 455 // Construct instruction block.
350 InstructionBlock* instruction_block = new (zone()) InstructionBlock( 456 auto instruction_block = new (zone()) InstructionBlock(
351 zone(), block_id, rpo, rpo, loop_header, loop_end, false); 457 zone(), block_id, rpo, rpo, loop_header, loop_end, false);
352 instruction_blocks_.push_back(instruction_block); 458 instruction_blocks_.push_back(instruction_block);
353 current_block_ = instruction_block; 459 current_block_ = instruction_block;
354 sequence()->StartBlock(rpo); 460 sequence()->StartBlock(rpo);
355 return instruction_block; 461 return instruction_block;
356 } 462 }
357 463
358 void WireBlocks() { 464 void WireBlocks() {
359 CHECK(instruction_blocks_.size() == completions_.size()); 465 CHECK(instruction_blocks_.size() == completions_.size());
360 size_t offset = 0; 466 size_t offset = 0;
(...skipping 12 matching lines...) Expand all
373 } 479 }
374 ++offset; 480 ++offset;
375 } 481 }
376 } 482 }
377 483
378 void WireBlock(size_t block_offset, int jump_offset) { 484 void WireBlock(size_t block_offset, int jump_offset) {
379 size_t target_block_offset = 485 size_t target_block_offset =
380 block_offset + static_cast<size_t>(jump_offset); 486 block_offset + static_cast<size_t>(jump_offset);
381 CHECK(block_offset < instruction_blocks_.size()); 487 CHECK(block_offset < instruction_blocks_.size());
382 CHECK(target_block_offset < instruction_blocks_.size()); 488 CHECK(target_block_offset < instruction_blocks_.size());
383 InstructionBlock* block = instruction_blocks_[block_offset]; 489 auto block = instruction_blocks_[block_offset];
384 InstructionBlock* target = instruction_blocks_[target_block_offset]; 490 auto target = instruction_blocks_[target_block_offset];
385 block->successors().push_back(target->rpo_number()); 491 block->successors().push_back(target->rpo_number());
386 target->predecessors().push_back(block->rpo_number()); 492 target->predecessors().push_back(block->rpo_number());
387 } 493 }
388 494
495 int Emit(int instruction_index, InstructionCode code, size_t outputs_size,
496 InstructionOperand** outputs, size_t inputs_size = 0,
497 InstructionOperand* *inputs = nullptr, size_t temps_size = 0,
498 InstructionOperand* *temps = nullptr) {
499 auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
500 inputs, temps_size, temps);
501 return AddInstruction(instruction_index, instruction);
502 }
503
504 int AddInstruction(int instruction_index, Instruction* instruction) {
505 sequence()->AddInstruction(instruction);
506 return instruction_index;
507 }
508
389 struct LoopData { 509 struct LoopData {
390 Rpo loop_header_; 510 Rpo loop_header_;
391 int expected_blocks_; 511 int expected_blocks_;
392 }; 512 };
513
393 typedef std::vector<LoopData> LoopBlocks; 514 typedef std::vector<LoopData> LoopBlocks;
515 typedef std::map<int, const Instruction*> Instructions;
394 typedef std::vector<BlockCompletion> Completions; 516 typedef std::vector<BlockCompletion> Completions;
395 517
396 SmartPointer<RegisterConfiguration> config_; 518 SmartPointer<RegisterConfiguration> config_;
397 SmartPointer<Frame> frame_; 519 SmartPointer<Frame> frame_;
398 SmartPointer<RegisterAllocator> allocator_; 520 SmartPointer<RegisterAllocator> allocator_;
399 SmartPointer<InstructionSequence> sequence_; 521 SmartPointer<InstructionSequence> sequence_;
400 int num_general_registers_; 522 int num_general_registers_;
401 int num_double_registers_; 523 int num_double_registers_;
402 524
403 // Block building state. 525 // Block building state.
404 InstructionBlocks instruction_blocks_; 526 InstructionBlocks instruction_blocks_;
527 Instructions instructions_;
528 int current_instruction_index_;
405 Completions completions_; 529 Completions completions_;
406 LoopBlocks loop_blocks_; 530 LoopBlocks loop_blocks_;
407 InstructionBlock* current_block_; 531 InstructionBlock* current_block_;
408 bool is_last_block_;
409 bool block_returns_; 532 bool block_returns_;
410 }; 533 };
411 534
412 535
413 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { 536 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
414 StartLastBlock(); 537 // return p0 + p1;
415 int a_reg = Parameter(); 538 StartBlock();
416 int b_reg = Parameter(); 539 auto a_reg = Parameter();
417 int c_reg = NewReg(); 540 auto b_reg = Parameter();
418 Instruction* res = EmitRRR(c_reg, a_reg, b_reg); 541 auto c_reg = EmitOII(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
419 Return(c_reg); 542 Return(c_reg);
420 EndBlock(); 543 EndBlock(Last());
421 544
422 Allocate(); 545 Allocate();
423
424 ASSERT_TRUE(res->OutputAt(0)->IsRegister());
425 } 546 }
426 547
427 548
428 TEST_F(RegisterAllocatorTest, SimpleLoop) { 549 TEST_F(RegisterAllocatorTest, SimpleLoop) {
429 // i = K; 550 // i = K;
430 // while(true) { i++ } 551 // while(true) { i++ }
431
432 StartBlock(); 552 StartBlock();
433 int i_reg = DefineConstant(); 553 auto i_reg = DefineConstant();
434 EndBlock(); 554 EndBlock();
435 555
436 { 556 {
437 StartLoop(1); 557 StartLoop(1);
438 558
439 StartLastBlock(); 559 StartBlock();
440 PhiInstruction* phi = Phi(i_reg); 560 auto phi = Phi(i_reg);
441 int ipp = NewReg(); 561 auto ipp = EmitOII(Same(), Reg(phi), Use(DefineConstant()));
442 EmitFRU(ipp, phi->virtual_register(), DefineConstant()); 562 Extend(phi, ipp);
443 phi->operands().push_back(ipp);
444 EndBlock(Jump(0)); 563 EndBlock(Jump(0));
445 564
446 EndLoop(); 565 EndLoop();
447 } 566 }
448 567
449 Allocate(); 568 Allocate();
450 } 569 }
451 570
452 571
453 TEST_F(RegisterAllocatorTest, SimpleBranch) { 572 TEST_F(RegisterAllocatorTest, SimpleBranch) {
454 // return i ? K1 : K2 573 // return i ? K1 : K2
455 StartBlock(); 574 StartBlock();
456 int i_reg = DefineConstant(); 575 auto i = DefineConstant();
457 EndBlock(Branch(i_reg, 1, 2)); 576 EndBlock(Branch(Reg(i), 1, 2));
458 577
459 StartBlock(); 578 StartBlock();
460 Return(DefineConstant()); 579 Return(DefineConstant());
461 EndBlock(); 580 EndBlock(Last());
462 581
463 StartLastBlock(); 582 StartBlock();
464 Return(DefineConstant()); 583 Return(DefineConstant());
584 EndBlock(Last());
585
586 Allocate();
587 }
588
589
590 TEST_F(RegisterAllocatorTest, SimpleDiamond) {
591 // return p0 ? p0 : p0
592 StartBlock();
593 auto param = Parameter();
594 EndBlock(Branch(Reg(param), 1, 2));
595
596 StartBlock();
597 EndBlock(Jump(2));
598
599 StartBlock();
600 EndBlock(Jump(1));
601
602 StartBlock();
603 Return(param);
465 EndBlock(); 604 EndBlock();
466 605
467 Allocate(); 606 Allocate();
607 }
608
609
610 TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) {
611 // return i ? K1 : K2
612 StartBlock();
613 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
614
615 StartBlock();
616 auto t_val = DefineConstant();
617 EndBlock(Jump(2));
618
619 StartBlock();
620 auto f_val = DefineConstant();
621 EndBlock(Jump(1));
622
623 StartBlock();
624 Return(Reg(Phi(t_val, f_val)));
625 EndBlock();
626
627 Allocate();
628 }
629
630
631 TEST_F(RegisterAllocatorTest, DiamondManyPhis) {
632 const int kPhis = kDefaultNRegs * 2;
633
634 StartBlock();
635 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
636
637 StartBlock();
638 VReg t_vals[kPhis];
639 for (int i = 0; i < kPhis; ++i) {
640 t_vals[i] = DefineConstant();
641 }
642 EndBlock(Jump(2));
643
644 StartBlock();
645 VReg f_vals[kPhis];
646 for (int i = 0; i < kPhis; ++i) {
647 f_vals[i] = DefineConstant();
648 }
649 EndBlock(Jump(1));
650
651 StartBlock();
652 TestOperand merged[kPhis];
653 for (int i = 0; i < kPhis; ++i) {
654 merged[i] = Use(Phi(t_vals[i], f_vals[i]));
655 }
656 Return(EmitCall(Reg(), kPhis, merged));
657 EndBlock();
658
659 Allocate();
660 }
661
662
663 TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
664 const int kPhis = kDefaultNRegs * 2;
665
666 // First diamond.
667 StartBlock();
668 VReg vals[kPhis];
669 for (int i = 0; i < kPhis; ++i) {
670 vals[i] = Parameter(Slot(i));
671 }
672 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
673
674 StartBlock();
675 EndBlock(Jump(2));
676
677 StartBlock();
678 EndBlock(Jump(1));
679
680 // Second diamond.
681 StartBlock();
682 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
683
684 StartBlock();
685 EndBlock(Jump(2));
686
687 StartBlock();
688 EndBlock(Jump(1));
689
690 StartBlock();
691 TestOperand merged[kPhis];
692 for (int i = 0; i < kPhis; ++i) {
693 merged[i] = Use(Phi(vals[i], vals[i]));
694 }
695 Return(EmitCall(Reg(), kPhis, merged));
696 EndBlock();
697
698 Allocate();
468 } 699 }
469 700
470 701
471 TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) { 702 TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
472 const size_t kNumRegs = 3; 703 const size_t kNumRegs = 3;
473 const size_t kParams = kNumRegs + 1; 704 const size_t kParams = kNumRegs + 1;
474 int parameters[kParams];
475
476 // Override number of registers. 705 // Override number of registers.
477 SetNumRegs(kNumRegs, kNumRegs); 706 SetNumRegs(kNumRegs, kNumRegs);
478 707
479 // Initial block.
480 StartBlock(); 708 StartBlock();
481 int constant = DefineConstant(); 709 auto constant = DefineConstant();
710 VReg parameters[kParams];
482 for (size_t i = 0; i < arraysize(parameters); ++i) { 711 for (size_t i = 0; i < arraysize(parameters); ++i) {
483 parameters[i] = DefineConstant(); 712 parameters[i] = DefineConstant();
484 } 713 }
485 EndBlock(); 714 EndBlock();
486 715
487 PhiInstruction* phis[kParams]; 716 PhiInstruction* phis[kParams];
488 { 717 {
489 StartLoop(2); 718 StartLoop(2);
490 719
491 // Loop header. 720 // Loop header.
492 StartBlock(); 721 StartBlock();
493 722
494 for (size_t i = 0; i < arraysize(parameters); ++i) { 723 for (size_t i = 0; i < arraysize(parameters); ++i) {
495 phis[i] = Phi(parameters[i]); 724 phis[i] = Phi(parameters[i]);
496 } 725 }
497 726
498 // Perform some computations. 727 // Perform some computations.
499 // something like phi[i] += const 728 // something like phi[i] += const
500 for (size_t i = 0; i < arraysize(parameters); ++i) { 729 for (size_t i = 0; i < arraysize(parameters); ++i) {
501 int result = NewReg(); 730 auto result = EmitOII(Same(), Reg(phis[i]), Use(constant));
502 EmitFRU(result, phis[i]->virtual_register(), constant); 731 Extend(phis[i], result);
503 phis[i]->operands().push_back(result);
504 } 732 }
505 733
506 EndBlock(Branch(DefineConstant(), 1, 2)); 734 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
507 735
508 // Jump back to loop header. 736 // Jump back to loop header.
509 StartBlock(); 737 StartBlock();
510 EndBlock(Jump(-1)); 738 EndBlock(Jump(-1));
511 739
512 EndLoop(); 740 EndLoop();
513 } 741 }
514 742
515 // End block. 743 StartBlock();
516 StartLastBlock();
517
518 // Return sum.
519 Return(DefineConstant()); 744 Return(DefineConstant());
520 EndBlock(); 745 EndBlock();
521 746
522 Allocate(); 747 Allocate();
523 } 748 }
524 749
525 } // namespace compiler 750 } // namespace compiler
526 } // namespace internal 751 } // namespace internal
527 } // namespace v8 752 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698