85cc870e9d4bcc65b0c285998095c98d766c0a9a
[platform/upstream/nodejs.git] / deps / 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         fake_stub(main_isolate()),
34         info(&fake_stub, main_isolate()),
35         common(zone()),
36         machine(zone()),
37         code(NULL) {}
38
39   Isolate* isolate;
40   Graph graph;
41   Schedule schedule;
42   FakeStubForTesting fake_stub;
43   CompilationInfoWithZone info;
44   CommonOperatorBuilder common;
45   MachineOperatorBuilder machine;
46   TestInstrSeq* code;
47
48   Zone* zone() { return main_zone(); }
49
50   void allocCode() {
51     if (schedule.rpo_order()->size() == 0) {
52       // Compute the RPO order.
53       Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
54       DCHECK(schedule.rpo_order()->size() > 0);
55     }
56     InstructionBlocks* instruction_blocks =
57         TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
58     code = new (main_zone())
59         TestInstrSeq(main_isolate(), main_zone(), instruction_blocks);
60   }
61
62   Node* Int32Constant(int32_t val) {
63     Node* node = graph.NewNode(common.Int32Constant(val));
64     schedule.AddNode(schedule.start(), node);
65     return node;
66   }
67
68   Node* Float64Constant(double val) {
69     Node* node = graph.NewNode(common.Float64Constant(val));
70     schedule.AddNode(schedule.start(), node);
71     return node;
72   }
73
74   Node* Parameter(int32_t which) {
75     Node* node = graph.NewNode(common.Parameter(which));
76     schedule.AddNode(schedule.start(), node);
77     return node;
78   }
79
80   Node* NewNode(BasicBlock* block) {
81     Node* node = graph.NewNode(common.Int32Constant(111));
82     schedule.AddNode(block, node);
83     return node;
84   }
85
86   int NewInstr() {
87     InstructionCode opcode = static_cast<InstructionCode>(110);
88     TestInstr* instr = TestInstr::New(zone(), opcode);
89     return code->AddInstruction(instr);
90   }
91
92   UnallocatedOperand* NewUnallocated(int vreg) {
93     return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone());
94   }
95
96   InstructionBlock* BlockAt(BasicBlock* block) {
97     return code->InstructionBlockAt(block->GetRpoNumber());
98   }
99   BasicBlock* GetBasicBlock(int instruction_index) {
100     const InstructionBlock* block =
101         code->GetInstructionBlock(instruction_index);
102     return schedule.rpo_order()->at(block->rpo_number().ToSize());
103   }
104   int first_instruction_index(BasicBlock* block) {
105     return BlockAt(block)->first_instruction_index();
106   }
107   int last_instruction_index(BasicBlock* block) {
108     return BlockAt(block)->last_instruction_index();
109   }
110 };
111
112
113 TEST(InstructionBasic) {
114   InstructionTester R;
115
116   for (int i = 0; i < 10; i++) {
117     R.Int32Constant(i);  // Add some nodes to the graph.
118   }
119
120   BasicBlock* last = R.schedule.start();
121   for (int i = 0; i < 5; i++) {
122     BasicBlock* block = R.schedule.NewBasicBlock();
123     R.schedule.AddGoto(last, block);
124     last = block;
125   }
126
127   R.allocCode();
128
129   BasicBlockVector* blocks = R.schedule.rpo_order();
130   CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
131
132   for (auto block : *blocks) {
133     CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
134     CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
135     CHECK(!block->loop_end());
136   }
137 }
138
139
140 TEST(InstructionGetBasicBlock) {
141   InstructionTester R;
142
143   BasicBlock* b0 = R.schedule.start();
144   BasicBlock* b1 = R.schedule.NewBasicBlock();
145   BasicBlock* b2 = R.schedule.NewBasicBlock();
146   BasicBlock* b3 = R.schedule.end();
147
148   R.schedule.AddGoto(b0, b1);
149   R.schedule.AddGoto(b1, b2);
150   R.schedule.AddGoto(b2, b3);
151
152   R.allocCode();
153
154   R.code->StartBlock(b0->GetRpoNumber());
155   int i0 = R.NewInstr();
156   int i1 = R.NewInstr();
157   R.code->EndBlock(b0->GetRpoNumber());
158   R.code->StartBlock(b1->GetRpoNumber());
159   int i2 = R.NewInstr();
160   int i3 = R.NewInstr();
161   int i4 = R.NewInstr();
162   int i5 = R.NewInstr();
163   R.code->EndBlock(b1->GetRpoNumber());
164   R.code->StartBlock(b2->GetRpoNumber());
165   int i6 = R.NewInstr();
166   int i7 = R.NewInstr();
167   int i8 = R.NewInstr();
168   R.code->EndBlock(b2->GetRpoNumber());
169   R.code->StartBlock(b3->GetRpoNumber());
170   R.code->EndBlock(b3->GetRpoNumber());
171
172   CHECK_EQ(b0, R.GetBasicBlock(i0));
173   CHECK_EQ(b0, R.GetBasicBlock(i1));
174
175   CHECK_EQ(b1, R.GetBasicBlock(i2));
176   CHECK_EQ(b1, R.GetBasicBlock(i3));
177   CHECK_EQ(b1, R.GetBasicBlock(i4));
178   CHECK_EQ(b1, R.GetBasicBlock(i5));
179
180   CHECK_EQ(b2, R.GetBasicBlock(i6));
181   CHECK_EQ(b2, R.GetBasicBlock(i7));
182   CHECK_EQ(b2, R.GetBasicBlock(i8));
183
184   CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
185   CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
186
187   CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
188   CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
189
190   CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
191   CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
192
193   CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
194   CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
195 }
196
197
198 TEST(InstructionIsGapAt) {
199   InstructionTester R;
200
201   BasicBlock* b0 = R.schedule.start();
202   R.schedule.AddReturn(b0, R.Int32Constant(1));
203
204   R.allocCode();
205   TestInstr* i0 = TestInstr::New(R.zone(), 100);
206   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
207   R.code->StartBlock(b0->GetRpoNumber());
208   R.code->AddInstruction(i0);
209   R.code->AddInstruction(g);
210   R.code->EndBlock(b0->GetRpoNumber());
211
212   CHECK(R.code->instructions().size() == 4);
213   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
214     CHECK_EQ(i % 2 == 0, R.code->instructions()[i]->IsGapMoves());
215   }
216 }
217
218
219 TEST(InstructionIsGapAt2) {
220   InstructionTester R;
221
222   BasicBlock* b0 = R.schedule.start();
223   BasicBlock* b1 = R.schedule.end();
224   R.schedule.AddGoto(b0, b1);
225   R.schedule.AddReturn(b1, R.Int32Constant(1));
226
227   R.allocCode();
228   TestInstr* i0 = TestInstr::New(R.zone(), 100);
229   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
230   R.code->StartBlock(b0->GetRpoNumber());
231   R.code->AddInstruction(i0);
232   R.code->AddInstruction(g);
233   R.code->EndBlock(b0->GetRpoNumber());
234
235   TestInstr* i1 = TestInstr::New(R.zone(), 102);
236   TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
237   R.code->StartBlock(b1->GetRpoNumber());
238   R.code->AddInstruction(i1);
239   R.code->AddInstruction(g1);
240   R.code->EndBlock(b1->GetRpoNumber());
241
242   CHECK(R.code->instructions().size() == 8);
243   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
244     CHECK_EQ(i % 2 == 0, R.code->instructions()[i]->IsGapMoves());
245   }
246 }
247
248
249 TEST(InstructionAddGapMove) {
250   InstructionTester R;
251
252   BasicBlock* b0 = R.schedule.start();
253   R.schedule.AddReturn(b0, R.Int32Constant(1));
254
255   R.allocCode();
256   TestInstr* i0 = TestInstr::New(R.zone(), 100);
257   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
258   R.code->StartBlock(b0->GetRpoNumber());
259   R.code->AddInstruction(i0);
260   R.code->AddInstruction(g);
261   R.code->EndBlock(b0->GetRpoNumber());
262
263   CHECK(R.code->instructions().size() == 4);
264   for (size_t i = 0; i < R.code->instructions().size(); ++i) {
265     CHECK_EQ(i % 2 == 0, R.code->instructions()[i]->IsGapMoves());
266   }
267
268   int indexes[] = {0, 2, -1};
269   for (int i = 0; indexes[i] >= 0; i++) {
270     int index = indexes[i];
271
272     UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
273     UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
274
275     R.code->AddGapMove(index, op1, op2);
276     GapInstruction* gap = R.code->GapAt(index);
277     ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
278     CHECK(move);
279     const ZoneList<MoveOperands>* move_operands = move->move_operands();
280     CHECK_EQ(1, move_operands->length());
281     MoveOperands* cur = &move_operands->at(0);
282     CHECK_EQ(op1, cur->source());
283     CHECK_EQ(op2, cur->destination());
284   }
285 }
286
287
288 TEST(InstructionOperands) {
289   Zone zone;
290
291   {
292     TestInstr* i = TestInstr::New(&zone, 101);
293     CHECK_EQ(0, static_cast<int>(i->OutputCount()));
294     CHECK_EQ(0, static_cast<int>(i->InputCount()));
295     CHECK_EQ(0, static_cast<int>(i->TempCount()));
296   }
297
298   int vreg = 15;
299   InstructionOperand outputs[] = {
300       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
301       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
302       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
303       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
304
305   InstructionOperand inputs[] = {
306       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
307       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
308       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
309       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
310
311   InstructionOperand temps[] = {
312       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
313       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
314       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
315       UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
316
317   for (size_t i = 0; i < arraysize(outputs); i++) {
318     for (size_t j = 0; j < arraysize(inputs); j++) {
319       for (size_t k = 0; k < arraysize(temps); k++) {
320         TestInstr* m =
321             TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
322         CHECK(i == m->OutputCount());
323         CHECK(j == m->InputCount());
324         CHECK(k == m->TempCount());
325
326         for (size_t z = 0; z < i; z++) {
327           CHECK(outputs[z].Equals(m->OutputAt(z)));
328         }
329
330         for (size_t z = 0; z < j; z++) {
331           CHECK(inputs[z].Equals(m->InputAt(z)));
332         }
333
334         for (size_t z = 0; z < k; z++) {
335           CHECK(temps[z].Equals(m->TempAt(z)));
336         }
337       }
338     }
339   }
340 }