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.
5 #include "src/compiler/simplified-lowering.h"
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/graph-inl.h"
12 #include "src/compiler/node-properties-inl.h"
13 #include "src/compiler/representation-change.h"
14 #include "src/compiler/simplified-lowering.h"
15 #include "src/compiler/simplified-operator.h"
16 #include "src/objects.h"
22 // Macro for outputting trace information from representation inference.
24 if (FLAG_trace_representation) PrintF x
26 // Representation selection and lowering of {Simplified} operators to machine
27 // operators are interwined. We use a fixpoint calculation to compute both the
28 // output representation and the best possible lowering for {Simplified} nodes.
29 // Representation change insertion ensures that all values are in the correct
30 // machine representation after this phase, as dictated by the machine
31 // operators themselves.
33 // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
34 // backwards from uses to definitions, around cycles in phis, according
35 // to local rules for each operator.
36 // During this phase, the usage information for a node determines the best
37 // possible lowering for each operator so far, and that in turn determines
38 // the output representation.
39 // Therefore, to be correct, this phase must iterate to a fixpoint before
40 // the next phase can begin.
43 // 2.) LOWER: perform lowering for all {Simplified} nodes by replacing some
44 // operators for some nodes, expanding some nodes to multiple nodes, or
45 // removing some (redundant) nodes.
46 // During this phase, use the {RepresentationChanger} to insert
47 // representation changes between uses that demand a particular
48 // representation and nodes that produce a different representation.
53 class RepresentationSelector {
55 // Information for each node tracked during the fixpoint.
57 RepTypeUnion use : 14; // Union of all usages for the node.
58 bool queued : 1; // Bookkeeping for the traversal.
59 bool visited : 1; // Bookkeeping for the traversal.
60 RepTypeUnion output : 14; // Output type of the node.
63 RepresentationSelector(JSGraph* jsgraph, Zone* zone,
64 RepresentationChanger* changer)
66 count_(jsgraph->graph()->NodeCount()),
67 info_(zone->NewArray<NodeInfo>(count_)),
68 nodes_(NodeVector::allocator_type(zone)),
69 replacements_(NodeVector::allocator_type(zone)),
70 contains_js_nodes_(false),
73 queue_(std::deque<Node*, NodePtrZoneAllocator>(
74 NodePtrZoneAllocator(zone))) {
75 memset(info_, 0, sizeof(NodeInfo) * count_);
78 void Run(SimplifiedLowering* lowering) {
79 // Run propagation phase to a fixpoint.
80 TRACE(("--{Propagation phase}--\n"));
82 Enqueue(jsgraph_->graph()->end());
83 // Process nodes from the queue until it is empty.
84 while (!queue_.empty()) {
85 Node* node = queue_.front();
86 NodeInfo* info = GetInfo(node);
89 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
90 VisitNode(node, info->use, NULL);
91 TRACE((" ==> output "));
92 PrintInfo(info->output);
96 // Run lowering and change insertion phase.
97 TRACE(("--{Simplified lowering phase}--\n"));
99 // Process nodes from the collected {nodes_} vector.
100 for (NodeVector::iterator i = nodes_.begin(); i != nodes_.end(); ++i) {
102 TRACE((" visit #%d: %s\n", node->id(), node->op()->mnemonic()));
103 // Reuse {VisitNode()} so the representation rules are in one place.
104 VisitNode(node, GetUseInfo(node), lowering);
107 // Perform the final replacements.
108 for (NodeVector::iterator i = replacements_.begin();
109 i != replacements_.end(); ++i) {
111 Node* replacement = *(++i);
112 node->ReplaceUses(replacement);
116 // Enqueue {node} if the {use} contains new information for that node.
117 // Add {node} to {nodes_} if this is the first time it's been visited.
118 void Enqueue(Node* node, RepTypeUnion use = 0) {
119 if (phase_ != PROPAGATE) return;
120 NodeInfo* info = GetInfo(node);
121 if (!info->visited) {
122 // First visit of this node.
123 info->visited = true;
125 nodes_.push_back(node);
127 TRACE((" initial: "));
132 TRACE((" queue?: "));
134 if ((info->use & use) != use) {
135 // New usage information for the node is available.
141 TRACE((" inqueue: "));
148 bool lower() { return phase_ == LOWER; }
150 void Enqueue(Node* node, RepType use) {
151 Enqueue(node, static_cast<RepTypeUnion>(use));
154 void SetOutput(Node* node, RepTypeUnion output) {
155 // Every node should have at most one output representation. Note that
156 // phis can have 0, if they have not been used in a representation-inducing
158 DCHECK((output & rMask) == 0 || IsPowerOf2(output & rMask));
159 GetInfo(node)->output = output;
162 bool BothInputsAre(Node* node, Type* type) {
163 DCHECK_EQ(2, node->InputCount());
164 return NodeProperties::GetBounds(node->InputAt(0)).upper->Is(type) &&
165 NodeProperties::GetBounds(node->InputAt(1)).upper->Is(type);
168 void ProcessInput(Node* node, int index, RepTypeUnion use) {
169 Node* input = node->InputAt(index);
170 if (phase_ == PROPAGATE) {
171 // In the propagate phase, propagate the usage information backward.
174 // In the change phase, insert a change before the use if necessary.
175 if ((use & rMask) == 0) return; // No input requirement on the use.
176 RepTypeUnion output = GetInfo(input)->output;
177 if ((output & rMask & use) == 0) {
178 // Output representation doesn't match usage.
179 TRACE((" change: #%d:%s(@%d #%d:%s) ", node->id(),
180 node->op()->mnemonic(), index, input->id(),
181 input->op()->mnemonic()));
187 Node* n = changer_->GetRepresentationFor(input, output, use);
188 node->ReplaceInput(index, n);
193 static const RepTypeUnion kFloat64 = rFloat64 | tNumber;
194 static const RepTypeUnion kInt32 = rWord32 | tInt32;
195 static const RepTypeUnion kUint32 = rWord32 | tUint32;
196 static const RepTypeUnion kInt64 = rWord64 | tInt64;
197 static const RepTypeUnion kUint64 = rWord64 | tUint64;
198 static const RepTypeUnion kAnyTagged = rTagged | tAny;
200 // The default, most general visitation case. For {node}, process all value,
201 // context, effect, and control inputs, assuming that value inputs should have
202 // {rTagged} representation and can observe all output values {tAny}.
203 void VisitInputs(Node* node) {
204 InputIter i = node->inputs().begin();
205 for (int j = OperatorProperties::GetValueInputCount(node->op()); j > 0;
207 ProcessInput(node, i.index(), kAnyTagged); // Value inputs
209 for (int j = OperatorProperties::GetContextInputCount(node->op()); j > 0;
211 ProcessInput(node, i.index(), kAnyTagged); // Context inputs
213 for (int j = OperatorProperties::GetEffectInputCount(node->op()); j > 0;
215 Enqueue(*i); // Effect inputs: just visit
217 for (int j = OperatorProperties::GetControlInputCount(node->op()); j > 0;
219 Enqueue(*i); // Control inputs: just visit
221 SetOutput(node, kAnyTagged);
224 // Helper for binops of the I x I -> O variety.
225 void VisitBinop(Node* node, RepTypeUnion input_use, RepTypeUnion output) {
226 DCHECK_EQ(2, node->InputCount());
227 ProcessInput(node, 0, input_use);
228 ProcessInput(node, 1, input_use);
229 SetOutput(node, output);
232 // Helper for unops of the I -> O variety.
233 void VisitUnop(Node* node, RepTypeUnion input_use, RepTypeUnion output) {
234 DCHECK_EQ(1, node->InputCount());
235 ProcessInput(node, 0, input_use);
236 SetOutput(node, output);
239 // Helper for leaf nodes.
240 void VisitLeaf(Node* node, RepTypeUnion output) {
241 DCHECK_EQ(0, node->InputCount());
242 SetOutput(node, output);
245 // Helpers for specific types of binops.
246 void VisitFloat64Binop(Node* node) { VisitBinop(node, kFloat64, kFloat64); }
247 void VisitInt32Binop(Node* node) { VisitBinop(node, kInt32, kInt32); }
248 void VisitUint32Binop(Node* node) { VisitBinop(node, kUint32, kUint32); }
249 void VisitInt64Binop(Node* node) { VisitBinop(node, kInt64, kInt64); }
250 void VisitUint64Binop(Node* node) { VisitBinop(node, kUint64, kUint64); }
251 void VisitFloat64Cmp(Node* node) { VisitBinop(node, kFloat64, rBit); }
252 void VisitInt32Cmp(Node* node) { VisitBinop(node, kInt32, rBit); }
253 void VisitUint32Cmp(Node* node) { VisitBinop(node, kUint32, rBit); }
254 void VisitInt64Cmp(Node* node) { VisitBinop(node, kInt64, rBit); }
255 void VisitUint64Cmp(Node* node) { VisitBinop(node, kUint64, rBit); }
257 // Helper for handling phis.
258 void VisitPhi(Node* node, RepTypeUnion use) {
259 // First, propagate the usage information to inputs of the phi.
260 int values = OperatorProperties::GetValueInputCount(node->op());
261 Node::Inputs inputs = node->inputs();
262 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
264 // Propagate {use} of the phi to value inputs, and 0 to control.
265 // TODO(titzer): it'd be nice to have distinguished edge kinds here.
266 ProcessInput(node, iter.index(), values > 0 ? use : 0);
268 // Phis adapt to whatever output representation their uses demand,
269 // pushing representation changes to their inputs.
270 RepTypeUnion use_rep = GetUseInfo(node) & rMask;
271 RepTypeUnion use_type = GetUseInfo(node) & tMask;
272 RepTypeUnion rep = 0;
273 if (use_rep & rTagged) {
274 rep = rTagged; // Tagged overrides everything.
275 } else if (use_rep & rFloat64) {
277 } else if (use_rep & rWord64) {
279 } else if (use_rep & rWord32) {
281 } else if (use_rep & rBit) {
284 // There was no representation associated with any of the uses.
285 // TODO(titzer): Select the best rep using phi's type, not the usage type?
286 if (use_type & tAny) {
288 } else if (use_type & tNumber) {
290 } else if (use_type & tInt64 || use_type & tUint64) {
292 } else if (use_type & tInt32 || use_type & tUint32) {
294 } else if (use_type & tBool) {
297 UNREACHABLE(); // should have at least a usage type!
300 // Preserve the usage type, but set the representation.
301 Type* upper = NodeProperties::GetBounds(node).upper;
302 SetOutput(node, rep | changer_->TypeFromUpperBound(upper));
305 Operator* Int32Op(Node* node) {
306 return changer_->Int32OperatorFor(node->opcode());
309 Operator* Uint32Op(Node* node) {
310 return changer_->Uint32OperatorFor(node->opcode());
313 Operator* Float64Op(Node* node) {
314 return changer_->Float64OperatorFor(node->opcode());
317 // Dispatching routine for visiting the node {node} with the usage {use}.
318 // Depending on the operator, propagate new usage info to the inputs.
319 void VisitNode(Node* node, RepTypeUnion use, SimplifiedLowering* lowering) {
320 switch (node->opcode()) {
321 //------------------------------------------------------------------
323 //------------------------------------------------------------------
324 case IrOpcode::kStart:
325 case IrOpcode::kDead:
326 return VisitLeaf(node, 0);
327 case IrOpcode::kParameter: {
328 // TODO(titzer): use representation from linkage.
329 Type* upper = NodeProperties::GetBounds(node).upper;
330 ProcessInput(node, 0, 0);
331 SetOutput(node, rTagged | changer_->TypeFromUpperBound(upper));
334 case IrOpcode::kInt32Constant:
335 return VisitLeaf(node, rWord32);
336 case IrOpcode::kInt64Constant:
337 return VisitLeaf(node, rWord64);
338 case IrOpcode::kFloat64Constant:
339 return VisitLeaf(node, rFloat64);
340 case IrOpcode::kExternalConstant:
341 return VisitLeaf(node, rPtr);
342 case IrOpcode::kNumberConstant:
343 return VisitLeaf(node, rTagged);
344 case IrOpcode::kHeapConstant:
345 return VisitLeaf(node, rTagged);
348 case IrOpcode::kIfTrue:
349 case IrOpcode::kIfFalse:
350 case IrOpcode::kReturn:
351 case IrOpcode::kMerge:
352 case IrOpcode::kThrow:
353 return VisitInputs(node); // default visit for all node inputs.
355 case IrOpcode::kBranch:
356 ProcessInput(node, 0, rBit);
357 Enqueue(NodeProperties::GetControlInput(node, 0));
360 return VisitPhi(node, use);
362 //------------------------------------------------------------------
363 // JavaScript operators.
364 //------------------------------------------------------------------
365 // For now, we assume that all JS operators were too complex to lower
366 // to Simplified and that they will always require tagged value inputs
367 // and produce tagged value outputs.
368 // TODO(turbofan): it might be possible to lower some JSOperators here,
369 // but that responsibility really lies in the typed lowering phase.
370 #define DEFINE_JS_CASE(x) case IrOpcode::k##x:
371 JS_OP_LIST(DEFINE_JS_CASE)
372 #undef DEFINE_JS_CASE
373 contains_js_nodes_ = true;
375 return SetOutput(node, rTagged);
377 //------------------------------------------------------------------
378 // Simplified operators.
379 //------------------------------------------------------------------
380 case IrOpcode::kBooleanNot: {
382 RepTypeUnion input = GetInfo(node->InputAt(0))->output;
384 // BooleanNot(x: rBit) => WordEqual(x, #0)
385 node->set_op(lowering->machine()->WordEqual());
386 node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
388 // BooleanNot(x: rTagged) => WordEqual(x, #false)
389 node->set_op(lowering->machine()->WordEqual());
390 node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
393 // No input representation requirement; adapt during lowering.
394 ProcessInput(node, 0, tBool);
395 SetOutput(node, rBit);
399 case IrOpcode::kNumberEqual:
400 case IrOpcode::kNumberLessThan:
401 case IrOpcode::kNumberLessThanOrEqual: {
402 // Number comparisons reduce to integer comparisons for integer inputs.
403 if (BothInputsAre(node, Type::Signed32())) {
404 // => signed Int32Cmp
406 if (lower()) node->set_op(Int32Op(node));
407 } else if (BothInputsAre(node, Type::Unsigned32())) {
408 // => unsigned Int32Cmp
409 VisitUint32Cmp(node);
410 if (lower()) node->set_op(Uint32Op(node));
413 VisitFloat64Cmp(node);
414 if (lower()) node->set_op(Float64Op(node));
418 case IrOpcode::kNumberAdd:
419 case IrOpcode::kNumberSubtract: {
420 // Add and subtract reduce to Int32Add/Sub if the inputs
421 // are already integers and all uses are truncating.
422 if (BothInputsAre(node, Type::Signed32()) &&
423 (use & (tUint32 | tNumber | tAny)) == 0) {
424 // => signed Int32Add/Sub
425 VisitInt32Binop(node);
426 if (lower()) node->set_op(Int32Op(node));
427 } else if (BothInputsAre(node, Type::Unsigned32()) &&
428 (use & (tInt32 | tNumber | tAny)) == 0) {
429 // => unsigned Int32Add/Sub
430 VisitUint32Binop(node);
431 if (lower()) node->set_op(Uint32Op(node));
434 VisitFloat64Binop(node);
435 if (lower()) node->set_op(Float64Op(node));
439 case IrOpcode::kNumberMultiply:
440 case IrOpcode::kNumberDivide:
441 case IrOpcode::kNumberModulus: {
442 // Float64Mul/Div/Mod
443 VisitFloat64Binop(node);
444 if (lower()) node->set_op(Float64Op(node));
447 case IrOpcode::kNumberToInt32: {
448 RepTypeUnion use_rep = use & rMask;
450 RepTypeUnion in = GetInfo(node->InputAt(0))->output;
451 if ((in & tMask) == tInt32 || (in & rMask) == rWord32) {
452 // If the input has type int32, or is already a word32, just change
453 // representation if necessary.
454 VisitUnop(node, tInt32 | use_rep, tInt32 | use_rep);
455 DeferReplacement(node, node->InputAt(0));
457 // Require the input in float64 format and perform truncation.
458 // TODO(turbofan): could also avoid the truncation with a tag check.
459 VisitUnop(node, tInt32 | rFloat64, tInt32 | rWord32);
460 // TODO(titzer): should be a truncation.
461 node->set_op(lowering->machine()->ChangeFloat64ToInt32());
464 // Propagate a type to the input, but pass through representation.
465 VisitUnop(node, tInt32, tInt32 | use_rep);
469 case IrOpcode::kNumberToUint32: {
470 RepTypeUnion use_rep = use & rMask;
472 RepTypeUnion in = GetInfo(node->InputAt(0))->output;
473 if ((in & tMask) == tUint32 || (in & rMask) == rWord32) {
474 // The input has type int32, just change representation.
475 VisitUnop(node, tUint32 | use_rep, tUint32 | use_rep);
476 DeferReplacement(node, node->InputAt(0));
478 // Require the input in float64 format to perform truncation.
479 // TODO(turbofan): could also avoid the truncation with a tag check.
480 VisitUnop(node, tUint32 | rFloat64, tUint32 | rWord32);
481 // TODO(titzer): should be a truncation.
482 node->set_op(lowering->machine()->ChangeFloat64ToUint32());
485 // Propagate a type to the input, but pass through representation.
486 VisitUnop(node, tUint32, tUint32 | use_rep);
490 case IrOpcode::kReferenceEqual: {
491 VisitBinop(node, kAnyTagged, rBit);
492 if (lower()) node->set_op(lowering->machine()->WordEqual());
495 case IrOpcode::kStringEqual: {
496 VisitBinop(node, kAnyTagged, rBit);
497 // TODO(titzer): lower StringEqual to stub/runtime call.
500 case IrOpcode::kStringLessThan: {
501 VisitBinop(node, kAnyTagged, rBit);
502 // TODO(titzer): lower StringLessThan to stub/runtime call.
505 case IrOpcode::kStringLessThanOrEqual: {
506 VisitBinop(node, kAnyTagged, rBit);
507 // TODO(titzer): lower StringLessThanOrEqual to stub/runtime call.
510 case IrOpcode::kStringAdd: {
511 VisitBinop(node, kAnyTagged, kAnyTagged);
512 // TODO(titzer): lower StringAdd to stub/runtime call.
515 case IrOpcode::kLoadField: {
516 FieldAccess access = FieldAccessOf(node->op());
517 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
518 SetOutput(node, changer_->TypeForField(access));
519 if (lower()) lowering->DoLoadField(node);
522 case IrOpcode::kStoreField: {
523 FieldAccess access = FieldAccessOf(node->op());
524 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
525 ProcessInput(node, 1, changer_->TypeForField(access));
527 if (lower()) lowering->DoStoreField(node);
530 case IrOpcode::kLoadElement: {
531 ElementAccess access = ElementAccessOf(node->op());
532 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
533 ProcessInput(node, 1, kInt32); // element index
534 SetOutput(node, changer_->TypeForElement(access));
535 if (lower()) lowering->DoLoadElement(node);
538 case IrOpcode::kStoreElement: {
539 ElementAccess access = ElementAccessOf(node->op());
540 ProcessInput(node, 0, changer_->TypeForBasePointer(access));
541 ProcessInput(node, 1, kInt32); // element index
542 ProcessInput(node, 2, changer_->TypeForElement(access));
544 if (lower()) lowering->DoStoreElement(node);
548 //------------------------------------------------------------------
549 // Machine-level operators.
550 //------------------------------------------------------------------
551 case IrOpcode::kLoad: {
552 // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
553 RepType tBase = rTagged;
554 MachineType rep = OpParameter<MachineType>(node);
555 ProcessInput(node, 0, tBase); // pointer or object
556 ProcessInput(node, 1, kInt32); // index
557 SetOutput(node, changer_->TypeForMachineType(rep));
560 case IrOpcode::kStore: {
561 // TODO(titzer): machine loads/stores need to know BaseTaggedness!?
562 RepType tBase = rTagged;
563 StoreRepresentation rep = OpParameter<StoreRepresentation>(node);
564 ProcessInput(node, 0, tBase); // pointer or object
565 ProcessInput(node, 1, kInt32); // index
566 ProcessInput(node, 2, changer_->TypeForMachineType(rep.rep));
570 case IrOpcode::kWord32Shr:
571 // We output unsigned int32 for shift right because JavaScript.
572 return VisitBinop(node, rWord32, rWord32 | tUint32);
573 case IrOpcode::kWord32And:
574 case IrOpcode::kWord32Or:
575 case IrOpcode::kWord32Xor:
576 case IrOpcode::kWord32Shl:
577 case IrOpcode::kWord32Sar:
578 // We use signed int32 as the output type for these word32 operations,
579 // though the machine bits are the same for either signed or unsigned,
580 // because JavaScript considers the result from these operations signed.
581 return VisitBinop(node, rWord32, rWord32 | tInt32);
582 case IrOpcode::kWord32Equal:
583 return VisitBinop(node, rWord32, rBit);
585 case IrOpcode::kInt32Add:
586 case IrOpcode::kInt32Sub:
587 case IrOpcode::kInt32Mul:
588 case IrOpcode::kInt32Div:
589 case IrOpcode::kInt32Mod:
590 return VisitInt32Binop(node);
591 case IrOpcode::kInt32UDiv:
592 case IrOpcode::kInt32UMod:
593 return VisitUint32Binop(node);
594 case IrOpcode::kInt32LessThan:
595 case IrOpcode::kInt32LessThanOrEqual:
596 return VisitInt32Cmp(node);
598 case IrOpcode::kUint32LessThan:
599 case IrOpcode::kUint32LessThanOrEqual:
600 return VisitUint32Cmp(node);
602 case IrOpcode::kInt64Add:
603 case IrOpcode::kInt64Sub:
604 case IrOpcode::kInt64Mul:
605 case IrOpcode::kInt64Div:
606 case IrOpcode::kInt64Mod:
607 return VisitInt64Binop(node);
608 case IrOpcode::kInt64LessThan:
609 case IrOpcode::kInt64LessThanOrEqual:
610 return VisitInt64Cmp(node);
612 case IrOpcode::kInt64UDiv:
613 case IrOpcode::kInt64UMod:
614 return VisitUint64Binop(node);
616 case IrOpcode::kWord64And:
617 case IrOpcode::kWord64Or:
618 case IrOpcode::kWord64Xor:
619 case IrOpcode::kWord64Shl:
620 case IrOpcode::kWord64Shr:
621 case IrOpcode::kWord64Sar:
622 return VisitBinop(node, rWord64, rWord64);
623 case IrOpcode::kWord64Equal:
624 return VisitBinop(node, rWord64, rBit);
626 case IrOpcode::kConvertInt32ToInt64:
627 return VisitUnop(node, tInt32 | rWord32, tInt32 | rWord64);
628 case IrOpcode::kConvertInt64ToInt32:
629 return VisitUnop(node, tInt64 | rWord64, tInt32 | rWord32);
631 case IrOpcode::kChangeInt32ToFloat64:
632 return VisitUnop(node, tInt32 | rWord32, tInt32 | rFloat64);
633 case IrOpcode::kChangeUint32ToFloat64:
634 return VisitUnop(node, tUint32 | rWord32, tUint32 | rFloat64);
635 case IrOpcode::kChangeFloat64ToInt32:
636 return VisitUnop(node, tInt32 | rFloat64, tInt32 | rWord32);
637 case IrOpcode::kChangeFloat64ToUint32:
638 return VisitUnop(node, tUint32 | rFloat64, tUint32 | rWord32);
640 case IrOpcode::kFloat64Add:
641 case IrOpcode::kFloat64Sub:
642 case IrOpcode::kFloat64Mul:
643 case IrOpcode::kFloat64Div:
644 case IrOpcode::kFloat64Mod:
645 return VisitFloat64Binop(node);
646 case IrOpcode::kFloat64Equal:
647 case IrOpcode::kFloat64LessThan:
648 case IrOpcode::kFloat64LessThanOrEqual:
649 return VisitFloat64Cmp(node);
656 void DeferReplacement(Node* node, Node* replacement) {
657 if (replacement->id() < count_) {
658 // Replace with a previously existing node eagerly.
659 node->ReplaceUses(replacement);
661 // Otherwise, we are replacing a node with a representation change.
662 // Such a substitution must be done after all lowering is done, because
663 // new nodes do not have {NodeInfo} entries, and that would confuse
664 // the representation change insertion for uses of it.
665 replacements_.push_back(node);
666 replacements_.push_back(replacement);
668 // TODO(titzer) node->RemoveAllInputs(); // Node is now dead.
671 void PrintUseInfo(Node* node) {
672 TRACE(("#%d:%-20s ", node->id(), node->op()->mnemonic()));
673 PrintInfo(GetUseInfo(node));
677 void PrintInfo(RepTypeUnion info) {
678 if (FLAG_trace_representation) {
679 char buf[REP_TYPE_STRLEN];
680 RenderRepTypeUnion(buf, info);
687 int count_; // number of nodes in the graph
688 NodeInfo* info_; // node id -> usage information
689 NodeVector nodes_; // collected nodes
690 NodeVector replacements_; // replacements to be done after lowering
691 bool contains_js_nodes_; // {true} if a JS operator was seen
692 Phase phase_; // current phase of algorithm
693 RepresentationChanger* changer_; // for inserting representation changes
695 std::queue<Node*, std::deque<Node*, NodePtrZoneAllocator> > queue_;
697 NodeInfo* GetInfo(Node* node) {
698 DCHECK(node->id() >= 0);
699 DCHECK(node->id() < count_);
700 return &info_[node->id()];
703 RepTypeUnion GetUseInfo(Node* node) { return GetInfo(node)->use; }
707 Node* SimplifiedLowering::IsTagged(Node* node) {
708 // TODO(titzer): factor this out to a TaggingScheme abstraction.
709 STATIC_ASSERT(kSmiTagMask == 1); // Only works if tag is the low bit.
710 return graph()->NewNode(machine()->WordAnd(), node,
711 jsgraph()->Int32Constant(kSmiTagMask));
715 void SimplifiedLowering::LowerAllNodes() {
716 SimplifiedOperatorBuilder simplified(graph()->zone());
717 RepresentationChanger changer(jsgraph(), &simplified, machine(),
718 graph()->zone()->isolate());
719 RepresentationSelector selector(jsgraph(), zone(), &changer);
722 LoweringBuilder::LowerAllNodes();
726 Node* SimplifiedLowering::Untag(Node* node) {
727 // TODO(titzer): factor this out to a TaggingScheme abstraction.
728 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
729 return graph()->NewNode(machine()->WordSar(), node, shift_amount);
733 Node* SimplifiedLowering::SmiTag(Node* node) {
734 // TODO(titzer): factor this out to a TaggingScheme abstraction.
735 Node* shift_amount = jsgraph()->Int32Constant(kSmiTagSize + kSmiShiftSize);
736 return graph()->NewNode(machine()->WordShl(), node, shift_amount);
740 Node* SimplifiedLowering::OffsetMinusTagConstant(int32_t offset) {
741 return jsgraph()->Int32Constant(offset - kHeapObjectTag);
745 static void UpdateControlSuccessors(Node* before, Node* node) {
746 DCHECK(IrOpcode::IsControlOpcode(before->opcode()));
747 UseIter iter = before->uses().begin();
748 while (iter != before->uses().end()) {
749 if (IrOpcode::IsControlOpcode((*iter)->opcode()) &&
750 NodeProperties::IsControlEdge(iter.edge())) {
751 iter = iter.UpdateToAndIncrement(node);
759 void SimplifiedLowering::DoChangeTaggedToUI32(Node* node, Node* effect,
760 Node* control, bool is_signed) {
761 // if (IsTagged(val))
762 // ConvertFloat64To(Int32|Uint32)(Load[kMachineFloat64](input, #value_offset))
764 Node* val = node->InputAt(0);
765 Node* branch = graph()->NewNode(common()->Branch(), IsTagged(val), control);
768 Node* tbranch = graph()->NewNode(common()->IfTrue(), branch);
769 Node* loaded = graph()->NewNode(
770 machine()->Load(kMachineFloat64), val,
771 OffsetMinusTagConstant(HeapNumber::kValueOffset), effect);
772 Operator* op = is_signed ? machine()->ChangeFloat64ToInt32()
773 : machine()->ChangeFloat64ToUint32();
774 Node* converted = graph()->NewNode(op, loaded);
777 Node* fbranch = graph()->NewNode(common()->IfFalse(), branch);
778 Node* untagged = Untag(val);
781 Node* merge = graph()->NewNode(common()->Merge(2), tbranch, fbranch);
782 Node* phi = graph()->NewNode(common()->Phi(2), converted, untagged, merge);
783 UpdateControlSuccessors(control, merge);
784 branch->ReplaceInput(1, control);
785 node->ReplaceUses(phi);
789 void SimplifiedLowering::DoChangeTaggedToFloat64(Node* node, Node* effect,
791 // if (IsTagged(input)) Load[kMachineFloat64](input, #value_offset)
792 // else ConvertFloat64(Untag(input))
793 Node* val = node->InputAt(0);
794 Node* branch = graph()->NewNode(common()->Branch(), IsTagged(val), control);
797 Node* tbranch = graph()->NewNode(common()->IfTrue(), branch);
798 Node* loaded = graph()->NewNode(
799 machine()->Load(kMachineFloat64), val,
800 OffsetMinusTagConstant(HeapNumber::kValueOffset), effect);
803 Node* fbranch = graph()->NewNode(common()->IfFalse(), branch);
804 Node* untagged = Untag(val);
806 graph()->NewNode(machine()->ChangeInt32ToFloat64(), untagged);
809 Node* merge = graph()->NewNode(common()->Merge(2), tbranch, fbranch);
810 Node* phi = graph()->NewNode(common()->Phi(2), loaded, converted, merge);
811 UpdateControlSuccessors(control, merge);
812 branch->ReplaceInput(1, control);
813 node->ReplaceUses(phi);
817 void SimplifiedLowering::DoChangeUI32ToTagged(Node* node, Node* effect,
818 Node* control, bool is_signed) {
819 Node* val = node->InputAt(0);
822 if (SmiValuesAre32Bits()) {
823 // All int32s fit in this case.
824 DCHECK(kPointerSize == 8);
825 return node->ReplaceUses(SmiTag(val));
827 // TODO(turbofan): use an Int32AddWithOverflow to tag and check here.
828 Node* lt = graph()->NewNode(machine()->Int32LessThanOrEqual(), val,
829 jsgraph()->Int32Constant(Smi::kMaxValue));
831 graph()->NewNode(machine()->Int32LessThanOrEqual(),
832 jsgraph()->Int32Constant(Smi::kMinValue), val);
833 is_smi = graph()->NewNode(machine()->Word32And(), lt, gt);
836 // Check if Uint32 value is in the smi range.
837 is_smi = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
838 jsgraph()->Int32Constant(Smi::kMaxValue));
841 // TODO(turbofan): fold smi test branch eagerly.
842 // if (IsSmi(input)) SmiTag(input);
843 // else InlineAllocAndInitHeapNumber(ConvertToFloat64(input)))
844 Node* branch = graph()->NewNode(common()->Branch(), is_smi, control);
847 Node* tbranch = graph()->NewNode(common()->IfTrue(), branch);
848 Node* smi_tagged = SmiTag(val);
851 Node* fbranch = graph()->NewNode(common()->IfFalse(), branch);
852 Node* heap_num = jsgraph()->Constant(0.0); // TODO(titzer): alloc and init
855 Node* merge = graph()->NewNode(common()->Merge(2), tbranch, fbranch);
856 Node* phi = graph()->NewNode(common()->Phi(2), smi_tagged, heap_num, merge);
857 UpdateControlSuccessors(control, merge);
858 branch->ReplaceInput(1, control);
859 node->ReplaceUses(phi);
863 void SimplifiedLowering::DoChangeFloat64ToTagged(Node* node, Node* effect,
865 return; // TODO(titzer): need to call runtime to allocate in one branch
869 void SimplifiedLowering::DoChangeBoolToBit(Node* node, Node* effect,
871 Node* cmp = graph()->NewNode(machine()->WordEqual(), node->InputAt(0),
872 jsgraph()->TrueConstant());
873 node->ReplaceUses(cmp);
877 void SimplifiedLowering::DoChangeBitToBool(Node* node, Node* effect,
879 Node* val = node->InputAt(0);
880 Node* branch = graph()->NewNode(common()->Branch(), val, control);
883 Node* tbranch = graph()->NewNode(common()->IfTrue(), branch);
885 Node* fbranch = graph()->NewNode(common()->IfFalse(), branch);
887 Node* merge = graph()->NewNode(common()->Merge(2), tbranch, fbranch);
888 Node* phi = graph()->NewNode(common()->Phi(2), jsgraph()->TrueConstant(),
889 jsgraph()->FalseConstant(), merge);
890 UpdateControlSuccessors(control, merge);
891 branch->ReplaceInput(1, control);
892 node->ReplaceUses(phi);
896 static WriteBarrierKind ComputeWriteBarrierKind(BaseTaggedness base_is_tagged,
897 MachineType representation,
899 // TODO(turbofan): skip write barriers for Smis, etc.
900 if (base_is_tagged == kTaggedBase && representation == kMachineTagged) {
901 // Write barriers are only for writes into heap objects (i.e. tagged base).
902 return kFullWriteBarrier;
904 return kNoWriteBarrier;
908 void SimplifiedLowering::DoLoadField(Node* node) {
909 const FieldAccess& access = FieldAccessOf(node->op());
910 node->set_op(machine_.Load(access.representation));
911 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
912 node->InsertInput(zone(), 1, offset);
916 void SimplifiedLowering::DoStoreField(Node* node) {
917 const FieldAccess& access = FieldAccessOf(node->op());
918 WriteBarrierKind kind = ComputeWriteBarrierKind(
919 access.base_is_tagged, access.representation, access.type);
920 node->set_op(machine_.Store(access.representation, kind));
921 Node* offset = jsgraph()->Int32Constant(access.offset - access.tag());
922 node->InsertInput(zone(), 1, offset);
926 Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
928 int element_size = 0;
929 switch (access.representation) {
931 element_size = kPointerSize;
943 case kMachineFloat64:
950 if (element_size != 1) {
951 index = graph()->NewNode(machine()->Int32Mul(),
952 jsgraph()->Int32Constant(element_size), index);
954 int fixed_offset = access.header_size - access.tag();
955 if (fixed_offset == 0) return index;
956 return graph()->NewNode(machine()->Int32Add(), index,
957 jsgraph()->Int32Constant(fixed_offset));
961 void SimplifiedLowering::DoLoadElement(Node* node) {
962 const ElementAccess& access = ElementAccessOf(node->op());
963 node->set_op(machine_.Load(access.representation));
964 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
968 void SimplifiedLowering::DoStoreElement(Node* node) {
969 const ElementAccess& access = ElementAccessOf(node->op());
970 WriteBarrierKind kind = ComputeWriteBarrierKind(
971 access.base_is_tagged, access.representation, access.type);
972 node->set_op(machine_.Store(access.representation, kind));
973 node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
977 void SimplifiedLowering::Lower(Node* node) {}
980 void SimplifiedLowering::LowerChange(Node* node, Node* effect, Node* control) {
981 switch (node->opcode()) {
982 case IrOpcode::kChangeTaggedToInt32:
983 DoChangeTaggedToUI32(node, effect, control, true);
985 case IrOpcode::kChangeTaggedToUint32:
986 DoChangeTaggedToUI32(node, effect, control, false);
988 case IrOpcode::kChangeTaggedToFloat64:
989 DoChangeTaggedToFloat64(node, effect, control);
991 case IrOpcode::kChangeInt32ToTagged:
992 DoChangeUI32ToTagged(node, effect, control, true);
994 case IrOpcode::kChangeUint32ToTagged:
995 DoChangeUI32ToTagged(node, effect, control, false);
997 case IrOpcode::kChangeFloat64ToTagged:
998 DoChangeFloat64ToTagged(node, effect, control);
1000 case IrOpcode::kChangeBoolToBit:
1001 DoChangeBoolToBit(node, effect, control);
1003 case IrOpcode::kChangeBitToBool:
1004 DoChangeBitToBool(node, effect, control);
1012 } // namespace compiler
1013 } // namespace internal