V8 Project
instruction-selector-unittest.cc
Go to the documentation of this file.
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 
6 
8 #include "src/flags.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
14 namespace {
15 
17 
18 } // namespace
19 
20 
22 
23 
25 
26 
27 InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
28  InstructionSelector::Features features,
30  Schedule* schedule = Export();
31  if (FLAG_trace_turbo) {
32  OFStream out(stdout);
33  out << "=== Schedule before instruction selection ===" << endl << *schedule;
34  }
35  EXPECT_NE(0, graph()->NodeCount());
36  CompilationInfo info(test_->isolate(), test_->zone());
37  Linkage linkage(&info, call_descriptor());
38  InstructionSequence sequence(&linkage, graph(), schedule);
39  SourcePositionTable source_position_table(graph());
40  InstructionSelector selector(&sequence, &source_position_table, features);
41  selector.SelectInstructions();
42  if (FLAG_trace_turbo) {
43  OFStream out(stdout);
44  out << "=== Code sequence after instruction selection ===" << endl
45  << sequence;
46  }
47  Stream s;
48  std::set<int> virtual_registers;
49  for (InstructionSequence::const_iterator i = sequence.begin();
50  i != sequence.end(); ++i) {
51  Instruction* instr = *i;
52  if (instr->opcode() < 0) continue;
53  if (mode == kTargetInstructions) {
54  switch (instr->arch_opcode()) {
55 #define CASE(Name) \
56  case k##Name: \
57  break;
59 #undef CASE
60  default:
61  continue;
62  }
63  }
64  if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
65  continue;
66  }
67  for (size_t i = 0; i < instr->OutputCount(); ++i) {
68  InstructionOperand* output = instr->OutputAt(i);
69  EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
70  if (output->IsConstant()) {
71  s.constants_.insert(std::make_pair(
72  output->index(), sequence.GetConstant(output->index())));
73  virtual_registers.insert(output->index());
74  } else if (output->IsUnallocated()) {
75  virtual_registers.insert(
76  UnallocatedOperand::cast(output)->virtual_register());
77  }
78  }
79  for (size_t i = 0; i < instr->InputCount(); ++i) {
80  InstructionOperand* input = instr->InputAt(i);
81  EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
82  if (input->IsImmediate()) {
83  s.immediates_.insert(std::make_pair(
84  input->index(), sequence.GetImmediate(input->index())));
85  } else if (input->IsUnallocated()) {
86  virtual_registers.insert(
87  UnallocatedOperand::cast(input)->virtual_register());
88  }
89  }
90  s.instructions_.push_back(instr);
91  }
92  for (std::set<int>::const_iterator i = virtual_registers.begin();
93  i != virtual_registers.end(); ++i) {
94  int virtual_register = *i;
95  if (sequence.IsDouble(virtual_register)) {
96  EXPECT_FALSE(sequence.IsReference(virtual_register));
97  s.doubles_.insert(virtual_register);
98  }
99  if (sequence.IsReference(virtual_register)) {
100  EXPECT_FALSE(sequence.IsDouble(virtual_register));
101  s.references_.insert(virtual_register);
102  }
103  }
104  for (int i = 0; i < sequence.GetFrameStateDescriptorCount(); i++) {
105  s.deoptimization_entries_.push_back(sequence.GetFrameStateDescriptor(
106  InstructionSequence::StateId::FromInt(i)));
107  }
108  return s;
109 }
110 
111 
112 // -----------------------------------------------------------------------------
113 // Return.
114 
115 
116 TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) {
117  const float kValue = 4.2f;
118  StreamBuilder m(this, kMachFloat32);
119  m.Return(m.Float32Constant(kValue));
120  Stream s = m.Build(kAllInstructions);
121  ASSERT_EQ(2U, s.size());
122  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
123  ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
124  EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0)));
125  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
126  EXPECT_EQ(1U, s[1]->InputCount());
127 }
128 
129 
131  StreamBuilder m(this, kMachInt32, kMachInt32);
132  m.Return(m.Parameter(0));
133  Stream s = m.Build(kAllInstructions);
134  ASSERT_EQ(2U, s.size());
135  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
136  ASSERT_EQ(1U, s[0]->OutputCount());
137  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
138  EXPECT_EQ(1U, s[1]->InputCount());
139 }
140 
141 
143  StreamBuilder m(this, kMachInt32);
144  m.Return(m.Int32Constant(0));
145  Stream s = m.Build(kAllInstructions);
146  ASSERT_EQ(2U, s.size());
147  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
148  ASSERT_EQ(1U, s[0]->OutputCount());
149  EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
150  EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
151  EXPECT_EQ(kArchRet, s[1]->arch_opcode());
152  EXPECT_EQ(1U, s[1]->InputCount());
153 }
154 
155 
156 // -----------------------------------------------------------------------------
157 // Conversions.
158 
159 
160 TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
161  StreamBuilder m(this, kMachInt32, kMachFloat64);
162  m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
163  Stream s = m.Build(kAllInstructions);
164  ASSERT_EQ(3U, s.size());
165  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
166  EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
167  EXPECT_EQ(1U, s[1]->InputCount());
168  EXPECT_EQ(1U, s[1]->OutputCount());
169  EXPECT_EQ(kArchRet, s[2]->arch_opcode());
170 }
171 
172 
173 // -----------------------------------------------------------------------------
174 // Parameters.
175 
176 
178  StreamBuilder m(this, kMachFloat64, kMachFloat64);
179  Node* param = m.Parameter(0);
180  m.Return(param);
181  Stream s = m.Build(kAllInstructions);
182  EXPECT_TRUE(s.IsDouble(param->id()));
183 }
184 
185 
187  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
188  Node* param = m.Parameter(0);
189  m.Return(param);
190  Stream s = m.Build(kAllInstructions);
191  EXPECT_TRUE(s.IsReference(param->id()));
192 }
193 
194 
195 // -----------------------------------------------------------------------------
196 // Finish.
197 
198 
200  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
201  Node* param = m.Parameter(0);
202  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
203  m.Return(finish);
204  Stream s = m.Build(kAllInstructions);
205  ASSERT_EQ(3U, s.size());
206  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
207  ASSERT_EQ(1U, s[0]->OutputCount());
208  ASSERT_TRUE(s[0]->Output()->IsUnallocated());
209  EXPECT_EQ(param->id(), s.ToVreg(s[0]->Output()));
210  EXPECT_EQ(kArchNop, s[1]->arch_opcode());
211  ASSERT_EQ(1U, s[1]->InputCount());
212  ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
213  EXPECT_EQ(param->id(), s.ToVreg(s[1]->InputAt(0)));
214  ASSERT_EQ(1U, s[1]->OutputCount());
215  ASSERT_TRUE(s[1]->Output()->IsUnallocated());
216  EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
217  EXPECT_EQ(finish->id(), s.ToVreg(s[1]->Output()));
218  EXPECT_TRUE(s.IsReference(finish->id()));
219 }
220 
221 
222 // -----------------------------------------------------------------------------
223 // Phi.
224 
225 
226 typedef InstructionSelectorTestWithParam<MachineType>
228 
229 
231  const MachineType type = GetParam();
232  StreamBuilder m(this, type, type, type);
233  Node* param0 = m.Parameter(0);
234  Node* param1 = m.Parameter(1);
235  MLabel a, b, c;
236  m.Branch(m.Int32Constant(0), &a, &b);
237  m.Bind(&a);
238  m.Goto(&c);
239  m.Bind(&b);
240  m.Goto(&c);
241  m.Bind(&c);
242  Node* phi = m.Phi(type, param0, param1);
243  m.Return(phi);
244  Stream s = m.Build(kAllInstructions);
245  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param0->id()));
246  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param1->id()));
247 }
248 
249 
251  const MachineType type = GetParam();
252  StreamBuilder m(this, type, type, type);
253  Node* param0 = m.Parameter(0);
254  Node* param1 = m.Parameter(1);
255  MLabel a, b, c;
256  m.Branch(m.Int32Constant(1), &a, &b);
257  m.Bind(&a);
258  m.Goto(&c);
259  m.Bind(&b);
260  m.Goto(&c);
261  m.Bind(&c);
262  Node* phi = m.Phi(type, param0, param1);
263  m.Return(phi);
264  Stream s = m.Build(kAllInstructions);
265  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param0->id()));
266  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param1->id()));
267 }
268 
269 
271  ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
275 
276 
277 // -----------------------------------------------------------------------------
278 // ValueEffect.
279 
280 
282  StreamBuilder m1(this, kMachInt32, kMachPtr);
283  Node* p1 = m1.Parameter(0);
284  m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
285  Stream s1 = m1.Build(kAllInstructions);
286  StreamBuilder m2(this, kMachInt32, kMachPtr);
287  Node* p2 = m2.Parameter(0);
288  m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
289  m2.NewNode(m2.common()->ValueEffect(1), p2)));
290  Stream s2 = m2.Build(kAllInstructions);
291  EXPECT_LE(3U, s1.size());
292  ASSERT_EQ(s1.size(), s2.size());
293  TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
294  const Instruction* i1 = s1[i];
295  const Instruction* i2 = s2[i];
296  EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
297  EXPECT_EQ(i1->InputCount(), i2->InputCount());
298  EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
299  }
300 }
301 
302 
303 // -----------------------------------------------------------------------------
304 // Calls with deoptimization.
305 
306 
307 TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
308  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
310 
311  BailoutId bailout_id(42);
312 
313  Node* function_node = m.Parameter(0);
314  Node* receiver = m.Parameter(1);
315  Node* context = m.Parameter(2);
316 
317  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1));
318  Node* locals = m.NewNode(m.common()->StateValues(0));
319  Node* stack = m.NewNode(m.common()->StateValues(0));
320  Node* context_dummy = m.Int32Constant(0);
321 
322  Node* state_node = m.NewNode(
323  m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters,
324  locals, stack, context_dummy, m.UndefinedConstant());
325  Node* call = m.CallJS0(function_node, receiver, context, state_node);
326  m.Return(call);
327 
328  Stream s = m.Build(kAllExceptNopInstructions);
329 
330  // Skip until kArchCallJSFunction.
331  size_t index = 0;
332  for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
333  index++) {
334  }
335  // Now we should have two instructions: call and return.
336  ASSERT_EQ(index + 2, s.size());
337 
338  EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
339  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
340 
341  // TODO(jarin) Check deoptimization table.
342 }
343 
344 
345 TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) {
346  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
348 
349  BailoutId bailout_id_before(42);
350 
351  // Some arguments for the call node.
352  Node* function_node = m.Parameter(0);
353  Node* receiver = m.Parameter(1);
354  Node* context = m.Int32Constant(1); // Context is ignored.
355 
356  // Build frame state for the state before the call.
357  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
358  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
359  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
360 
361  Node* context_sentinel = m.Int32Constant(0);
362  Node* frame_state_before = m.NewNode(
363  m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
364  parameters, locals, stack, context_sentinel, m.UndefinedConstant());
365 
366  // Build the call.
367  Node* call = m.CallFunctionStub0(function_node, receiver, context,
368  frame_state_before, CALL_AS_METHOD);
369 
370  m.Return(call);
371 
372  Stream s = m.Build(kAllExceptNopInstructions);
373 
374  // Skip until kArchCallJSFunction.
375  size_t index = 0;
376  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
377  index++) {
378  }
379  // Now we should have two instructions: call, return.
380  ASSERT_EQ(index + 2, s.size());
381 
382  // Check the call instruction
383  const Instruction* call_instr = s[index++];
384  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
385  size_t num_operands =
386  1 + // Code object.
387  1 +
388  4 + // Frame state deopt id + one input for each value in frame state.
389  1 + // Function.
390  1; // Context.
391  ASSERT_EQ(num_operands, call_instr->InputCount());
392 
393  // Code object.
394  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
395 
396  // Deoptimization id.
397  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
398  FrameStateDescriptor* desc_before =
399  s.GetFrameStateDescriptor(deopt_id_before);
400  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
401  EXPECT_EQ(kPushOutput, desc_before->state_combine());
402  EXPECT_EQ(1u, desc_before->parameters_count());
403  EXPECT_EQ(1u, desc_before->locals_count());
404  EXPECT_EQ(1u, desc_before->stack_count());
405  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(2)));
406  EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(3)));
407  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(4)));
408  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(5)));
409 
410  // Function.
411  EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(6)));
412  // Context.
413  EXPECT_EQ(context->id(), s.ToVreg(call_instr->InputAt(7)));
414 
415  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
416 
417  EXPECT_EQ(index, s.size());
418 }
419 
420 
422  CallFunctionStubDeoptRecursiveFrameState) {
423  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged, kMachAnyTagged,
425 
426  BailoutId bailout_id_before(42);
427  BailoutId bailout_id_parent(62);
428 
429  // Some arguments for the call node.
430  Node* function_node = m.Parameter(0);
431  Node* receiver = m.Parameter(1);
432  Node* context = m.Int32Constant(66);
433 
434  // Build frame state for the state before the call.
435  Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
436  Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
437  Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
438  Node* frame_state_parent = m.NewNode(
439  m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput),
440  parameters, locals, stack, context, m.UndefinedConstant());
441 
442  Node* context2 = m.Int32Constant(46);
443  Node* parameters2 =
444  m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
445  Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
446  Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
447  Node* frame_state_before = m.NewNode(
448  m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
449  parameters2, locals2, stack2, context2, frame_state_parent);
450 
451  // Build the call.
452  Node* call = m.CallFunctionStub0(function_node, receiver, context2,
453  frame_state_before, CALL_AS_METHOD);
454 
455  m.Return(call);
456 
457  Stream s = m.Build(kAllExceptNopInstructions);
458 
459  // Skip until kArchCallJSFunction.
460  size_t index = 0;
461  for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
462  index++) {
463  }
464  // Now we should have three instructions: call, return.
465  EXPECT_EQ(index + 2, s.size());
466 
467  // Check the call instruction
468  const Instruction* call_instr = s[index++];
469  EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
470  size_t num_operands =
471  1 + // Code object.
472  1 + // Frame state deopt id
473  4 + // One input for each value in frame state + context.
474  4 + // One input for each value in the parent frame state + context.
475  1 + // Function.
476  1; // Context.
477  EXPECT_EQ(num_operands, call_instr->InputCount());
478  // Code object.
479  EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
480 
481  // Deoptimization id.
482  int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(1));
483  FrameStateDescriptor* desc_before =
484  s.GetFrameStateDescriptor(deopt_id_before);
485  EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
486  EXPECT_EQ(1u, desc_before->parameters_count());
487  EXPECT_EQ(1u, desc_before->locals_count());
488  EXPECT_EQ(1u, desc_before->stack_count());
489  EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(2)));
490  // Context:
491  EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(3)));
492  EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(4)));
493  EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(5)));
494  // Values from parent environment should follow.
495  EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(6)));
496  EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(7)));
497  EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(8)));
498  EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(9)));
499 
500  // Function.
501  EXPECT_EQ(function_node->id(), s.ToVreg(call_instr->InputAt(10)));
502  // Context.
503  EXPECT_EQ(context2->id(), s.ToVreg(call_instr->InputAt(11)));
504  // Continuation.
505 
506  EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
507  EXPECT_EQ(index, s.size());
508 }
509 
510 } // namespace compiler
511 } // namespace internal
512 } // namespace v8
OutputFrameStateCombine state_combine() const
Definition: instruction.h:732
InstructionOperand * InputAt(size_t i) const
Definition: instruction.h:416
static const UnallocatedOperand * cast(const InstructionOperand *op)
Definition: instruction.h:160
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
#define TARGET_ARCH_OPCODE_LIST(V)
#define CASE(Name)
int int32_t
Definition: unicode.cc:24
InstructionSelectorTestWithParam< MachineType > InstructionSelectorPhiTest
TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged)
TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool)
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest, ::testing::ValuesIn(kDPIs))
const SwVfpRegister s1
const SwVfpRegister s2
OStream & endl(OStream &os)
Definition: ostreams.cc:112
@ CALL_AS_METHOD
Definition: globals.h:470
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20