OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/common-operator.h" | 5 #include "src/compiler/common-operator.h" |
6 #include "src/compiler/control-reducer.h" | 6 #include "src/compiler/control-reducer.h" |
7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/node-marker.h" | 9 #include "src/compiler/node-marker.h" |
10 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 ReplaceNode(node, dead()); // uses will be added to revisit queue. | 162 ReplaceNode(node, dead()); // uses will be added to revisit queue. |
163 } | 163 } |
164 } | 164 } |
165 return TryRevisit(); // try to push a node onto the stack. | 165 return TryRevisit(); // try to push a node onto the stack. |
166 } | 166 } |
167 | 167 |
168 // Connect {loop}, the header of a non-terminating loop, to the end node. | 168 // Connect {loop}, the header of a non-terminating loop, to the end node. |
169 Node* ConnectNTL(Node* loop) { | 169 Node* ConnectNTL(Node* loop) { |
170 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); | 170 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); |
171 | 171 |
172 if (loop->opcode() != IrOpcode::kTerminate) { | 172 Node* always = graph()->NewNode(common_->Always()); |
173 // Insert a {Terminate} node if the loop has effects. | 173 // Mark the node as visited so that we can revisit later. |
174 ZoneDeque<Node*> effects(zone_); | 174 MarkAsVisited(always); |
175 for (Node* const use : loop->uses()) { | 175 |
176 if (use->opcode() == IrOpcode::kEffectPhi) effects.push_back(use); | 176 Node* branch = graph()->NewNode(common_->Branch(), always, loop); |
177 } | 177 // Mark the node as visited so that we can revisit later. |
178 int count = static_cast<int>(effects.size()); | 178 MarkAsVisited(branch); |
179 if (count > 0) { | 179 |
180 Node** inputs = zone_->NewArray<Node*>(1 + count); | 180 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |
181 for (int i = 0; i < count; i++) inputs[i] = effects[i]; | 181 // Mark the node as visited so that we can revisit later. |
182 inputs[count] = loop; | 182 MarkAsVisited(if_true); |
183 loop = graph()->NewNode(common_->Terminate(count), 1 + count, inputs); | 183 |
184 TRACE(("AddTerminate: #%d:%s[%d]\n", loop->id(), loop->op()->mnemonic(), | 184 Node* if_false = graph()->NewNode(common_->IfFalse(), branch); |
185 count)); | 185 // Mark the node as visited so that we can revisit later. |
| 186 MarkAsVisited(if_false); |
| 187 |
| 188 // Hook up the branch into the loop and collect all loop effects. |
| 189 NodeVector effects(zone_); |
| 190 for (auto edge : loop->use_edges()) { |
| 191 DCHECK_EQ(loop, edge.to()); |
| 192 DCHECK(NodeProperties::IsControlEdge(edge)); |
| 193 if (edge.from() == branch) continue; |
| 194 switch (edge.from()->opcode()) { |
| 195 #define CASE(Opcode) case IrOpcode::k##Opcode: |
| 196 CONTROL_OP_LIST(CASE) |
| 197 #undef CASE |
| 198 // Update all control nodes (except {branch}) pointing to the {loop}. |
| 199 edge.UpdateTo(if_true); |
| 200 break; |
| 201 case IrOpcode::kEffectPhi: |
| 202 effects.push_back(edge.from()); |
| 203 break; |
| 204 default: |
| 205 break; |
186 } | 206 } |
187 } | 207 } |
188 | 208 |
189 Node* to_add = loop; | 209 // Compute effects for the Return. |
| 210 Node* effect = graph()->start(); |
| 211 int const effects_count = static_cast<int>(effects.size()); |
| 212 if (effects_count == 1) { |
| 213 effect = effects[0]; |
| 214 } else if (effects_count > 1) { |
| 215 effect = graph()->NewNode(common_->EffectSet(effects_count), |
| 216 effects_count, &effects.front()); |
| 217 // Mark the node as visited so that we can revisit later. |
| 218 MarkAsVisited(effect); |
| 219 } |
| 220 |
| 221 // Add a return to connect the NTL to the end. |
| 222 Node* ret = graph()->NewNode( |
| 223 common_->Return(), jsgraph_->UndefinedConstant(), effect, if_false); |
| 224 // Mark the node as visited so that we can revisit later. |
| 225 MarkAsVisited(ret); |
| 226 |
190 Node* end = graph()->end(); | 227 Node* end = graph()->end(); |
191 CHECK_EQ(IrOpcode::kEnd, end->opcode()); | 228 CHECK_EQ(IrOpcode::kEnd, end->opcode()); |
192 Node* merge = end->InputAt(0); | 229 Node* merge = end->InputAt(0); |
193 if (merge == NULL || merge->opcode() == IrOpcode::kDead) { | 230 if (merge == NULL || merge->opcode() == IrOpcode::kDead) { |
194 // The end node died; just connect end to {loop}. | 231 // The end node died; just connect end to {ret}. |
195 end->ReplaceInput(0, loop); | 232 end->ReplaceInput(0, ret); |
196 } else if (merge->opcode() != IrOpcode::kMerge) { | 233 } else if (merge->opcode() != IrOpcode::kMerge) { |
197 // Introduce a final merge node for {end->InputAt(0)} and {loop}. | 234 // Introduce a final merge node for {end->InputAt(0)} and {ret}. |
198 merge = graph()->NewNode(common_->Merge(2), merge, loop); | 235 merge = graph()->NewNode(common_->Merge(2), merge, ret); |
199 end->ReplaceInput(0, merge); | 236 end->ReplaceInput(0, merge); |
200 to_add = merge; | 237 ret = merge; |
201 // Mark the node as visited so that we can revisit later. | 238 // Mark the node as visited so that we can revisit later. |
202 EnsureStateSize(merge->id()); | 239 MarkAsVisited(merge); |
203 state_[merge->id()] = kVisited; | |
204 } else { | 240 } else { |
205 // Append a new input to the final merge at the end. | 241 // Append a new input to the final merge at the end. |
206 merge->AppendInput(graph()->zone(), loop); | 242 merge->AppendInput(graph()->zone(), ret); |
207 merge->set_op(common_->Merge(merge->InputCount())); | 243 merge->set_op(common_->Merge(merge->InputCount())); |
208 } | 244 } |
209 return to_add; | 245 return ret; |
210 } | 246 } |
211 | 247 |
212 void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) { | 248 void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) { |
213 Node* end = graph()->end(); | 249 Node* end = graph()->end(); |
214 marked.SetReachableFromEnd(end); | 250 marked.SetReachableFromEnd(end); |
215 if (!end->IsDead()) { | 251 if (!end->IsDead()) { |
216 nodes.push_back(end); | 252 nodes.push_back(end); |
217 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); | 253 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); |
218 } | 254 } |
219 } | 255 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 // Queue a node to be revisited if it has been visited once already. | 366 // Queue a node to be revisited if it has been visited once already. |
331 void Revisit(Node* node) { | 367 void Revisit(Node* node) { |
332 size_t id = static_cast<size_t>(node->id()); | 368 size_t id = static_cast<size_t>(node->id()); |
333 if (id < state_.size() && state_[id] == kVisited) { | 369 if (id < state_.size() && state_[id] == kVisited) { |
334 TRACE((" Revisit #%d:%s\n", node->id(), node->op()->mnemonic())); | 370 TRACE((" Revisit #%d:%s\n", node->id(), node->op()->mnemonic())); |
335 state_[id] = kRevisit; | 371 state_[id] = kRevisit; |
336 revisit_.push_back(node); | 372 revisit_.push_back(node); |
337 } | 373 } |
338 } | 374 } |
339 | 375 |
| 376 // Mark {node} as visited. |
| 377 void MarkAsVisited(Node* node) { |
| 378 size_t id = static_cast<size_t>(node->id()); |
| 379 EnsureStateSize(id); |
| 380 state_[id] = kVisited; |
| 381 } |
| 382 |
340 Node* dead() { | 383 Node* dead() { |
341 if (dead_ == NULL) dead_ = graph()->NewNode(common_->Dead()); | 384 if (dead_ == NULL) dead_ = graph()->NewNode(common_->Dead()); |
342 return dead_; | 385 return dead_; |
343 } | 386 } |
344 | 387 |
345 //=========================================================================== | 388 //=========================================================================== |
346 // Reducer implementation: perform reductions on a node. | 389 // Reducer implementation: perform reductions on a node. |
347 //=========================================================================== | 390 //=========================================================================== |
348 Node* ReduceNode(Node* node) { | 391 Node* ReduceNode(Node* node) { |
349 if (node->op()->ControlInputCount() == 1) { | 392 if (node->op()->ControlInputCount() == 1) { |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 return impl.ReduceIfTrue(node); | 634 return impl.ReduceIfTrue(node); |
592 case IrOpcode::kIfFalse: | 635 case IrOpcode::kIfFalse: |
593 return impl.ReduceIfFalse(node); | 636 return impl.ReduceIfFalse(node); |
594 default: | 637 default: |
595 return node; | 638 return node; |
596 } | 639 } |
597 } | 640 } |
598 } | 641 } |
599 } | 642 } |
600 } // namespace v8::internal::compiler | 643 } // namespace v8::internal::compiler |
OLD | NEW |