blob: c79a9e4eaa0380208c15818b2d289618081b8d0d [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include "test/unittests/compiler/instruction-selector-unittest.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include "src/compiler/graph-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/flags.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009#include "test/unittests/compiler/compiler-test-utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15namespace {
16
17typedef RawMachineAssembler::Label MLabel;
18
19} // namespace
20
21
22InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
23
24
25InstructionSelectorTest::~InstructionSelectorTest() {}
26
27
28InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
29 InstructionSelector::Features features,
30 InstructionSelectorTest::StreamBuilderMode mode) {
31 Schedule* schedule = Export();
32 if (FLAG_trace_turbo) {
33 OFStream out(stdout);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034 out << "=== Schedule before instruction selection ===" << std::endl
35 << *schedule;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036 }
37 EXPECT_NE(0, graph()->NodeCount());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 int initial_node_count = graph()->NodeCount();
39 Linkage linkage(test_->zone(), call_descriptor());
40 InstructionBlocks* instruction_blocks =
41 InstructionSequence::InstructionBlocksFor(test_->zone(), schedule);
42 InstructionSequence sequence(test_->zone(), instruction_blocks);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 SourcePositionTable source_position_table(graph());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 InstructionSelector selector(test_->zone(), graph(), &linkage, &sequence,
45 schedule, &source_position_table, features);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 selector.SelectInstructions();
47 if (FLAG_trace_turbo) {
48 OFStream out(stdout);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040049 PrintableInstructionSequence printable = {
50 RegisterConfiguration::ArchDefault(), &sequence};
51 out << "=== Code sequence after instruction selection ===" << std::endl
52 << printable;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053 }
54 Stream s;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055 // Map virtual registers.
56 {
57 const NodeToVregMap& node_map = selector.GetNodeMapForTesting();
58 for (int i = 0; i < initial_node_count; ++i) {
59 if (node_map[i] != InstructionSelector::kNodeUnmapped) {
60 s.virtual_registers_.insert(std::make_pair(i, node_map[i]));
61 }
62 }
63 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 std::set<int> virtual_registers;
65 for (InstructionSequence::const_iterator i = sequence.begin();
66 i != sequence.end(); ++i) {
67 Instruction* instr = *i;
68 if (instr->opcode() < 0) continue;
69 if (mode == kTargetInstructions) {
70 switch (instr->arch_opcode()) {
71#define CASE(Name) \
72 case k##Name: \
73 break;
74 TARGET_ARCH_OPCODE_LIST(CASE)
75#undef CASE
76 default:
77 continue;
78 }
79 }
80 if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
81 continue;
82 }
83 for (size_t i = 0; i < instr->OutputCount(); ++i) {
84 InstructionOperand* output = instr->OutputAt(i);
85 EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
86 if (output->IsConstant()) {
87 s.constants_.insert(std::make_pair(
88 output->index(), sequence.GetConstant(output->index())));
89 virtual_registers.insert(output->index());
90 } else if (output->IsUnallocated()) {
91 virtual_registers.insert(
92 UnallocatedOperand::cast(output)->virtual_register());
93 }
94 }
95 for (size_t i = 0; i < instr->InputCount(); ++i) {
96 InstructionOperand* input = instr->InputAt(i);
97 EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
98 if (input->IsImmediate()) {
99 s.immediates_.insert(std::make_pair(
100 input->index(), sequence.GetImmediate(input->index())));
101 } else if (input->IsUnallocated()) {
102 virtual_registers.insert(
103 UnallocatedOperand::cast(input)->virtual_register());
104 }
105 }
106 s.instructions_.push_back(instr);
107 }
108 for (std::set<int>::const_iterator i = virtual_registers.begin();
109 i != virtual_registers.end(); ++i) {
110 int virtual_register = *i;
111 if (sequence.IsDouble(virtual_register)) {
112 EXPECT_FALSE(sequence.IsReference(virtual_register));
113 s.doubles_.insert(virtual_register);
114 }
115 if (sequence.IsReference(virtual_register)) {
116 EXPECT_FALSE(sequence.IsDouble(virtual_register));
117 s.references_.insert(virtual_register);
118 }
119 }
120 for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
121 s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
122 InstructionSequence::StateId::FromInt(i)));
123 }
124 return s;
125}
126
127
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128int InstructionSelectorTest::Stream::ToVreg(const Node* node) const {
129 VirtualRegisters::const_iterator i = virtual_registers_.find(node->id());
130 CHECK(i != virtual_registers_.end());
131 return i->second;
132}
133
134
135bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand,
136 Register reg) const {
137 if (!operand->IsUnallocated()) return false;
138 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
139 if (!unallocated->HasFixedRegisterPolicy()) return false;
140 const int index = Register::ToAllocationIndex(reg);
141 return unallocated->fixed_register_index() == index;
142}
143
144
145bool InstructionSelectorTest::Stream::IsSameAsFirst(
146 const InstructionOperand* operand) const {
147 if (!operand->IsUnallocated()) return false;
148 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
149 return unallocated->HasSameAsInputPolicy();
150}
151
152
153bool InstructionSelectorTest::Stream::IsUsedAtStart(
154 const InstructionOperand* operand) const {
155 if (!operand->IsUnallocated()) return false;
156 const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
157 return unallocated->IsUsedAtStart();
158}
159
160
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161// -----------------------------------------------------------------------------
162// Return.
163
164
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) {
166 const float kValue = 4.2f;
167 StreamBuilder m(this, kMachFloat32);
168 m.Return(m.Float32Constant(kValue));
169 Stream s = m.Build(kAllInstructions);
170 ASSERT_EQ(2U, s.size());
171 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
172 ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
173 EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0)));
174 EXPECT_EQ(kArchRet, s[1]->arch_opcode());
175 EXPECT_EQ(1U, s[1]->InputCount());
176}
177
178
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
180 StreamBuilder m(this, kMachInt32, kMachInt32);
181 m.Return(m.Parameter(0));
182 Stream s = m.Build(kAllInstructions);
183 ASSERT_EQ(2U, s.size());
184 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
185 ASSERT_EQ(1U, s[0]->OutputCount());
186 EXPECT_EQ(kArchRet, s[1]->arch_opcode());
187 EXPECT_EQ(1U, s[1]->InputCount());
188}
189
190
191TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
192 StreamBuilder m(this, kMachInt32);
193 m.Return(m.Int32Constant(0));
194 Stream s = m.Build(kAllInstructions);
195 ASSERT_EQ(2U, s.size());
196 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
197 ASSERT_EQ(1U, s[0]->OutputCount());
198 EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
199 EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
200 EXPECT_EQ(kArchRet, s[1]->arch_opcode());
201 EXPECT_EQ(1U, s[1]->InputCount());
202}
203
204
205// -----------------------------------------------------------------------------
206// Conversions.
207
208
209TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
210 StreamBuilder m(this, kMachInt32, kMachFloat64);
211 m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
212 Stream s = m.Build(kAllInstructions);
213 ASSERT_EQ(3U, s.size());
214 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
215 EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
216 EXPECT_EQ(1U, s[1]->InputCount());
217 EXPECT_EQ(1U, s[1]->OutputCount());
218 EXPECT_EQ(kArchRet, s[2]->arch_opcode());
219}
220
221
222// -----------------------------------------------------------------------------
223// Parameters.
224
225
226TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
227 StreamBuilder m(this, kMachFloat64, kMachFloat64);
228 Node* param = m.Parameter(0);
229 m.Return(param);
230 Stream s = m.Build(kAllInstructions);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 EXPECT_TRUE(s.IsDouble(param));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232}
233
234
235TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
236 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
237 Node* param = m.Parameter(0);
238 m.Return(param);
239 Stream s = m.Build(kAllInstructions);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400240 EXPECT_TRUE(s.IsReference(param));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241}
242
243
244// -----------------------------------------------------------------------------
245// Finish.
246
247
248TARGET_TEST_F(InstructionSelectorTest, Finish) {
249 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
250 Node* param = m.Parameter(0);
251 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
252 m.Return(finish);
253 Stream s = m.Build(kAllInstructions);
254 ASSERT_EQ(3U, s.size());
255 EXPECT_EQ(kArchNop, s[0]->arch_opcode());
256 ASSERT_EQ(1U, s[0]->OutputCount());
257 ASSERT_TRUE(s[0]->Output()->IsUnallocated());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400258 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259 EXPECT_EQ(kArchNop, s[1]->arch_opcode());
260 ASSERT_EQ(1U, s[1]->InputCount());
261 ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(0)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000263 ASSERT_EQ(1U, s[1]->OutputCount());
264 ASSERT_TRUE(s[1]->Output()->IsUnallocated());
265 EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400266 EXPECT_EQ(s.ToVreg(finish), s.ToVreg(s[1]->Output()));
267 EXPECT_TRUE(s.IsReference(finish));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268}
269
270
271// -----------------------------------------------------------------------------
272// Phi.
273
274
275typedef InstructionSelectorTestWithParam<MachineType>
276 InstructionSelectorPhiTest;
277
278
279TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) {
280 const MachineType type = GetParam();
281 StreamBuilder m(this, type, type, type);
282 Node* param0 = m.Parameter(0);
283 Node* param1 = m.Parameter(1);
284 MLabel a, b, c;
285 m.Branch(m.Int32Constant(0), &a, &b);
286 m.Bind(&a);
287 m.Goto(&c);
288 m.Bind(&b);
289 m.Goto(&c);
290 m.Bind(&c);
291 Node* phi = m.Phi(type, param0, param1);
292 m.Return(phi);
293 Stream s = m.Build(kAllInstructions);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param0));
295 EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296}
297
298
299TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) {
300 const MachineType type = GetParam();
301 StreamBuilder m(this, type, type, type);
302 Node* param0 = m.Parameter(0);
303 Node* param1 = m.Parameter(1);
304 MLabel a, b, c;
305 m.Branch(m.Int32Constant(1), &a, &b);
306 m.Bind(&a);
307 m.Goto(&c);
308 m.Bind(&b);
309 m.Goto(&c);
310 m.Bind(&c);
311 Node* phi = m.Phi(type, param0, param1);
312 m.Return(phi);
313 Stream s = m.Build(kAllInstructions);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400314 EXPECT_EQ(s.IsReference(phi), s.IsReference(param0));
315 EXPECT_EQ(s.IsReference(phi), s.IsReference(param1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316}
317
318
319INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
320 ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
321 kMachInt16, kMachUint16, kMachInt32,
322 kMachUint32, kMachInt64, kMachUint64,
323 kMachPtr, kMachAnyTagged));
324
325
326// -----------------------------------------------------------------------------
327// ValueEffect.
328
329
330TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
331 StreamBuilder m1(this, kMachInt32, kMachPtr);
332 Node* p1 = m1.Parameter(0);
333 m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
334 Stream s1 = m1.Build(kAllInstructions);
335 StreamBuilder m2(this, kMachInt32, kMachPtr);
336 Node* p2 = m2.Parameter(0);
337 m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
338 m2.NewNode(m2.common()->ValueEffect(1), p2)));
339 Stream s2 = m2.Build(kAllInstructions);
340 EXPECT_LE(3U, s1.size());
341 ASSERT_EQ(s1.size(), s2.size());
342 TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
343 const Instruction* i1 = s1[i];
344 const Instruction* i2 = s2[i];
345 EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
346 EXPECT_EQ(i1->InputCount(), i2->InputCount());
347 EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
348 }
349}
350
351
352// -----------------------------------------------------------------------------
353// Calls with deoptimization.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400354
355
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
357 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
358 kMachAnyTagged);
359
360 BailoutId bailout_id(42);
361
362 Node* function_node = m.Parameter(0);
363 Node* receiver = m.Parameter(1);
364 Node* context = m.Parameter(2);
365
366 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
367 Node* locals = m.NewNode(m.common()->StateValues(0));
368 Node* stack = m.NewNode(m.common()->StateValues(0));
369 Node* context_dummy = m.Int32Constant(0);
370
371 Node* state_node = m.NewNode(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 m.common()->FrameState(JS_FRAME, bailout_id,
373 OutputFrameStateCombine::Push()),
374 parameters, locals, stack, context_dummy, m.UndefinedConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 Node* call = m.CallJS0(function_node, receiver, context, state_node);
376 m.Return(call);
377
378 Stream s = m.Build(kAllExceptNopInstructions);
379
380 // Skip until kArchCallJSFunction.
381 size_t index = 0;
382 for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
383 index++) {
384 }
385 // Now we should have two instructions: call and return.
386 ASSERT_EQ(index + 2, s.size());
387
388 EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
389 EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
390
391 // TODO(jarin) Check deoptimization table.
392}
393
394
395TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
396 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
397 kMachAnyTagged);
398
399 BailoutId bailout_id_before(42);
400
401 // Some arguments for the call node.
402 Node* function_node = m.Parameter(0);
403 Node* receiver = m.Parameter(1);
404 Node* context = m.Int32Constant(1); // Context is ignored.
405
406 // Build frame state for the state before the call.
407 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400408 Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5));
409 Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410
411 Node* context_sentinel = m.Int32Constant(0);
412 Node* frame_state_before = m.NewNode(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400413 m.common()->FrameState(JS_FRAME, bailout_id_before,
414 OutputFrameStateCombine::Push()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 parameters, locals, stack, context_sentinel, m.UndefinedConstant());
416
417 // Build the call.
418 Node* call = m.CallFunctionStub0(function_node, receiver, context,
419 frame_state_before, CALL_AS_METHOD);
420
421 m.Return(call);
422
423 Stream s = m.Build(kAllExceptNopInstructions);
424
425 // Skip until kArchCallJSFunction.
426 size_t index = 0;
427 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
428 index++) {
429 }
430 // Now we should have two instructions: call, return.
431 ASSERT_EQ(index + 2, s.size());
432
433 // Check the call instruction
434 const Instruction* call_instr = s[index++];
435 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
436 size_t num_operands =
437 1 + // Code object.
438 1 +
439 4 + // Frame state deopt id + one input for each value in frame state.
440 1 + // Function.
441 1; // Context.
442 ASSERT_EQ(num_operands, call_instr->InputCount());
443
444 // Code object.
445 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
446
447 // Deoptimization id.
448 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
449 FrameStateDescriptor* desc_before =
450 s.GetFrameStateDescriptor(deopt_id_before);
451 EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400452 EXPECT_EQ(OutputFrameStateCombine::kPushOutput,
453 desc_before->state_combine().kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000454 EXPECT_EQ(1u, desc_before->parameters_count());
455 EXPECT_EQ(1u, desc_before->locals_count());
456 EXPECT_EQ(1u, desc_before->stack_count());
457 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400458 EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3))); // This should be a context.
459 // We inserted 0 here.
460 EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(4)));
461 EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(5))->IsUndefined());
462 EXPECT_EQ(kMachInt32, desc_before->GetType(0));
463 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1)); // context is always
464 // tagged/any.
465 EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
466 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467
468 // Function.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400469 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(6)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000470 // Context.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400471 EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(7)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472
473 EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
474
475 EXPECT_EQ(index, s.size());
476}
477
478
479TARGET_TEST_F(InstructionSelectorTest,
480 CallFunctionStubDeoptRecursiveFrameState) {
481 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
482 kMachAnyTagged);
483
484 BailoutId bailout_id_before(42);
485 BailoutId bailout_id_parent(62);
486
487 // Some arguments for the call node.
488 Node* function_node = m.Parameter(0);
489 Node* receiver = m.Parameter(1);
490 Node* context = m.Int32Constant(66);
491
492 // Build frame state for the state before the call.
493 Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
494 Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
495 Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400496 Node* frame_state_parent =
497 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
498 OutputFrameStateCombine::Ignore()),
499 parameters, locals, stack, context, m.UndefinedConstant());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500
501 Node* context2 = m.Int32Constant(46);
502 Node* parameters2 =
503 m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400504 Node* locals2 =
505 m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25));
506 Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44),
507 m.Int32Constant(45));
508 Node* frame_state_before =
509 m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
510 OutputFrameStateCombine::Push()),
511 parameters2, locals2, stack2, context2, frame_state_parent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512
513 // Build the call.
514 Node* call = m.CallFunctionStub0(function_node, receiver, context2,
515 frame_state_before, CALL_AS_METHOD);
516
517 m.Return(call);
518
519 Stream s = m.Build(kAllExceptNopInstructions);
520
521 // Skip until kArchCallJSFunction.
522 size_t index = 0;
523 for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
524 index++) {
525 }
526 // Now we should have three instructions: call, return.
527 EXPECT_EQ(index + 2, s.size());
528
529 // Check the call instruction
530 const Instruction* call_instr = s[index++];
531 EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
532 size_t num_operands =
533 1 + // Code object.
534 1 + // Frame state deopt id
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400535 5 + // One input for each value in frame state + context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 4 + // One input for each value in the parent frame state + context.
537 1 + // Function.
538 1; // Context.
539 EXPECT_EQ(num_operands, call_instr->InputCount());
540 // Code object.
541 EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
542
543 // Deoptimization id.
544 int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
545 FrameStateDescriptor* desc_before =
546 s.GetFrameStateDescriptor(deopt_id_before);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400547 FrameStateDescriptor* desc_before_outer = desc_before->outer_state();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 EXPECT_EQ(1u, desc_before_outer->parameters_count());
550 EXPECT_EQ(1u, desc_before_outer->locals_count());
551 EXPECT_EQ(1u, desc_before_outer->stack_count());
552 // Values from parent environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553 EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400554 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 // Context:
556 EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400557 EXPECT_EQ(kMachAnyTagged, desc_before_outer->GetType(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000558 EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400561 EXPECT_EQ(kMachInt32, desc_before_outer->GetType(3));
562 // Values from the nested frame.
563 EXPECT_EQ(1u, desc_before->parameters_count());
564 EXPECT_EQ(1u, desc_before->locals_count());
565 EXPECT_EQ(2u, desc_before->stack_count());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400567 EXPECT_EQ(kMachInt32, desc_before->GetType(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400569 EXPECT_EQ(kMachAnyTagged, desc_before->GetType(1));
570 EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(8)));
571 EXPECT_EQ(kMachFloat64, desc_before->GetType(2));
572 EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(9)));
573 EXPECT_EQ(kMachInt32, desc_before->GetType(3));
574 EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(10)));
575 EXPECT_EQ(kMachInt32, desc_before->GetType(4));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576
577 // Function.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400578 EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(11)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000579 // Context.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400580 EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(12)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 // Continuation.
582
583 EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
584 EXPECT_EQ(index, s.size());
585}
586
587} // namespace compiler
588} // namespace internal
589} // namespace v8