blob: 4cf72a55ce4d6f50085bb2a4108d8b1487e08255 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/compiler/code-generator.h"
6#include "src/compiler/common-operator.h"
7#include "src/compiler/graph.h"
8#include "src/compiler/instruction.h"
9#include "src/compiler/linkage.h"
10#include "src/compiler/machine-operator.h"
11#include "src/compiler/node.h"
12#include "src/compiler/operator.h"
13#include "src/compiler/schedule.h"
14#include "src/compiler/scheduler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "test/cctest/cctest.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017namespace v8 {
18namespace internal {
19namespace compiler {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020
21typedef v8::internal::compiler::Instruction TestInstr;
22typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
23
24// A testing helper for the register code abstraction.
25class InstructionTester : public HandleAndZoneScope {
26 public: // We're all friends here.
27 InstructionTester()
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 : graph(zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029 schedule(zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 common(zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031 machine(zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 code(NULL) {}
33
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034 Graph graph;
35 Schedule schedule;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 CommonOperatorBuilder common;
37 MachineOperatorBuilder machine;
38 TestInstrSeq* code;
39
40 Zone* zone() { return main_zone(); }
41
42 void allocCode() {
43 if (schedule.rpo_order()->size() == 0) {
44 // Compute the RPO order.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040045 Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 CHECK_NE(0u, schedule.rpo_order()->size());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048 InstructionBlocks* instruction_blocks =
49 TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050 code = new (main_zone())
51 TestInstrSeq(main_isolate(), main_zone(), instruction_blocks);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052 }
53
54 Node* Int32Constant(int32_t val) {
55 Node* node = graph.NewNode(common.Int32Constant(val));
56 schedule.AddNode(schedule.start(), node);
57 return node;
58 }
59
60 Node* Float64Constant(double val) {
61 Node* node = graph.NewNode(common.Float64Constant(val));
62 schedule.AddNode(schedule.start(), node);
63 return node;
64 }
65
66 Node* Parameter(int32_t which) {
67 Node* node = graph.NewNode(common.Parameter(which));
68 schedule.AddNode(schedule.start(), node);
69 return node;
70 }
71
72 Node* NewNode(BasicBlock* block) {
73 Node* node = graph.NewNode(common.Int32Constant(111));
74 schedule.AddNode(block, node);
75 return node;
76 }
77
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078 int NewInstr() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 InstructionCode opcode = static_cast<InstructionCode>(110);
80 TestInstr* instr = TestInstr::New(zone(), opcode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040081 return code->AddInstruction(instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 }
83
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 UnallocatedOperand Unallocated(int vreg) {
85 return UnallocatedOperand(UnallocatedOperand::ANY, vreg);
86 }
87
88 RpoNumber RpoFor(BasicBlock* block) {
89 return RpoNumber::FromInt(block->rpo_number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040091
92 InstructionBlock* BlockAt(BasicBlock* block) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000093 return code->InstructionBlockAt(RpoFor(block));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040094 }
95 BasicBlock* GetBasicBlock(int instruction_index) {
96 const InstructionBlock* block =
97 code->GetInstructionBlock(instruction_index);
98 return schedule.rpo_order()->at(block->rpo_number().ToSize());
99 }
100 int first_instruction_index(BasicBlock* block) {
101 return BlockAt(block)->first_instruction_index();
102 }
103 int last_instruction_index(BasicBlock* block) {
104 return BlockAt(block)->last_instruction_index();
105 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106};
107
108
109TEST(InstructionBasic) {
110 InstructionTester R;
111
112 for (int i = 0; i < 10; i++) {
113 R.Int32Constant(i); // Add some nodes to the graph.
114 }
115
116 BasicBlock* last = R.schedule.start();
117 for (int i = 0; i < 5; i++) {
118 BasicBlock* block = R.schedule.NewBasicBlock();
119 R.schedule.AddGoto(last, block);
120 last = block;
121 }
122
123 R.allocCode();
124
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 BasicBlockVector* blocks = R.schedule.rpo_order();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400126 CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 for (auto block : *blocks) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129 CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 CHECK(!block->loop_end());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 }
132}
133
134
135TEST(InstructionGetBasicBlock) {
136 InstructionTester R;
137
138 BasicBlock* b0 = R.schedule.start();
139 BasicBlock* b1 = R.schedule.NewBasicBlock();
140 BasicBlock* b2 = R.schedule.NewBasicBlock();
141 BasicBlock* b3 = R.schedule.end();
142
143 R.schedule.AddGoto(b0, b1);
144 R.schedule.AddGoto(b1, b2);
145 R.schedule.AddGoto(b2, b3);
146
147 R.allocCode();
148
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 R.code->StartBlock(R.RpoFor(b0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 int i0 = R.NewInstr();
151 int i1 = R.NewInstr();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 R.code->EndBlock(R.RpoFor(b0));
153 R.code->StartBlock(R.RpoFor(b1));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 int i2 = R.NewInstr();
155 int i3 = R.NewInstr();
156 int i4 = R.NewInstr();
157 int i5 = R.NewInstr();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 R.code->EndBlock(R.RpoFor(b1));
159 R.code->StartBlock(R.RpoFor(b2));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400160 int i6 = R.NewInstr();
161 int i7 = R.NewInstr();
162 int i8 = R.NewInstr();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 R.code->EndBlock(R.RpoFor(b2));
164 R.code->StartBlock(R.RpoFor(b3));
165 R.code->EndBlock(R.RpoFor(b3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400167 CHECK_EQ(b0, R.GetBasicBlock(i0));
168 CHECK_EQ(b0, R.GetBasicBlock(i1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 CHECK_EQ(b1, R.GetBasicBlock(i2));
171 CHECK_EQ(b1, R.GetBasicBlock(i3));
172 CHECK_EQ(b1, R.GetBasicBlock(i4));
173 CHECK_EQ(b1, R.GetBasicBlock(i5));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 CHECK_EQ(b2, R.GetBasicBlock(i6));
176 CHECK_EQ(b2, R.GetBasicBlock(i7));
177 CHECK_EQ(b2, R.GetBasicBlock(i8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400179 CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
180 CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182 CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
183 CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
186 CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400188 CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
189 CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190}
191
192
193TEST(InstructionIsGapAt) {
194 InstructionTester R;
195
196 BasicBlock* b0 = R.schedule.start();
197 R.schedule.AddReturn(b0, R.Int32Constant(1));
198
199 R.allocCode();
200 TestInstr* i0 = TestInstr::New(R.zone(), 100);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 TestInstr* g = TestInstr::New(R.zone(), 103);
202 R.code->StartBlock(R.RpoFor(b0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203 R.code->AddInstruction(i0);
204 R.code->AddInstruction(g);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 R.code->EndBlock(R.RpoFor(b0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 CHECK(R.code->instructions().size() == 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208}
209
210
211TEST(InstructionIsGapAt2) {
212 InstructionTester R;
213
214 BasicBlock* b0 = R.schedule.start();
215 BasicBlock* b1 = R.schedule.end();
216 R.schedule.AddGoto(b0, b1);
217 R.schedule.AddReturn(b1, R.Int32Constant(1));
218
219 R.allocCode();
220 TestInstr* i0 = TestInstr::New(R.zone(), 100);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 TestInstr* g = TestInstr::New(R.zone(), 103);
222 R.code->StartBlock(R.RpoFor(b0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223 R.code->AddInstruction(i0);
224 R.code->AddInstruction(g);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 R.code->EndBlock(R.RpoFor(b0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226
227 TestInstr* i1 = TestInstr::New(R.zone(), 102);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 TestInstr* g1 = TestInstr::New(R.zone(), 104);
229 R.code->StartBlock(R.RpoFor(b1));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400230 R.code->AddInstruction(i1);
231 R.code->AddInstruction(g1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 R.code->EndBlock(R.RpoFor(b1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234 CHECK(R.code->instructions().size() == 4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235}
236
237
238TEST(InstructionAddGapMove) {
239 InstructionTester R;
240
241 BasicBlock* b0 = R.schedule.start();
242 R.schedule.AddReturn(b0, R.Int32Constant(1));
243
244 R.allocCode();
245 TestInstr* i0 = TestInstr::New(R.zone(), 100);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 TestInstr* g = TestInstr::New(R.zone(), 103);
247 R.code->StartBlock(R.RpoFor(b0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400248 R.code->AddInstruction(i0);
249 R.code->AddInstruction(g);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 R.code->EndBlock(R.RpoFor(b0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252 CHECK(R.code->instructions().size() == 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 int index = 0;
255 for (auto instr : R.code->instructions()) {
256 UnallocatedOperand op1 = R.Unallocated(index++);
257 UnallocatedOperand op2 = R.Unallocated(index++);
258 instr->GetOrCreateParallelMove(TestInstr::START, R.zone())
259 ->AddMove(op1, op2);
260 ParallelMove* move = instr->GetParallelMove(TestInstr::START);
261 CHECK(move);
262 CHECK_EQ(1u, move->size());
263 MoveOperands* cur = move->at(0);
264 CHECK(op1.Equals(cur->source()));
265 CHECK(op2.Equals(cur->destination()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 }
267}
268
269
270TEST(InstructionOperands) {
Ben Murdochda12d292016-06-02 14:46:10 +0100271 base::AccountingAllocator allocator;
272 Zone zone(&allocator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273
274 {
275 TestInstr* i = TestInstr::New(&zone, 101);
276 CHECK_EQ(0, static_cast<int>(i->OutputCount()));
277 CHECK_EQ(0, static_cast<int>(i->InputCount()));
278 CHECK_EQ(0, static_cast<int>(i->TempCount()));
279 }
280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281 int vreg = 15;
282 InstructionOperand outputs[] = {
283 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
284 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
285 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
286 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 InstructionOperand inputs[] = {
289 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
290 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
291 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
292 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 InstructionOperand temps[] = {
295 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
296 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
297 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg),
298 UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER, vreg)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299
300 for (size_t i = 0; i < arraysize(outputs); i++) {
301 for (size_t j = 0; j < arraysize(inputs); j++) {
302 for (size_t k = 0; k < arraysize(temps); k++) {
303 TestInstr* m =
304 TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps);
305 CHECK(i == m->OutputCount());
306 CHECK(j == m->InputCount());
307 CHECK(k == m->TempCount());
308
309 for (size_t z = 0; z < i; z++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 CHECK(outputs[z].Equals(*m->OutputAt(z)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 }
312
313 for (size_t z = 0; z < j; z++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 CHECK(inputs[z].Equals(*m->InputAt(z)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 }
316
317 for (size_t z = 0; z < k; z++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 CHECK(temps[z].Equals(*m->TempAt(z)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 }
320 }
321 }
322 }
323}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324
325} // namespace compiler
326} // namespace internal
327} // namespace v8