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