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

Side by Side Diff: test/unittests/compiler/instruction-sequence-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
OLDNEW
(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/pipeline.h"
7 #include "test/unittests/compiler/instruction-sequence-unittest.h"
8 #include "test/unittests/test-utils.h"
9 #include "testing/gmock/include/gmock/gmock.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 static const char*
16 general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
17 static const char*
18 double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
19 static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
20 RegisterConfiguration::kMaxDoubleRegisters)];
21
22
23 static void InitializeRegisterNames() {
24 char* loc = register_names_;
25 for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
26 general_register_names_[i] = loc;
27 loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
28 *loc++ = 0;
29 }
30 for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
31 double_register_names_[i] = loc;
32 loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
33 *loc++ = 0;
34 }
35 }
36
37
38 InstructionSequenceTest::InstructionSequenceTest()
39 : sequence_(nullptr),
40 num_general_registers_(kDefaultNRegs),
41 num_double_registers_(kDefaultNRegs),
42 instruction_blocks_(zone()),
43 current_instruction_index_(-1),
44 current_block_(nullptr),
45 block_returns_(false) {
46 InitializeRegisterNames();
47 }
48
49
50 void InstructionSequenceTest::SetNumRegs(int num_general_registers,
51 int num_double_registers) {
52 CHECK(config_.is_empty());
53 CHECK(instructions_.empty());
54 CHECK(instruction_blocks_.empty());
55 num_general_registers_ = num_general_registers;
56 num_double_registers_ = num_double_registers;
57 }
58
59
60 RegisterConfiguration* InstructionSequenceTest::config() {
61 if (config_.is_empty()) {
62 config_.Reset(new RegisterConfiguration(
63 num_general_registers_, num_double_registers_, num_double_registers_,
64 general_register_names_, double_register_names_));
65 }
66 return config_.get();
67 }
68
69
70 InstructionSequence* InstructionSequenceTest::sequence() {
71 if (sequence_ == nullptr) {
72 sequence_ = new (zone()) InstructionSequence(zone(), &instruction_blocks_);
73 }
74 return sequence_;
75 }
76
77
78 void InstructionSequenceTest::StartLoop(int loop_blocks) {
79 CHECK(current_block_ == nullptr);
80 if (!loop_blocks_.empty()) {
81 CHECK(!loop_blocks_.back().loop_header_.IsValid());
82 }
83 LoopData loop_data = {Rpo::Invalid(), loop_blocks};
84 loop_blocks_.push_back(loop_data);
85 }
86
87
88 void InstructionSequenceTest::EndLoop() {
89 CHECK(current_block_ == nullptr);
90 CHECK(!loop_blocks_.empty());
91 CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
92 loop_blocks_.pop_back();
93 }
94
95
96 void InstructionSequenceTest::StartBlock() {
97 block_returns_ = false;
98 NewBlock();
99 }
100
101
102 int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
103 int instruction_index = kMinInt;
104 if (block_returns_) {
105 CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
106 completion.type_ = kBlockEnd;
107 }
108 switch (completion.type_) {
109 case kBlockEnd:
110 break;
111 case kFallThrough:
112 instruction_index = EmitFallThrough();
113 break;
114 case kJump:
115 CHECK(!block_returns_);
116 instruction_index = EmitJump();
117 break;
118 case kBranch:
119 CHECK(!block_returns_);
120 instruction_index = EmitBranch(completion.op_);
121 break;
122 }
123 completions_.push_back(completion);
124 CHECK(current_block_ != nullptr);
125 sequence()->EndBlock(current_block_->rpo_number());
126 current_block_ = nullptr;
127 return instruction_index;
128 }
129
130
131 InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
132 int index = sequence()->AddImmediate(Constant(imm));
133 return TestOperand(kImmediate, index);
134 }
135
136
137 InstructionSequenceTest::VReg InstructionSequenceTest::Define(
138 TestOperand output_op) {
139 VReg vreg = NewReg();
140 InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
141 Emit(vreg.value_, kArchNop, 1, outputs);
142 return vreg;
143 }
144
145
146 int InstructionSequenceTest::Return(TestOperand input_op_0) {
147 block_returns_ = true;
148 InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
149 return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
150 }
151
152
153 PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
154 VReg incoming_vreg_1,
155 VReg incoming_vreg_2,
156 VReg incoming_vreg_3) {
157 auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, 10);
158 VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
159 incoming_vreg_3};
160 for (size_t i = 0; i < arraysize(inputs); ++i) {
161 if (inputs[i].value_ == kNoValue) break;
162 Extend(phi, inputs[i]);
163 }
164 current_block_->AddPhi(phi);
165 return phi;
166 }
167
168
169 void InstructionSequenceTest::Extend(PhiInstruction* phi, VReg vreg) {
170 phi->Extend(zone(), vreg.value_);
171 }
172
173
174 InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
175 int32_t imm) {
176 VReg vreg = NewReg();
177 sequence()->AddConstant(vreg.value_, Constant(imm));
178 InstructionOperand* outputs[1]{ConstantOperand::Create(vreg.value_, zone())};
179 Emit(vreg.value_, kArchNop, 1, outputs);
180 return vreg;
181 }
182
183
184 int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
185
186
187 int InstructionSequenceTest::EmitI(TestOperand input_op_0) {
188 InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
189 return Emit(NewIndex(), kArchNop, 0, nullptr, 1, inputs);
190 }
191
192
193 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
194 TestOperand output_op, TestOperand input_op_0) {
195 VReg output_vreg = NewReg();
196 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
197 InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
198 Emit(output_vreg.value_, kArchNop, 1, outputs, 1, inputs);
199 return output_vreg;
200 }
201
202
203 InstructionSequenceTest::VReg InstructionSequenceTest::EmitOII(
204 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1) {
205 VReg output_vreg = NewReg();
206 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
207 InstructionOperand* inputs[2]{ConvertInputOp(input_op_0),
208 ConvertInputOp(input_op_1)};
209 Emit(output_vreg.value_, kArchNop, 1, outputs, 2, inputs);
210 return output_vreg;
211 }
212
213
214 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
215 TestOperand output_op, size_t input_size, TestOperand* inputs) {
216 VReg output_vreg = NewReg();
217 InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
218 CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy());
219 InstructionOperand** mapped_inputs =
220 zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
221 for (size_t i = 0; i < input_size; ++i) {
222 mapped_inputs[i] = ConvertInputOp(inputs[i]);
223 }
224 Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
225 mapped_inputs, 0, nullptr, true);
226 return output_vreg;
227 }
228
229
230 InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
231 TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
232 TestOperand input_op_2, TestOperand input_op_3) {
233 TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
234 size_t size = 0;
235 for (; size < arraysize(inputs); ++size) {
236 if (inputs[size].type_ == kInvalid) break;
237 }
238 return EmitCall(output_op, size, inputs);
239 }
240
241
242 const Instruction* InstructionSequenceTest::GetInstruction(
243 int instruction_index) {
244 auto it = instructions_.find(instruction_index);
245 CHECK(it != instructions_.end());
246 return it->second;
247 }
248
249
250 int InstructionSequenceTest::EmitBranch(TestOperand input_op) {
251 InstructionOperand* inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
252 ConvertInputOp(Imm()), ConvertInputOp(Imm())};
253 InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
254 FlagsConditionField::encode(kEqual);
255 auto instruction =
256 NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
257 return AddInstruction(NewIndex(), instruction);
258 }
259
260
261 int InstructionSequenceTest::EmitFallThrough() {
262 auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
263 return AddInstruction(NewIndex(), instruction);
264 }
265
266
267 int InstructionSequenceTest::EmitJump() {
268 InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
269 auto instruction =
270 NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
271 return AddInstruction(NewIndex(), instruction);
272 }
273
274
275 Instruction* InstructionSequenceTest::NewInstruction(
276 InstructionCode code, size_t outputs_size, InstructionOperand** outputs,
277 size_t inputs_size, InstructionOperand** inputs, size_t temps_size,
278 InstructionOperand** temps) {
279 CHECK_NE(nullptr, current_block_);
280 return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
281 inputs, temps_size, temps);
282 }
283
284
285 InstructionOperand* InstructionSequenceTest::Unallocated(
286 TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
287 auto unallocated = new (zone()) UnallocatedOperand(policy);
288 unallocated->set_virtual_register(op.vreg_.value_);
289 return unallocated;
290 }
291
292
293 InstructionOperand* InstructionSequenceTest::Unallocated(
294 TestOperand op, UnallocatedOperand::ExtendedPolicy policy,
295 UnallocatedOperand::Lifetime lifetime) {
296 auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
297 unallocated->set_virtual_register(op.vreg_.value_);
298 return unallocated;
299 }
300
301
302 InstructionOperand* InstructionSequenceTest::Unallocated(
303 TestOperand op, UnallocatedOperand::ExtendedPolicy policy, int index) {
304 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
305 unallocated->set_virtual_register(op.vreg_.value_);
306 return unallocated;
307 }
308
309
310 InstructionOperand* InstructionSequenceTest::Unallocated(
311 TestOperand op, UnallocatedOperand::BasicPolicy policy, int index) {
312 auto unallocated = new (zone()) UnallocatedOperand(policy, index);
313 unallocated->set_virtual_register(op.vreg_.value_);
314 return unallocated;
315 }
316
317
318 InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) {
319 if (op.type_ == kImmediate) {
320 CHECK_EQ(op.vreg_.value_, kNoValue);
321 return ImmediateOperand::Create(op.value_, zone());
322 }
323 CHECK_NE(op.vreg_.value_, kNoValue);
324 switch (op.type_) {
325 case kNone:
326 return Unallocated(op, UnallocatedOperand::NONE,
327 UnallocatedOperand::USED_AT_START);
328 case kRegister:
329 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
330 UnallocatedOperand::USED_AT_START);
331 case kFixedRegister:
332 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
333 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
334 case kFixedSlot:
335 return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
336 default:
337 break;
338 }
339 CHECK(false);
340 return NULL;
341 }
342
343
344 InstructionOperand* InstructionSequenceTest::ConvertOutputOp(VReg vreg,
345 TestOperand op) {
346 CHECK_EQ(op.vreg_.value_, kNoValue);
347 op.vreg_ = vreg;
348 switch (op.type_) {
349 case kSameAsFirst:
350 return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
351 case kRegister:
352 return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
353 case kFixedSlot:
354 return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
355 case kFixedRegister:
356 CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
357 return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
358 default:
359 break;
360 }
361 CHECK(false);
362 return NULL;
363 }
364
365
366 InstructionBlock* InstructionSequenceTest::NewBlock() {
367 CHECK(current_block_ == nullptr);
368 auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
369 Rpo rpo = Rpo::FromInt(block_id.ToInt());
370 Rpo loop_header = Rpo::Invalid();
371 Rpo loop_end = Rpo::Invalid();
372 if (!loop_blocks_.empty()) {
373 auto& loop_data = loop_blocks_.back();
374 // This is a loop header.
375 if (!loop_data.loop_header_.IsValid()) {
376 loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
377 loop_data.expected_blocks_--;
378 loop_data.loop_header_ = rpo;
379 } else {
380 // This is a loop body.
381 CHECK_NE(0, loop_data.expected_blocks_);
382 // TODO(dcarney): handle nested loops.
383 loop_data.expected_blocks_--;
384 loop_header = loop_data.loop_header_;
385 }
386 }
387 // Construct instruction block.
388 auto instruction_block = new (zone()) InstructionBlock(
389 zone(), block_id, rpo, rpo, loop_header, loop_end, false);
390 instruction_blocks_.push_back(instruction_block);
391 current_block_ = instruction_block;
392 sequence()->StartBlock(rpo);
393 return instruction_block;
394 }
395
396
397 void InstructionSequenceTest::WireBlocks() {
398 CHECK_EQ(nullptr, current_block());
399 CHECK(instruction_blocks_.size() == completions_.size());
400 size_t offset = 0;
401 for (const auto& completion : completions_) {
402 switch (completion.type_) {
403 case kBlockEnd:
404 break;
405 case kFallThrough: // Fallthrough.
406 case kJump:
407 WireBlock(offset, completion.offset_0_);
408 break;
409 case kBranch:
410 WireBlock(offset, completion.offset_0_);
411 WireBlock(offset, completion.offset_1_);
412 break;
413 }
414 ++offset;
415 }
416 }
417
418
419 void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
420 size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
421 CHECK(block_offset < instruction_blocks_.size());
422 CHECK(target_block_offset < instruction_blocks_.size());
423 auto block = instruction_blocks_[block_offset];
424 auto target = instruction_blocks_[target_block_offset];
425 block->successors().push_back(target->rpo_number());
426 target->predecessors().push_back(block->rpo_number());
427 }
428
429
430 int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code,
431 size_t outputs_size,
432 InstructionOperand** outputs,
433 size_t inputs_size,
434 InstructionOperand** inputs,
435 size_t temps_size, InstructionOperand** temps,
436 bool is_call) {
437 auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
438 inputs, temps_size, temps);
439 if (is_call) instruction->MarkAsCall();
440 return AddInstruction(instruction_index, instruction);
441 }
442
443
444 int InstructionSequenceTest::AddInstruction(int instruction_index,
445 Instruction* instruction) {
446 sequence()->AddInstruction(instruction);
447 return instruction_index;
448 }
449
450 } // namespace compiler
451 } // namespace internal
452 } // namespace v8
OLDNEW
« no previous file with comments | « test/unittests/compiler/instruction-sequence-unittest.h ('k') | test/unittests/compiler/move-optimizer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698