Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / compiler / test-instruction.cc
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/v8.h"
6 #include "test/cctest/cctest.h"
7
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"
19
20 using namespace v8::internal;
21 using namespace v8::internal::compiler;
22
23 typedef v8::internal::compiler::Instruction TestInstr;
24 typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
25
26 // A testing helper for the register code abstraction.
27 class InstructionTester : public HandleAndZoneScope {
28  public:  // We're all friends here.
29   InstructionTester()
30       : isolate(main_isolate()),
31         graph(zone()),
32         schedule(zone()),
33         info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
34         linkage(&info),
35         common(zone()),
36         code(NULL) {}
37
38   ~InstructionTester() { delete code; }
39
40   Isolate* isolate;
41   Graph graph;
42   Schedule schedule;
43   CompilationInfoWithZone info;
44   Linkage linkage;
45   CommonOperatorBuilder common;
46   MachineOperatorBuilder machine;
47   TestInstrSeq* code;
48
49   Zone* zone() { return main_zone(); }
50
51   void allocCode() {
52     if (schedule.rpo_order()->size() == 0) {
53       // Compute the RPO order.
54       Scheduler::ComputeSpecialRPO(&schedule);
55       DCHECK(schedule.rpo_order()->size() > 0);
56     }
57     code = new TestInstrSeq(&linkage, &graph, &schedule);
58   }
59
60   Node* Int32Constant(int32_t val) {
61     Node* node = graph.NewNode(common.Int32Constant(val));
62     schedule.AddNode(schedule.start(), node);
63     return node;
64   }
65
66   Node* Float64Constant(double val) {
67     Node* node = graph.NewNode(common.Float64Constant(val));
68     schedule.AddNode(schedule.start(), node);
69     return node;
70   }
71
72   Node* Parameter(int32_t which) {
73     Node* node = graph.NewNode(common.Parameter(which));
74     schedule.AddNode(schedule.start(), node);
75     return node;
76   }
77
78   Node* NewNode(BasicBlock* block) {
79     Node* node = graph.NewNode(common.Int32Constant(111));
80     schedule.AddNode(block, node);
81     return node;
82   }
83
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);
88   }
89
90   UnallocatedOperand* NewUnallocated(int vreg) {
91     UnallocatedOperand* unallocated =
92         new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
93     unallocated->set_virtual_register(vreg);
94     return unallocated;
95   }
96 };
97
98
99 TEST(InstructionBasic) {
100   InstructionTester R;
101
102   for (int i = 0; i < 10; i++) {
103     R.Int32Constant(i);  // Add some nodes to the graph.
104   }
105
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);
110     last = block;
111   }
112
113   R.allocCode();
114
115   CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
116
117   BasicBlockVector* blocks = R.schedule.rpo_order();
118   CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
119
120   int index = 0;
121   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
122        i++, index++) {
123     BasicBlock* block = *i;
124     CHECK_EQ(block, R.code->BlockAt(index));
125     CHECK_EQ(-1, R.code->GetLoopEnd(block));
126   }
127 }
128
129
130 TEST(InstructionGetBasicBlock) {
131   InstructionTester R;
132
133   BasicBlock* b0 = R.schedule.start();
134   BasicBlock* b1 = R.schedule.NewBasicBlock();
135   BasicBlock* b2 = R.schedule.NewBasicBlock();
136   BasicBlock* b3 = R.schedule.end();
137
138   R.schedule.AddGoto(b0, b1);
139   R.schedule.AddGoto(b1, b2);
140   R.schedule.AddGoto(b2, b3);
141
142   R.allocCode();
143
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);
161
162   CHECK_EQ(b0, R.code->GetBasicBlock(i0));
163   CHECK_EQ(b0, R.code->GetBasicBlock(i1));
164
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));
169
170   CHECK_EQ(b2, R.code->GetBasicBlock(i6));
171   CHECK_EQ(b2, R.code->GetBasicBlock(i7));
172   CHECK_EQ(b2, R.code->GetBasicBlock(i8));
173
174   CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
175   CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
176
177   CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
178   CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
179
180   CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
181   CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
182
183   CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
184   CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
185 }
186
187
188 TEST(InstructionIsGapAt) {
189   InstructionTester R;
190
191   BasicBlock* b0 = R.schedule.start();
192   R.schedule.AddReturn(b0, R.Int32Constant(1));
193
194   R.allocCode();
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);
201
202   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
203
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
210 }
211
212
213 TEST(InstructionIsGapAt2) {
214   InstructionTester R;
215
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));
220
221   R.allocCode();
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);
228
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);
235
236   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
237
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
244
245   CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
246
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
253 }
254
255
256 TEST(InstructionAddGapMove) {
257   InstructionTester R;
258
259   BasicBlock* b0 = R.schedule.start();
260   R.schedule.AddReturn(b0, R.Int32Constant(1));
261
262   R.allocCode();
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);
269
270   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
271
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
278
279   int indexes[] = {0, 1, 3, 4, -1};
280   for (int i = 0; indexes[i] >= 0; i++) {
281     int index = indexes[i];
282
283     UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
284     UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
285
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());
295   }
296 }
297
298
299 TEST(InstructionOperands) {
300   Zone zone(CcTest::InitIsolateOnce());
301
302   {
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()));
307   }
308
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)};
314
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)};
320
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)};
326
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++) {
330         TestInstr* m =
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());
335
336         for (size_t z = 0; z < i; z++) {
337           CHECK_EQ(outputs[z], m->OutputAt(z));
338         }
339
340         for (size_t z = 0; z < j; z++) {
341           CHECK_EQ(inputs[z], m->InputAt(z));
342         }
343
344         for (size_t z = 0; z < k; z++) {
345           CHECK_EQ(temps[z], m->TempAt(z));
346         }
347       }
348     }
349   }
350 }