Chromium Code Reviews| 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" |
| 11 #include "src/compiler/node-properties.h" | 11 #include "src/compiler/node-properties.h" |
| 12 #include "src/zone-containers.h" | 12 #include "src/zone-containers.h" |
| 13 | 13 |
| 14 #define TRACE(...) \ | |
|
Michael Starzinger
2015/03/17 17:08:07
nit: Can we move it into the namespaces for consis
titzer
2015/03/17 17:32:42
Done.
| |
| 15 do { \ | |
| 16 if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \ | |
| 17 } while (false) | |
| 18 | |
| 14 namespace v8 { | 19 namespace v8 { |
| 15 namespace internal { | 20 namespace internal { |
| 16 namespace compiler { | 21 namespace compiler { |
| 17 | 22 |
| 18 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; | 23 enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; |
| 19 enum Decision { kFalse, kUnknown, kTrue }; | 24 enum Decision { kFalse, kUnknown, kTrue }; |
| 20 | 25 |
| 21 class ReachabilityMarker : public NodeMarker<uint8_t> { | 26 class ReachabilityMarker : public NodeMarker<uint8_t> { |
| 22 public: | 27 public: |
| 23 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} | 28 explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {} |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 35 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } | 40 bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } |
| 36 void Push(Node* node) { Set(node, Get(node) | kFwStack); } | 41 void Push(Node* node) { Set(node, Get(node) | kFwStack); } |
| 37 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } | 42 void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } |
| 38 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } | 43 bool IsOnStack(Node* node) { return Get(node) & kFwStack; } |
| 39 | 44 |
| 40 private: | 45 private: |
| 41 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; | 46 enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; |
| 42 }; | 47 }; |
| 43 | 48 |
| 44 | 49 |
| 45 #define TRACE(x) \ | |
| 46 if (FLAG_trace_turbo_reduction) PrintF x | |
| 47 | |
| 48 class ControlReducerImpl { | 50 class ControlReducerImpl { |
| 49 public: | 51 public: |
| 50 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, | 52 ControlReducerImpl(Zone* zone, JSGraph* jsgraph, |
| 51 CommonOperatorBuilder* common) | 53 CommonOperatorBuilder* common) |
| 52 : zone_(zone), | 54 : zone_(zone), |
| 53 jsgraph_(jsgraph), | 55 jsgraph_(jsgraph), |
| 54 common_(common), | 56 common_(common), |
| 55 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), | 57 state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), |
| 56 stack_(zone_), | 58 stack_(zone_), |
| 57 revisit_(zone_) {} | 59 revisit_(zone_) {} |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 105 marked.SetReachableFromStart(start); | 107 marked.SetReachableFromStart(start); |
| 106 | 108 |
| 107 // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid | 109 // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid |
| 108 // O(n^2) traversal. | 110 // O(n^2) traversal. |
| 109 typedef std::pair<Node*, Node::Uses::const_iterator> FwIter; | 111 typedef std::pair<Node*, Node::Uses::const_iterator> FwIter; |
| 110 ZoneVector<FwIter> fw_stack(zone_); | 112 ZoneVector<FwIter> fw_stack(zone_); |
| 111 fw_stack.push_back(FwIter(start, start->uses().begin())); | 113 fw_stack.push_back(FwIter(start, start->uses().begin())); |
| 112 | 114 |
| 113 while (!fw_stack.empty()) { | 115 while (!fw_stack.empty()) { |
| 114 Node* node = fw_stack.back().first; | 116 Node* node = fw_stack.back().first; |
| 115 TRACE(("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic())); | 117 TRACE("ControlFw: #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 116 bool pop = true; | 118 bool pop = true; |
| 117 while (fw_stack.back().second != node->uses().end()) { | 119 while (fw_stack.back().second != node->uses().end()) { |
| 118 Node* succ = *(fw_stack.back().second); | 120 Node* succ = *(fw_stack.back().second); |
| 119 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { | 121 if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) { |
| 120 // {succ} is on stack and not reachable from end. | 122 // {succ} is on stack and not reachable from end. |
| 121 Node* added = ConnectNTL(succ); | 123 Node* added = ConnectNTL(succ); |
| 122 nodes.push_back(added); | 124 nodes.push_back(added); |
| 123 marked.SetReachableFromEnd(added); | 125 marked.SetReachableFromEnd(added); |
| 124 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); | 126 AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1); |
| 125 | 127 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 if (node->op()->ControlOutputCount() > 0 && | 160 if (node->op()->ControlOutputCount() > 0 && |
| 159 !marked.IsReachableFromStart(node)) { | 161 !marked.IsReachableFromStart(node)) { |
| 160 ReplaceNode(node, dead()); // uses will be added to revisit queue. | 162 ReplaceNode(node, dead()); // uses will be added to revisit queue. |
| 161 } | 163 } |
| 162 } | 164 } |
| 163 return TryRevisit(); // try to push a node onto the stack. | 165 return TryRevisit(); // try to push a node onto the stack. |
| 164 } | 166 } |
| 165 | 167 |
| 166 // 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. |
| 167 Node* ConnectNTL(Node* loop) { | 169 Node* ConnectNTL(Node* loop) { |
| 168 TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); | 170 TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); |
| 169 | 171 |
| 170 Node* always = graph()->NewNode(common_->Always()); | 172 Node* always = graph()->NewNode(common_->Always()); |
| 171 // Mark the node as visited so that we can revisit later. | 173 // Mark the node as visited so that we can revisit later. |
| 172 MarkAsVisited(always); | 174 MarkAsVisited(always); |
| 173 | 175 |
| 174 Node* branch = graph()->NewNode(common_->Branch(), always, loop); | 176 Node* branch = graph()->NewNode(common_->Branch(), always, loop); |
| 175 // Mark the node as visited so that we can revisit later. | 177 // Mark the node as visited so that we can revisit later. |
| 176 MarkAsVisited(branch); | 178 MarkAsVisited(branch); |
| 177 | 179 |
| 178 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); | 180 Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 TrimNodes(marked, nodes); | 275 TrimNodes(marked, nodes); |
| 274 } | 276 } |
| 275 | 277 |
| 276 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) { | 278 void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) { |
| 277 // Remove dead->live edges. | 279 // Remove dead->live edges. |
| 278 for (size_t j = 0; j < nodes.size(); j++) { | 280 for (size_t j = 0; j < nodes.size(); j++) { |
| 279 Node* node = nodes[j]; | 281 Node* node = nodes[j]; |
| 280 for (Edge edge : node->use_edges()) { | 282 for (Edge edge : node->use_edges()) { |
| 281 Node* use = edge.from(); | 283 Node* use = edge.from(); |
| 282 if (!marked.IsReachableFromEnd(use)) { | 284 if (!marked.IsReachableFromEnd(use)) { |
| 283 TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(), | 285 TRACE("DeadLink: #%d:%s(%d) -> #%d:%s\n", use->id(), |
| 284 use->op()->mnemonic(), edge.index(), node->id(), | 286 use->op()->mnemonic(), edge.index(), node->id(), |
| 285 node->op()->mnemonic())); | 287 node->op()->mnemonic()); |
| 286 edge.UpdateTo(NULL); | 288 edge.UpdateTo(NULL); |
| 287 } | 289 } |
| 288 } | 290 } |
| 289 } | 291 } |
| 290 #if DEBUG | 292 #if DEBUG |
| 291 // Verify that no inputs to live nodes are NULL. | 293 // Verify that no inputs to live nodes are NULL. |
| 292 for (Node* node : nodes) { | 294 for (Node* node : nodes) { |
| 293 for (int index = 0; index < node->InputCount(); index++) { | 295 for (int index = 0; index < node->InputCount(); index++) { |
| 294 Node* input = node->InputAt(index); | 296 Node* input = node->InputAt(index); |
| 295 if (input == nullptr) { | 297 if (input == nullptr) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 315 // Reduce the node on the top of the stack. | 317 // Reduce the node on the top of the stack. |
| 316 // If an input {i} is not yet visited or needs to be revisited, push {i} onto | 318 // If an input {i} is not yet visited or needs to be revisited, push {i} onto |
| 317 // the stack and return. Otherwise, all inputs are visited, so apply | 319 // the stack and return. Otherwise, all inputs are visited, so apply |
| 318 // reductions for {node} and pop it off the stack. | 320 // reductions for {node} and pop it off the stack. |
| 319 void ReduceTop() { | 321 void ReduceTop() { |
| 320 size_t height = stack_.size(); | 322 size_t height = stack_.size(); |
| 321 Node* node = stack_.back(); | 323 Node* node = stack_.back(); |
| 322 | 324 |
| 323 if (node->IsDead()) return Pop(); // Node was killed while on stack. | 325 if (node->IsDead()) return Pop(); // Node was killed while on stack. |
| 324 | 326 |
| 325 TRACE(("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic())); | 327 TRACE("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 326 | 328 |
| 327 // Recurse on an input if necessary. | 329 // Recurse on an input if necessary. |
| 328 for (Node* const input : node->inputs()) { | 330 for (Node* const input : node->inputs()) { |
| 329 DCHECK(input); | 331 DCHECK(input); |
| 330 if (Recurse(input)) return; | 332 if (Recurse(input)) return; |
| 331 } | 333 } |
| 332 | 334 |
| 333 // All inputs should be visited or on stack. Apply reductions to node. | 335 // All inputs should be visited or on stack. Apply reductions to node. |
| 334 Node* replacement = ReduceNode(node); | 336 Node* replacement = ReduceNode(node); |
| 335 if (replacement != node) ReplaceNode(node, replacement); | 337 if (replacement != node) ReplaceNode(node, replacement); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 367 DCHECK_GE(pos, 0); | 369 DCHECK_GE(pos, 0); |
| 368 DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]); | 370 DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]); |
| 369 state_[stack_[pos]->id()] = kVisited; | 371 state_[stack_[pos]->id()] = kVisited; |
| 370 stack_.pop_back(); | 372 stack_.pop_back(); |
| 371 } | 373 } |
| 372 | 374 |
| 373 // Queue a node to be revisited if it has been visited once already. | 375 // Queue a node to be revisited if it has been visited once already. |
| 374 void Revisit(Node* node) { | 376 void Revisit(Node* node) { |
| 375 size_t id = static_cast<size_t>(node->id()); | 377 size_t id = static_cast<size_t>(node->id()); |
| 376 if (id < state_.size() && state_[id] == kVisited) { | 378 if (id < state_.size() && state_[id] == kVisited) { |
| 377 TRACE((" Revisit #%d:%s\n", node->id(), node->op()->mnemonic())); | 379 TRACE(" Revisit #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 378 state_[id] = kRevisit; | 380 state_[id] = kRevisit; |
| 379 revisit_.push_back(node); | 381 revisit_.push_back(node); |
| 380 } | 382 } |
| 381 } | 383 } |
| 382 | 384 |
| 383 // Mark {node} as visited. | 385 // Mark {node} as visited. |
| 384 void MarkAsVisited(Node* node) { | 386 void MarkAsVisited(Node* node) { |
| 385 size_t id = static_cast<size_t>(node->id()); | 387 size_t id = static_cast<size_t>(node->id()); |
| 386 EnsureStateSize(id); | 388 EnsureStateSize(id); |
| 387 state_[id] = kVisited; | 389 state_[id] = kVisited; |
| 388 } | 390 } |
| 389 | 391 |
| 390 Node* dead() { return jsgraph_->DeadControl(); } | 392 Node* dead() { return jsgraph_->DeadControl(); } |
| 391 | 393 |
| 392 //=========================================================================== | 394 //=========================================================================== |
| 393 // Reducer implementation: perform reductions on a node. | 395 // Reducer implementation: perform reductions on a node. |
| 394 //=========================================================================== | 396 //=========================================================================== |
| 395 Node* ReduceNode(Node* node) { | 397 Node* ReduceNode(Node* node) { |
| 396 if (node->op()->ControlInputCount() == 1 || | 398 if (node->op()->ControlInputCount() == 1 || |
| 397 node->opcode() == IrOpcode::kLoop) { | 399 node->opcode() == IrOpcode::kLoop) { |
| 398 // If a node has only one control input and it is dead, replace with dead. | 400 // If a node has only one control input and it is dead, replace with dead. |
| 399 Node* control = NodeProperties::GetControlInput(node); | 401 Node* control = NodeProperties::GetControlInput(node); |
| 400 if (control->opcode() == IrOpcode::kDead) { | 402 if (control->opcode() == IrOpcode::kDead) { |
| 401 TRACE(("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic())); | 403 TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); |
| 402 return control; | 404 return control; |
| 403 } | 405 } |
| 404 } | 406 } |
| 405 | 407 |
| 406 // Reduce branches, phis, and merges. | 408 // Reduce branches, phis, and merges. |
| 407 switch (node->opcode()) { | 409 switch (node->opcode()) { |
| 408 case IrOpcode::kBranch: | 410 case IrOpcode::kBranch: |
| 409 return ReduceBranch(node); | 411 return ReduceBranch(node); |
| 410 case IrOpcode::kIfTrue: | 412 case IrOpcode::kIfTrue: |
| 411 return ReduceIfTrue(node); | 413 return ReduceIfTrue(node); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 int index = 0; | 502 int index = 0; |
| 501 int live_index = 0; | 503 int live_index = 0; |
| 502 for (Node* const input : node->inputs()) { | 504 for (Node* const input : node->inputs()) { |
| 503 if (input->opcode() != IrOpcode::kDead) { | 505 if (input->opcode() != IrOpcode::kDead) { |
| 504 live++; | 506 live++; |
| 505 live_index = index; | 507 live_index = index; |
| 506 } | 508 } |
| 507 index++; | 509 index++; |
| 508 } | 510 } |
| 509 | 511 |
| 510 TRACE(("ReduceMerge: #%d:%s (%d live)\n", node->id(), | 512 TRACE("ReduceMerge: #%d:%s (%d live)\n", node->id(), node->op()->mnemonic(), |
| 511 node->op()->mnemonic(), live)); | 513 live); |
| 512 | 514 |
| 513 if (live == 0) return dead(); // no remaining inputs. | 515 if (live == 0) return dead(); // no remaining inputs. |
| 514 | 516 |
| 515 // Gather phis and effect phis to be edited. | 517 // Gather phis and effect phis to be edited. |
| 516 ZoneVector<Node*> phis(zone_); | 518 ZoneVector<Node*> phis(zone_); |
| 517 for (Node* const use : node->uses()) { | 519 for (Node* const use : node->uses()) { |
| 518 if (NodeProperties::IsPhi(use)) phis.push_back(use); | 520 if (NodeProperties::IsPhi(use)) phis.push_back(use); |
| 519 } | 521 } |
| 520 | 522 |
| 521 if (live == 1) { | 523 if (live == 1) { |
| 522 // All phis are redundant. Replace them with their live input. | 524 // All phis are redundant. Replace them with their live input. |
| 523 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); | 525 for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); |
| 524 // The merge itself is redundant. | 526 // The merge itself is redundant. |
| 525 return node->InputAt(live_index); | 527 return node->InputAt(live_index); |
| 526 } | 528 } |
| 527 | 529 |
| 528 DCHECK_LE(2, live); | 530 DCHECK_LE(2, live); |
| 529 | 531 |
| 530 if (live < node->InputCount()) { | 532 if (live < node->InputCount()) { |
| 531 // Edit phis in place, removing dead inputs and revisiting them. | 533 // Edit phis in place, removing dead inputs and revisiting them. |
| 532 for (Node* const phi : phis) { | 534 for (Node* const phi : phis) { |
| 533 TRACE((" PhiInMerge: #%d:%s (%d live)\n", phi->id(), | 535 TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(), |
| 534 phi->op()->mnemonic(), live)); | 536 phi->op()->mnemonic(), live); |
| 535 RemoveDeadInputs(node, phi); | 537 RemoveDeadInputs(node, phi); |
| 536 Revisit(phi); | 538 Revisit(phi); |
| 537 } | 539 } |
| 538 // Edit the merge in place, removing dead inputs. | 540 // Edit the merge in place, removing dead inputs. |
| 539 RemoveDeadInputs(node, node); | 541 RemoveDeadInputs(node, node); |
| 540 } | 542 } |
| 541 | 543 |
| 542 DCHECK_EQ(live, node->InputCount()); | 544 DCHECK_EQ(live, node->InputCount()); |
| 543 | 545 |
| 544 // Check if it's an unused diamond. | 546 // Check if it's an unused diamond. |
| 545 if (live == 2 && phis.empty()) { | 547 if (live == 2 && phis.empty()) { |
| 546 Node* node0 = node->InputAt(0); | 548 Node* node0 = node->InputAt(0); |
| 547 Node* node1 = node->InputAt(1); | 549 Node* node1 = node->InputAt(1); |
| 548 if (((node0->opcode() == IrOpcode::kIfTrue && | 550 if (((node0->opcode() == IrOpcode::kIfTrue && |
| 549 node1->opcode() == IrOpcode::kIfFalse) || | 551 node1->opcode() == IrOpcode::kIfFalse) || |
| 550 (node1->opcode() == IrOpcode::kIfTrue && | 552 (node1->opcode() == IrOpcode::kIfTrue && |
| 551 node0->opcode() == IrOpcode::kIfFalse)) && | 553 node0->opcode() == IrOpcode::kIfFalse)) && |
| 552 node0->OwnedBy(node) && node1->OwnedBy(node)) { | 554 node0->OwnedBy(node) && node1->OwnedBy(node)) { |
| 553 Node* branch0 = NodeProperties::GetControlInput(node0); | 555 Node* branch0 = NodeProperties::GetControlInput(node0); |
| 554 Node* branch1 = NodeProperties::GetControlInput(node1); | 556 Node* branch1 = NodeProperties::GetControlInput(node1); |
| 555 if (branch0 == branch1) { | 557 if (branch0 == branch1) { |
| 556 // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes | 558 // It's a dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
| 557 // have users except for the Merge and the Merge has no Phi or | 559 // have users except for the Merge and the Merge has no Phi or |
| 558 // EffectPhi uses, so replace the Merge with the control input of the | 560 // EffectPhi uses, so replace the Merge with the control input of the |
| 559 // diamond. | 561 // diamond. |
| 560 TRACE((" DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(), | 562 TRACE(" DeadDiamond: #%d:%s #%d:%s #%d:%s\n", node0->id(), |
| 561 node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(), | 563 node0->op()->mnemonic(), node1->id(), node1->op()->mnemonic(), |
| 562 branch0->id(), branch0->op()->mnemonic())); | 564 branch0->id(), branch0->op()->mnemonic()); |
| 563 return NodeProperties::GetControlInput(branch0); | 565 return NodeProperties::GetControlInput(branch0); |
| 564 } | 566 } |
| 565 } | 567 } |
| 566 } | 568 } |
| 567 | 569 |
| 568 return node; | 570 return node; |
| 569 } | 571 } |
| 570 | 572 |
| 571 // Reduce branches if they have constant inputs. | 573 // Reduce branches if they have constant inputs. |
| 572 Node* ReduceIfTrue(Node* node) { | 574 Node* ReduceIfTrue(Node* node) { |
| 573 Node* branch = node->InputAt(0); | 575 Node* branch = node->InputAt(0); |
| 574 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 576 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 575 Decision result = DecideCondition(branch->InputAt(0)); | 577 Decision result = DecideCondition(branch->InputAt(0)); |
| 576 if (result == kTrue) { | 578 if (result == kTrue) { |
| 577 // fold a true branch by replacing IfTrue with the branch control. | 579 // fold a true branch by replacing IfTrue with the branch control. |
| 578 TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 580 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
| 579 branch->op()->mnemonic(), node->id(), node->op()->mnemonic())); | 581 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 580 return branch->InputAt(1); | 582 return branch->InputAt(1); |
| 581 } | 583 } |
| 582 return result == kUnknown ? node : dead(); | 584 return result == kUnknown ? node : dead(); |
| 583 } | 585 } |
| 584 | 586 |
| 585 // Reduce branches if they have constant inputs. | 587 // Reduce branches if they have constant inputs. |
| 586 Node* ReduceIfFalse(Node* node) { | 588 Node* ReduceIfFalse(Node* node) { |
| 587 Node* branch = node->InputAt(0); | 589 Node* branch = node->InputAt(0); |
| 588 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | 590 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 589 Decision result = DecideCondition(branch->InputAt(0)); | 591 Decision result = DecideCondition(branch->InputAt(0)); |
| 590 if (result == kFalse) { | 592 if (result == kFalse) { |
| 591 // fold a false branch by replacing IfFalse with the branch control. | 593 // fold a false branch by replacing IfFalse with the branch control. |
| 592 TRACE(("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), | 594 TRACE("BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
| 593 branch->op()->mnemonic(), node->id(), node->op()->mnemonic())); | 595 branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
| 594 return branch->InputAt(1); | 596 return branch->InputAt(1); |
| 595 } | 597 } |
| 596 return result == kUnknown ? node : dead(); | 598 return result == kUnknown ? node : dead(); |
| 597 } | 599 } |
| 598 | 600 |
| 599 // Remove inputs to {node} corresponding to the dead inputs to {merge} | 601 // Remove inputs to {node} corresponding to the dead inputs to {merge} |
| 600 // and compact the remaining inputs, updating the operator. | 602 // and compact the remaining inputs, updating the operator. |
| 601 void RemoveDeadInputs(Node* merge, Node* node) { | 603 void RemoveDeadInputs(Node* merge, Node* node) { |
| 602 int live = 0; | 604 int live = 0; |
| 603 for (int i = 0; i < merge->InputCount(); i++) { | 605 for (int i = 0; i < merge->InputCount(); i++) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 615 } | 617 } |
| 616 DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); | 618 DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); |
| 617 DCHECK_NE(total, node->InputCount()); | 619 DCHECK_NE(total, node->InputCount()); |
| 618 node->TrimInputCount(total); | 620 node->TrimInputCount(total); |
| 619 node->set_op(common_->ResizeMergeOrPhi(node->op(), live)); | 621 node->set_op(common_->ResizeMergeOrPhi(node->op(), live)); |
| 620 } | 622 } |
| 621 | 623 |
| 622 // Replace uses of {node} with {replacement} and revisit the uses. | 624 // Replace uses of {node} with {replacement} and revisit the uses. |
| 623 void ReplaceNode(Node* node, Node* replacement) { | 625 void ReplaceNode(Node* node, Node* replacement) { |
| 624 if (node == replacement) return; | 626 if (node == replacement) return; |
| 625 TRACE((" Replace: #%d:%s with #%d:%s\n", node->id(), | 627 TRACE(" Replace: #%d:%s with #%d:%s\n", node->id(), node->op()->mnemonic(), |
| 626 node->op()->mnemonic(), replacement->id(), | 628 replacement->id(), replacement->op()->mnemonic()); |
| 627 replacement->op()->mnemonic())); | |
| 628 for (Node* const use : node->uses()) { | 629 for (Node* const use : node->uses()) { |
| 629 // Don't revisit this node if it refers to itself. | 630 // Don't revisit this node if it refers to itself. |
| 630 if (use != node) Revisit(use); | 631 if (use != node) Revisit(use); |
| 631 } | 632 } |
| 632 node->ReplaceUses(replacement); | 633 node->ReplaceUses(replacement); |
| 633 node->Kill(); | 634 node->Kill(); |
| 634 } | 635 } |
| 635 | 636 |
| 636 Graph* graph() { return jsgraph_->graph(); } | 637 Graph* graph() { return jsgraph_->graph(); } |
| 637 }; | 638 }; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 677 return impl.ReduceIfTrue(node); | 678 return impl.ReduceIfTrue(node); |
| 678 case IrOpcode::kIfFalse: | 679 case IrOpcode::kIfFalse: |
| 679 return impl.ReduceIfFalse(node); | 680 return impl.ReduceIfFalse(node); |
| 680 default: | 681 default: |
| 681 return node; | 682 return node; |
| 682 } | 683 } |
| 683 } | 684 } |
| 684 } | 685 } |
| 685 } | 686 } |
| 686 } // namespace v8::internal::compiler | 687 } // namespace v8::internal::compiler |
| OLD | NEW |