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

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

Issue 750813004: [turbofan] add initial move optimizer (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 6 years 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
« no previous file with comments | « test/unittests/compiler/move-optimizer-unittest.cc ('k') | test/unittests/unittests.gyp » ('j') | 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"
6 #include "src/compiler/instruction.h"
7 #include "src/compiler/pipeline.h" 5 #include "src/compiler/pipeline.h"
8 #include "test/unittests/test-utils.h" 6 #include "test/unittests/compiler/instruction-sequence-unittest.h"
9 #include "testing/gmock/include/gmock/gmock.h"
10 7
11 namespace v8 { 8 namespace v8 {
12 namespace internal { 9 namespace internal {
13 namespace compiler { 10 namespace compiler {
14 11
15 typedef BasicBlock::RpoNumber Rpo; 12 class RegisterAllocatorTest : public InstructionSequenceTest {
16
17 static const char*
18 general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
19 static const char*
20 double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
21 static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
22 RegisterConfiguration::kMaxDoubleRegisters)];
23
24 static void InitializeRegisterNames() {
25 char* loc = register_names_;
26 for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
27 general_register_names_[i] = loc;
28 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
29 *loc++ = 0;
30 }
31 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
32 double_register_names_[i] = loc;
33 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
34 *loc++ = 0;
35 }
36 }
37
38
39 class RegisterAllocatorTest : public TestWithZone {
40 public: 13 public:
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 }
125
126 RegisterAllocatorTest()
127 : frame_(nullptr),
128 sequence_(nullptr),
129 num_general_registers_(kDefaultNRegs),
130 num_double_registers_(kDefaultNRegs),
131 instruction_blocks_(zone()),
132 current_instruction_index_(-1),
133 current_block_(nullptr),
134 block_returns_(false) {
135 InitializeRegisterNames();
136 }
137
138 void SetNumRegs(int num_general_registers, int num_double_registers) {
139 CHECK(config_.is_empty());
140 CHECK(instructions_.empty());
141 CHECK(instruction_blocks_.empty());
142 num_general_registers_ = num_general_registers;
143 num_double_registers_ = num_double_registers;
144 }
145
146 RegisterConfiguration* config() {
147 if (config_.is_empty()) {
148 config_.Reset(new RegisterConfiguration(
149 num_general_registers_, num_double_registers_, num_double_registers_,
150 general_register_names_, double_register_names_));
151 }
152 return config_.get();
153 }
154
155 Frame* frame() {
156 if (frame_ == nullptr) {
157 frame_ = new (zone()) Frame();
158 }
159 return frame_;
160 }
161
162 InstructionSequence* sequence() {
163 if (sequence_ == nullptr) {
164 sequence_ =
165 new (zone()) InstructionSequence(zone(), &instruction_blocks_);
166 }
167 return sequence_;
168 }
169
170 void StartLoop(int loop_blocks) {
171 CHECK(current_block_ == nullptr);
172 if (!loop_blocks_.empty()) {
173 CHECK(!loop_blocks_.back().loop_header_.IsValid());
174 }
175 LoopData loop_data = {Rpo::Invalid(), loop_blocks};
176 loop_blocks_.push_back(loop_data);
177 }
178
179 void EndLoop() {
180 CHECK(current_block_ == nullptr);
181 CHECK(!loop_blocks_.empty());
182 CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
183 loop_blocks_.pop_back();
184 }
185
186 void StartBlock() {
187 block_returns_ = false;
188 NewBlock();
189 }
190
191 int EndBlock(BlockCompletion completion = FallThrough()) {
192 int instruction_index = kMinInt;
193 if (block_returns_) {
194 CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
195 completion.type_ = kBlockEnd;
196 }
197 switch (completion.type_) {
198 case kBlockEnd:
199 break;
200 case kFallThrough:
201 instruction_index = EmitFallThrough();
202 break;
203 case kJump:
204 CHECK(!block_returns_);
205 instruction_index = EmitJump();
206 break;
207 case kBranch:
208 CHECK(!block_returns_);
209 instruction_index = EmitBranch(completion.op_);
210 break;
211 }
212 completions_.push_back(completion);
213 CHECK(current_block_ != nullptr);
214 sequence()->EndBlock(current_block_->rpo_number());
215 current_block_ = nullptr;
216 return instruction_index;
217 }
218
219 void Allocate() { 14 void Allocate() {
220 CHECK_EQ(nullptr, current_block_);
221 WireBlocks(); 15 WireBlocks();
222 Pipeline::AllocateRegistersForTesting(config(), sequence(), true); 16 Pipeline::AllocateRegistersForTesting(config(), sequence(), true);
223 } 17 }
224
225 TestOperand Imm(int32_t imm = 0) {
226 int index = sequence()->AddImmediate(Constant(imm));
227 return TestOperand(kImmediate, index);
228 }
229
230 VReg Parameter(TestOperand output_op = Reg()) {
231 VReg vreg = NewReg();
232 InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
233 Emit(vreg.value_, kArchNop, 1, outputs);
234 return vreg;
235 }
236
237 int Return(TestOperand input_op_0) {
238 block_returns_ = true;
239 InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
240 return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
241 }
242
243 int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
244
245 PhiInstruction* Phi(VReg incoming_vreg) {
246 PhiInstruction* phi =
247 new (zone()) PhiInstruction(zone(), NewReg().value_, 10);
248 phi->Extend(zone(), incoming_vreg.value_);
249 current_block_->AddPhi(phi);
250 return phi;
251 }
252
253 PhiInstruction* Phi(VReg incoming_vreg_0, VReg incoming_vreg_1) {
254 auto phi = Phi(incoming_vreg_0);
255 Extend(phi, incoming_vreg_1);
256 return phi;
257 }
258
259 void Extend(PhiInstruction* phi, VReg vreg) {
260 phi->Extend(zone(), vreg.value_);
261 }
262
263 VReg DefineConstant(int32_t imm = 0) {
264 VReg vreg = NewReg();
265 sequence()->AddConstant(vreg.value_, Constant(imm));
266 InstructionOperand* outputs[1]{
267 ConstantOperand::Create(vreg.value_, zone())};
268 Emit(vreg.value_, kArchNop, 1, outputs);
269 return vreg;
270 }
271
272 VReg EmitOII(TestOperand output_op, TestOperand input_op_0,
273 TestOperand input_op_1) {
274 VReg output_vreg = NewReg();
275 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
276 InstructionOperand* inputs[2]{ConvertInputOp(input_op_0),
277 ConvertInputOp(input_op_1)};
278 Emit(output_vreg.value_, kArchNop, 1, outputs, 2, inputs);
279 return output_vreg;
280 }
281
282 VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs) {
283 VReg output_vreg = NewReg();
284 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
285 InstructionOperand** mapped_inputs =
286 zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
287 for (size_t i = 0; i < input_size; ++i) {
288 mapped_inputs[i] = ConvertInputOp(inputs[i]);
289 }
290 Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
291 mapped_inputs);
292 return output_vreg;
293 }
294
295 // Get defining instruction vreg or value returned at instruction creation
296 // time when there is no return value.
297 const Instruction* GetInstruction(int instruction_index) {
298 auto it = instructions_.find(instruction_index);
299 CHECK(it != instructions_.end());
300 return it->second;
301 }
302
303 private:
304 VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
305 int NewIndex() { return current_instruction_index_--; }
306
307 static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
308
309 int EmitBranch(TestOperand input_op) {
310 InstructionOperand* inputs[4]{ConvertInputOp(input_op),
311 ConvertInputOp(Imm()), ConvertInputOp(Imm()),
312 ConvertInputOp(Imm())};
313 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
314 FlagsConditionField::encode(kEqual);
315 auto instruction =
316 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
317 return AddInstruction(NewIndex(), instruction);
318 }
319
320 int EmitFallThrough() {
321 auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
322 return AddInstruction(NewIndex(), instruction);
323 }
324
325 int EmitJump() {
326 InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
327 auto instruction =
328 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
329 return AddInstruction(NewIndex(), instruction);
330 }
331
332 Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
333 InstructionOperand** outputs,
334 size_t inputs_size = 0,
335 InstructionOperand* *inputs = nullptr,
336 size_t temps_size = 0,
337 InstructionOperand* *temps = nullptr) {
338 CHECK_NE(nullptr, current_block_);
339 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
340 inputs, temps_size, temps);
341 }
342
343 InstructionOperand* Unallocated(TestOperand op,
344 UnallocatedOperand::ExtendedPolicy policy) {
345 auto unallocated = new (zone()) UnallocatedOperand(policy);
346 unallocated->set_virtual_register(op.vreg_.value_);
347 return unallocated;
348 }
349
350 InstructionOperand* Unallocated(TestOperand op,
351 UnallocatedOperand::ExtendedPolicy policy,
352 UnallocatedOperand::Lifetime lifetime) {
353 auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
354 unallocated->set_virtual_register(op.vreg_.value_);
355 return unallocated;
356 }
357
358 InstructionOperand* Unallocated(TestOperand op,
359 UnallocatedOperand::ExtendedPolicy policy,
360 int index) {
361 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
362 unallocated->set_virtual_register(op.vreg_.value_);
363 return unallocated;
364 }
365
366 InstructionOperand* Unallocated(TestOperand op,
367 UnallocatedOperand::BasicPolicy policy,
368 int index) {
369 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
370 unallocated->set_virtual_register(op.vreg_.value_);
371 return unallocated;
372 }
373
374 InstructionOperand* ConvertInputOp(TestOperand op) {
375 if (op.type_ == kImmediate) {
376 CHECK_EQ(op.vreg_.value_, kNoValue);
377 return ImmediateOperand::Create(op.value_, zone());
378 }
379 CHECK_NE(op.vreg_.value_, kNoValue);
380 switch (op.type_) {
381 case kNone:
382 return Unallocated(op, UnallocatedOperand::NONE,
383 UnallocatedOperand::USED_AT_START);
384 case kRegister:
385 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
386 UnallocatedOperand::USED_AT_START);
387 case kFixedRegister:
388 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
389 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
390 default:
391 break;
392 }
393 CHECK(false);
394 return NULL;
395 }
396
397 InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op) {
398 CHECK_EQ(op.vreg_.value_, kNoValue);
399 op.vreg_ = vreg;
400 switch (op.type_) {
401 case kSameAsFirst:
402 return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
403 case kRegister:
404 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
405 case kFixedSlot:
406 return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
407 case kFixedRegister:
408 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
409 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
410 default:
411 break;
412 }
413 CHECK(false);
414 return NULL;
415 }
416
417 InstructionBlock* NewBlock() {
418 CHECK(current_block_ == nullptr);
419 auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
420 Rpo rpo = Rpo::FromInt(block_id.ToInt());
421 Rpo loop_header = Rpo::Invalid();
422 Rpo loop_end = Rpo::Invalid();
423 if (!loop_blocks_.empty()) {
424 auto& loop_data = loop_blocks_.back();
425 // This is a loop header.
426 if (!loop_data.loop_header_.IsValid()) {
427 loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
428 loop_data.expected_blocks_--;
429 loop_data.loop_header_ = rpo;
430 } else {
431 // This is a loop body.
432 CHECK_NE(0, loop_data.expected_blocks_);
433 // TODO(dcarney): handle nested loops.
434 loop_data.expected_blocks_--;
435 loop_header = loop_data.loop_header_;
436 }
437 }
438 // Construct instruction block.
439 auto instruction_block = new (zone()) InstructionBlock(
440 zone(), block_id, rpo, rpo, loop_header, loop_end, false);
441 instruction_blocks_.push_back(instruction_block);
442 current_block_ = instruction_block;
443 sequence()->StartBlock(rpo);
444 return instruction_block;
445 }
446
447 void WireBlocks() {
448 CHECK(instruction_blocks_.size() == completions_.size());
449 size_t offset = 0;
450 for (const auto& completion : completions_) {
451 switch (completion.type_) {
452 case kBlockEnd:
453 break;
454 case kFallThrough: // Fallthrough.
455 case kJump:
456 WireBlock(offset, completion.offset_0_);
457 break;
458 case kBranch:
459 WireBlock(offset, completion.offset_0_);
460 WireBlock(offset, completion.offset_1_);
461 break;
462 }
463 ++offset;
464 }
465 }
466
467 void WireBlock(size_t block_offset, int jump_offset) {
468 size_t target_block_offset =
469 block_offset + static_cast<size_t>(jump_offset);
470 CHECK(block_offset < instruction_blocks_.size());
471 CHECK(target_block_offset < instruction_blocks_.size());
472 auto block = instruction_blocks_[block_offset];
473 auto target = instruction_blocks_[target_block_offset];
474 block->successors().push_back(target->rpo_number());
475 target->predecessors().push_back(block->rpo_number());
476 }
477
478 int Emit(int instruction_index, InstructionCode code, size_t outputs_size,
479 InstructionOperand** outputs, size_t inputs_size = 0,
480 InstructionOperand* *inputs = nullptr, size_t temps_size = 0,
481 InstructionOperand* *temps = nullptr) {
482 auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
483 inputs, temps_size, temps);
484 return AddInstruction(instruction_index, instruction);
485 }
486
487 int AddInstruction(int instruction_index, Instruction* instruction) {
488 sequence()->AddInstruction(instruction);
489 return instruction_index;
490 }
491
492 struct LoopData {
493 Rpo loop_header_;
494 int expected_blocks_;
495 };
496
497 typedef std::vector<LoopData> LoopBlocks;
498 typedef std::map<int, const Instruction*> Instructions;
499 typedef std::vector<BlockCompletion> Completions;
500
501 SmartPointer<RegisterConfiguration> config_;
502 Frame* frame_;
503 InstructionSequence* sequence_;
504 int num_general_registers_;
505 int num_double_registers_;
506
507 // Block building state.
508 InstructionBlocks instruction_blocks_;
509 Instructions instructions_;
510 int current_instruction_index_;
511 Completions completions_;
512 LoopBlocks loop_blocks_;
513 InstructionBlock* current_block_;
514 bool block_returns_;
515 }; 18 };
516 19
517 20
518 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { 21 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
519 // return p0 + p1; 22 // return p0 + p1;
520 StartBlock(); 23 StartBlock();
521 auto a_reg = Parameter(); 24 auto a_reg = Parameter();
522 auto b_reg = Parameter(); 25 auto b_reg = Parameter();
523 auto c_reg = EmitOII(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0)); 26 auto c_reg = EmitOII(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
524 Return(c_reg); 27 Return(c_reg);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 for (int i = 0; i < kPhis; ++i) { 131 for (int i = 0; i < kPhis; ++i) {
629 f_vals[i] = DefineConstant(); 132 f_vals[i] = DefineConstant();
630 } 133 }
631 EndBlock(Jump(1)); 134 EndBlock(Jump(1));
632 135
633 StartBlock(); 136 StartBlock();
634 TestOperand merged[kPhis]; 137 TestOperand merged[kPhis];
635 for (int i = 0; i < kPhis; ++i) { 138 for (int i = 0; i < kPhis; ++i) {
636 merged[i] = Use(Phi(t_vals[i], f_vals[i])); 139 merged[i] = Use(Phi(t_vals[i], f_vals[i]));
637 } 140 }
638 Return(EmitCall(Reg(), kPhis, merged)); 141 Return(EmitCall(Slot(-1), kPhis, merged));
639 EndBlock(); 142 EndBlock();
640 143
641 Allocate(); 144 Allocate();
642 } 145 }
643 146
644 147
645 TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) { 148 TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
646 const int kPhis = kDefaultNRegs * 2; 149 const int kPhis = kDefaultNRegs * 2;
647 150
648 // First diamond. 151 // First diamond.
(...skipping 18 matching lines...) Expand all
667 EndBlock(Jump(2)); 170 EndBlock(Jump(2));
668 171
669 StartBlock(); 172 StartBlock();
670 EndBlock(Jump(1)); 173 EndBlock(Jump(1));
671 174
672 StartBlock(); 175 StartBlock();
673 TestOperand merged[kPhis]; 176 TestOperand merged[kPhis];
674 for (int i = 0; i < kPhis; ++i) { 177 for (int i = 0; i < kPhis; ++i) {
675 merged[i] = Use(Phi(vals[i], vals[i])); 178 merged[i] = Use(Phi(vals[i], vals[i]));
676 } 179 }
677 Return(EmitCall(Reg(), kPhis, merged)); 180 Return(EmitCall(Reg(0), kPhis, merged));
678 EndBlock(); 181 EndBlock();
679 182
680 Allocate(); 183 Allocate();
681 } 184 }
682 185
683 186
684 TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) { 187 TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
685 const size_t kNumRegs = 3; 188 const size_t kNumRegs = 3;
686 const size_t kParams = kNumRegs + 1; 189 const size_t kParams = kNumRegs + 1;
687 // Override number of registers. 190 // Override number of registers.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 EndLoop(); 225 EndLoop();
723 } 226 }
724 227
725 StartBlock(); 228 StartBlock();
726 Return(DefineConstant()); 229 Return(DefineConstant());
727 EndBlock(); 230 EndBlock();
728 231
729 Allocate(); 232 Allocate();
730 } 233 }
731 234
235
236 TEST_F(RegisterAllocatorTest, SpillPhi) {
237 StartBlock();
238 EndBlock(Branch(Imm(), 1, 2));
239
240 StartBlock();
241 auto left = Define(Reg(0));
242 EndBlock(Jump(2));
243
244 StartBlock();
245 auto right = Define(Reg(0));
246 EndBlock();
247
248 StartBlock();
249 auto phi = Phi(left, right);
250 EmitCall(Slot(-1));
251 Return(Reg(phi));
252 EndBlock();
253
254 Allocate();
255 }
256
257
258 TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
259 StartBlock();
260 VReg constants[kDefaultNRegs];
261 for (size_t i = 0; i < arraysize(constants); ++i) {
262 constants[i] = DefineConstant();
263 }
264 TestOperand call_ops[kDefaultNRegs * 2];
265 for (int i = 0; i < kDefaultNRegs; ++i) {
266 call_ops[i] = Reg(constants[i], i);
267 }
268 for (int i = 0; i < kDefaultNRegs; ++i) {
269 call_ops[i + kDefaultNRegs] = Slot(constants[i], i);
270 }
271 EmitCall(Slot(-1), arraysize(call_ops), call_ops);
272 EndBlock(Last());
273
274 Allocate();
275 }
276
732 } // namespace compiler 277 } // namespace compiler
733 } // namespace internal 278 } // namespace internal
734 } // namespace v8 279 } // namespace v8
OLDNEW
« no previous file with comments | « test/unittests/compiler/move-optimizer-unittest.cc ('k') | test/unittests/unittests.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698