LCOV - code coverage report
Current view: top level - src/compiler - graph-reducer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 108 115 93.9 %
Date: 2017-10-20 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    22230902 : void Reducer::Finalize() {}
      27             : 
      28     4023680 : 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     8047360 :       stack_(zone) {
      35     4023689 :   if (dead != nullptr) {
      36     3558538 :     NodeProperties::SetType(dead_, Type::None());
      37             :   }
      38     4023689 : }
      39             : 
      40     8047366 : GraphReducer::~GraphReducer() {}
      41             : 
      42             : 
      43    17781770 : void GraphReducer::AddReducer(Reducer* reducer) {
      44    17781770 :   reducers_.push_back(reducer);
      45    17781771 : }
      46             : 
      47             : 
      48     9485913 : void GraphReducer::ReduceNode(Node* node) {
      49             :   DCHECK(stack_.empty());
      50             :   DCHECK(revisit_.empty());
      51     9485913 :   Push(node);
      52             :   for (;;) {
      53   660164734 :     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   638088552 :       ReduceTop();
      57    22076182 :     } else if (!revisit_.empty()) {
      58             :       // If the stack becomes empty, revisit any nodes in the revisit queue.
      59    12539477 :       Node* const node = revisit_.front();
      60             :       revisit_.pop();
      61    12539370 :       if (state_.Get(node) == State::kRevisit) {
      62             :         // state can change while in queue.
      63     8825765 :         Push(node);
      64             :       }
      65             :     } else {
      66             :       // Run all finalizers.
      67    42734537 :       for (Reducer* const reducer : reducers_) reducer->Finalize();
      68             : 
      69             :       // Check if we have new nodes to revisit.
      70     9536727 :       if (revisit_.empty()) break;
      71             :     }
      72             :   }
      73             :   DCHECK(revisit_.empty());
      74             :   DCHECK(stack_.empty());
      75     9485912 : }
      76             : 
      77             : 
      78     4002349 : void GraphReducer::ReduceGraph() { ReduceNode(graph()->end()); }
      79             : 
      80             : 
      81   331567149 : Reduction GraphReducer::Reduce(Node* const node) {
      82             :   auto skip = reducers_.end();
      83  2263284222 :   for (auto i = reducers_.begin(); i != reducers_.end();) {
      84  1606878745 :     if (i != skip) {
      85  1530935318 :       Reduction reduction = (*i)->Reduce(node);
      86  1531199823 :       if (!reduction.Changed()) {
      87             :         // No change from this reducer.
      88    82877552 :       } 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    75884226 :         if (FLAG_trace_turbo_reduction) {
      93           0 :           OFStream os(stdout);
      94           0 :           os << "- In-place update of " << *node << " by reducer "
      95           0 :              << (*i)->reducer_name() << std::endl;
      96             :         }
      97             :         skip = i;
      98             :         i = reducers_.begin();
      99             :         continue;
     100             :       } else {
     101             :         // {node} was replaced by another node.
     102     6993326 :         if (FLAG_trace_turbo_reduction) {
     103           0 :           OFStream os(stdout);
     104           0 :           os << "- Replacement of " << *node << " with "
     105           0 :              << *(reduction.replacement()) << " by reducer "
     106           0 :              << (*i)->reducer_name() << std::endl;
     107             :         }
     108     6993326 :         return reduction;
     109             :       }
     110             :     }
     111             :     ++i;
     112             :   }
     113   324838328 :   if (skip == reducers_.end()) {
     114             :     // No change from any reducer.
     115             :     return Reducer::NoChange();
     116             :   }
     117             :   // At least one reducer did some in-place reduction.
     118             :   return Reducer::Changed(node);
     119             : }
     120             : 
     121             : 
     122   969231772 : void GraphReducer::ReduceTop() {
     123             :   NodeState& entry = stack_.top();
     124   637566617 :   Node* node = entry.node;
     125             :   DCHECK_EQ(State::kOnStack, state_.Get(node));
     126             : 
     127   637566617 :   if (node->IsDead()) return Pop();  // Node was killed while on stack.
     128             : 
     129             :   Node::Inputs node_inputs = node->inputs();
     130             : 
     131             :   // Recurse on an input if necessary.
     132   637007264 :   int start = entry.input_index < node_inputs.count() ? entry.input_index : 0;
     133  1419299333 :   for (int i = start; i < node_inputs.count(); ++i) {
     134             :     Node* input = node_inputs[i];
     135  1087496259 :     if (input != node && Recurse(input)) {
     136   305834576 :       entry.input_index = i + 1;
     137   305834576 :       return;
     138             :     }
     139             :   }
     140   312454794 :   for (int i = 0; i < start; ++i) {
     141             :     Node* input = node_inputs[i];
     142   312592713 :     if (input != node && Recurse(input)) {
     143      151157 :       entry.input_index = i + 1;
     144      151157 :       return;
     145             :     }
     146             :   }
     147             : 
     148             :   // Remember the max node id before reduction.
     149   331665155 :   NodeId const max_id = static_cast<NodeId>(graph()->NodeCount() - 1);
     150             : 
     151             :   // All inputs should be visited or on stack. Apply reductions to node.
     152   331665155 :   Reduction reduction = Reduce(node);
     153             : 
     154             :   // If there was no reduction, pop {node} and continue.
     155   331827119 :   if (!reduction.Changed()) return Pop();
     156             : 
     157             :   // Check if the reduction is an in-place update of the {node}.
     158             :   Node* const replacement = reduction.replacement();
     159    69278336 :   if (replacement == node) {
     160             :     // In-place update of {node}, may need to recurse on an input.
     161             :     Node::Inputs node_inputs = node->inputs();
     162   279951602 :     for (int i = 0; i < node_inputs.count(); ++i) {
     163             :       Node* input = node_inputs[i];
     164   220969171 :       if (input != node && Recurse(input)) {
     165     3305418 :         entry.input_index = i + 1;
     166             :         return;
     167             :       }
     168             :     }
     169             :   }
     170             : 
     171             :   // After reducing the node, pop it off the stack.
     172    65986288 :   Pop();
     173             : 
     174             :   // Check if we have a new replacement.
     175    65975711 :   if (replacement != node) {
     176     6993313 :     Replace(node, replacement, max_id);
     177             :   } else {
     178             :     // Revisit all uses of the node.
     179   266182018 :     for (Node* const user : node->uses()) {
     180             :       // Don't revisit this node if it refers to itself.
     181   207198172 :       if (user != node) Revisit(user);
     182             :     }
     183             :   }
     184             : }
     185             : 
     186             : 
     187     1562512 : void GraphReducer::Replace(Node* node, Node* replacement) {
     188     1620982 :   Replace(node, replacement, std::numeric_limits<NodeId>::max());
     189     1562511 : }
     190             : 
     191             : 
     192    25842678 : void GraphReducer::Replace(Node* node, Node* replacement, NodeId max_id) {
     193     8614226 :   if (node == graph()->start()) graph()->SetStart(replacement);
     194     8614226 :   if (node == graph()->end()) graph()->SetEnd(replacement);
     195     8614226 :   if (replacement->id() <= max_id) {
     196             :     // {replacement} is an old node, so unlink {node} and assume that
     197             :     // {replacement} was already reduced and finish.
     198    28907959 :     for (Edge edge : node->use_edges()) {
     199             :       Node* const user = edge.from();
     200             :       Verifier::VerifyEdgeInputReplacement(edge, replacement);
     201    10920468 :       edge.UpdateTo(replacement);
     202             :       // Don't revisit this node if it refers to itself.
     203    10920470 :       if (user != node) Revisit(user);
     204             :     }
     205     7067023 :     node->Kill();
     206             :   } else {
     207             :     // Replace all old uses of {node} with {replacement}, but allow new nodes
     208             :     // created by this reduction to use {node}.
     209    15072358 :     for (Edge edge : node->use_edges()) {
     210     6762572 :       Node* const user = edge.from();
     211     6762572 :       if (user->id() <= max_id) {
     212     6762575 :         edge.UpdateTo(replacement);
     213             :         // Don't revisit this node if it refers to itself.
     214     6762579 :         if (user != node) Revisit(user);
     215             :       }
     216             :     }
     217             :     // Unlink {node} if it's no longer used.
     218     1547214 :     if (node->uses().empty()) node->Kill();
     219             : 
     220             :     // If there was a replacement, reduce it after popping {node}.
     221     1547210 :     Recurse(replacement);
     222             :   }
     223     8614246 : }
     224             : 
     225             : 
     226     4923410 : void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
     227             :                                     Node* control) {
     228     4639607 :   if (effect == nullptr && node->op()->EffectInputCount() > 0) {
     229      996893 :     effect = NodeProperties::GetEffectInput(node);
     230             :   }
     231     5207086 :   if (control == nullptr && node->op()->ControlInputCount() > 0) {
     232     1190551 :     control = NodeProperties::GetControlInput(node);
     233             :   }
     234             : 
     235             :   // Requires distinguishing between value, effect and control edges.
     236    23602231 :   for (Edge edge : node->use_edges()) {
     237     2436908 :     Node* const user = edge.from();
     238             :     DCHECK(!user->IsDead());
     239    10617155 :     if (NodeProperties::IsControlEdge(edge)) {
     240     2436908 :       if (user->opcode() == IrOpcode::kIfSuccess) {
     241             :         Replace(user, control);
     242     2378438 :       } else if (user->opcode() == IrOpcode::kIfException) {
     243             :         DCHECK_NOT_NULL(dead_);
     244       58254 :         edge.UpdateTo(dead_);
     245       58254 :         Revisit(user);
     246             :       } else {
     247             :         DCHECK_NOT_NULL(control);
     248     2320184 :         edge.UpdateTo(control);
     249     2320184 :         Revisit(user);
     250             :       }
     251     8180234 :     } else if (NodeProperties::IsEffectEdge(edge)) {
     252             :       DCHECK_NOT_NULL(effect);
     253     2550940 :       edge.UpdateTo(effect);
     254     2551011 :       Revisit(user);
     255             :     } else {
     256             :       DCHECK_NOT_NULL(value);
     257     5629559 :       edge.UpdateTo(value);
     258     5629606 :       Revisit(user);
     259             :     }
     260             :   }
     261     2367921 : }
     262             : 
     263             : 
     264   328998442 : void GraphReducer::Pop() {
     265   328998442 :   Node* node = stack_.top().node;
     266             :   state_.Set(node, State::kVisited);
     267             :   stack_.pop();
     268   329012411 : }
     269             : 
     270             : 
     271   329035146 : void GraphReducer::Push(Node* const node) {
     272             :   DCHECK_NE(State::kOnStack, state_.Get(node));
     273             :   state_.Set(node, State::kOnStack);
     274   658179808 :   stack_.push({node, 0});
     275   329147173 : }
     276             : 
     277             : 
     278  1621996737 : bool GraphReducer::Recurse(Node* node) {
     279  1621986439 :   if (state_.Get(node) > State::kRevisit) return false;
     280   310768535 :   Push(node);
     281   310841551 :   return true;
     282             : }
     283             : 
     284             : 
     285   235831608 : void GraphReducer::Revisit(Node* node) {
     286   471662647 :   if (state_.Get(node) == State::kVisited) {
     287             :     state_.Set(node, State::kRevisit);
     288             :     revisit_.push(node);
     289             :   }
     290   235831023 : }
     291             : 
     292             : }  // namespace compiler
     293             : }  // namespace internal
     294             : }  // namespace v8

Generated by: LCOV version 1.10