Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Side by Side Diff: test/compiler-unittests/instruction-selector-unittest.cc

Issue 530693002: [turbofan] Merge compiler unit tests into src. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "test/compiler-unittests/instruction-selector-unittest.h"
6
7 #include "src/flags.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12
13 namespace {
14
15 typedef RawMachineAssembler::Label MLabel;
16
17 } // namespace
18
19
20 InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
21
22
23 InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
24 InstructionSelector::Features features,
25 InstructionSelectorTest::StreamBuilderMode mode) {
26 Schedule* schedule = Export();
27 if (FLAG_trace_turbo) {
28 OFStream out(stdout);
29 out << "=== Schedule before instruction selection ===" << endl << *schedule;
30 }
31 EXPECT_NE(0, graph()->NodeCount());
32 CompilationInfo info(test_->isolate(), test_->zone());
33 Linkage linkage(&info, call_descriptor());
34 InstructionSequence sequence(&linkage, graph(), schedule);
35 SourcePositionTable source_position_table(graph());
36 InstructionSelector selector(&sequence, &source_position_table, features);
37 selector.SelectInstructions();
38 if (FLAG_trace_turbo) {
39 OFStream out(stdout);
40 out << "=== Code sequence after instruction selection ===" << endl
41 << sequence;
42 }
43 Stream s;
44 std::set<int> virtual_registers;
45 for (InstructionSequence::const_iterator i = sequence.begin();
46 i != sequence.end(); ++i) {
47 Instruction* instr = *i;
48 if (instr->opcode() < 0) continue;
49 if (mode == kTargetInstructions) {
50 switch (instr->arch_opcode()) {
51 #define CASE(Name) \
52 case k##Name: \
53 break;
54 TARGET_ARCH_OPCODE_LIST(CASE)
55 #undef CASE
56 default:
57 continue;
58 }
59 }
60 if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
61 continue;
62 }
63 for (size_t i = 0; i < instr->OutputCount(); ++i) {
64 InstructionOperand* output = instr->OutputAt(i);
65 EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
66 if (output->IsConstant()) {
67 s.constants_.insert(std::make_pair(
68 output->index(), sequence.GetConstant(output->index())));
69 virtual_registers.insert(output->index());
70 } else if (output->IsUnallocated()) {
71 virtual_registers.insert(
72 UnallocatedOperand::cast(output)->virtual_register());
73 }
74 }
75 for (size_t i = 0; i < instr->InputCount(); ++i) {
76 InstructionOperand* input = instr->InputAt(i);
77 EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
78 if (input->IsImmediate()) {
79 s.immediates_.insert(std::make_pair(
80 input->index(), sequence.GetImmediate(input->index())));
81 } else if (input->IsUnallocated()) {
82 virtual_registers.insert(
83 UnallocatedOperand::cast(input)->virtual_register());
84 }
85 }
86 s.instructions_.push_back(instr);
87 }
88 for (std::set<int>::const_iterator i = virtual_registers.begin();
89 i != virtual_registers.end(); ++i) {
90 int virtual_register = *i;
91 if (sequence.IsDouble(virtual_register)) {
92 EXPECT_FALSE(sequence.IsReference(virtual_register));
93 s.doubles_.insert(virtual_register);
94 }
95 if (sequence.IsReference(virtual_register)) {
96 EXPECT_FALSE(sequence.IsDouble(virtual_register));
97 s.references_.insert(virtual_register);
98 }
99 }
100 for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
101 s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
102 InstructionSequence::StateId::FromInt(i)));
103 }
104 return s;
105 }
106
107
108 // -----------------------------------------------------------------------------
109 // Return.
110
111
112 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
113 StreamBuilder m(this, kMachInt32, kMachInt32);
114 m.Return(m.Parameter(0));
115 Stream s = m.Build(kAllInstructions);
116 ASSERT_EQ(2U, s.size());
117 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
118 ASSERT_EQ(1U, s[0]->OutputCount());
119 EXPECT_EQ(kArchRet, s[1]->arch_opcode());
120 EXPECT_EQ(1U, s[1]->InputCount());
121 }
122
123
124 TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
125 StreamBuilder m(this, kMachInt32);
126 m.Return(m.Int32Constant(0));
127 Stream s = m.Build(kAllInstructions);
128 ASSERT_EQ(2U, s.size());
129 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
130 ASSERT_EQ(1U, s[0]->OutputCount());
131 EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
132 EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
133 EXPECT_EQ(kArchRet, s[1]->arch_opcode());
134 EXPECT_EQ(1U, s[1]->InputCount());
135 }
136
137
138 // -----------------------------------------------------------------------------
139 // Conversions.
140
141
142 TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
143 StreamBuilder m(this, kMachInt32, kMachFloat64);
144 m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
145 Stream s = m.Build(kAllInstructions);
146 ASSERT_EQ(3U, s.size());
147 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
148 EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
149 EXPECT_EQ(1U, s[1]->InputCount());
150 EXPECT_EQ(1U, s[1]->OutputCount());
151 EXPECT_EQ(kArchRet, s[2]->arch_opcode());
152 }
153
154
155 // -----------------------------------------------------------------------------
156 // Parameters.
157
158
159 TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
160 StreamBuilder m(this, kMachFloat64, kMachFloat64);
161 Node* param = m.Parameter(0);
162 m.Return(param);
163 Stream s = m.Build(kAllInstructions);
164 EXPECT_TRUE(s.IsDouble(param->id()));
165 }
166
167
168 TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
169 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
170 Node* param = m.Parameter(0);
171 m.Return(param);
172 Stream s = m.Build(kAllInstructions);
173 EXPECT_TRUE(s.IsReference(param->id()));
174 }
175
176
177 // -----------------------------------------------------------------------------
178 // Finish.
179
180
181 typedef InstructionSelectorTestWithParam<MachineType>
182 InstructionSelectorFinishTest;
183
184
185 TARGET_TEST_P(InstructionSelectorFinishTest, Parameter) {
186 const MachineType type = GetParam();
187 StreamBuilder m(this, type, type);
188 Node* param = m.Parameter(0);
189 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
190 m.Return(finish);
191 Stream s = m.Build(kAllInstructions);
192 ASSERT_EQ(3U, s.size());
193 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
194 ASSERT_EQ(1U, s[0]->OutputCount());
195 ASSERT_TRUE(s[0]->Output()->IsUnallocated());
196 EXPECT_EQ(param->id(), s.ToVreg(s[0]->Output()));
197 EXPECT_EQ(kArchNop, s[1]->arch_opcode());
198 ASSERT_EQ(1U, s[1]->InputCount());
199 ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
200 EXPECT_EQ(param->id(), s.ToVreg(s[1]->InputAt(0)));
201 ASSERT_EQ(1U, s[1]->OutputCount());
202 ASSERT_TRUE(s[1]->Output()->IsUnallocated());
203 EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
204 EXPECT_EQ(finish->id(), s.ToVreg(s[1]->Output()));
205 }
206
207
208 TARGET_TEST_P(InstructionSelectorFinishTest, PropagateDoubleness) {
209 const MachineType type = GetParam();
210 StreamBuilder m(this, type, type);
211 Node* param = m.Parameter(0);
212 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
213 m.Return(finish);
214 Stream s = m.Build(kAllInstructions);
215 EXPECT_EQ(s.IsDouble(param->id()), s.IsDouble(finish->id()));
216 }
217
218
219 TARGET_TEST_P(InstructionSelectorFinishTest, PropagateReferenceness) {
220 const MachineType type = GetParam();
221 StreamBuilder m(this, type, type);
222 Node* param = m.Parameter(0);
223 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
224 m.Return(finish);
225 Stream s = m.Build(kAllInstructions);
226 EXPECT_EQ(s.IsReference(param->id()), s.IsReference(finish->id()));
227 }
228
229
230 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFinishTest,
231 ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
232 kMachInt16, kMachUint16, kMachInt32,
233 kMachUint32, kMachInt64, kMachUint64,
234 kMachPtr, kMachAnyTagged));
235
236
237 // -----------------------------------------------------------------------------
238 // Finish.
239
240
241 typedef InstructionSelectorTestWithParam<MachineType>
242 InstructionSelectorPhiTest;
243
244
245 TARGET_TEST_P(InstructionSelectorPhiTest, PropagateDoubleness) {
246 const MachineType type = GetParam();
247 StreamBuilder m(this, type, type, type);
248 Node* param0 = m.Parameter(0);
249 Node* param1 = m.Parameter(1);
250 MLabel a, b, c;
251 m.Branch(m.Int32Constant(0), &a, &b);
252 m.Bind(&a);
253 m.Goto(&c);
254 m.Bind(&b);
255 m.Goto(&c);
256 m.Bind(&c);
257 Node* phi = m.Phi(param0, param1);
258 m.Return(phi);
259 Stream s = m.Build(kAllInstructions);
260 EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param0->id()));
261 EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param1->id()));
262 }
263
264
265 TARGET_TEST_P(InstructionSelectorPhiTest, PropagateReferenceness) {
266 const MachineType type = GetParam();
267 StreamBuilder m(this, type, type, type);
268 Node* param0 = m.Parameter(0);
269 Node* param1 = m.Parameter(1);
270 MLabel a, b, c;
271 m.Branch(m.Int32Constant(1), &a, &b);
272 m.Bind(&a);
273 m.Goto(&c);
274 m.Bind(&b);
275 m.Goto(&c);
276 m.Bind(&c);
277 Node* phi = m.Phi(param0, param1);
278 m.Return(phi);
279 Stream s = m.Build(kAllInstructions);
280 EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param0->id()));
281 EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param1->id()));
282 }
283
284
285 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
286 ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
287 kMachInt16, kMachUint16, kMachInt32,
288 kMachUint32, kMachInt64, kMachUint64,
289 kMachPtr, kMachAnyTagged));
290
291
292 // -----------------------------------------------------------------------------
293 // ValueEffect.
294
295
296 TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
297 StreamBuilder m1(this, kMachInt32, kMachPtr);
298 Node* p1 = m1.Parameter(0);
299 m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
300 Stream s1 = m1.Build(kAllInstructions);
301 StreamBuilder m2(this, kMachInt32, kMachPtr);
302 Node* p2 = m2.Parameter(0);
303 m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
304 m2.NewNode(m2.common()->ValueEffect(1), p2)));
305 Stream s2 = m2.Build(kAllInstructions);
306 EXPECT_LE(3U, s1.size());
307 ASSERT_EQ(s1.size(), s2.size());
308 TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
309 const Instruction* i1 = s1[i];
310 const Instruction* i2 = s2[i];
311 EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
312 EXPECT_EQ(i1->InputCount(), i2->InputCount());
313 EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
314 }
315 }
316
317
318 // -----------------------------------------------------------------------------
319 // Calls with deoptimization.
320 TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
321 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged);
322
323 BailoutId bailout_id(42);
324
325 Node* function_node = m.Parameter(0);
326 Node* receiver = m.Parameter(1);
327
328 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
329 Node* locals = m.NewNode(m.common()->StateValues(0));
330 Node* stack = m.NewNode(m.common()->StateValues(0));
331 Node* context_dummy = m.Int32Constant(0);
332
333 Node* state_node = m.NewNode(m.common()->FrameState(bailout_id, kPushOutput),
334 parameters, locals, stack, context_dummy);
335 Node* call = m.CallJS0(function_node, receiver, state_node);
336 m.Return(call);
337
338 Stream s = m.Build(kAllExceptNopInstructions);
339
340 // Skip until kArchCallJSFunction.
341 size_t index = 0;
342 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
343 index++) {
344 }
345 // Now we should have two instructions: call and return.
346 ASSERT_EQ(index + 2, s.size());
347
348 EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
349 EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
350
351 // TODO(jarin) Check deoptimization table.
352 }
353
354
355 TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
356 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
357 kMachAnyTagged);
358
359 BailoutId bailout_id_before(42);
360
361 // Some arguments for the call node.
362 Node* function_node = m.Parameter(0);
363 Node* receiver = m.Parameter(1);
364 Node* context = m.Int32Constant(1); // Context is ignored.
365
366 // Build frame state for the state before the call.
367 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
368 Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
369 Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
370 Node* context_sentinel = m.Int32Constant(0);
371 Node* frame_state_before =
372 m.NewNode(m.common()->FrameState(bailout_id_before, kPushOutput),
373 parameters, locals, stack, context_sentinel);
374
375 // Build the call.
376 Node* call = m.CallFunctionStub0(function_node, receiver, context,
377 frame_state_before, CALL_AS_METHOD);
378
379 m.Return(call);
380
381 Stream s = m.Build(kAllExceptNopInstructions);
382
383 // Skip until kArchCallJSFunction.
384 size_t index = 0;
385 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
386 index++) {
387 }
388 // Now we should have two instructions: call, return.
389 ASSERT_EQ(index + 2, s.size());
390
391 // Check the call instruction
392 const Instruction* call_instr = s[index++];
393 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
394 size_t num_operands =
395 1 + // Code object.
396 1 +
397 4 + // Frame state deopt id + one input for each value in frame state.
398 1 + // Function.
399 1; // Context.
400 ASSERT_EQ(num_operands, call_instr->InputCount());
401
402 // Code object.
403 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
404
405 // Deoptimization id.
406 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
407 FrameStateDescriptor* desc_before =
408 s.GetFrameStateDescriptor(deopt_id_before);
409 EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
410 EXPECT_EQ(kPushOutput, desc_before->state_combine());
411 EXPECT_EQ(1, desc_before->parameters_count());
412 EXPECT_EQ(1, desc_before->locals_count());
413 EXPECT_EQ(1, desc_before->stack_count());
414 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
415 EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));
416 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4)));
417 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5)));
418
419 // Function.
420 EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(6)));
421 // Context.
422 EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(7)));
423
424 EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
425
426 EXPECT_EQ(index, s.size());
427 }
428
429 } // namespace compiler
430 } // namespace internal
431 } // namespace v8
OLDNEW
« no previous file with comments | « test/compiler-unittests/instruction-selector-unittest.h ('k') | test/compiler-unittests/machine-operator-reducer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698