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