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()),
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 Scheduler::ComputeSpecialRPO(&schedule);
55 DCHECK(schedule.rpo_order()->size() > 0);
57 code = new TestInstrSeq(&linkage, &graph, &schedule);
60 Node* Int32Constant(int32_t val) {
61 Node* node = graph.NewNode(common.Int32Constant(val));
62 schedule.AddNode(schedule.start(), node);
66 Node* Float64Constant(double val) {
67 Node* node = graph.NewNode(common.Float64Constant(val));
68 schedule.AddNode(schedule.start(), node);
72 Node* Parameter(int32_t which) {
73 Node* node = graph.NewNode(common.Parameter(which));
74 schedule.AddNode(schedule.start(), node);
78 Node* NewNode(BasicBlock* block) {
79 Node* node = graph.NewNode(common.Int32Constant(111));
80 schedule.AddNode(block, node);
84 int NewInstr(BasicBlock* block) {
85 InstructionCode opcode = static_cast<InstructionCode>(110);
86 TestInstr* instr = TestInstr::New(zone(), opcode);
87 return code->AddInstruction(instr, block);
90 UnallocatedOperand* NewUnallocated(int vreg) {
91 UnallocatedOperand* unallocated =
92 new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
93 unallocated->set_virtual_register(vreg);
99 TEST(InstructionBasic) {
102 for (int i = 0; i < 10; i++) {
103 R.Int32Constant(i); // Add some nodes to the graph.
106 BasicBlock* last = R.schedule.start();
107 for (int i = 0; i < 5; i++) {
108 BasicBlock* block = R.schedule.NewBasicBlock();
109 R.schedule.AddGoto(last, block);
115 CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
117 BasicBlockVector* blocks = R.schedule.rpo_order();
118 CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
121 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
123 BasicBlock* block = *i;
124 CHECK_EQ(block, R.code->BlockAt(index));
125 CHECK_EQ(-1, R.code->GetLoopEnd(block));
130 TEST(InstructionGetBasicBlock) {
133 BasicBlock* b0 = R.schedule.start();
134 BasicBlock* b1 = R.schedule.NewBasicBlock();
135 BasicBlock* b2 = R.schedule.NewBasicBlock();
136 BasicBlock* b3 = R.schedule.end();
138 R.schedule.AddGoto(b0, b1);
139 R.schedule.AddGoto(b1, b2);
140 R.schedule.AddGoto(b2, b3);
144 R.code->StartBlock(b0);
145 int i0 = R.NewInstr(b0);
146 int i1 = R.NewInstr(b0);
147 R.code->EndBlock(b0);
148 R.code->StartBlock(b1);
149 int i2 = R.NewInstr(b1);
150 int i3 = R.NewInstr(b1);
151 int i4 = R.NewInstr(b1);
152 int i5 = R.NewInstr(b1);
153 R.code->EndBlock(b1);
154 R.code->StartBlock(b2);
155 int i6 = R.NewInstr(b2);
156 int i7 = R.NewInstr(b2);
157 int i8 = R.NewInstr(b2);
158 R.code->EndBlock(b2);
159 R.code->StartBlock(b3);
160 R.code->EndBlock(b3);
162 CHECK_EQ(b0, R.code->GetBasicBlock(i0));
163 CHECK_EQ(b0, R.code->GetBasicBlock(i1));
165 CHECK_EQ(b1, R.code->GetBasicBlock(i2));
166 CHECK_EQ(b1, R.code->GetBasicBlock(i3));
167 CHECK_EQ(b1, R.code->GetBasicBlock(i4));
168 CHECK_EQ(b1, R.code->GetBasicBlock(i5));
170 CHECK_EQ(b2, R.code->GetBasicBlock(i6));
171 CHECK_EQ(b2, R.code->GetBasicBlock(i7));
172 CHECK_EQ(b2, R.code->GetBasicBlock(i8));
174 CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
175 CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
177 CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
178 CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
180 CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
181 CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
183 CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
184 CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
188 TEST(InstructionIsGapAt) {
191 BasicBlock* b0 = R.schedule.start();
192 R.schedule.AddReturn(b0, R.Int32Constant(1));
195 TestInstr* i0 = TestInstr::New(R.zone(), 100);
196 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
197 R.code->StartBlock(b0);
198 R.code->AddInstruction(i0, b0);
199 R.code->AddInstruction(g, b0);
200 R.code->EndBlock(b0);
202 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
204 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
205 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
206 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
207 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
208 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
209 CHECK_EQ(false, R.code->IsGapAt(5)); // g
213 TEST(InstructionIsGapAt2) {
216 BasicBlock* b0 = R.schedule.start();
217 BasicBlock* b1 = R.schedule.end();
218 R.schedule.AddGoto(b0, b1);
219 R.schedule.AddReturn(b1, R.Int32Constant(1));
222 TestInstr* i0 = TestInstr::New(R.zone(), 100);
223 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
224 R.code->StartBlock(b0);
225 R.code->AddInstruction(i0, b0);
226 R.code->AddInstruction(g, b0);
227 R.code->EndBlock(b0);
229 TestInstr* i1 = TestInstr::New(R.zone(), 102);
230 TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
231 R.code->StartBlock(b1);
232 R.code->AddInstruction(i1, b1);
233 R.code->AddInstruction(g1, b1);
234 R.code->EndBlock(b1);
236 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
238 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
239 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
240 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
241 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
242 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
243 CHECK_EQ(false, R.code->IsGapAt(5)); // g
245 CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
247 CHECK_EQ(true, R.code->IsGapAt(6)); // Label
248 CHECK_EQ(true, R.code->IsGapAt(7)); // Gap
249 CHECK_EQ(false, R.code->IsGapAt(8)); // i1
250 CHECK_EQ(true, R.code->IsGapAt(9)); // Gap
251 CHECK_EQ(true, R.code->IsGapAt(10)); // Gap
252 CHECK_EQ(false, R.code->IsGapAt(11)); // g1
256 TEST(InstructionAddGapMove) {
259 BasicBlock* b0 = R.schedule.start();
260 R.schedule.AddReturn(b0, R.Int32Constant(1));
263 TestInstr* i0 = TestInstr::New(R.zone(), 100);
264 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
265 R.code->StartBlock(b0);
266 R.code->AddInstruction(i0, b0);
267 R.code->AddInstruction(g, b0);
268 R.code->EndBlock(b0);
270 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
272 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
273 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
274 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
275 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
276 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
277 CHECK_EQ(false, R.code->IsGapAt(5)); // g
279 int indexes[] = {0, 1, 3, 4, -1};
280 for (int i = 0; indexes[i] >= 0; i++) {
281 int index = indexes[i];
283 UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
284 UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
286 R.code->AddGapMove(index, op1, op2);
287 GapInstruction* gap = R.code->GapAt(index);
288 ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
289 CHECK_NE(NULL, move);
290 const ZoneList<MoveOperands>* move_operands = move->move_operands();
291 CHECK_EQ(1, move_operands->length());
292 MoveOperands* cur = &move_operands->at(0);
293 CHECK_EQ(op1, cur->source());
294 CHECK_EQ(op2, cur->destination());
299 TEST(InstructionOperands) {
300 Zone zone(CcTest::InitIsolateOnce());
303 TestInstr* i = TestInstr::New(&zone, 101);
304 CHECK_EQ(0, static_cast<int>(i->OutputCount()));
305 CHECK_EQ(0, static_cast<int>(i->InputCount()));
306 CHECK_EQ(0, static_cast<int>(i->TempCount()));
309 InstructionOperand* outputs[] = {
310 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
311 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
312 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
313 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
315 InstructionOperand* inputs[] = {
316 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
317 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
318 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
319 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
321 InstructionOperand* temps[] = {
322 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
323 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
324 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
325 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
327 for (size_t i = 0; i < arraysize(outputs); i++) {
328 for (size_t j = 0; j < arraysize(inputs); j++) {
329 for (size_t k = 0; k < arraysize(temps); k++) {
331 TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
332 CHECK(i == m->OutputCount());
333 CHECK(j == m->InputCount());
334 CHECK(k == m->TempCount());
336 for (size_t z = 0; z < i; z++) {
337 CHECK_EQ(outputs[z], m->OutputAt(z));
340 for (size_t z = 0; z < j; z++) {
341 CHECK_EQ(inputs[z], m->InputAt(z));
344 for (size_t z = 0; z < k; z++) {
345 CHECK_EQ(temps[z], m->TempAt(z));