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.
30 : isolate(main_isolate()),
33 fake_stub(main_isolate()),
34 info(&fake_stub, main_isolate()),
42 FakeStubForTesting fake_stub;
43 CompilationInfoWithZone info;
44 CommonOperatorBuilder common;
45 MachineOperatorBuilder machine;
48 Zone* zone() { return main_zone(); }
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);
56 InstructionBlocks* instruction_blocks =
57 TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
58 code = new (main_zone())
59 TestInstrSeq(main_isolate(), main_zone(), instruction_blocks);
62 Node* Int32Constant(int32_t val) {
63 Node* node = graph.NewNode(common.Int32Constant(val));
64 schedule.AddNode(schedule.start(), node);
68 Node* Float64Constant(double val) {
69 Node* node = graph.NewNode(common.Float64Constant(val));
70 schedule.AddNode(schedule.start(), node);
74 Node* Parameter(int32_t which) {
75 Node* node = graph.NewNode(common.Parameter(which));
76 schedule.AddNode(schedule.start(), node);
80 Node* NewNode(BasicBlock* block) {
81 Node* node = graph.NewNode(common.Int32Constant(111));
82 schedule.AddNode(block, node);
87 InstructionCode opcode = static_cast<InstructionCode>(110);
88 TestInstr* instr = TestInstr::New(zone(), opcode);
89 return code->AddInstruction(instr);
92 UnallocatedOperand* NewUnallocated(int vreg) {
93 return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone());
96 InstructionBlock* BlockAt(BasicBlock* block) {
97 return code->InstructionBlockAt(block->GetRpoNumber());
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());
104 int first_instruction_index(BasicBlock* block) {
105 return BlockAt(block)->first_instruction_index();
107 int last_instruction_index(BasicBlock* block) {
108 return BlockAt(block)->last_instruction_index();
113 TEST(InstructionBasic) {
116 for (int i = 0; i < 10; i++) {
117 R.Int32Constant(i); // Add some nodes to the graph.
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);
129 BasicBlockVector* blocks = R.schedule.rpo_order();
130 CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
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());
140 TEST(InstructionGetBasicBlock) {
143 BasicBlock* b0 = R.schedule.start();
144 BasicBlock* b1 = R.schedule.NewBasicBlock();
145 BasicBlock* b2 = R.schedule.NewBasicBlock();
146 BasicBlock* b3 = R.schedule.end();
148 R.schedule.AddGoto(b0, b1);
149 R.schedule.AddGoto(b1, b2);
150 R.schedule.AddGoto(b2, b3);
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());
172 CHECK_EQ(b0, R.GetBasicBlock(i0));
173 CHECK_EQ(b0, R.GetBasicBlock(i1));
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));
180 CHECK_EQ(b2, R.GetBasicBlock(i6));
181 CHECK_EQ(b2, R.GetBasicBlock(i7));
182 CHECK_EQ(b2, R.GetBasicBlock(i8));
184 CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
185 CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
187 CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
188 CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
190 CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
191 CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
193 CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
194 CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
198 TEST(InstructionIsGapAt) {
201 BasicBlock* b0 = R.schedule.start();
202 R.schedule.AddReturn(b0, R.Int32Constant(1));
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());
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());
219 TEST(InstructionIsGapAt2) {
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));
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());
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());
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());
249 TEST(InstructionAddGapMove) {
252 BasicBlock* b0 = R.schedule.start();
253 R.schedule.AddReturn(b0, R.Int32Constant(1));
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());
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());
268 int indexes[] = {0, 2, -1};
269 for (int i = 0; indexes[i] >= 0; i++) {
270 int index = indexes[i];
272 UnallocatedOperand* op1 = R.NewUnallocated(index + 6);
273 UnallocatedOperand* op2 = R.NewUnallocated(index + 12);
275 R.code->AddGapMove(index, op1, op2);
276 GapInstruction* gap = R.code->GapAt(index);
277 ParallelMove* move = gap->GetParallelMove(GapInstruction::START);
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());
288 TEST(InstructionOperands) {
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()));
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)};
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)};
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)};
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++) {
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());
326 for (size_t z = 0; z < i; z++) {
327 CHECK(outputs[z].Equals(m->OutputAt(z)));
330 for (size_t z = 0; z < j; z++) {
331 CHECK(inputs[z].Equals(m->InputAt(z)));
334 for (size_t z = 0; z < k; z++) {
335 CHECK(temps[z].Equals(m->TempAt(z)));