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