LCOV - code coverage report
Current view: top level - src/compiler - loop-variable-optimizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 156 168 92.9 %
Date: 2017-10-20 Functions: 17 20 85.0 %

          Line data    Source code
       1             : // Copyright 2016 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 "src/compiler/loop-variable-optimizer.h"
       6             : 
       7             : #include "src/compiler/common-operator.h"
       8             : #include "src/compiler/graph.h"
       9             : #include "src/compiler/node-marker.h"
      10             : #include "src/compiler/node-properties.h"
      11             : #include "src/compiler/node.h"
      12             : #include "src/zone/zone-containers.h"
      13             : #include "src/zone/zone.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace compiler {
      18             : 
      19             : // Macro for outputting trace information from representation inference.
      20             : #define TRACE(...)                                  \
      21             :   do {                                              \
      22             :     if (FLAG_trace_turbo_loop) PrintF(__VA_ARGS__); \
      23             :   } while (false)
      24             : 
      25      886762 : LoopVariableOptimizer::LoopVariableOptimizer(Graph* graph,
      26             :                                              CommonOperatorBuilder* common,
      27             :                                              Zone* zone)
      28             :     : graph_(graph),
      29             :       common_(common),
      30             :       zone_(zone),
      31             :       limits_(graph->NodeCount(), zone),
      32      886763 :       induction_vars_(zone) {}
      33             : 
      34     1330144 : void LoopVariableOptimizer::Run() {
      35      443382 :   ZoneQueue<Node*> queue(zone());
      36      886762 :   queue.push(graph()->start());
      37             :   NodeMarker<bool> queued(graph(), 2);
      38     7305492 :   while (!queue.empty()) {
      39    13724220 :     Node* node = queue.front();
      40             :     queue.pop();
      41             :     queued.Set(node, false);
      42             : 
      43             :     DCHECK_NULL(limits_[node->id()]);
      44             :     bool all_inputs_visited = true;
      45             :     int inputs_end = (node->opcode() == IrOpcode::kLoop)
      46             :                          ? kFirstBackedge
      47     6862110 :                          : node->op()->ControlInputCount();
      48    15490974 :     for (int i = 0; i < inputs_end; i++) {
      49    27158817 :       if (limits_[NodeProperties::GetControlInput(node, i)->id()] == nullptr) {
      50             :         all_inputs_visited = false;
      51             :         break;
      52             :       }
      53             :     }
      54     6862113 :     if (!all_inputs_visited) continue;
      55             : 
      56     6438036 :     VisitNode(node);
      57             :     DCHECK_NOT_NULL(limits_[node->id()]);
      58             : 
      59             :     // Queue control outputs.
      60    70854656 :     for (Edge edge : node->use_edges()) {
      61    45256053 :       if (NodeProperties::IsControlEdge(edge) &&
      62    13047743 :           edge.from()->op()->ControlOutputCount() > 0) {
      63     6577200 :         Node* use = edge.from();
      64    13239606 :         if (use->opcode() == IrOpcode::kLoop &&
      65       85206 :             edge.index() != kAssumedLoopEntryIndex) {
      66       42603 :           VisitBackedge(node, use);
      67     6534597 :         } else if (!queued.Get(use)) {
      68             :           queue.push(use);
      69     6418730 :           queued.Set(use, true);
      70             :         }
      71             :       }
      72             :     }
      73             :   }
      74      443382 : }
      75             : 
      76             : class LoopVariableOptimizer::Constraint : public ZoneObject {
      77             :  public:
      78             :   InductionVariable::ConstraintKind kind() const { return kind_; }
      79             :   Node* left() const { return left_; }
      80             :   Node* right() const { return right_; }
      81             : 
      82             :   const Constraint* next() const { return next_; }
      83             : 
      84             :   Constraint(Node* left, InductionVariable::ConstraintKind kind, Node* right,
      85             :              const Constraint* next)
      86      113480 :       : left_(left), right_(right), kind_(kind), next_(next) {}
      87             : 
      88             :  private:
      89             :   Node* left_;
      90             :   Node* right_;
      91             :   InductionVariable::ConstraintKind kind_;
      92             :   const Constraint* next_;
      93             : };
      94             : 
      95             : class LoopVariableOptimizer::VariableLimits : public ZoneObject {
      96             :  public:
      97             :   static VariableLimits* Empty(Zone* zone) {
      98             :     return new (zone) VariableLimits();
      99             :   }
     100             : 
     101             :   VariableLimits* Copy(Zone* zone) const {
     102             :     return new (zone) VariableLimits(this);
     103             :   }
     104             : 
     105             :   void Add(Node* left, InductionVariable::ConstraintKind kind, Node* right,
     106             :            Zone* zone) {
     107      226960 :     head_ = new (zone) Constraint(left, kind, right, head_);
     108      113480 :     limit_count_++;
     109             :   }
     110             : 
     111      431211 :   void Merge(const VariableLimits* other) {
     112             :     // Change the current condition list to a longest common tail
     113             :     // of this condition list and the other list. (The common tail
     114             :     // should correspond to the list from the common dominator.)
     115             : 
     116             :     // First, we throw away the prefix of the longer list, so that
     117             :     // we have lists of the same length.
     118      431211 :     size_t other_size = other->limit_count_;
     119      472510 :     const Constraint* other_limit = other->head_;
     120      869789 :     while (other_size > limit_count_) {
     121             :       other_limit = other_limit->next();
     122        7367 :       other_size--;
     123             :     }
     124      431330 :     while (limit_count_ > other_size) {
     125       34051 :       head_ = head_->next();
     126         119 :       limit_count_--;
     127             :     }
     128             : 
     129             :     // Then we go through both lists in lock-step until we find
     130             :     // the common tail.
     131      465143 :     while (head_ != other_limit) {
     132             :       DCHECK_LT(0, limit_count_);
     133       33932 :       limit_count_--;
     134             :       other_limit = other_limit->next();
     135       33932 :       head_ = head_->next();
     136             :     }
     137      431211 :   }
     138             : 
     139             :   const Constraint* head() const { return head_; }
     140             : 
     141             :  private:
     142      443382 :   VariableLimits() {}
     143             :   explicit VariableLimits(const VariableLimits* other)
     144     1427504 :       : head_(other->head_), limit_count_(other->limit_count_) {}
     145             : 
     146             :   const Constraint* head_ = nullptr;
     147             :   size_t limit_count_ = 0;
     148             : };
     149             : 
     150       22622 : void InductionVariable::AddUpperBound(Node* bound,
     151           0 :                                       InductionVariable::ConstraintKind kind) {
     152       22622 :   if (FLAG_trace_turbo_loop) {
     153           0 :     OFStream os(stdout);
     154           0 :     os << "New upper bound for " << phi()->id() << " (loop "
     155           0 :        << NodeProperties::GetControlInput(phi())->id() << "): " << *bound
     156           0 :        << std::endl;
     157             :   }
     158       45244 :   upper_bounds_.push_back(Bound(bound, kind));
     159       22622 : }
     160             : 
     161        1082 : void InductionVariable::AddLowerBound(Node* bound,
     162           0 :                                       InductionVariable::ConstraintKind kind) {
     163        1082 :   if (FLAG_trace_turbo_loop) {
     164           0 :     OFStream os(stdout);
     165           0 :     os << "New lower bound for " << phi()->id() << " (loop "
     166           0 :        << NodeProperties::GetControlInput(phi())->id() << "): " << *bound;
     167             :   }
     168        2164 :   lower_bounds_.push_back(Bound(bound, kind));
     169        1082 : }
     170             : 
     171       85206 : void LoopVariableOptimizer::VisitBackedge(Node* from, Node* loop) {
     172       85206 :   if (loop->op()->ControlInputCount() != 2) return;
     173             : 
     174             :   // Go through the constraints, and update the induction variables in
     175             :   // this loop if they are involved in the constraint.
     176       85206 :   const VariableLimits* limits = limits_[from->id()];
     177      148862 :   for (const Constraint* constraint = limits->head(); constraint != nullptr;
     178             :        constraint = constraint->next()) {
     179       83836 :     if (constraint->left()->opcode() == IrOpcode::kPhi &&
     180       25370 :         NodeProperties::GetControlInput(constraint->left()) == loop) {
     181       67866 :       auto var = induction_vars_.find(constraint->left()->id());
     182       22622 :       if (var != induction_vars_.end()) {
     183       22622 :         var->second->AddUpperBound(constraint->right(), constraint->kind());
     184             :       }
     185             :     }
     186       63480 :     if (constraint->right()->opcode() == IrOpcode::kPhi &&
     187        5014 :         NodeProperties::GetControlInput(constraint->right()) == loop) {
     188        4401 :       auto var = induction_vars_.find(constraint->right()->id());
     189        1467 :       if (var != induction_vars_.end()) {
     190        1082 :         var->second->AddLowerBound(constraint->left(), constraint->kind());
     191             :       }
     192             :     }
     193             :   }
     194             : }
     195             : 
     196     6438043 : void LoopVariableOptimizer::VisitNode(Node* node) {
     197     6438043 :   switch (node->opcode()) {
     198             :     case IrOpcode::kMerge:
     199      273712 :       return VisitMerge(node);
     200             :     case IrOpcode::kLoop:
     201             :       return VisitLoop(node);
     202             :     case IrOpcode::kIfFalse:
     203      576896 :       return VisitIf(node, false);
     204             :     case IrOpcode::kIfTrue:
     205      576896 :       return VisitIf(node, true);
     206             :     case IrOpcode::kStart:
     207      443380 :       return VisitStart(node);
     208             :     case IrOpcode::kLoopExit:
     209             :       return VisitLoopExit(node);
     210             :     default:
     211             :       return VisitOtherControl(node);
     212             :   }
     213             : }
     214             : 
     215      273712 : void LoopVariableOptimizer::VisitMerge(Node* node) {
     216             :   // Merge the limits of all incoming edges.
     217     1526059 :   VariableLimits* merged = limits_[node->InputAt(0)->id()]->Copy(zone());
     218     1409846 :   for (int i = 1; i < node->InputCount(); i++) {
     219     1293633 :     merged->Merge(limits_[node->InputAt(i)->id()]);
     220             :   }
     221      547424 :   limits_[node->id()] = merged;
     222      273712 : }
     223             : 
     224           0 : void LoopVariableOptimizer::VisitLoop(Node* node) {
     225       42603 :   DetectInductionVariables(node);
     226             :   // Conservatively take the limits from the loop entry here.
     227       42603 :   return TakeConditionsFromFirstControl(node);
     228             : }
     229             : 
     230     3461376 : void LoopVariableOptimizer::VisitIf(Node* node, bool polarity) {
     231             :   Node* branch = node->InputAt(0);
     232     1153792 :   Node* cond = branch->InputAt(0);
     233     3461376 :   VariableLimits* limits = limits_[branch->id()]->Copy(zone());
     234             :   // Normalize to less than comparison.
     235     1153792 :   switch (cond->opcode()) {
     236             :     case IrOpcode::kJSLessThan:
     237             :     case IrOpcode::kSpeculativeNumberLessThan:
     238      129070 :       AddCmpToLimits(limits, cond, InductionVariable::kStrict, polarity);
     239      129070 :       break;
     240             :     case IrOpcode::kJSGreaterThan:
     241       20460 :       AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, !polarity);
     242       20460 :       break;
     243             :     case IrOpcode::kJSLessThanOrEqual:
     244             :     case IrOpcode::kSpeculativeNumberLessThanOrEqual:
     245        6344 :       AddCmpToLimits(limits, cond, InductionVariable::kNonStrict, polarity);
     246        6344 :       break;
     247             :     case IrOpcode::kJSGreaterThanOrEqual:
     248        4332 :       AddCmpToLimits(limits, cond, InductionVariable::kStrict, !polarity);
     249        4332 :       break;
     250             :     default:
     251             :       break;
     252             :   }
     253     2307584 :   limits_[node->id()] = limits;
     254     1153792 : }
     255             : 
     256      160206 : void LoopVariableOptimizer::AddCmpToLimits(
     257             :     VariableLimits* limits, Node* node, InductionVariable::ConstraintKind kind,
     258      113480 :     bool polarity) {
     259             :   Node* left = node->InputAt(0);
     260             :   Node* right = node->InputAt(1);
     261      160206 :   if (FindInductionVariable(left) || FindInductionVariable(right)) {
     262      113480 :     if (polarity) {
     263             :       limits->Add(left, kind, right, zone());
     264             :     } else {
     265             :       kind = (kind == InductionVariable::kStrict)
     266             :                  ? InductionVariable::kNonStrict
     267       56740 :                  : InductionVariable::kStrict;
     268             :       limits->Add(right, kind, left, zone());
     269             :     }
     270             :   }
     271      160206 : }
     272             : 
     273      886762 : void LoopVariableOptimizer::VisitStart(Node* node) {
     274      886763 :   limits_[node->id()] = VariableLimits::Empty(zone());
     275      443382 : }
     276             : 
     277           0 : void LoopVariableOptimizer::VisitLoopExit(Node* node) {
     278      108738 :   return TakeConditionsFromFirstControl(node);
     279             : }
     280             : 
     281           0 : void LoopVariableOptimizer::VisitOtherControl(Node* node) {
     282             :   DCHECK_EQ(1, node->op()->ControlInputCount());
     283     4415818 :   return TakeConditionsFromFirstControl(node);
     284             : }
     285             : 
     286     9134319 : void LoopVariableOptimizer::TakeConditionsFromFirstControl(Node* node) {
     287             :   const VariableLimits* limits =
     288    13701479 :       limits_[NodeProperties::GetControlInput(node, 0)->id()];
     289             :   DCHECK_NOT_NULL(limits);
     290     9134320 :   limits_[node->id()] = limits;
     291     4567160 : }
     292             : 
     293      216650 : const InductionVariable* LoopVariableOptimizer::FindInductionVariable(
     294      216650 :     Node* node) {
     295      433300 :   auto var = induction_vars_.find(node->id());
     296      216650 :   if (var != induction_vars_.end()) {
     297      113480 :     return var->second;
     298             :   }
     299             :   return nullptr;
     300             : }
     301             : 
     302      105268 : InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) {
     303             :   DCHECK_EQ(2, phi->op()->ValueInputCount());
     304             :   DCHECK_EQ(IrOpcode::kLoop, NodeProperties::GetControlInput(phi)->opcode());
     305             :   Node* initial = phi->InputAt(0);
     306       73860 :   Node* arith = phi->InputAt(1);
     307             :   InductionVariable::ArithmeticType arithmeticType;
     308      145223 :   if (arith->opcode() == IrOpcode::kJSAdd ||
     309      144808 :       arith->opcode() == IrOpcode::kSpeculativeNumberAdd ||
     310             :       arith->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd) {
     311             :     arithmeticType = InductionVariable::ArithmeticType::kAddition;
     312      120298 :   } else if (arith->opcode() == IrOpcode::kJSSubtract ||
     313      119999 :              arith->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
     314             :              arith->opcode() == IrOpcode::kSpeculativeSafeIntegerSubtract) {
     315             :     arithmeticType = InductionVariable::ArithmeticType::kSubtraction;
     316             :   } else {
     317             :     return nullptr;
     318             :   }
     319             : 
     320             :   // TODO(jarin) Support both sides.
     321       33252 :   if (arith->InputAt(0) != phi) {
     322       14092 :     if ((arith->InputAt(0)->opcode() != IrOpcode::kJSToNumber &&
     323       12256 :          arith->InputAt(0)->opcode() != IrOpcode::kSpeculativeToNumber) ||
     324             :         arith->InputAt(0)->InputAt(0) != phi) {
     325             :       return nullptr;
     326             :     }
     327             :   }
     328             :   Node* incr = arith->InputAt(1);
     329             :   return new (zone())
     330       31408 :       InductionVariable(phi, arith, incr, initial, zone(), arithmeticType);
     331             : }
     332             : 
     333       42603 : void LoopVariableOptimizer::DetectInductionVariables(Node* loop) {
     334       85206 :   if (loop->op()->ControlInputCount() != 2) return;
     335       42603 :   TRACE("Loop variables for loop %i:", loop->id());
     336      809597 :   for (Edge edge : loop->use_edges()) {
     337      766994 :     if (NodeProperties::IsControlEdge(edge) &&
     338      383497 :         edge.from()->opcode() == IrOpcode::kPhi) {
     339       31408 :       Node* phi = edge.from();
     340       73860 :       InductionVariable* induction_var = TryGetInductionVariable(phi);
     341       73860 :       if (induction_var) {
     342       31408 :         induction_vars_[phi->id()] = induction_var;
     343       31408 :         TRACE(" %i", induction_var->phi()->id());
     344             :       }
     345             :     }
     346             :   }
     347       42603 :   TRACE("\n");
     348             : }
     349             : 
     350      514098 : void LoopVariableOptimizer::ChangeToInductionVariablePhis() {
     351      918168 :   for (auto entry : induction_vars_) {
     352             :     // It only make sense to analyze the induction variables if
     353             :     // there is a bound.
     354       94225 :     InductionVariable* induction_var = entry.second;
     355             :     DCHECK_EQ(MachineRepresentation::kTagged,
     356             :               PhiRepresentationOf(induction_var->phi()->op()));
     357       71702 :     if (induction_var->upper_bounds().size() == 0 &&
     358        8886 :         induction_var->lower_bounds().size() == 0) {
     359             :       continue;
     360             :     }
     361             :     // Insert the increment value to the value inputs.
     362             :     induction_var->phi()->InsertInput(graph()->zone(),
     363             :                                       induction_var->phi()->InputCount() - 1,
     364       47014 :                                       induction_var->increment());
     365             :     // Insert the bound inputs to the value inputs.
     366       48096 :     for (auto bound : induction_var->lower_bounds()) {
     367             :       induction_var->phi()->InsertInput(
     368        2164 :           graph()->zone(), induction_var->phi()->InputCount() - 1, bound.bound);
     369             :     }
     370       69636 :     for (auto bound : induction_var->upper_bounds()) {
     371             :       induction_var->phi()->InsertInput(
     372       45244 :           graph()->zone(), induction_var->phi()->InputCount() - 1, bound.bound);
     373             :     }
     374             :     NodeProperties::ChangeOp(
     375             :         induction_var->phi(),
     376       70521 :         common()->InductionVariablePhi(induction_var->phi()->InputCount() - 1));
     377             :   }
     378      443380 : }
     379             : 
     380      486803 : void LoopVariableOptimizer::ChangeToPhisAndInsertGuards() {
     381      918170 :   for (auto entry : induction_vars_) {
     382      145350 :     InductionVariable* induction_var = entry.second;
     383       62816 :     if (induction_var->phi()->opcode() == IrOpcode::kInductionVariablePhi) {
     384             :       // Turn the induction variable phi back to normal phi.
     385             :       int value_count = 2;
     386       23507 :       Node* control = NodeProperties::GetControlInput(induction_var->phi());
     387             :       DCHECK_EQ(value_count, control->op()->ControlInputCount());
     388       23507 :       induction_var->phi()->TrimInputCount(value_count + 1);
     389       23507 :       induction_var->phi()->ReplaceInput(value_count, control);
     390             :       NodeProperties::ChangeOp(
     391             :           induction_var->phi(),
     392       47014 :           common()->Phi(MachineRepresentation::kTagged, value_count));
     393             : 
     394             :       // If the backedge is not a subtype of the phi's type, we insert a sigma
     395             :       // to get the typing right.
     396             :       Node* backedge_value = induction_var->phi()->InputAt(1);
     397             :       Type* backedge_type = NodeProperties::GetType(backedge_value);
     398             :       Type* phi_type = NodeProperties::GetType(induction_var->phi());
     399       23507 :       if (!backedge_type->Is(phi_type)) {
     400             :         Node* backedge_control =
     401        9957 :             NodeProperties::GetControlInput(induction_var->phi())->InputAt(1);
     402             :         Node* rename = graph()->NewNode(common()->TypeGuard(phi_type),
     403        9957 :                                         backedge_value, backedge_control);
     404        9957 :         induction_var->phi()->ReplaceInput(1, rename);
     405             :       }
     406             :     }
     407             :   }
     408      443380 : }
     409             : 
     410             : #undef TRACE
     411             : 
     412             : }  // namespace compiler
     413             : }  // namespace internal
     414             : }  // namespace v8

Generated by: LCOV version 1.10