LCOV - code coverage report
Current view: top level - src/compiler - graph-reducer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 108 112 96.4 %
Date: 2017-04-26 Functions: 15 16 93.8 %

          Line data    Source code
       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.
       4             : 
       5             : #include <functional>
       6             : #include <limits>
       7             : 
       8             : #include "src/compiler/graph.h"
       9             : #include "src/compiler/graph-reducer.h"
      10             : #include "src/compiler/node.h"
      11             : #include "src/compiler/node-properties.h"
      12             : #include "src/compiler/verifier.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace compiler {
      17             : 
      18             : enum class GraphReducer::State : uint8_t {
      19             :   kUnvisited,
      20             :   kRevisit,
      21             :   kOnStack,
      22             :   kVisited
      23             : };
      24             : 
      25             : 
      26    20915635 : void Reducer::Finalize() {}
      27             : 
      28     3296096 : GraphReducer::GraphReducer(Zone* zone, Graph* graph, Node* dead)
      29             :     : graph_(graph),
      30             :       dead_(dead),
      31             :       state_(graph, 4),
      32             :       reducers_(zone),
      33             :       revisit_(zone),
      34     6592179 :       stack_(zone) {
      35     3296162 :   if (dead != nullptr) {
      36     2870377 :     NodeProperties::SetType(dead_, Type::None());
      37             :   }
      38     3296162 : }
      39             : 
      40     6592210 : GraphReducer::~GraphReducer() {}
      41             : 
      42             : 
      43    16096936 : void GraphReducer::AddReducer(Reducer* reducer) {
      44    16096936 :   reducers_.push_back(reducer);
      45    16096841 : }
      46             : 
      47             : 
      48     8290612 : void GraphReducer::ReduceNode(Node* node) {
      49             :   DCHECK(stack_.empty());
      50             :   DCHECK(revisit_.empty());
      51     8290612 :   Push(node);
      52             :   for (;;) {
      53   617249347 :     if (!stack_.empty()) {
      54             :       // Process the node on the top of the stack, potentially pushing more or
      55             :       // popping the node off the stack.
      56   593366923 :       ReduceTop();
      57    23882424 :     } else if (!revisit_.empty()) {
      58             :       // If the stack becomes empty, revisit any nodes in the revisit queue.
      59    15557695 :       Node* const node = revisit_.top();
      60             :       revisit_.pop();
      61    15557121 :       if (state_.Get(node) == State::kRevisit) {
      62             :         // state can change while in queue.
      63    12377883 :         Push(node);
      64             :       }
      65             :     } else {
      66             :       // Run all finalizers.
      67    38033538 :       for (Reducer* const reducer : reducers_) reducer->Finalize();
      68             : 
      69             :       // Check if we have new nodes to revisit.
      70     8324727 :       if (revisit_.empty()) break;
      71             :     }
      72             :   }
      73             :   DCHECK(revisit_.empty());
      74             :   DCHECK(stack_.empty());
      75     8290730 : }
      76             : 
      77             : 
      78     3271402 : void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); }
      79             : 
      80             : 
      81   309862710 : Reduction GraphReducer::Reduce(Node* const node) {
      82             :   auto skip = reducers_.end();
      83  2236248148 :   for (auto i = reducers_.begin(); i != reducers_.end();) {
      84  1624049089 :     if (i != skip) {
      85  1551368248 :       Reduction reduction = (*i)->Reduce(node);
      86  1551573028 :       if (!reduction.Changed()) {
      87             :         // No change from this reducer.
      88    80316276 :       } else if (reduction.replacement() == node) {
      89             :         // {replacement} == {node} represents an in-place reduction. Rerun
      90             :         // all the other reducers for this node, as now there may be more
      91             :         // opportunities for reduction.
      92             :         skip = i;
      93             :         i = reducers_.begin();
      94             :         continue;
      95             :       } else {
      96             :         // {node} was replaced by another node.
      97     7731141 :         return reduction;
      98             :       }
      99             :     }
     100             :     ++i;
     101             :   }
     102   302336349 :   if (skip == reducers_.end()) {
     103             :     // No change from any reducer.
     104             :     return Reducer::NoChange();
     105             :   }
     106             :   // At least one reducer did some in-place reduction.
     107             :   return Reducer::Changed(node);
     108             : }
     109             : 
     110             : 
     111   903518626 : void GraphReducer::ReduceTop() {
     112             :   NodeState& entry = stack_.top();
     113   593496020 :   Node* node = entry.node;
     114             :   DCHECK(state_.Get(node) == State::kOnStack);
     115             : 
     116   593496020 :   if (node->IsDead()) return Pop();  // Node was killed while on stack.
     117             : 
     118             :   Node::Inputs node_inputs = node->inputs();
     119             : 
     120             :   // Recurse on an input if necessary.
     121   592863938 :   int start = entry.input_index < node_inputs.count() ? entry.input_index : 0;
     122  1318160397 :   for (int i = start; i < node_inputs.count(); ++i) {
     123             :     Node* input = node_inputs[i];
     124  1007985600 :     if (input != node && Recurse(input)) {
     125   282843518 :       entry.input_index = i + 1;
     126   282843518 :       return;
     127             :     }
     128             :   }
     129   292413647 :   for (int i = 0; i < start; ++i) {
     130             :     Node* input = node_inputs[i];
     131   292565838 :     if (input != node && Recurse(input)) {
     132      147420 :       entry.input_index = i + 1;
     133      147420 :       return;
     134             :     }
     135             :   }
     136             : 
     137             :   // Remember the max node id before reduction.
     138   310022606 :   NodeId const max_id = static_cast<NodeId>(graph()->NodeCount() - 1);
     139             : 
     140             :   // All inputs should be visited or on stack. Apply reductions to node.
     141   310022606 :   Reduction reduction = Reduce(node);
     142             : 
     143             :   // If there was no reduction, pop {node} and continue.
     144   310062789 :   if (!reduction.Changed()) return Pop();
     145             : 
     146             :   // Check if the reduction is an in-place update of the {node}.
     147             :   Node* const replacement = reduction.replacement();
     148    68379923 :   if (replacement == node) {
     149    60664629 :     if (FLAG_trace_turbo_reduction) {
     150           0 :       OFStream os(stdout);
     151           0 :       os << "- In-place update of " << *replacement << std::endl;
     152             :     }
     153             :     // In-place update of {node}, may need to recurse on an input.
     154             :     Node::Inputs node_inputs = node->inputs();
     155   267266589 :     for (int i = 0; i < node_inputs.count(); ++i) {
     156             :       Node* input = node_inputs[i];
     157   209299809 :       if (input != node && Recurse(input)) {
     158     2686213 :         entry.input_index = i + 1;
     159             :         return;
     160             :       }
     161             :     }
     162             :   }
     163             : 
     164             :   // After reducing the node, pop it off the stack.
     165    65682074 :   Pop();
     166             : 
     167             :   // Check if we have a new replacement.
     168    65698030 :   if (replacement != node) {
     169     7731124 :     Replace(node, replacement, max_id);
     170             :   } else {
     171             :     // Revisit all uses of the node.
     172   245440810 :     for (Node* const user : node->uses()) {
     173             :       // Don't revisit this node if it refers to itself.
     174   187476786 :       if (user != node) Revisit(user);
     175             :     }
     176             :   }
     177             : }
     178             : 
     179             : 
     180     1957736 : void GraphReducer::Replace(Node* node, Node* replacement) {
     181     2054661 :   Replace(node, replacement, std::numeric_limits<NodeId>::max());
     182     1957741 : }
     183             : 
     184             : 
     185    39143100 : void GraphReducer::Replace(Node* node, Node* replacement, NodeId max_id) {
     186     9785775 :   if (FLAG_trace_turbo_reduction) {
     187           0 :     OFStream os(stdout);
     188           0 :     os << "- Replacing " << *node << " with " << *replacement << std::endl;
     189             :   }
     190     9785775 :   if (node == graph()->start()) graph()->SetStart(replacement);
     191     9785775 :   if (node == graph()->end()) graph()->SetEnd(replacement);
     192     9785775 :   if (replacement->id() <= max_id) {
     193             :     // {replacement} is an old node, so unlink {node} and assume that
     194             :     // {replacement} was already reduced and finish.
     195    36193953 :     for (Edge edge : node->use_edges()) {
     196             :       Node* const user = edge.from();
     197             :       Verifier::VerifyEdgeInputReplacement(edge, replacement);
     198    14079628 :       edge.UpdateTo(replacement);
     199             :       // Don't revisit this node if it refers to itself.
     200    14079626 :       if (user != node) Revisit(user);
     201             :     }
     202     8034697 :     node->Kill();
     203             :   } else {
     204             :     // Replace all old uses of {node} with {replacement}, but allow new nodes
     205             :     // created by this reduction to use {node}.
     206    13568544 :     for (Edge edge : node->use_edges()) {
     207     5908737 :       Node* const user = edge.from();
     208     5908737 :       if (user->id() <= max_id) {
     209     5908735 :         edge.UpdateTo(replacement);
     210             :         // Don't revisit this node if it refers to itself.
     211     5908735 :         if (user != node) Revisit(user);
     212             :       }
     213             :     }
     214             :     // Unlink {node} if it's no longer used.
     215     1751070 :     if (node->uses().empty()) node->Kill();
     216             : 
     217             :     // If there was a replacement, reduce it after popping {node}.
     218     1751072 :     Recurse(replacement);
     219             :   }
     220     9785889 : }
     221             : 
     222             : 
     223     4798136 : void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
     224             :                                     Node* control) {
     225     4527938 :   if (effect == nullptr && node->op()->EffectInputCount() > 0) {
     226     1014226 :     effect = NodeProperties::GetEffectInput(node);
     227             :   }
     228     5068257 :   if (control == nullptr && node->op()->ControlInputCount() > 0) {
     229     1183452 :     control = NodeProperties::GetControlInput(node);
     230             :   }
     231             : 
     232             :   // Requires distinguishing between value, effect and control edges.
     233    23501183 :   for (Edge edge : node->use_edges()) {
     234     2235113 :     Node* const user = edge.from();
     235             :     DCHECK(!user->IsDead());
     236    10639216 :     if (NodeProperties::IsControlEdge(edge)) {
     237     2235113 :       if (user->opcode() == IrOpcode::kIfSuccess) {
     238             :         Replace(user, control);
     239     2138188 :       } else if (user->opcode() == IrOpcode::kIfException) {
     240             :         DCHECK_NOT_NULL(dead_);
     241       96641 :         edge.UpdateTo(dead_);
     242       96641 :         Revisit(user);
     243             :       } else {
     244             :         DCHECK_NOT_NULL(control);
     245     2041547 :         edge.UpdateTo(control);
     246     2041547 :         Revisit(user);
     247             :         // TODO(jarin) Check that the node cannot throw (otherwise, it
     248             :         // would have to be connected via IfSuccess/IfException).
     249             :       }
     250     8404108 :     } else if (NodeProperties::IsEffectEdge(edge)) {
     251             :       DCHECK_NOT_NULL(effect);
     252     2551576 :       edge.UpdateTo(effect);
     253     2551624 :       Revisit(user);
     254             :     } else {
     255             :       DCHECK_NOT_NULL(value);
     256     5852703 :       edge.UpdateTo(value);
     257     5852732 :       Revisit(user);
     258             :     }
     259             :   }
     260     2222751 : }
     261             : 
     262             : 
     263   307924638 : void GraphReducer::Pop() {
     264   307924638 :   Node* node = stack_.top().node;
     265             :   state_.Set(node, State::kVisited);
     266             :   stack_.pop();
     267   307936484 : }
     268             : 
     269             : 
     270   307975167 : void GraphReducer::Push(Node* const node) {
     271             :   DCHECK(state_.Get(node) != State::kOnStack);
     272             :   state_.Set(node, State::kOnStack);
     273   616061095 :   stack_.push({node, 0});
     274   308086429 : }
     275             : 
     276             : 
     277  1510398087 : bool GraphReducer::Recurse(Node* node) {
     278  1510410117 :   if (state_.Get(node) > State::kRevisit) return false;
     279   287365412 :   Push(node);
     280   287427944 :   return true;
     281             : }
     282             : 
     283             : 
     284   218512762 : void GraphReducer::Revisit(Node* node) {
     285   437025524 :   if (state_.Get(node) == State::kVisited) {
     286             :     state_.Set(node, State::kRevisit);
     287             :     revisit_.push(node);
     288             :   }
     289   218512256 : }
     290             : 
     291             : }  // namespace compiler
     292             : }  // namespace internal
     293             : }  // namespace v8

Generated by: LCOV version 1.10