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

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

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

Powered by Google App Engine
This is Rietveld 408576698