blob: 294812fdfb7161fb8498b5349766ae63e0e6d74a [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
20using namespace v8::internal;
21using namespace v8::internal::compiler;
22
23typedef v8::internal::compiler::Instruction TestInstr;
24typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
25
26// A testing helper for the register code abstraction.
27class 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()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034 linkage(zone(), &info),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035 common(zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 machine(zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037 code(NULL) {}
38
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 Isolate* isolate;
40 Graph graph;
41 Schedule schedule;
42 CompilationInfoWithZone info;
43 Linkage linkage;
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.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053 Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 DCHECK(schedule.rpo_order()->size() > 0);
55 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040056 InstructionBlocks* instruction_blocks =
57 TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
58 code = new (main_zone()) TestInstrSeq(main_zone(), instruction_blocks);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000059 }
60
61 Node* Int32Constant(int32_t val) {
62 Node* node = graph.NewNode(common.Int32Constant(val));
63 schedule.AddNode(schedule.start(), node);
64 return node;
65 }
66
67 Node* Float64Constant(double val) {
68 Node* node = graph.NewNode(common.Float64Constant(val));
69 schedule.AddNode(schedule.start(), node);
70 return node;
71 }
72
73 Node* Parameter(int32_t which) {
74 Node* node = graph.NewNode(common.Parameter(which));
75 schedule.AddNode(schedule.start(), node);
76 return node;
77 }
78
79 Node* NewNode(BasicBlock* block) {
80 Node* node = graph.NewNode(common.Int32Constant(111));
81 schedule.AddNode(block, node);
82 return node;
83 }
84
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 int NewInstr() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000086 InstructionCode opcode = static_cast<InstructionCode>(110);
87 TestInstr* instr = TestInstr::New(zone(), opcode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040088 return code->AddInstruction(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 }
90
91 UnallocatedOperand* NewUnallocated(int vreg) {
92 UnallocatedOperand* unallocated =
93 new (zone()) UnallocatedOperand(UnallocatedOperand::ANY);
94 unallocated->set_virtual_register(vreg);
95 return unallocated;
96 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097
98 InstructionBlock* BlockAt(BasicBlock* block) {
99 return code->InstructionBlockAt(block->GetRpoNumber());
100 }
101 BasicBlock* GetBasicBlock(int instruction_index) {
102 const InstructionBlock* block =
103 code->GetInstructionBlock(instruction_index);
104 return schedule.rpo_order()->at(block->rpo_number().ToSize());
105 }
106 int first_instruction_index(BasicBlock* block) {
107 return BlockAt(block)->first_instruction_index();
108 }
109 int last_instruction_index(BasicBlock* block) {
110 return BlockAt(block)->last_instruction_index();
111 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112};
113
114
115TEST(InstructionBasic) {
116 InstructionTester R;
117
118 for (int i = 0; i < 10; i++) {
119 R.Int32Constant(i); // Add some nodes to the graph.
120 }
121
122 BasicBlock* last = R.schedule.start();
123 for (int i = 0; i < 5; i++) {
124 BasicBlock* block = R.schedule.NewBasicBlock();
125 R.schedule.AddGoto(last, block);
126 last = block;
127 }
128
129 R.allocCode();
130
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 BasicBlockVector* blocks = R.schedule.rpo_order();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132 CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133
134 int index = 0;
135 for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
136 i++, index++) {
137 BasicBlock* block = *i;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400138 CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
139 CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
140 CHECK_EQ(NULL, block->loop_end());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142}
143
144
145TEST(InstructionGetBasicBlock) {
146 InstructionTester R;
147
148 BasicBlock* b0 = R.schedule.start();
149 BasicBlock* b1 = R.schedule.NewBasicBlock();
150 BasicBlock* b2 = R.schedule.NewBasicBlock();
151 BasicBlock* b3 = R.schedule.end();
152
153 R.schedule.AddGoto(b0, b1);
154 R.schedule.AddGoto(b1, b2);
155 R.schedule.AddGoto(b2, b3);
156
157 R.allocCode();
158
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400159 R.code->StartBlock(b0->GetRpoNumber());
160 int i0 = R.NewInstr();
161 int i1 = R.NewInstr();
162 R.code->EndBlock(b0->GetRpoNumber());
163 R.code->StartBlock(b1->GetRpoNumber());
164 int i2 = R.NewInstr();
165 int i3 = R.NewInstr();
166 int i4 = R.NewInstr();
167 int i5 = R.NewInstr();
168 R.code->EndBlock(b1->GetRpoNumber());
169 R.code->StartBlock(b2->GetRpoNumber());
170 int i6 = R.NewInstr();
171 int i7 = R.NewInstr();
172 int i8 = R.NewInstr();
173 R.code->EndBlock(b2->GetRpoNumber());
174 R.code->StartBlock(b3->GetRpoNumber());
175 R.code->EndBlock(b3->GetRpoNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177 CHECK_EQ(b0, R.GetBasicBlock(i0));
178 CHECK_EQ(b0, R.GetBasicBlock(i1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400180 CHECK_EQ(b1, R.GetBasicBlock(i2));
181 CHECK_EQ(b1, R.GetBasicBlock(i3));
182 CHECK_EQ(b1, R.GetBasicBlock(i4));
183 CHECK_EQ(b1, R.GetBasicBlock(i5));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 CHECK_EQ(b2, R.GetBasicBlock(i6));
186 CHECK_EQ(b2, R.GetBasicBlock(i7));
187 CHECK_EQ(b2, R.GetBasicBlock(i8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
190 CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400192 CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
193 CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000194
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400195 CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
196 CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400198 CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
199 CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200}
201
202
203TEST(InstructionIsGapAt) {
204 InstructionTester R;
205
206 BasicBlock* b0 = R.schedule.start();
207 R.schedule.AddReturn(b0, R.Int32Constant(1));
208
209 R.allocCode();
210 TestInstr* i0 = TestInstr::New(R.zone(), 100);
211 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400212 R.code->StartBlock(b0->GetRpoNumber());
213 R.code->AddInstruction(i0);
214 R.code->AddInstruction(g);
215 R.code->EndBlock(b0->GetRpoNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216
217 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
218
219 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
220 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
221 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
222 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
223 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
224 CHECK_EQ(false, R.code->IsGapAt(5)); // g
225}
226
227
228TEST(InstructionIsGapAt2) {
229 InstructionTester R;
230
231 BasicBlock* b0 = R.schedule.start();
232 BasicBlock* b1 = R.schedule.end();
233 R.schedule.AddGoto(b0, b1);
234 R.schedule.AddReturn(b1, R.Int32Constant(1));
235
236 R.allocCode();
237 TestInstr* i0 = TestInstr::New(R.zone(), 100);
238 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 R.code->StartBlock(b0->GetRpoNumber());
240 R.code->AddInstruction(i0);
241 R.code->AddInstruction(g);
242 R.code->EndBlock(b0->GetRpoNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243
244 TestInstr* i1 = TestInstr::New(R.zone(), 102);
245 TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 R.code->StartBlock(b1->GetRpoNumber());
247 R.code->AddInstruction(i1);
248 R.code->AddInstruction(g1);
249 R.code->EndBlock(b1->GetRpoNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250
251 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
252
253 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
254 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
255 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
256 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
257 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
258 CHECK_EQ(false, R.code->IsGapAt(5)); // g
259
260 CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart());
261
262 CHECK_EQ(true, R.code->IsGapAt(6)); // Label
263 CHECK_EQ(true, R.code->IsGapAt(7)); // Gap
264 CHECK_EQ(false, R.code->IsGapAt(8)); // i1
265 CHECK_EQ(true, R.code->IsGapAt(9)); // Gap
266 CHECK_EQ(true, R.code->IsGapAt(10)); // Gap
267 CHECK_EQ(false, R.code->IsGapAt(11)); // g1
268}
269
270
271TEST(InstructionAddGapMove) {
272 InstructionTester R;
273
274 BasicBlock* b0 = R.schedule.start();
275 R.schedule.AddReturn(b0, R.Int32Constant(1));
276
277 R.allocCode();
278 TestInstr* i0 = TestInstr::New(R.zone(), 100);
279 TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400280 R.code->StartBlock(b0->GetRpoNumber());
281 R.code->AddInstruction(i0);
282 R.code->AddInstruction(g);
283 R.code->EndBlock(b0->GetRpoNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284
285 CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
286
287 CHECK_EQ(true, R.code->IsGapAt(0)); // Label
288 CHECK_EQ(true, R.code->IsGapAt(1)); // Gap
289 CHECK_EQ(false, R.code->IsGapAt(2)); // i0
290 CHECK_EQ(true, R.code->IsGapAt(3)); // Gap
291 CHECK_EQ(true, R.code->IsGapAt(4)); // Gap
292 CHECK_EQ(false, R.code->IsGapAt(5)); // g
293
294 int indexes[] = {0, 1, 3, 4, -1};
295 for (int i = 0; indexes[i] >= 0; i++) {
296 int index = indexes[i];
297
298 UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
299 UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
300
301 R.code->AddGapMove(index, op1, op2);
302 GapInstruction* gap = R.code->GapAt(index);
303 ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
304 CHECK_NE(NULL, move);
305 const ZoneList<MoveOperands>* move_operands = move->move_operands();
306 CHECK_EQ(1, move_operands->length());
307 MoveOperands* cur = &move_operands->at(0);
308 CHECK_EQ(op1, cur->source());
309 CHECK_EQ(op2, cur->destination());
310 }
311}
312
313
314TEST(InstructionOperands) {
315 Zone zone(CcTest::InitIsolateOnce());
316
317 {
318 TestInstr* i = TestInstr::New(&zone, 101);
319 CHECK_EQ(0, static_cast<int>(i->OutputCount()));
320 CHECK_EQ(0, static_cast<int>(i->InputCount()));
321 CHECK_EQ(0, static_cast<int>(i->TempCount()));
322 }
323
324 InstructionOperand* outputs[] = {
325 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
326 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
327 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
328 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
329
330 InstructionOperand* inputs[] = {
331 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
332 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
333 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
334 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
335
336 InstructionOperand* temps[] = {
337 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
338 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
339 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER),
340 new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)};
341
342 for (size_t i = 0; i < arraysize(outputs); i++) {
343 for (size_t j = 0; j < arraysize(inputs); j++) {
344 for (size_t k = 0; k < arraysize(temps); k++) {
345 TestInstr* m =
346 TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
347 CHECK(i == m->OutputCount());
348 CHECK(j == m->InputCount());
349 CHECK(k == m->TempCount());
350
351 for (size_t z = 0; z < i; z++) {
352 CHECK_EQ(outputs[z], m->OutputAt(z));
353 }
354
355 for (size_t z = 0; z < j; z++) {
356 CHECK_EQ(inputs[z], m->InputAt(z));
357 }
358
359 for (size_t z = 0; z < k; z++) {
360 CHECK_EQ(temps[z], m->TempAt(z));
361 }
362 }
363 }
364 }
365}