Index: src/compiler/control-reducer.cc |
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc |
index 7f4bf317496270ce723f3adf46bd3b5a7e5d02e6..d40d414cfe1785ddb6f41e673af795432ba74a91 100644 |
--- a/src/compiler/control-reducer.cc |
+++ b/src/compiler/control-reducer.cc |
@@ -169,44 +169,80 @@ class ControlReducerImpl { |
Node* ConnectNTL(Node* loop) { |
TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); |
- if (loop->opcode() != IrOpcode::kTerminate) { |
- // Insert a {Terminate} node if the loop has effects. |
- ZoneDeque<Node*> effects(zone_); |
- for (Node* const use : loop->uses()) { |
- if (use->opcode() == IrOpcode::kEffectPhi) effects.push_back(use); |
- } |
- int count = static_cast<int>(effects.size()); |
- if (count > 0) { |
- Node** inputs = zone_->NewArray<Node*>(1 + count); |
- for (int i = 0; i < count; i++) inputs[i] = effects[i]; |
- inputs[count] = loop; |
- loop = graph()->NewNode(common_->Terminate(count), 1 + count, inputs); |
- TRACE(("AddTerminate: #%d:%s[%d]\n", loop->id(), loop->op()->mnemonic(), |
- count)); |
+ Node* always = graph()->NewNode(common_->Always()); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(always); |
+ |
+ Node* branch = graph()->NewNode(common_->Branch(), always, loop); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(branch); |
+ |
+ Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(if_true); |
+ |
+ Node* if_false = graph()->NewNode(common_->IfFalse(), branch); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(if_false); |
+ |
+ // Hook up the branch into the loop and collect all loop effects. |
+ NodeVector effects(zone_); |
+ for (auto edge : loop->use_edges()) { |
+ DCHECK_EQ(loop, edge.to()); |
+ DCHECK(NodeProperties::IsControlEdge(edge)); |
+ if (edge.from() == branch) continue; |
+ switch (edge.from()->opcode()) { |
+#define CASE(Opcode) case IrOpcode::k##Opcode: |
+ CONTROL_OP_LIST(CASE) |
+#undef CASE |
+ // Update all control nodes (except {branch}) pointing to the {loop}. |
+ edge.UpdateTo(if_true); |
+ break; |
+ case IrOpcode::kEffectPhi: |
+ effects.push_back(edge.from()); |
+ break; |
+ default: |
+ break; |
} |
} |
- Node* to_add = loop; |
+ // Compute effects for the Return. |
+ Node* effect = graph()->start(); |
+ int const effects_count = static_cast<int>(effects.size()); |
+ if (effects_count == 1) { |
+ effect = effects[0]; |
+ } else if (effects_count > 1) { |
+ effect = graph()->NewNode(common_->EffectSet(effects_count), |
+ effects_count, &effects.front()); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(effect); |
+ } |
+ |
+ // Add a return to connect the NTL to the end. |
+ Node* ret = graph()->NewNode( |
+ common_->Return(), jsgraph_->UndefinedConstant(), effect, if_false); |
+ // Mark the node as visited so that we can revisit later. |
+ MarkAsVisited(ret); |
+ |
Node* end = graph()->end(); |
CHECK_EQ(IrOpcode::kEnd, end->opcode()); |
Node* merge = end->InputAt(0); |
if (merge == NULL || merge->opcode() == IrOpcode::kDead) { |
- // The end node died; just connect end to {loop}. |
- end->ReplaceInput(0, loop); |
+ // The end node died; just connect end to {ret}. |
+ end->ReplaceInput(0, ret); |
} else if (merge->opcode() != IrOpcode::kMerge) { |
- // Introduce a final merge node for {end->InputAt(0)} and {loop}. |
- merge = graph()->NewNode(common_->Merge(2), merge, loop); |
+ // Introduce a final merge node for {end->InputAt(0)} and {ret}. |
+ merge = graph()->NewNode(common_->Merge(2), merge, ret); |
end->ReplaceInput(0, merge); |
- to_add = merge; |
+ ret = merge; |
// Mark the node as visited so that we can revisit later. |
- EnsureStateSize(merge->id()); |
- state_[merge->id()] = kVisited; |
+ MarkAsVisited(merge); |
} else { |
// Append a new input to the final merge at the end. |
- merge->AppendInput(graph()->zone(), loop); |
+ merge->AppendInput(graph()->zone(), ret); |
merge->set_op(common_->Merge(merge->InputCount())); |
} |
- return to_add; |
+ return ret; |
} |
void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) { |
@@ -337,6 +373,13 @@ class ControlReducerImpl { |
} |
} |
+ // Mark {node} as visited. |
+ void MarkAsVisited(Node* node) { |
+ size_t id = static_cast<size_t>(node->id()); |
+ EnsureStateSize(id); |
+ state_[id] = kVisited; |
+ } |
+ |
Node* dead() { |
if (dead_ == NULL) dead_ = graph()->NewNode(common_->Dead()); |
return dead_; |