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.
6 #include "test/cctest/cctest.h"
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"
20 using namespace v8::internal;
21 using namespace v8::internal::compiler;
23 typedef v8::internal::compiler::Instruction TestInstr;
24 typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
26 // A testing helper for the register code abstraction.
27 class InstructionTester : public HandleAndZoneScope {
28 public: // We're all friends here.
38 CommonOperatorBuilder common;
39 MachineOperatorBuilder machine;
42 Zone* zone() { return main_zone(); }
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);
50 InstructionBlocks* instruction_blocks =
51 TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
52 code = new (main_zone())
53 TestInstrSeq(main_isolate(), main_zone(), instruction_blocks);
56 Node* Int32Constant(int32_t val) {
57 Node* node = graph.NewNode(common.Int32Constant(val));
58 schedule.AddNode(schedule.start(), node);
62 Node* Float64Constant(double val) {
63 Node* node = graph.NewNode(common.Float64Constant(val));
64 schedule.AddNode(schedule.start(), node);
68 Node* Parameter(int32_t which) {
69 Node* node = graph.NewNode(common.Parameter(which));
70 schedule.AddNode(schedule.start(), node);
74 Node* NewNode(BasicBlock* block) {
75 Node* node = graph.NewNode(common.Int32Constant(111));
76 schedule.AddNode(block, node);
81 InstructionCode opcode = static_cast<InstructionCode>(110);
82 TestInstr* instr = TestInstr::New(zone(), opcode);
83 return code->AddInstruction(instr);
86 UnallocatedOperand* NewUnallocated(int vreg) {
87 return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone());
90 RpoNumber RpoFor(BasicBlock* block) {
91 return RpoNumber::FromInt(block->rpo_number());
94 InstructionBlock* BlockAt(BasicBlock* block) {
95 return code->InstructionBlockAt(RpoFor(block));
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());
102 int first_instruction_index(BasicBlock* block) {
103 return BlockAt(block)->first_instruction_index();
105 int last_instruction_index(BasicBlock* block) {
106 return BlockAt(block)->last_instruction_index();
111 TEST(InstructionBasic) {
114 for (int i = 0; i < 10; i++) {
115 R.Int32Constant(i); // Add some nodes to the graph.
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);
127 BasicBlockVector* blocks = R.schedule.rpo_order();
128 CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
130 for (auto block : *blocks) {
131 CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
132 CHECK(!block->loop_end());
137 TEST(InstructionGetBasicBlock) {
140 BasicBlock* b0 = R.schedule.start();
141 BasicBlock* b1 = R.schedule.NewBasicBlock();
142 BasicBlock* b2 = R.schedule.NewBasicBlock();
143 BasicBlock* b3 = R.schedule.end();
145 R.schedule.AddGoto(b0, b1);
146 R.schedule.AddGoto(b1, b2);
147 R.schedule.AddGoto(b2, b3);
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));
169 CHECK_EQ(b0, R.GetBasicBlock(i0));
170 CHECK_EQ(b0, R.GetBasicBlock(i1));
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));
177 CHECK_EQ(b2, R.GetBasicBlock(i6));
178 CHECK_EQ(b2, R.GetBasicBlock(i7));
179 CHECK_EQ(b2, R.GetBasicBlock(i8));
181 CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
182 CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
184 CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
185 CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
187 CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
188 CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
190 CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
191 CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
195 TEST(InstructionIsGapAt) {
198 BasicBlock* b0 = R.schedule.start();
199 R.schedule.AddReturn(b0, R.Int32Constant(1));
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));
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());
216 TEST(InstructionIsGapAt2) {
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));
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));
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));
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());
246 TEST(InstructionAddGapMove) {
249 BasicBlock* b0 = R.schedule.start();
250 R.schedule.AddReturn(b0, R.Int32Constant(1));
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));
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());
265 int indexes[] = {0, 2, -1};
266 for (int i = 0; indexes[i] >= 0; i++) {
267 int index = indexes[i];
269 UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
270 UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
272 R.code->AddGapMove(index, op1, op2);
273 GapInstruction* gap = R.code->GapAt(index);
274 ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
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());
285 TEST(InstructionOperands) {
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()));
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)};
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)};
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)};
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++) {
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());
323 for (size_t z = 0; z < i; z++) {
324 CHECK(outputs[z].Equals(m->OutputAt(z)));
327 for (size_t z = 0; z < j; z++) {
328 CHECK(inputs[z].Equals(m->InputAt(z)));
331 for (size_t z = 0; z < k; z++) {
332 CHECK(temps[z].Equals(m->TempAt(z)));