Upstream version 11.40.277.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(zone(), &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       ZonePool zone_pool(isolate);
55       Scheduler::ComputeSpecialRPO(&zone_pool, &schedule);
56       DCHECK(schedule.rpo_order()->size() > 0);
57     }
58     InstructionBlocks* instruction_blocks =
59         TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
60     code = new TestInstrSeq(main_zone(), instruction_blocks);
61   }
62
63   Node* Int32Constant(int32_t val) {
64     Node* node = graph.NewNode(common.Int32Constant(val));
65     schedule.AddNode(schedule.start(), node);
66     return node;
67   }
68
69   Node* Float64Constant(double val) {
70     Node* node = graph.NewNode(common.Float64Constant(val));
71     schedule.AddNode(schedule.start(), node);
72     return node;
73   }
74
75   Node* Parameter(int32_t which) {
76     Node* node = graph.NewNode(common.Parameter(which));
77     schedule.AddNode(schedule.start(), node);
78     return node;
79   }
80
81   Node* NewNode(BasicBlock* block) {
82     Node* node = graph.NewNode(common.Int32Constant(111));
83     schedule.AddNode(block, node);
84     return node;
85   }
86
87   int NewInstr() {
88     InstructionCode opcode = static_cast<InstructionCode>(110);
89     TestInstr* instr = TestInstr::New(zone(), opcode);
90     return code->AddInstruction(instr);
91   }
92
93   UnallocatedOperand* NewUnallocated(int vreg) {
94     UnallocatedOperand* unallocated =
95         new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
96     unallocated->set_virtual_register(vreg);
97     return unallocated;
98   }
99
100   InstructionBlock* BlockAt(BasicBlock* block) {
101     return code->InstructionBlockAt(block->GetRpoNumber());
102   }
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());
107   }
108   int first_instruction_index(BasicBlock* block) {
109     return BlockAt(block)->first_instruction_index();
110   }
111   int last_instruction_index(BasicBlock* block) {
112     return BlockAt(block)->last_instruction_index();
113   }
114 };
115
116
117 TEST(InstructionBasic) {
118   InstructionTester R;
119
120   for (int i = 0; i < 10; i++) {
121     R.Int32Constant(i);  // Add some nodes to the graph.
122   }
123
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);
128     last = block;
129   }
130
131   R.allocCode();
132
133   BasicBlockVector* blocks = R.schedule.rpo_order();
134   CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
135
136   int index = 0;
137   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
138        i++, index++) {
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());
143   }
144 }
145
146
147 TEST(InstructionGetBasicBlock) {
148   InstructionTester R;
149
150   BasicBlock* b0 = R.schedule.start();
151   BasicBlock* b1 = R.schedule.NewBasicBlock();
152   BasicBlock* b2 = R.schedule.NewBasicBlock();
153   BasicBlock* b3 = R.schedule.end();
154
155   R.schedule.AddGoto(b0, b1);
156   R.schedule.AddGoto(b1, b2);
157   R.schedule.AddGoto(b2, b3);
158
159   R.allocCode();
160
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);
178
179   CHECK_EQ(b0, R.GetBasicBlock(i0));
180   CHECK_EQ(b0, R.GetBasicBlock(i1));
181
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));
186
187   CHECK_EQ(b2, R.GetBasicBlock(i6));
188   CHECK_EQ(b2, R.GetBasicBlock(i7));
189   CHECK_EQ(b2, R.GetBasicBlock(i8));
190
191   CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
192   CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
193
194   CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
195   CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
196
197   CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
198   CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
199
200   CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
201   CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
202 }
203
204
205 TEST(InstructionIsGapAt) {
206   InstructionTester R;
207
208   BasicBlock* b0 = R.schedule.start();
209   R.schedule.AddReturn(b0, R.Int32Constant(1));
210
211   R.allocCode();
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);
218
219   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
220
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
227 }
228
229
230 TEST(InstructionIsGapAt2) {
231   InstructionTester R;
232
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));
237
238   R.allocCode();
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);
245
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);
252
253   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
254
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
261
262   CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
263
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
270 }
271
272
273 TEST(InstructionAddGapMove) {
274   InstructionTester R;
275
276   BasicBlock* b0 = R.schedule.start();
277   R.schedule.AddReturn(b0, R.Int32Constant(1));
278
279   R.allocCode();
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);
286
287   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
288
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
295
296   int indexes[] = {0, 1, 3, 4, -1};
297   for (int i = 0; indexes[i] >= 0; i++) {
298     int index = indexes[i];
299
300     UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
301     UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
302
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());
312   }
313 }
314
315
316 TEST(InstructionOperands) {
317   Zone zone(CcTest::InitIsolateOnce());
318
319   {
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()));
324   }
325
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)};
331
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)};
337
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)};
343
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++) {
347         TestInstr* m =
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());
352
353         for (size_t z = 0; z < i; z++) {
354           CHECK_EQ(outputs[z], m->OutputAt(z));
355         }
356
357         for (size_t z = 0; z < j; z++) {
358           CHECK_EQ(inputs[z], m->InputAt(z));
359         }
360
361         for (size_t z = 0; z < k; z++) {
362           CHECK_EQ(temps[z], m->TempAt(z));
363         }
364       }
365     }
366   }
367 }