| 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/graph-reducer.h" | 
| 8 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" | 
| 9 #include "src/compiler/node-marker.h" | 10 #include "src/compiler/node-marker.h" | 
| 10 #include "src/compiler/node-matchers.h" | 11 #include "src/compiler/node-matchers.h" | 
| 11 #include "src/compiler/node-properties.h" | 12 #include "src/compiler/node-properties.h" | 
| 12 #include "src/zone-containers.h" | 13 #include "src/zone-containers.h" | 
| 13 | 14 | 
| 14 namespace v8 { | 15 namespace v8 { | 
| 15 namespace internal { | 16 namespace internal { | 
| 16 namespace compiler { | 17 namespace compiler { | 
| 17 | 18 | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 40   bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } | 41   bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; } | 
| 41   void Push(Node* node) { Set(node, Get(node) | kFwStack); } | 42   void Push(Node* node) { Set(node, Get(node) | kFwStack); } | 
| 42   void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } | 43   void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); } | 
| 43   bool IsOnStack(Node* node) { return Get(node) & kFwStack; } | 44   bool IsOnStack(Node* node) { return Get(node) & kFwStack; } | 
| 44 | 45 | 
| 45  private: | 46  private: | 
| 46   enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; | 47   enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 }; | 
| 47 }; | 48 }; | 
| 48 | 49 | 
| 49 | 50 | 
| 50 class ControlReducerImpl { | 51 class ControlReducerImpl final : public Reducer { | 
| 51  public: | 52  public: | 
| 52   ControlReducerImpl(Zone* zone, JSGraph* jsgraph, |  | 
| 53                      CommonOperatorBuilder* common) |  | 
| 54       : zone_(zone), |  | 
| 55         jsgraph_(jsgraph), |  | 
| 56         common_(common), |  | 
| 57         state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_), |  | 
| 58         stack_(zone_), |  | 
| 59         revisit_(zone_), |  | 
| 60         max_phis_for_select_(0) {} |  | 
| 61 |  | 
| 62   Zone* zone_; | 53   Zone* zone_; | 
| 63   JSGraph* jsgraph_; | 54   JSGraph* jsgraph_; | 
| 64   CommonOperatorBuilder* common_; |  | 
| 65   ZoneVector<VisitState> state_; |  | 
| 66   ZoneDeque<Node*> stack_; |  | 
| 67   ZoneDeque<Node*> revisit_; |  | 
| 68   int max_phis_for_select_; | 55   int max_phis_for_select_; | 
| 69 | 56 | 
| 70   void Reduce() { | 57   ControlReducerImpl(Zone* zone, JSGraph* jsgraph) | 
| 71     Push(graph()->end()); | 58       : zone_(zone), jsgraph_(jsgraph), max_phis_for_select_(0) {} | 
| 72     do { |  | 
| 73       // Process the node on the top of the stack, potentially pushing more |  | 
| 74       // or popping the node off the stack. |  | 
| 75       ReduceTop(); |  | 
| 76       // If the stack becomes empty, revisit any nodes in the revisit queue. |  | 
| 77       // If no nodes in the revisit queue, try removing dead loops. |  | 
| 78       // If no dead loops, then finish. |  | 
| 79     } while (!stack_.empty() || TryRevisit() || RepairAndRemoveLoops()); |  | 
| 80   } |  | 
| 81 | 59 | 
| 82   bool TryRevisit() { | 60   Graph* graph() { return jsgraph_->graph(); } | 
| 83     while (!revisit_.empty()) { | 61   CommonOperatorBuilder* common() { return jsgraph_->common(); } | 
| 84       Node* n = revisit_.back(); | 62   Node* dead() { return jsgraph_->DeadControl(); } | 
| 85       revisit_.pop_back(); |  | 
| 86       if (state_[n->id()] == kRevisit) {  // state can change while in queue. |  | 
| 87         Push(n); |  | 
| 88         return true; |  | 
| 89       } |  | 
| 90     } |  | 
| 91     return false; |  | 
| 92   } |  | 
| 93 | 63 | 
| 94   // Repair the graph after the possible creation of non-terminating or dead | 64   // Finish reducing the graph by trimming nodes and/or connecting NTLs. | 
| 95   // loops. Removing dead loops can produce more opportunities for reduction. | 65   bool Finish() final { | 
| 96   bool RepairAndRemoveLoops() { | 66     bool done = true; | 
| 97     // TODO(turbofan): we can skip this if the graph has no loops, but |  | 
| 98     // we have to be careful about proper loop detection during reduction. |  | 
| 99 |  | 
| 100     // Gather all nodes backwards-reachable from end (through inputs). | 67     // Gather all nodes backwards-reachable from end (through inputs). | 
| 101     ReachabilityMarker marked(graph()); | 68     ReachabilityMarker marked(graph()); | 
| 102     NodeVector nodes(zone_); | 69     NodeVector nodes(zone_); | 
| 103     AddNodesReachableFromRoots(marked, nodes); | 70     AddNodesReachableFromRoots(marked, nodes); | 
| 104 | 71 | 
| 105     // Walk forward through control nodes, looking for back edges to nodes | 72     // Walk forward through control nodes, looking for back edges to nodes | 
| 106     // that are not connected to end. Those are non-terminating loops (NTLs). | 73     // that are not connected to end. Those are non-terminating loops (NTLs). | 
| 107     Node* start = graph()->start(); | 74     Node* start = graph()->start(); | 
| 108     marked.Push(start); | 75     marked.Push(start); | 
| 109     marked.SetReachableFromStart(start); | 76     marked.SetReachableFromStart(start); | 
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 157       } | 124       } | 
| 158     } | 125     } | 
| 159 | 126 | 
| 160     // Trim references from dead nodes to live nodes first. | 127     // Trim references from dead nodes to live nodes first. | 
| 161     TrimNodes(marked, nodes); | 128     TrimNodes(marked, nodes); | 
| 162 | 129 | 
| 163     // Any control nodes not reachable from start are dead, even loops. | 130     // Any control nodes not reachable from start are dead, even loops. | 
| 164     for (size_t i = 0; i < nodes.size(); i++) { | 131     for (size_t i = 0; i < nodes.size(); i++) { | 
| 165       Node* node = nodes[i]; | 132       Node* node = nodes[i]; | 
| 166       if (node->op()->ControlOutputCount() > 0 && | 133       if (node->op()->ControlOutputCount() > 0 && | 
| 167           !marked.IsReachableFromStart(node)) { | 134           !marked.IsReachableFromStart(node) && | 
| 168         ReplaceNode(node, dead());  // uses will be added to revisit queue. | 135           node->opcode() != IrOpcode::kDead) { | 
|  | 136         TRACE("Dead: #%d:%s\n", node->id(), node->op()->mnemonic()); | 
|  | 137         node->ReplaceUses(dead()); | 
|  | 138         done = false; | 
| 169       } | 139       } | 
| 170     } | 140     } | 
| 171     return TryRevisit();  // try to push a node onto the stack. | 141 | 
|  | 142     return done; | 
| 172   } | 143   } | 
| 173 | 144 | 
| 174   // Connect {loop}, the header of a non-terminating loop, to the end node. | 145   // Connect {loop}, the header of a non-terminating loop, to the end node. | 
| 175   Node* ConnectNTL(Node* loop) { | 146   Node* ConnectNTL(Node* loop) { | 
| 176     TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); | 147     TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()); | 
| 177     DCHECK_EQ(IrOpcode::kLoop, loop->opcode()); | 148     DCHECK_EQ(IrOpcode::kLoop, loop->opcode()); | 
| 178 | 149 | 
| 179     Node* always = graph()->NewNode(common_->Always()); | 150     Node* always = graph()->NewNode(common()->Always()); | 
| 180     // Mark the node as visited so that we can revisit later. | 151     Node* branch = graph()->NewNode(common()->Branch(), always, loop); | 
| 181     MarkAsVisited(always); | 152     Node* if_true = graph()->NewNode(common()->IfTrue(), branch); | 
|  | 153     Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | 
| 182 | 154 | 
| 183     Node* branch = graph()->NewNode(common_->Branch(), always, loop); | 155     // Insert the branch into the loop and collect all loop effects. | 
| 184     // Mark the node as visited so that we can revisit later. |  | 
| 185     MarkAsVisited(branch); |  | 
| 186 |  | 
| 187     Node* if_true = graph()->NewNode(common_->IfTrue(), branch); |  | 
| 188     // Mark the node as visited so that we can revisit later. |  | 
| 189     MarkAsVisited(if_true); |  | 
| 190 |  | 
| 191     Node* if_false = graph()->NewNode(common_->IfFalse(), branch); |  | 
| 192     // Mark the node as visited so that we can revisit later. |  | 
| 193     MarkAsVisited(if_false); |  | 
| 194 |  | 
| 195     // Hook up the branch into the loop and collect all loop effects. |  | 
| 196     NodeVector effects(zone_); | 156     NodeVector effects(zone_); | 
| 197     for (auto edge : loop->use_edges()) { | 157     for (auto edge : loop->use_edges()) { | 
| 198       DCHECK_EQ(loop, edge.to()); | 158       DCHECK_EQ(loop, edge.to()); | 
| 199       DCHECK(NodeProperties::IsControlEdge(edge)); | 159       DCHECK(NodeProperties::IsControlEdge(edge)); | 
| 200       if (edge.from() == branch) continue; | 160       if (edge.from() == branch) continue; | 
| 201       switch (edge.from()->opcode()) { | 161       switch (edge.from()->opcode()) { | 
| 202         case IrOpcode::kPhi: | 162         case IrOpcode::kPhi: | 
| 203           break; | 163           break; | 
| 204         case IrOpcode::kEffectPhi: | 164         case IrOpcode::kEffectPhi: | 
| 205           effects.push_back(edge.from()); | 165           effects.push_back(edge.from()); | 
| 206           break; | 166           break; | 
| 207         default: | 167         default: | 
| 208           // Update all control edges (except {branch}) pointing to the {loop}. | 168           // Update all control edges (except {branch}) pointing to the {loop}. | 
| 209           edge.UpdateTo(if_true); | 169           edge.UpdateTo(if_true); | 
| 210           break; | 170           break; | 
| 211       } | 171       } | 
| 212     } | 172     } | 
| 213 | 173 | 
| 214     // Compute effects for the Return. | 174     // Compute effects for the Return. | 
| 215     Node* effect = graph()->start(); | 175     Node* effect = graph()->start(); | 
| 216     int const effects_count = static_cast<int>(effects.size()); | 176     int const effects_count = static_cast<int>(effects.size()); | 
| 217     if (effects_count == 1) { | 177     if (effects_count == 1) { | 
| 218       effect = effects[0]; | 178       effect = effects[0]; | 
| 219     } else if (effects_count > 1) { | 179     } else if (effects_count > 1) { | 
| 220       effect = graph()->NewNode(common_->EffectSet(effects_count), | 180       effect = graph()->NewNode(common()->EffectSet(effects_count), | 
| 221                                 effects_count, &effects.front()); | 181                                 effects_count, &effects.front()); | 
| 222       // Mark the node as visited so that we can revisit later. |  | 
| 223       MarkAsVisited(effect); |  | 
| 224     } | 182     } | 
| 225 | 183 | 
| 226     // Add a return to connect the NTL to the end. | 184     // Add a return to connect the NTL to the end. | 
| 227     Node* ret = graph()->NewNode( | 185     Node* ret = graph()->NewNode( | 
| 228         common_->Return(), jsgraph_->UndefinedConstant(), effect, if_false); | 186         common()->Return(), jsgraph_->UndefinedConstant(), effect, if_false); | 
| 229     // Mark the node as visited so that we can revisit later. |  | 
| 230     MarkAsVisited(ret); |  | 
| 231 | 187 | 
| 232     Node* end = graph()->end(); | 188     Node* end = graph()->end(); | 
| 233     CHECK_EQ(IrOpcode::kEnd, end->opcode()); | 189     if (end->opcode() == IrOpcode::kDead) { | 
|  | 190       // End is actually the dead node. Make a new end. | 
|  | 191       end = graph()->NewNode(common()->End(), ret); | 
|  | 192       graph()->SetEnd(end); | 
|  | 193       return end; | 
|  | 194     } | 
|  | 195     // End is not dead. | 
| 234     Node* merge = end->InputAt(0); | 196     Node* merge = end->InputAt(0); | 
| 235     if (merge == NULL || merge->opcode() == IrOpcode::kDead) { | 197     if (merge == NULL || merge->opcode() == IrOpcode::kDead) { | 
| 236       // The end node died; just connect end to {ret}. | 198       // The end node died; just connect end to {ret}. | 
| 237       end->ReplaceInput(0, ret); | 199       end->ReplaceInput(0, ret); | 
| 238     } else if (merge->opcode() != IrOpcode::kMerge) { | 200     } else if (merge->opcode() != IrOpcode::kMerge) { | 
| 239       // Introduce a final merge node for {end->InputAt(0)} and {ret}. | 201       // Introduce a final merge node for {end->InputAt(0)} and {ret}. | 
| 240       merge = graph()->NewNode(common_->Merge(2), merge, ret); | 202       merge = graph()->NewNode(common()->Merge(2), merge, ret); | 
| 241       end->ReplaceInput(0, merge); | 203       end->ReplaceInput(0, merge); | 
| 242       ret = merge; | 204       ret = merge; | 
| 243       // Mark the node as visited so that we can revisit later. |  | 
| 244       MarkAsVisited(merge); |  | 
| 245     } else { | 205     } else { | 
| 246       // Append a new input to the final merge at the end. | 206       // Append a new input to the final merge at the end. | 
| 247       merge->AppendInput(graph()->zone(), ret); | 207       merge->AppendInput(graph()->zone(), ret); | 
| 248       merge->set_op(common_->Merge(merge->InputCount())); | 208       merge->set_op(common()->Merge(merge->InputCount())); | 
| 249     } | 209     } | 
| 250     return ret; | 210     return ret; | 
| 251   } | 211   } | 
| 252 | 212 | 
| 253   void AddNodesReachableFromRoots(ReachabilityMarker& marked, | 213   void AddNodesReachableFromRoots(ReachabilityMarker& marked, | 
| 254                                   NodeVector& nodes) { | 214                                   NodeVector& nodes) { | 
| 255     jsgraph_->GetCachedNodes(&nodes);  // Consider cached nodes roots. | 215     jsgraph_->GetCachedNodes(&nodes);  // Consider cached nodes roots. | 
| 256     Node* end = graph()->end(); | 216     Node* end = graph()->end(); | 
| 257     marked.SetReachableFromEnd(end); | 217     marked.SetReachableFromEnd(end); | 
| 258     if (!end->IsDead()) nodes.push_back(end);  // Consider end to be a root. | 218     if (!end->IsDead()) nodes.push_back(end);  // Consider end to be a root. | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 313           FATAL(str.str().c_str()); | 273           FATAL(str.str().c_str()); | 
| 314         } | 274         } | 
| 315       } | 275       } | 
| 316       for (Node* use : node->uses()) { | 276       for (Node* use : node->uses()) { | 
| 317         CHECK(marked.IsReachableFromEnd(use)); | 277         CHECK(marked.IsReachableFromEnd(use)); | 
| 318       } | 278       } | 
| 319     } | 279     } | 
| 320 #endif | 280 #endif | 
| 321   } | 281   } | 
| 322 | 282 | 
| 323   // Reduce the node on the top of the stack. |  | 
| 324   // If an input {i} is not yet visited or needs to be revisited, push {i} onto |  | 
| 325   // the stack and return. Otherwise, all inputs are visited, so apply |  | 
| 326   // reductions for {node} and pop it off the stack. |  | 
| 327   void ReduceTop() { |  | 
| 328     size_t height = stack_.size(); |  | 
| 329     Node* node = stack_.back(); |  | 
| 330 |  | 
| 331     if (node->IsDead()) return Pop();  // Node was killed while on stack. |  | 
| 332 |  | 
| 333     TRACE("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic()); |  | 
| 334 |  | 
| 335     // Recurse on an input if necessary. |  | 
| 336     for (Node* const input : node->inputs()) { |  | 
| 337       DCHECK(input); |  | 
| 338       if (Recurse(input)) return; |  | 
| 339     } |  | 
| 340 |  | 
| 341     // All inputs should be visited or on stack. Apply reductions to node. |  | 
| 342     Node* replacement = ReduceNode(node); |  | 
| 343     if (replacement != node) ReplaceNode(node, replacement); |  | 
| 344 |  | 
| 345     // After reducing the node, pop it off the stack. |  | 
| 346     CHECK_EQ(static_cast<int>(height), static_cast<int>(stack_.size())); |  | 
| 347     Pop(); |  | 
| 348 |  | 
| 349     // If there was a replacement, reduce it after popping {node}. |  | 
| 350     if (replacement != node) Recurse(replacement); |  | 
| 351   } |  | 
| 352 |  | 
| 353   void EnsureStateSize(size_t id) { |  | 
| 354     if (id >= state_.size()) { |  | 
| 355       state_.resize((3 * id) / 2, kUnvisited); |  | 
| 356     } |  | 
| 357   } |  | 
| 358 |  | 
| 359   // Push a node onto the stack if its state is {kUnvisited} or {kRevisit}. |  | 
| 360   bool Recurse(Node* node) { |  | 
| 361     size_t id = static_cast<size_t>(node->id()); |  | 
| 362     EnsureStateSize(id); |  | 
| 363     if (state_[id] != kRevisit && state_[id] != kUnvisited) return false; |  | 
| 364     Push(node); |  | 
| 365     return true; |  | 
| 366   } |  | 
| 367 |  | 
| 368   void Push(Node* node) { |  | 
| 369     state_[node->id()] = kOnStack; |  | 
| 370     stack_.push_back(node); |  | 
| 371   } |  | 
| 372 |  | 
| 373   void Pop() { |  | 
| 374     int pos = static_cast<int>(stack_.size()) - 1; |  | 
| 375     DCHECK_GE(pos, 0); |  | 
| 376     DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]); |  | 
| 377     state_[stack_[pos]->id()] = kVisited; |  | 
| 378     stack_.pop_back(); |  | 
| 379   } |  | 
| 380 |  | 
| 381   // Queue a node to be revisited if it has been visited once already. |  | 
| 382   void Revisit(Node* node) { |  | 
| 383     size_t id = static_cast<size_t>(node->id()); |  | 
| 384     if (id < state_.size() && state_[id] == kVisited) { |  | 
| 385       TRACE("  Revisit #%d:%s\n", node->id(), node->op()->mnemonic()); |  | 
| 386       state_[id] = kRevisit; |  | 
| 387       revisit_.push_back(node); |  | 
| 388     } |  | 
| 389   } |  | 
| 390 |  | 
| 391   // Mark {node} as visited. |  | 
| 392   void MarkAsVisited(Node* node) { |  | 
| 393     size_t id = static_cast<size_t>(node->id()); |  | 
| 394     EnsureStateSize(id); |  | 
| 395     state_[id] = kVisited; |  | 
| 396   } |  | 
| 397 |  | 
| 398   Node* dead() { return jsgraph_->DeadControl(); } |  | 
| 399 |  | 
| 400   //=========================================================================== | 283   //=========================================================================== | 
| 401   // Reducer implementation: perform reductions on a node. | 284   // Reducer implementation: perform reductions on a node. | 
| 402   //=========================================================================== | 285   //=========================================================================== | 
| 403   Node* ReduceNode(Node* node) { | 286   Reduction Reduce(Node* node) override { | 
| 404     if (node->op()->ControlInputCount() == 1 || | 287     if (node->op()->ControlInputCount() == 1 || | 
| 405         node->opcode() == IrOpcode::kLoop) { | 288         node->opcode() == IrOpcode::kLoop) { | 
| 406       // If a node has only one control input and it is dead, replace with dead. | 289       // If a node has only one control input and it is dead, replace with dead. | 
| 407       Node* control = NodeProperties::GetControlInput(node); | 290       Node* control = NodeProperties::GetControlInput(node); | 
| 408       if (control->opcode() == IrOpcode::kDead) { | 291       if (control->opcode() == IrOpcode::kDead) { | 
| 409         TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); | 292         TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); | 
| 410         return control; | 293         return Replace(control); | 
| 411       } | 294       } | 
| 412     } | 295     } | 
| 413 | 296 | 
|  | 297     Node* result = node; | 
| 414     // Reduce branches, phis, and merges. | 298     // Reduce branches, phis, and merges. | 
| 415     switch (node->opcode()) { | 299     switch (node->opcode()) { | 
| 416       case IrOpcode::kBranch: | 300       case IrOpcode::kBranch: | 
| 417         return ReduceBranch(node); | 301         result = ReduceBranch(node); | 
|  | 302         break; | 
| 418       case IrOpcode::kIfTrue: | 303       case IrOpcode::kIfTrue: | 
| 419         return ReduceIfProjection(node, kTrue); | 304         result = ReduceIfProjection(node, kTrue); | 
|  | 305         break; | 
| 420       case IrOpcode::kIfFalse: | 306       case IrOpcode::kIfFalse: | 
| 421         return ReduceIfProjection(node, kFalse); | 307         result = ReduceIfProjection(node, kFalse); | 
| 422       case IrOpcode::kLoop: | 308         break; | 
|  | 309       case IrOpcode::kLoop:  // fallthrough | 
| 423       case IrOpcode::kMerge: | 310       case IrOpcode::kMerge: | 
| 424         return ReduceMerge(node); | 311         result = ReduceMerge(node); | 
|  | 312         break; | 
| 425       case IrOpcode::kSelect: | 313       case IrOpcode::kSelect: | 
| 426         return ReduceSelect(node); | 314         result = ReduceSelect(node); | 
|  | 315         break; | 
| 427       case IrOpcode::kPhi: | 316       case IrOpcode::kPhi: | 
| 428       case IrOpcode::kEffectPhi: | 317       case IrOpcode::kEffectPhi: | 
| 429         return ReducePhi(node); | 318         result = ReducePhi(node); | 
|  | 319         break; | 
| 430       default: | 320       default: | 
| 431         return node; | 321         break; | 
| 432     } | 322     } | 
|  | 323 | 
|  | 324     return result == node ? NoChange() : Replace(result); | 
| 433   } | 325   } | 
| 434 | 326 | 
| 435   // Try to statically fold a condition. | 327   // Try to statically fold a condition. | 
| 436   Decision DecideCondition(Node* cond, bool recurse = true) { | 328   Decision DecideCondition(Node* cond, bool recurse = true) { | 
| 437     switch (cond->opcode()) { | 329     switch (cond->opcode()) { | 
| 438       case IrOpcode::kInt32Constant: | 330       case IrOpcode::kInt32Constant: | 
| 439         return Int32Matcher(cond).Is(0) ? kFalse : kTrue; | 331         return Int32Matcher(cond).Is(0) ? kFalse : kTrue; | 
| 440       case IrOpcode::kInt64Constant: | 332       case IrOpcode::kInt64Constant: | 
| 441         return Int64Matcher(cond).Is(0) ? kFalse : kTrue; | 333         return Int64Matcher(cond).Is(0) ? kFalse : kTrue; | 
| 442       case IrOpcode::kNumberConstant: | 334       case IrOpcode::kNumberConstant: | 
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 536     if (live == 0) return dead();  // no remaining inputs. | 428     if (live == 0) return dead();  // no remaining inputs. | 
| 537 | 429 | 
| 538     // Gather phis and effect phis to be edited. | 430     // Gather phis and effect phis to be edited. | 
| 539     NodeVector phis(zone_); | 431     NodeVector phis(zone_); | 
| 540     for (Node* const use : node->uses()) { | 432     for (Node* const use : node->uses()) { | 
| 541       if (NodeProperties::IsPhi(use)) phis.push_back(use); | 433       if (NodeProperties::IsPhi(use)) phis.push_back(use); | 
| 542     } | 434     } | 
| 543 | 435 | 
| 544     if (live == 1) { | 436     if (live == 1) { | 
| 545       // All phis are redundant. Replace them with their live input. | 437       // All phis are redundant. Replace them with their live input. | 
| 546       for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index)); | 438       for (Node* const phi : phis) { | 
|  | 439         Replace(phi, phi->InputAt(live_index)); | 
|  | 440       } | 
| 547       // The merge itself is redundant. | 441       // The merge itself is redundant. | 
| 548       return node->InputAt(live_index); | 442       return node->InputAt(live_index); | 
| 549     } | 443     } | 
| 550 | 444 | 
| 551     DCHECK_LE(2, live); | 445     DCHECK_LE(2, live); | 
| 552 | 446 | 
| 553     if (live < node->InputCount()) { | 447     if (live < node->InputCount()) { | 
| 554       // Edit phis in place, removing dead inputs and revisiting them. | 448       // Edit phis in place, removing dead inputs and revisiting them. | 
| 555       for (Node* const phi : phis) { | 449       for (Node* const phi : phis) { | 
| 556         TRACE("  PhiInMerge: #%d:%s (%d live)\n", phi->id(), | 450         TRACE("  PhiInMerge: #%d:%s (%d live)\n", phi->id(), | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 576           // No phis. Remove the branch altogether. | 470           // No phis. Remove the branch altogether. | 
| 577           TRACE("  DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", | 471           TRACE("  DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", | 
| 578                 matcher.Branch()->id(), matcher.IfTrue()->id(), | 472                 matcher.Branch()->id(), matcher.IfTrue()->id(), | 
| 579                 matcher.IfFalse()->id()); | 473                 matcher.IfFalse()->id()); | 
| 580           return control; | 474           return control; | 
| 581         } else { | 475         } else { | 
| 582           // A small number of phis. Replace with selects. | 476           // A small number of phis. Replace with selects. | 
| 583           Node* cond = matcher.Branch()->InputAt(0); | 477           Node* cond = matcher.Branch()->InputAt(0); | 
| 584           for (Node* phi : phis) { | 478           for (Node* phi : phis) { | 
| 585             Node* select = graph()->NewNode( | 479             Node* select = graph()->NewNode( | 
| 586                 common_->Select(OpParameter<MachineType>(phi), | 480                 common()->Select(OpParameter<MachineType>(phi), | 
| 587                                 BranchHintOf(matcher.Branch()->op())), | 481                                  BranchHintOf(matcher.Branch()->op())), | 
| 588                 cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi)); | 482                 cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi)); | 
| 589             TRACE("  MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n", | 483             TRACE("  MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n", | 
| 590                   matcher.Branch()->id(), matcher.IfTrue()->id(), | 484                   matcher.Branch()->id(), matcher.IfTrue()->id(), | 
| 591                   matcher.IfFalse()->id(), select->id()); | 485                   matcher.IfFalse()->id(), select->id()); | 
| 592             ReplaceNode(phi, select); | 486             Replace(phi, select); | 
| 593           } | 487           } | 
| 594           return control; | 488           return control; | 
| 595         } | 489         } | 
| 596       } | 490       } | 
| 597     } | 491     } | 
| 598 | 492 | 
| 599     return node; | 493     return node; | 
| 600   } | 494   } | 
| 601 | 495 | 
| 602   bool CheckPhisForSelect(const NodeVector& phis) { | 496   bool CheckPhisForSelect(const NodeVector& phis) { | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 634     } | 528     } | 
| 635     // compact remaining inputs. | 529     // compact remaining inputs. | 
| 636     int total = live; | 530     int total = live; | 
| 637     for (int i = merge->InputCount(); i < node->InputCount(); i++) { | 531     for (int i = merge->InputCount(); i < node->InputCount(); i++) { | 
| 638       if (total != i) node->ReplaceInput(total, node->InputAt(i)); | 532       if (total != i) node->ReplaceInput(total, node->InputAt(i)); | 
| 639       total++; | 533       total++; | 
| 640     } | 534     } | 
| 641     DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); | 535     DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); | 
| 642     DCHECK_NE(total, node->InputCount()); | 536     DCHECK_NE(total, node->InputCount()); | 
| 643     node->TrimInputCount(total); | 537     node->TrimInputCount(total); | 
| 644     node->set_op(common_->ResizeMergeOrPhi(node->op(), live)); | 538     node->set_op(common()->ResizeMergeOrPhi(node->op(), live)); | 
| 645   } | 539   } | 
| 646 |  | 
| 647   // Replace uses of {node} with {replacement} and revisit the uses. |  | 
| 648   void ReplaceNode(Node* node, Node* replacement) { |  | 
| 649     if (node == replacement) return; |  | 
| 650     TRACE("  Replace: #%d:%s with #%d:%s\n", node->id(), node->op()->mnemonic(), |  | 
| 651           replacement->id(), replacement->op()->mnemonic()); |  | 
| 652     for (Node* const use : node->uses()) { |  | 
| 653       // Don't revisit this node if it refers to itself. |  | 
| 654       if (use != node) Revisit(use); |  | 
| 655     } |  | 
| 656     node->ReplaceUses(replacement); |  | 
| 657     node->Kill(); |  | 
| 658   } |  | 
| 659 |  | 
| 660   Graph* graph() { return jsgraph_->graph(); } |  | 
| 661 }; | 540 }; | 
| 662 | 541 | 
| 663 | 542 | 
| 664 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, | 543 void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, | 
| 665                                  CommonOperatorBuilder* common, |  | 
| 666                                  int max_phis_for_select) { | 544                                  int max_phis_for_select) { | 
| 667   ControlReducerImpl impl(zone, jsgraph, common); | 545   GraphReducer graph_reducer(jsgraph->graph(), zone); | 
|  | 546   ControlReducerImpl impl(zone, jsgraph); | 
| 668   impl.max_phis_for_select_ = max_phis_for_select; | 547   impl.max_phis_for_select_ = max_phis_for_select; | 
| 669   impl.Reduce(); | 548   graph_reducer.AddReducer(&impl); | 
|  | 549   graph_reducer.ReduceGraph(); | 
| 670 } | 550 } | 
| 671 | 551 | 
| 672 | 552 | 
| 673 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { | 553 void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) { | 
| 674   ControlReducerImpl impl(zone, jsgraph, NULL); | 554   ControlReducerImpl impl(zone, jsgraph); | 
| 675   impl.Trim(); | 555   impl.Trim(); | 
| 676 } | 556 } | 
| 677 | 557 | 
| 678 | 558 | 
| 679 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, | 559 namespace { | 
| 680                                   CommonOperatorBuilder* common, Node* node, | 560 | 
|  | 561 class DummyObserver final : public Reducer::Observer { | 
|  | 562  public: | 
|  | 563   void Replace(Node* node, Node* replacement) final { | 
|  | 564     node->ReplaceUses(replacement); | 
|  | 565   } | 
|  | 566   void Revisit(Node* node) final {} | 
|  | 567 }; | 
|  | 568 | 
|  | 569 }  // namespace | 
|  | 570 | 
|  | 571 | 
|  | 572 Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node, | 
| 681                                   int max_phis_for_select) { | 573                                   int max_phis_for_select) { | 
| 682   Zone zone; | 574   Zone zone; | 
| 683   ControlReducerImpl impl(&zone, jsgraph, common); | 575   DummyObserver observer; | 
|  | 576   ControlReducerImpl impl(&zone, jsgraph); | 
| 684   impl.max_phis_for_select_ = max_phis_for_select; | 577   impl.max_phis_for_select_ = max_phis_for_select; | 
|  | 578   impl.set_observer(&observer); | 
| 685   return impl.ReduceMerge(node); | 579   return impl.ReduceMerge(node); | 
| 686 } | 580 } | 
| 687 | 581 | 
| 688 | 582 | 
| 689 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, | 583 Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, Node* node) { | 
| 690                                           CommonOperatorBuilder* common, |  | 
| 691                                           Node* node) { |  | 
| 692   Zone zone; | 584   Zone zone; | 
| 693   ControlReducerImpl impl(&zone, jsgraph, common); | 585   DummyObserver observer; | 
|  | 586   ControlReducerImpl impl(&zone, jsgraph); | 
|  | 587   impl.set_observer(&observer); | 
| 694   return impl.ReducePhi(node); | 588   return impl.ReducePhi(node); | 
| 695 } | 589 } | 
| 696 | 590 | 
| 697 | 591 | 
| 698 Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph, | 592 Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph, Node* node) { | 
| 699                                              CommonOperatorBuilder* common, |  | 
| 700                                              Node* node) { |  | 
| 701   Zone zone; | 593   Zone zone; | 
| 702   ControlReducerImpl impl(&zone, jsgraph, common); | 594   DummyObserver observer; | 
|  | 595   ControlReducerImpl impl(&zone, jsgraph); | 
|  | 596   impl.set_observer(&observer); | 
| 703   switch (node->opcode()) { | 597   switch (node->opcode()) { | 
| 704     case IrOpcode::kIfTrue: | 598     case IrOpcode::kIfTrue: | 
| 705       return impl.ReduceIfProjection(node, kTrue); | 599       return impl.ReduceIfProjection(node, kTrue); | 
| 706     case IrOpcode::kIfFalse: | 600     case IrOpcode::kIfFalse: | 
| 707       return impl.ReduceIfProjection(node, kFalse); | 601       return impl.ReduceIfProjection(node, kFalse); | 
| 708     default: | 602     default: | 
| 709       return node; | 603       return node; | 
| 710   } | 604   } | 
| 711 } | 605 } | 
| 712 } | 606 | 
| 713 } | 607 }  // namespace compiler | 
| 714 }  // namespace v8::internal::compiler | 608 }  // namespace internal | 
|  | 609 }  // namespace v8 | 
| OLD | NEW | 
|---|