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.
6 #include "test/cctest/cctest.h"
8 #include "src/compiler/code-generator.h"
9 #include "src/compiler/common-operator.h"
10 #include "src/compiler/graph.h"
11 #include "src/compiler/instruction.h"
12 #include "src/compiler/linkage.h"
13 #include "src/compiler/machine-operator.h"
14 #include "src/compiler/node.h"
15 #include "src/compiler/operator.h"
16 #include "src/compiler/schedule.h"
17 #include "src/compiler/scheduler.h"
18 #include "src/lithium.h"
20 using namespace v8::internal;
21 using namespace v8::internal::compiler;
23 typedef v8::internal::compiler::Instruction TestInstr;
24 typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
26 // A testing helper for the register code abstraction.
27 class InstructionTester : public HandleAndZoneScope {
28 public: // We're all friends here.
30 : isolate(main_isolate()),
33 info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
34 linkage(zone(), &info),
38 ~InstructionTester() { delete code; }
43 CompilationInfoWithZone info;
45 CommonOperatorBuilder common;
46 MachineOperatorBuilder machine;
49 Zone* zone() { return main_zone(); }
52 if (schedule.rpo_order()->size() == 0) {
53 // Compute the RPO order.
54 ZonePool zone_pool(isolate);
55 Scheduler::ComputeSpecialRPO(&zone_pool, &schedule);
56 DCHECK(schedule.rpo_order()->size() > 0);
58 InstructionBlocks* instruction_blocks =
59 TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
60 code = new TestInstrSeq(main_zone(), instruction_blocks);
63 Node* Int32Constant(int32_t val) {
64 Node* node = graph.NewNode(common.Int32Constant(val));
65 schedule.AddNode(schedule.start(), node);
69 Node* Float64Constant(double val) {
70 Node* node = graph.NewNode(common.Float64Constant(val));
71 schedule.AddNode(schedule.start(), node);
75 Node* Parameter(int32_t which) {
76 Node* node = graph.NewNode(common.Parameter(which));
77 schedule.AddNode(schedule.start(), node);
81 Node* NewNode(BasicBlock* block) {
82 Node* node = graph.NewNode(common.Int32Constant(111));
83 schedule.AddNode(block, node);
88 InstructionCode opcode = static_cast<InstructionCode>(110);
89 TestInstr* instr = TestInstr::New(zone(), opcode);
90 return code->AddInstruction(instr);
93 UnallocatedOperand* NewUnallocated(int vreg) {
94 UnallocatedOperand* unallocated =
95 new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
96 unallocated->set_virtual_register(vreg);
100 InstructionBlock* BlockAt(BasicBlock* block) {
101 return code->InstructionBlockAt(block->GetRpoNumber());
103 BasicBlock* GetBasicBlock(int instruction_index) {
104 const InstructionBlock* block =
105 code->GetInstructionBlock(instruction_index);
106 return schedule.rpo_order()->at(block->rpo_number().ToSize());
108 int first_instruction_index(BasicBlock* block) {
109 return BlockAt(block)->first_instruction_index();
111 int last_instruction_index(BasicBlock* block) {
112 return BlockAt(block)->last_instruction_index();
117 TEST(InstructionBasic) {
120 for (int i = 0; i < 10; i++) {
121 R.Int32Constant(i); // Add some nodes to the graph.
124 BasicBlock* last = R.schedule.start();
125 for (int i = 0; i < 5; i++) {
126 BasicBlock* block = R.schedule.NewBasicBlock();
127 R.schedule.AddGoto(last, block);
133 BasicBlockVector* blocks = R.schedule.rpo_order();
134 CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
137 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
139 BasicBlock* block = *i;
140 CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
141 CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
142 CHECK_EQ(-1, block->loop_end());
147 TEST(InstructionGetBasicBlock) {
150 BasicBlock* b0 = R.schedule.start();
151 BasicBlock* b1 = R.schedule.NewBasicBlock();
152 BasicBlock* b2 = R.schedule.NewBasicBlock();
153 BasicBlock* b3 = R.schedule.end();
155 R.schedule.AddGoto(b0, b1);
156 R.schedule.AddGoto(b1, b2);
157 R.schedule.AddGoto(b2, b3);
161 R.code->StartBlock(b0);
162 int i0 = R.NewInstr();
163 int i1 = R.NewInstr();
164 R.code->EndBlock(b0);
165 R.code->StartBlock(b1);
166 int i2 = R.NewInstr();
167 int i3 = R.NewInstr();
168 int i4 = R.NewInstr();
169 int i5 = R.NewInstr();
170 R.code->EndBlock(b1);
171 R.code->StartBlock(b2);
172 int i6 = R.NewInstr();
173 int i7 = R.NewInstr();
174 int i8 = R.NewInstr();
175 R.code->EndBlock(b2);
176 R.code->StartBlock(b3);
177 R.code->EndBlock(b3);
179 CHECK_EQ(b0, R.GetBasicBlock(i0));
180 CHECK_EQ(b0, R.GetBasicBlock(i1));
182 CHECK_EQ(b1, R.GetBasicBlock(i2));
183 CHECK_EQ(b1, R.GetBasicBlock(i3));
184 CHECK_EQ(b1, R.GetBasicBlock(i4));
185 CHECK_EQ(b1, R.GetBasicBlock(i5));
187 CHECK_EQ(b2, R.GetBasicBlock(i6));
188 CHECK_EQ(b2, R.GetBasicBlock(i7));
189 CHECK_EQ(b2, R.GetBasicBlock(i8));
191 CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
192 CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
194 CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
195 CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
197 CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
198 CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
200 CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
201 CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
205 TEST(InstructionIsGapAt) {
208 BasicBlock* b0 = R.schedule.start();
209 R.schedule.AddReturn(b0, R.Int32Constant(1));
212 TestInstr* i0 = TestInstr::New(R.zone(), 100);
213 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
214 R.code->StartBlock(b0);
215 R.code->AddInstruction(i0);
216 R.code->AddInstruction(g);
217 R.code->EndBlock(b0);
219 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
221 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
222 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
223 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
224 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
225 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
226 CHECK_EQ(false, R.code->IsGapAt(5)); // g
230 TEST(InstructionIsGapAt2) {
233 BasicBlock* b0 = R.schedule.start();
234 BasicBlock* b1 = R.schedule.end();
235 R.schedule.AddGoto(b0, b1);
236 R.schedule.AddReturn(b1, R.Int32Constant(1));
239 TestInstr* i0 = TestInstr::New(R.zone(), 100);
240 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
241 R.code->StartBlock(b0);
242 R.code->AddInstruction(i0);
243 R.code->AddInstruction(g);
244 R.code->EndBlock(b0);
246 TestInstr* i1 = TestInstr::New(R.zone(), 102);
247 TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
248 R.code->StartBlock(b1);
249 R.code->AddInstruction(i1);
250 R.code->AddInstruction(g1);
251 R.code->EndBlock(b1);
253 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
255 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
256 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
257 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
258 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
259 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
260 CHECK_EQ(false, R.code->IsGapAt(5)); // g
262 CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
264 CHECK_EQ(true, R.code->IsGapAt(6)); // Label
265 CHECK_EQ(true, R.code->IsGapAt(7)); // Gap
266 CHECK_EQ(false, R.code->IsGapAt(8)); // i1
267 CHECK_EQ(true, R.code->IsGapAt(9)); // Gap
268 CHECK_EQ(true, R.code->IsGapAt(10)); // Gap
269 CHECK_EQ(false, R.code->IsGapAt(11)); // g1
273 TEST(InstructionAddGapMove) {
276 BasicBlock* b0 = R.schedule.start();
277 R.schedule.AddReturn(b0, R.Int32Constant(1));
280 TestInstr* i0 = TestInstr::New(R.zone(), 100);
281 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
282 R.code->StartBlock(b0);
283 R.code->AddInstruction(i0);
284 R.code->AddInstruction(g);
285 R.code->EndBlock(b0);
287 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
289 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
290 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
291 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
292 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
293 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
294 CHECK_EQ(false, R.code->IsGapAt(5)); // g
296 int indexes[] = {0, 1, 3, 4, -1};
297 for (int i = 0; indexes[i] >= 0; i++) {
298 int index = indexes[i];
300 UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
301 UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
303 R.code->AddGapMove(index, op1, op2);
304 GapInstruction* gap = R.code->GapAt(index);
305 ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
306 CHECK_NE(NULL, move);
307 const ZoneList<MoveOperands>* move_operands = move->move_operands();
308 CHECK_EQ(1, move_operands->length());
309 MoveOperands* cur = &move_operands->at(0);
310 CHECK_EQ(op1, cur->source());
311 CHECK_EQ(op2, cur->destination());
316 TEST(InstructionOperands) {
317 Zone zone(CcTest::InitIsolateOnce());
320 TestInstr* i = TestInstr::New(&zone, 101);
321 CHECK_EQ(0, static_cast<int>(i->OutputCount()));
322 CHECK_EQ(0, static_cast<int>(i->InputCount()));
323 CHECK_EQ(0, static_cast<int>(i->TempCount()));
326 InstructionOperand* outputs[] = {
327 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
328 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
329 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
330 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
332 InstructionOperand* inputs[] = {
333 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
334 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
335 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
336 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
338 InstructionOperand* temps[] = {
339 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
340 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
341 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
342 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
344 for (size_t i = 0; i < arraysize(outputs); i++) {
345 for (size_t j = 0; j < arraysize(inputs); j++) {
346 for (size_t k = 0; k < arraysize(temps); k++) {
348 TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
349 CHECK(i == m->OutputCount());
350 CHECK(j == m->InputCount());
351 CHECK(k == m->TempCount());
353 for (size_t z = 0; z < i; z++) {
354 CHECK_EQ(outputs[z], m->OutputAt(z));
357 for (size_t z = 0; z < j; z++) {
358 CHECK_EQ(inputs[z], m->InputAt(z));
361 for (size_t z = 0; z < k; z++) {
362 CHECK_EQ(temps[z], m->TempAt(z));