V8 Project
simplified-lowering.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 
7 #include "src/base/bits.h"
8 #include "src/code-factory.h"
10 #include "src/compiler/graph-inl.h"
15 #include "src/objects.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 // Macro for outputting trace information from representation inference.
22 #define TRACE(x) \
23  if (FLAG_trace_representation) PrintF x
24 
25 // Representation selection and lowering of {Simplified} operators to machine
26 // operators are interwined. We use a fixpoint calculation to compute both the
27 // output representation and the best possible lowering for {Simplified} nodes.
28 // Representation change insertion ensures that all values are in the correct
29 // machine representation after this phase, as dictated by the machine
30 // operators themselves.
31 enum Phase {
32  // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
33  // backwards from uses to definitions, around cycles in phis, according
34  // to local rules for each operator.
35  // During this phase, the usage information for a node determines the best
36  // possible lowering for each operator so far, and that in turn determines
37  // the output representation.
38  // Therefore, to be correct, this phase must iterate to a fixpoint before
39  // the next phase can begin.
41 
42  // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some
43  // operators for some nodes, expanding some nodes to multiple nodes, or
44  // removing some (redundant) nodes.
45  // During this phase, use the {RepresentationChanger} to insert
46  // representation changes between uses that demand a particular
47  // representation and nodes that produce a different representation.
48  LOWER
49 };
50 
51 
53  public:
54  // Information for each node tracked during the fixpoint.
55  struct NodeInfo {
56  MachineTypeUnion use : 15; // Union of all usages for the node.
57  bool queued : 1; // Bookkeeping for the traversal.
58  bool visited : 1; // Bookkeeping for the traversal.
59  MachineTypeUnion output : 15; // Output type of the node.
60  };
61 
63  RepresentationChanger* changer)
64  : jsgraph_(jsgraph),
65  count_(jsgraph->graph()->NodeCount()),
66  info_(zone->NewArray<NodeInfo>(count_)),
67  nodes_(zone),
68  replacements_(zone),
71  changer_(changer),
72  queue_(zone) {
73  memset(info_, 0, sizeof(NodeInfo) * count_);
74  }
75 
76  void Run(SimplifiedLowering* lowering) {
77  // Run propagation phase to a fixpoint.
78  TRACE(("--{Propagation phase}--\n"));
79  phase_ = PROPAGATE;
80  Enqueue(jsgraph_->graph()->end());
81  // Process nodes from the queue until it is empty.
82  while (!queue_.empty()) {
83  Node* node = queue_.front();
84  NodeInfo* info = GetInfo(node);
85  queue_.pop();
86  info->queued = false;
87  TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
88  VisitNode(node, info->use, NULL);
89  TRACE((" ==> output "));
90  PrintInfo(info->output);
91  TRACE(("\n"));
92  }
93 
94  // Run lowering and change insertion phase.
95  TRACE(("--{Simplified lowering phase}--\n"));
96  phase_ = LOWER;
97  // Process nodes from the collected {nodes_} vector.
98  for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
99  Node* node = *i;
100  TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
101  // Reuse {VisitNode()} so the representation rules are in one place.
102  VisitNode(node, GetUseInfo(node), lowering);
103  }
104 
105  // Perform the final replacements.
106  for (NodeVector::iterator i = replacements_.begin();
107  i != replacements_.end(); ++i) {
108  Node* node = *i;
109  Node* replacement = *(++i);
110  node->ReplaceUses(replacement);
111  }
112  }
113 
114  // Enqueue {node} if the {use} contains new information for that node.
115  // Add {node} to {nodes_} if this is the first time it's been visited.
116  void Enqueue(Node* node, MachineTypeUnion use = 0) {
117  if (phase_ != PROPAGATE) return;
118  NodeInfo* info = GetInfo(node);
119  if (!info->visited) {
120  // First visit of this node.
121  info->visited = true;
122  info->queued = true;
123  nodes_.push_back(node);
124  queue_.push(node);
125  TRACE((" initial: "));
126  info->use |= use;
127  PrintUseInfo(node);
128  return;
129  }
130  TRACE((" queue?: "));
131  PrintUseInfo(node);
132  if ((info->use & use) != use) {
133  // New usage information for the node is available.
134  if (!info->queued) {
135  queue_.push(node);
136  info->queued = true;
137  TRACE((" added: "));
138  } else {
139  TRACE((" inqueue: "));
140  }
141  info->use |= use;
142  PrintUseInfo(node);
143  }
144  }
145 
146  bool lower() { return phase_ == LOWER; }
147 
148  void Enqueue(Node* node, MachineType use) {
149  Enqueue(node, static_cast<MachineTypeUnion>(use));
150  }
151 
152  void SetOutput(Node* node, MachineTypeUnion output) {
153  // Every node should have at most one output representation. Note that
154  // phis can have 0, if they have not been used in a representation-inducing
155  // instruction.
156  DCHECK((output & kRepMask) == 0 ||
158  GetInfo(node)->output = output;
159  }
160 
161  bool BothInputsAre(Node* node, Type* type) {
162  DCHECK_EQ(2, node->InputCount());
163  return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
164  NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
165  }
166 
167  void ProcessInput(Node* node, int index, MachineTypeUnion use) {
168  Node* input = node->InputAt(index);
169  if (phase_ == PROPAGATE) {
170  // In the propagate phase, propagate the usage information backward.
171  Enqueue(input, use);
172  } else {
173  // In the change phase, insert a change before the use if necessary.
174  if ((use & kRepMask) == 0) return; // No input requirement on the use.
175  MachineTypeUnion output = GetInfo(input)->output;
176  if ((output & kRepMask & use) == 0) {
177  // Output representation doesn't match usage.
178  TRACE((" change: #%d:%s(@%d #%d:%s) ", node->id(),
179  node->op()->mnemonic(), index, input->id(),
180  input->op()->mnemonic()));
181  TRACE((" from "));
182  PrintInfo(output);
183  TRACE((" to "));
184  PrintInfo(use);
185  TRACE(("\n"));
186  Node* n = changer_->GetRepresentationFor(input, output, use);
187  node->ReplaceInput(index, n);
188  }
189  }
190  }
191 
192  void ProcessRemainingInputs(Node* node, int index) {
195  for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
196  i < NodeProperties::PastEffectIndex(node); ++i) {
197  Enqueue(node->InputAt(i)); // Effect inputs: just visit
198  }
199  for (int i = std::max(index, NodeProperties::FirstControlIndex(node));
200  i < NodeProperties::PastControlIndex(node); ++i) {
201  Enqueue(node->InputAt(i)); // Control inputs: just visit
202  }
203  }
204 
205  // The default, most general visitation case. For {node}, process all value,
206  // context, effect, and control inputs, assuming that value inputs should have
207  // {kRepTagged} representation and can observe all output values {kTypeAny}.
208  void VisitInputs(Node* node) {
209  InputIter i = node->inputs().begin();
210  for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
211  ++i, j--) {
212  ProcessInput(node, i.index(), kMachAnyTagged); // Value inputs
213  }
214  for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
215  ++i, j--) {
216  ProcessInput(node, i.index(), kMachAnyTagged); // Context inputs
217  }
218  for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
219  ++i, j--) {
220  Enqueue(*i); // Effect inputs: just visit
221  }
222  for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
223  ++i, j--) {
224  Enqueue(*i); // Control inputs: just visit
225  }
226  SetOutput(node, kMachAnyTagged);
227  }
228 
229  // Helper for binops of the I x I -> O variety.
230  void VisitBinop(Node* node, MachineTypeUnion input_use,
231  MachineTypeUnion output) {
232  DCHECK_EQ(2, node->InputCount());
233  ProcessInput(node, 0, input_use);
234  ProcessInput(node, 1, input_use);
235  SetOutput(node, output);
236  }
237 
238  // Helper for unops of the I -> O variety.
239  void VisitUnop(Node* node, MachineTypeUnion input_use,
240  MachineTypeUnion output) {
241  DCHECK_EQ(1, node->InputCount());
242  ProcessInput(node, 0, input_use);
243  SetOutput(node, output);
244  }
245 
246  // Helper for leaf nodes.
247  void VisitLeaf(Node* node, MachineTypeUnion output) {
248  DCHECK_EQ(0, node->InputCount());
249  SetOutput(node, output);
250  }
251 
252  // Helpers for specific types of binops.
253  void VisitFloat64Binop(Node* node) {
255  }
256  void VisitInt32Binop(Node* node) { VisitBinop(node, kMachInt32, kMachInt32); }
257  void VisitUint32Binop(Node* node) {
259  }
260  void VisitInt64Binop(Node* node) { VisitBinop(node, kMachInt64, kMachInt64); }
261  void VisitUint64Binop(Node* node) {
263  }
264  void VisitFloat64Cmp(Node* node) { VisitBinop(node, kMachFloat64, kRepBit); }
265  void VisitInt32Cmp(Node* node) { VisitBinop(node, kMachInt32, kRepBit); }
266  void VisitUint32Cmp(Node* node) { VisitBinop(node, kMachUint32, kRepBit); }
267  void VisitInt64Cmp(Node* node) { VisitBinop(node, kMachInt64, kRepBit); }
268  void VisitUint64Cmp(Node* node) { VisitBinop(node, kMachUint64, kRepBit); }
269 
270  // Helper for handling phis.
271  void VisitPhi(Node* node, MachineTypeUnion use,
272  SimplifiedLowering* lowering) {
273  // First, propagate the usage information to inputs of the phi.
274  if (!lower()) {
275  int values = OperatorProperties::GetValueInputCount(node->op());
276  // Propagate {use} of the phi to value inputs, and 0 to control.
277  Node::Inputs inputs = node->inputs();
278  for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
279  ++iter, --values) {
280  // TODO(titzer): it'd be nice to have distinguished edge kinds here.
281  ProcessInput(node, iter.index(), values > 0 ? use : 0);
282  }
283  }
284  // Phis adapt to whatever output representation their uses demand,
285  // pushing representation changes to their inputs.
286  MachineTypeUnion use_rep = GetUseInfo(node) & kRepMask;
287  MachineTypeUnion use_type = GetUseInfo(node) & kTypeMask;
288  MachineTypeUnion rep = 0;
289  if (use_rep & kRepTagged) {
290  rep = kRepTagged; // Tagged overrides everything.
291  } else if (use_rep & kRepFloat32) {
292  rep = kRepFloat32;
293  } else if (use_rep & kRepFloat64) {
294  rep = kRepFloat64;
295  } else if (use_rep & kRepWord64) {
296  rep = kRepWord64;
297  } else if (use_rep & kRepWord32) {
298  rep = kRepWord32;
299  } else if (use_rep & kRepBit) {
300  rep = kRepBit;
301  } else {
302  // There was no representation associated with any of the uses.
303  // TODO(titzer): Select the best rep using phi's type, not the usage type?
304  if (use_type & kTypeAny) {
305  rep = kRepTagged;
306  } else if (use_type & kTypeNumber) {
307  rep = kRepFloat64;
308  } else if (use_type & kTypeInt64 || use_type & kTypeUint64) {
309  rep = kRepWord64;
310  } else if (use_type & kTypeInt32 || use_type & kTypeUint32) {
311  rep = kRepWord32;
312  } else if (use_type & kTypeBool) {
313  rep = kRepBit;
314  } else {
315  UNREACHABLE(); // should have at least a usage type!
316  }
317  }
318  // Preserve the usage type, but set the representation.
319  Type* upper = NodeProperties::GetBounds(node).upper;
320  MachineTypeUnion output_type = rep | changer_->TypeFromUpperBound(upper);
321  SetOutput(node, output_type);
322 
323  if (lower()) {
324  int values = OperatorProperties::GetValueInputCount(node->op());
325 
326  // Update the phi operator.
327  MachineType type = static_cast<MachineType>(output_type);
328  if (type != OpParameter<MachineType>(node)) {
329  node->set_op(lowering->common()->Phi(type, values));
330  }
331 
332  // Convert inputs to the output representation of this phi.
333  Node::Inputs inputs = node->inputs();
334  for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
335  ++iter, --values) {
336  // TODO(titzer): it'd be nice to have distinguished edge kinds here.
337  ProcessInput(node, iter.index(), values > 0 ? output_type : 0);
338  }
339  }
340  }
341 
342  const Operator* Int32Op(Node* node) {
343  return changer_->Int32OperatorFor(node->opcode());
344  }
345 
346  const Operator* Uint32Op(Node* node) {
347  return changer_->Uint32OperatorFor(node->opcode());
348  }
349 
350  const Operator* Float64Op(Node* node) {
351  return changer_->Float64OperatorFor(node->opcode());
352  }
353 
354  // Dispatching routine for visiting the node {node} with the usage {use}.
355  // Depending on the operator, propagate new usage info to the inputs.
356  void VisitNode(Node* node, MachineTypeUnion use,
357  SimplifiedLowering* lowering) {
358  switch (node->opcode()) {
359  //------------------------------------------------------------------
360  // Common operators.
361  //------------------------------------------------------------------
362  case IrOpcode::kStart:
363  case IrOpcode::kDead:
364  return VisitLeaf(node, 0);
365  case IrOpcode::kParameter: {
366  // TODO(titzer): use representation from linkage.
367  Type* upper = NodeProperties::GetBounds(node).upper;
368  ProcessInput(node, 0, 0);
370  return;
371  }
372  case IrOpcode::kInt32Constant:
373  return VisitLeaf(node, kRepWord32);
374  case IrOpcode::kInt64Constant:
375  return VisitLeaf(node, kRepWord64);
376  case IrOpcode::kFloat64Constant:
377  return VisitLeaf(node, kRepFloat64);
378  case IrOpcode::kExternalConstant:
379  return VisitLeaf(node, kMachPtr);
380  case IrOpcode::kNumberConstant:
381  return VisitLeaf(node, kRepTagged);
382  case IrOpcode::kHeapConstant:
383  return VisitLeaf(node, kRepTagged);
384 
385  case IrOpcode::kEnd:
386  case IrOpcode::kIfTrue:
387  case IrOpcode::kIfFalse:
388  case IrOpcode::kReturn:
389  case IrOpcode::kMerge:
390  case IrOpcode::kThrow:
391  return VisitInputs(node); // default visit for all node inputs.
392 
393  case IrOpcode::kBranch:
394  ProcessInput(node, 0, kRepBit);
396  break;
397  case IrOpcode::kPhi:
398  return VisitPhi(node, use, lowering);
399 
400 //------------------------------------------------------------------
401 // JavaScript operators.
402 //------------------------------------------------------------------
403 // For now, we assume that all JS operators were too complex to lower
404 // to Simplified and that they will always require tagged value inputs
405 // and produce tagged value outputs.
406 // TODO(turbofan): it might be possible to lower some JSOperators here,
407 // but that responsibility really lies in the typed lowering phase.
408 #define DEFINE_JS_CASE(x) case IrOpcode::k##x:
410 #undef DEFINE_JS_CASE
411  contains_js_nodes_ = true;
412  VisitInputs(node);
413  return SetOutput(node, kRepTagged);
414 
415  //------------------------------------------------------------------
416  // Simplified operators.
417  //------------------------------------------------------------------
418  case IrOpcode::kBooleanNot: {
419  if (lower()) {
420  MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
421  if (input & kRepBit) {
422  // BooleanNot(x: kRepBit) => WordEqual(x, #0)
423  node->set_op(lowering->machine()->WordEqual());
424  node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
425  } else {
426  // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
427  node->set_op(lowering->machine()->WordEqual());
428  node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
429  }
430  } else {
431  // No input representation requirement; adapt during lowering.
432  ProcessInput(node, 0, kTypeBool);
433  SetOutput(node, kRepBit);
434  }
435  break;
436  }
437  case IrOpcode::kBooleanToNumber: {
438  if (lower()) {
439  MachineTypeUnion input = GetInfo(node->InputAt(0))->output;
440  if (input & kRepBit) {
441  // BooleanToNumber(x: kRepBit) => x
442  DeferReplacement(node, node->InputAt(0));
443  } else {
444  // BooleanToNumber(x: kRepTagged) => WordEqual(x, #true)
445  node->set_op(lowering->machine()->WordEqual());
446  node->AppendInput(jsgraph_->zone(), jsgraph_->TrueConstant());
447  }
448  } else {
449  // No input representation requirement; adapt during lowering.
450  ProcessInput(node, 0, kTypeBool);
451  SetOutput(node, kMachInt32);
452  }
453  break;
454  }
455  case IrOpcode::kNumberEqual:
456  case IrOpcode::kNumberLessThan:
457  case IrOpcode::kNumberLessThanOrEqual: {
458  // Number comparisons reduce to integer comparisons for integer inputs.
459  if (BothInputsAre(node, Type::Signed32())) {
460  // => signed Int32Cmp
461  VisitInt32Cmp(node);
462  if (lower()) node->set_op(Int32Op(node));
463  } else if (BothInputsAre(node, Type::Unsigned32())) {
464  // => unsigned Int32Cmp
465  VisitUint32Cmp(node);
466  if (lower()) node->set_op(Uint32Op(node));
467  } else {
468  // => Float64Cmp
469  VisitFloat64Cmp(node);
470  if (lower()) node->set_op(Float64Op(node));
471  }
472  break;
473  }
474  case IrOpcode::kNumberAdd:
475  case IrOpcode::kNumberSubtract: {
476  // Add and subtract reduce to Int32Add/Sub if the inputs
477  // are already integers and all uses are truncating.
478  if (BothInputsAre(node, Type::Signed32()) &&
479  (use & (kTypeUint32 | kTypeNumber | kTypeAny)) == 0) {
480  // => signed Int32Add/Sub
481  VisitInt32Binop(node);
482  if (lower()) node->set_op(Int32Op(node));
483  } else if (BothInputsAre(node, Type::Unsigned32()) &&
484  (use & (kTypeInt32 | kTypeNumber | kTypeAny)) == 0) {
485  // => unsigned Int32Add/Sub
486  VisitUint32Binop(node);
487  if (lower()) node->set_op(Uint32Op(node));
488  } else {
489  // => Float64Add/Sub
490  VisitFloat64Binop(node);
491  if (lower()) node->set_op(Float64Op(node));
492  }
493  break;
494  }
495  case IrOpcode::kNumberMultiply:
496  case IrOpcode::kNumberDivide:
497  case IrOpcode::kNumberModulus: {
498  // Float64Mul/Div/Mod
499  VisitFloat64Binop(node);
500  if (lower()) node->set_op(Float64Op(node));
501  break;
502  }
503  case IrOpcode::kNumberToInt32: {
504  MachineTypeUnion use_rep = use & kRepMask;
505  if (lower()) {
506  MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
507  if ((in & kTypeMask) == kTypeInt32 || (in & kRepMask) == kRepWord32) {
508  // If the input has type int32, or is already a word32, just change
509  // representation if necessary.
510  VisitUnop(node, kTypeInt32 | use_rep, kTypeInt32 | use_rep);
511  DeferReplacement(node, node->InputAt(0));
512  } else {
513  // Require the input in float64 format and perform truncation.
514  // TODO(turbofan): avoid a truncation with a smi check.
516  node->set_op(lowering->machine()->TruncateFloat64ToInt32());
517  }
518  } else {
519  // Propagate a type to the input, but pass through representation.
520  VisitUnop(node, kTypeInt32, kTypeInt32 | use_rep);
521  }
522  break;
523  }
524  case IrOpcode::kNumberToUint32: {
525  MachineTypeUnion use_rep = use & kRepMask;
526  if (lower()) {
527  MachineTypeUnion in = GetInfo(node->InputAt(0))->output;
528  if ((in & kTypeMask) == kTypeUint32 ||
529  (in & kRepMask) == kRepWord32) {
530  // The input has type int32, just change representation.
531  VisitUnop(node, kTypeUint32 | use_rep, kTypeUint32 | use_rep);
532  DeferReplacement(node, node->InputAt(0));
533  } else {
534  // Require the input in float64 format to perform truncation.
535  // TODO(turbofan): avoid the truncation with a smi check.
538  node->set_op(lowering->machine()->TruncateFloat64ToInt32());
539  }
540  } else {
541  // Propagate a type to the input, but pass through representation.
542  VisitUnop(node, kTypeUint32, kTypeUint32 | use_rep);
543  }
544  break;
545  }
546  case IrOpcode::kReferenceEqual: {
548  if (lower()) node->set_op(lowering->machine()->WordEqual());
549  break;
550  }
551  case IrOpcode::kStringEqual: {
553  if (lower()) lowering->DoStringEqual(node);
554  break;
555  }
556  case IrOpcode::kStringLessThan: {
558  if (lower()) lowering->DoStringLessThan(node);
559  break;
560  }
561  case IrOpcode::kStringLessThanOrEqual: {
563  if (lower()) lowering->DoStringLessThanOrEqual(node);
564  break;
565  }
566  case IrOpcode::kStringAdd: {
568  if (lower()) lowering->DoStringAdd(node);
569  break;
570  }
571  case IrOpcode::kLoadField: {
572  FieldAccess access = FieldAccessOf(node->op());
573  ProcessInput(node, 0, changer_->TypeForBasePointer(access));
574  ProcessRemainingInputs(node, 1);
575  SetOutput(node, access.machine_type);
576  if (lower()) lowering->DoLoadField(node);
577  break;
578  }
579  case IrOpcode::kStoreField: {
580  FieldAccess access = FieldAccessOf(node->op());
581  ProcessInput(node, 0, changer_->TypeForBasePointer(access));
582  ProcessInput(node, 1, access.machine_type);
583  ProcessRemainingInputs(node, 2);
584  SetOutput(node, 0);
585  if (lower()) lowering->DoStoreField(node);
586  break;
587  }
588  case IrOpcode::kLoadElement: {
589  ElementAccess access = ElementAccessOf(node->op());
590  ProcessInput(node, 0, changer_->TypeForBasePointer(access));
591  ProcessInput(node, 1, kMachInt32); // element index
592  ProcessInput(node, 2, kMachInt32); // length
593  ProcessRemainingInputs(node, 3);
594  SetOutput(node, access.machine_type);
595  if (lower()) lowering->DoLoadElement(node);
596  break;
597  }
598  case IrOpcode::kStoreElement: {
599  ElementAccess access = ElementAccessOf(node->op());
600  ProcessInput(node, 0, changer_->TypeForBasePointer(access));
601  ProcessInput(node, 1, kMachInt32); // element index
602  ProcessInput(node, 2, kMachInt32); // length
603  ProcessInput(node, 3, access.machine_type);
604  ProcessRemainingInputs(node, 4);
605  SetOutput(node, 0);
606  if (lower()) lowering->DoStoreElement(node);
607  break;
608  }
609 
610  //------------------------------------------------------------------
611  // Machine-level operators.
612  //------------------------------------------------------------------
613  case IrOpcode::kLoad: {
614  // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
615  MachineType tBase = kRepTagged;
616  LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
617  ProcessInput(node, 0, tBase); // pointer or object
618  ProcessInput(node, 1, kMachInt32); // index
619  ProcessRemainingInputs(node, 2);
620  SetOutput(node, rep);
621  break;
622  }
623  case IrOpcode::kStore: {
624  // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
625  MachineType tBase = kRepTagged;
626  StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
627  ProcessInput(node, 0, tBase); // pointer or object
628  ProcessInput(node, 1, kMachInt32); // index
629  ProcessInput(node, 2, rep.machine_type());
630  ProcessRemainingInputs(node, 3);
631  SetOutput(node, 0);
632  break;
633  }
634  case IrOpcode::kWord32Shr:
635  // We output unsigned int32 for shift right because JavaScript.
636  return VisitBinop(node, kRepWord32, kRepWord32 | kTypeUint32);
637  case IrOpcode::kWord32And:
638  case IrOpcode::kWord32Or:
639  case IrOpcode::kWord32Xor:
640  case IrOpcode::kWord32Shl:
641  case IrOpcode::kWord32Sar:
642  // We use signed int32 as the output type for these word32 operations,
643  // though the machine bits are the same for either signed or unsigned,
644  // because JavaScript considers the result from these operations signed.
645  return VisitBinop(node, kRepWord32, kRepWord32 | kTypeInt32);
646  case IrOpcode::kWord32Equal:
647  return VisitBinop(node, kRepWord32, kRepBit);
648 
649  case IrOpcode::kInt32Add:
650  case IrOpcode::kInt32Sub:
651  case IrOpcode::kInt32Mul:
652  case IrOpcode::kInt32Div:
653  case IrOpcode::kInt32Mod:
654  return VisitInt32Binop(node);
655  case IrOpcode::kInt32UDiv:
656  case IrOpcode::kInt32UMod:
657  return VisitUint32Binop(node);
658  case IrOpcode::kInt32LessThan:
659  case IrOpcode::kInt32LessThanOrEqual:
660  return VisitInt32Cmp(node);
661 
662  case IrOpcode::kUint32LessThan:
663  case IrOpcode::kUint32LessThanOrEqual:
664  return VisitUint32Cmp(node);
665 
666  case IrOpcode::kInt64Add:
667  case IrOpcode::kInt64Sub:
668  case IrOpcode::kInt64Mul:
669  case IrOpcode::kInt64Div:
670  case IrOpcode::kInt64Mod:
671  return VisitInt64Binop(node);
672  case IrOpcode::kInt64LessThan:
673  case IrOpcode::kInt64LessThanOrEqual:
674  return VisitInt64Cmp(node);
675 
676  case IrOpcode::kInt64UDiv:
677  case IrOpcode::kInt64UMod:
678  return VisitUint64Binop(node);
679 
680  case IrOpcode::kWord64And:
681  case IrOpcode::kWord64Or:
682  case IrOpcode::kWord64Xor:
683  case IrOpcode::kWord64Shl:
684  case IrOpcode::kWord64Shr:
685  case IrOpcode::kWord64Sar:
686  return VisitBinop(node, kRepWord64, kRepWord64);
687  case IrOpcode::kWord64Equal:
688  return VisitBinop(node, kRepWord64, kRepBit);
689 
690  case IrOpcode::kChangeInt32ToInt64:
691  return VisitUnop(node, kTypeInt32 | kRepWord32,
693  case IrOpcode::kChangeUint32ToUint64:
694  return VisitUnop(node, kTypeUint32 | kRepWord32,
696  case IrOpcode::kTruncateFloat64ToFloat32:
697  return VisitUnop(node, kTypeNumber | kRepFloat64,
699  case IrOpcode::kTruncateInt64ToInt32:
700  // TODO(titzer): Is kTypeInt32 correct here?
701  return VisitUnop(node, kTypeInt32 | kRepWord64,
703 
704  case IrOpcode::kChangeFloat32ToFloat64:
705  return VisitUnop(node, kTypeNumber | kRepFloat32,
707  case IrOpcode::kChangeInt32ToFloat64:
708  return VisitUnop(node, kTypeInt32 | kRepWord32,
710  case IrOpcode::kChangeUint32ToFloat64:
711  return VisitUnop(node, kTypeUint32 | kRepWord32,
713  case IrOpcode::kChangeFloat64ToInt32:
714  return VisitUnop(node, kTypeInt32 | kRepFloat64,
716  case IrOpcode::kChangeFloat64ToUint32:
717  return VisitUnop(node, kTypeUint32 | kRepFloat64,
719 
720  case IrOpcode::kFloat64Add:
721  case IrOpcode::kFloat64Sub:
722  case IrOpcode::kFloat64Mul:
723  case IrOpcode::kFloat64Div:
724  case IrOpcode::kFloat64Mod:
725  return VisitFloat64Binop(node);
726  case IrOpcode::kFloat64Sqrt:
727  return VisitUnop(node, kMachFloat64, kMachFloat64);
728  case IrOpcode::kFloat64Equal:
729  case IrOpcode::kFloat64LessThan:
730  case IrOpcode::kFloat64LessThanOrEqual:
731  return VisitFloat64Cmp(node);
732  default:
733  VisitInputs(node);
734  break;
735  }
736  }
737 
738  void DeferReplacement(Node* node, Node* replacement) {
739  if (replacement->id() < count_) {
740  // Replace with a previously existing node eagerly.
741  node->ReplaceUses(replacement);
742  } else {
743  // Otherwise, we are replacing a node with a representation change.
744  // Such a substitution must be done after all lowering is done, because
745  // new nodes do not have {NodeInfo} entries, and that would confuse
746  // the representation change insertion for uses of it.
747  replacements_.push_back(node);
748  replacements_.push_back(replacement);
749  }
750  // TODO(titzer) node->RemoveAllInputs(); // Node is now dead.
751  }
752 
753  void PrintUseInfo(Node* node) {
754  TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
755  PrintInfo(GetUseInfo(node));
756  TRACE(("\n"));
757  }
758 
760  if (FLAG_trace_representation) {
761  OFStream os(stdout);
762  os << static_cast<MachineType>(info);
763  }
764  }
765 
766  private:
768  int count_; // number of nodes in the graph
769  NodeInfo* info_; // node id -> usage information
770  NodeVector nodes_; // collected nodes
771  NodeVector replacements_; // replacements to be done after lowering
772  bool contains_js_nodes_; // {true} if a JS operator was seen
773  Phase phase_; // current phase of algorithm
774  RepresentationChanger* changer_; // for inserting representation changes
775  ZoneQueue<Node*> queue_; // queue for traversing the graph
776 
777  NodeInfo* GetInfo(Node* node) {
778  DCHECK(node->id() >= 0);
779  DCHECK(node->id() < count_);
780  return &info_[node->id()];
781  }
782 
783  MachineTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
784 };
785 
786 
787 Node* SimplifiedLowering::IsTagged(Node* node) {
788  // TODO(titzer): factor this out to a TaggingScheme abstraction.
789  STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit.
790  return graph()->NewNode(machine()->WordAnd(), node,
791  jsgraph()->Int32Constant(kSmiTagMask));
792 }
793 
794 
796  SimplifiedOperatorBuilder simplified(graph()->zone());
797  RepresentationChanger changer(jsgraph(), &simplified,
798  graph()->zone()->isolate());
799  RepresentationSelector selector(jsgraph(), zone(), &changer);
800  selector.Run(this);
801 }
802 
803 
804 Node* SimplifiedLowering::Untag(Node* node) {
805  // TODO(titzer): factor this out to a TaggingScheme abstraction.
806  Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
807  return graph()->NewNode(machine()->WordSar(), node, shift_amount);
808 }
809 
810 
811 Node* SimplifiedLowering::SmiTag(Node* node) {
812  // TODO(titzer): factor this out to a TaggingScheme abstraction.
813  Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
814  return graph()->NewNode(machine()->WordShl(), node, shift_amount);
815 }
816 
817 
819  return jsgraph()->Int32Constant(offset - kHeapObjectTag);
820 }
821 
822 
824  MachineType representation,
825  Type* type) {
826  // TODO(turbofan): skip write barriers for Smis, etc.
827  if (base_is_tagged == kTaggedBase &&
828  RepresentationOf(representation) == kRepTagged) {
829  // Write barriers are only for writes into heap objects (i.e. tagged base).
830  return kFullWriteBarrier;
831  }
832  return kNoWriteBarrier;
833 }
834 
835 
837  const FieldAccess& access = FieldAccessOf(node->op());
838  node->set_op(machine()->Load(access.machine_type));
839  Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
840  node->InsertInput(zone(), 1, offset);
841 }
842 
843 
845  const FieldAccess& access = FieldAccessOf(node->op());
847  access.base_is_tagged, access.machine_type, access.type);
848  node->set_op(
849  machine()->Store(StoreRepresentation(access.machine_type, kind)));
850  Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
851  node->InsertInput(zone(), 1, offset);
852 }
853 
854 
856  Node* index) {
857  int element_size = ElementSizeOf(access.machine_type);
858  if (element_size != 1) {
859  index = graph()->NewNode(machine()->Int32Mul(),
860  jsgraph()->Int32Constant(element_size), index);
861  }
862  int fixed_offset = access.header_size - access.tag();
863  if (fixed_offset == 0) return index;
864  return graph()->NewNode(machine()->Int32Add(), index,
865  jsgraph()->Int32Constant(fixed_offset));
866 }
867 
868 
870  const ElementAccess& access = ElementAccessOf(node->op());
871  node->set_op(machine()->Load(access.machine_type));
872  node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
873  node->RemoveInput(2);
874 }
875 
876 
878  const ElementAccess& access = ElementAccessOf(node->op());
880  access.base_is_tagged, access.machine_type, access.type);
881  node->set_op(
882  machine()->Store(StoreRepresentation(access.machine_type, kind)));
883  node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
884  node->RemoveInput(2);
885 }
886 
887 
889  Callable callable = CodeFactory::StringAdd(
890  zone()->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
891  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
892  CallDescriptor* desc =
893  Linkage::GetStubCallDescriptor(callable.descriptor(), 0, flags, zone());
894  node->set_op(common()->Call(desc));
895  node->InsertInput(zone(), 0, jsgraph()->HeapConstant(callable.code()));
896  node->AppendInput(zone(), jsgraph()->UndefinedConstant());
897  node->AppendInput(zone(), graph()->start());
898  node->AppendInput(zone(), graph()->start());
899 }
900 
901 
902 Node* SimplifiedLowering::StringComparison(Node* node, bool requires_ordering) {
903  CEntryStub stub(zone()->isolate(), 1);
905  requires_ordering ? Runtime::kStringCompare : Runtime::kStringEquals;
906  ExternalReference ref(f, zone()->isolate());
907  Operator::Properties props = node->op()->properties();
908  // TODO(mstarzinger): We should call StringCompareStub here instead, once an
909  // interface descriptor is available for it.
910  CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(f, 2, props, zone());
911  return graph()->NewNode(common()->Call(desc),
912  jsgraph()->HeapConstant(stub.GetCode()),
915  jsgraph()->ExternalConstant(ref),
916  jsgraph()->Int32Constant(2),
917  jsgraph()->UndefinedConstant());
918 }
919 
920 
922  node->set_op(machine()->WordEqual());
923  node->ReplaceInput(0, StringComparison(node, false));
924  node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
925 }
926 
927 
929  node->set_op(machine()->IntLessThan());
930  node->ReplaceInput(0, StringComparison(node, true));
931  node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
932 }
933 
934 
936  node->set_op(machine()->IntLessThanOrEqual());
937  node->ReplaceInput(0, StringComparison(node, true));
938  node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL));
939 }
940 
941 
942 } // namespace compiler
943 } // namespace internal
944 } // namespace v8
Node * NewNode(const Operator *op, int input_count, Node **inputs)
Definition: graph.cc:24
Node * Int32Constant(int32_t value)
Definition: js-graph.cc:150
CallDescriptor * GetStubCallDescriptor(CallInterfaceDescriptor descriptor, int stack_parameter_count=0, CallDescriptor::Flags flags=CallDescriptor::kNoFlags)
Definition: linkage.cc:103
CallDescriptor * GetRuntimeCallDescriptor(Runtime::FunctionId function, int parameter_count, Operator::Properties properties)
Definition: linkage.cc:95
static Node * GetValueInput(Node *node, int index)
static Node * GetControlInput(Node *node, int index=0)
static int GetEffectInputCount(const Operator *op)
static int GetContextInputCount(const Operator *op)
static int GetValueInputCount(const Operator *op)
static int GetControlInputCount(const Operator *op)
base::Flags< Property, uint8_t > Properties
Definition: operator.h:48
const Operator * Float64OperatorFor(IrOpcode::Value opcode)
Node * GetRepresentationFor(Node *node, MachineTypeUnion output_type, MachineTypeUnion use_type)
const Operator * Int32OperatorFor(IrOpcode::Value opcode)
MachineType TypeForBasePointer(const FieldAccess &access)
const Operator * Uint32OperatorFor(IrOpcode::Value opcode)
void VisitNode(Node *node, MachineTypeUnion use, SimplifiedLowering *lowering)
void VisitUnop(Node *node, MachineTypeUnion input_use, MachineTypeUnion output)
void VisitLeaf(Node *node, MachineTypeUnion output)
RepresentationSelector(JSGraph *jsgraph, Zone *zone, RepresentationChanger *changer)
void DeferReplacement(Node *node, Node *replacement)
void VisitPhi(Node *node, MachineTypeUnion use, SimplifiedLowering *lowering)
void ProcessInput(Node *node, int index, MachineTypeUnion use)
void VisitBinop(Node *node, MachineTypeUnion input_use, MachineTypeUnion output)
void SetOutput(Node *node, MachineTypeUnion output)
void Enqueue(Node *node, MachineTypeUnion use=0)
Node * ComputeIndex(const ElementAccess &access, Node *index)
Node * StringComparison(Node *node, bool requires_ordering)
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 enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to use(in kBytes)") DEFINE_INT(max_stack_trace_source_length
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 enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK_GE(v1, v2)
Definition: logging.h:208
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
int int32_t
Definition: unicode.cc:24
bool IsPowerOfTwo32(uint32_t value)
Definition: bits.h:77
const MachineTypeUnion kRepMask
Definition: machine-type.h:62
const ElementAccess & ElementAccessOf(const Operator *op)
STATIC_ASSERT(DoubleRegister::kMaxNumAllocatableRegisters >=Register::kMaxNumAllocatableRegisters)
MachineType RepresentationOf(MachineType machine_type)
Definition: machine-type.h:76
static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged, MachineType representation, Type *type)
Node::Inputs::iterator InputIter
Definition: node.h:82
const MachineTypeUnion kTypeMask
Definition: machine-type.h:65
const FieldAccess & FieldAccessOf(const Operator *op)
int ElementSizeOf(MachineType machine_type)
Definition: machine-type.h:83
T * NewArray(size_t size)
Definition: allocation.h:60
@ STRING_ADD_CHECK_NONE
Definition: code-stubs.h:1212
const int kSmiTagSize
Definition: v8.h:5743
const int kHeapObjectTag
Definition: v8.h:5737
const int kSmiShiftSize
Definition: v8.h:5805
const intptr_t kSmiTagMask
Definition: v8.h:5744
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
#define JS_OP_LIST(V)
Definition: opcodes.h:125
#define TRACE(x)
#define DEFINE_JS_CASE(x)