LCOV - code coverage report
Current view: top level - src/compiler - redundancy-elimination.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 93 102 91.2 %
Date: 2017-10-20 Functions: 17 21 81.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/redundancy-elimination.h"
       6             : 
       7             : #include "src/compiler/node-properties.h"
       8             : 
       9             : namespace v8 {
      10             : namespace internal {
      11             : namespace compiler {
      12             : 
      13      886706 : RedundancyElimination::RedundancyElimination(Editor* editor, Zone* zone)
      14     1773412 :     : AdvancedReducer(editor), node_checks_(zone), zone_(zone) {}
      15             : 
      16     1773402 : RedundancyElimination::~RedundancyElimination() {}
      17             : 
      18   164440515 : Reduction RedundancyElimination::Reduce(Node* node) {
      19    87599650 :   if (node_checks_.Get(node)) return NoChange();
      20    76840865 :   switch (node->opcode()) {
      21             :     case IrOpcode::kCheckBounds:
      22             :     case IrOpcode::kCheckFloat64Hole:
      23             :     case IrOpcode::kCheckHeapObject:
      24             :     case IrOpcode::kCheckIf:
      25             :     case IrOpcode::kCheckInternalizedString:
      26             :     case IrOpcode::kCheckNumber:
      27             :     case IrOpcode::kCheckReceiver:
      28             :     case IrOpcode::kCheckSmi:
      29             :     case IrOpcode::kCheckString:
      30             :     case IrOpcode::kCheckSeqString:
      31             :     case IrOpcode::kCheckNotTaggedHole:
      32             :     case IrOpcode::kCheckedFloat64ToInt32:
      33             :     case IrOpcode::kCheckedInt32Add:
      34             :     case IrOpcode::kCheckedInt32Sub:
      35             :     case IrOpcode::kCheckedInt32Div:
      36             :     case IrOpcode::kCheckedInt32Mod:
      37             :     case IrOpcode::kCheckedInt32Mul:
      38             :     case IrOpcode::kCheckedTaggedToFloat64:
      39             :     case IrOpcode::kCheckedTaggedSignedToInt32:
      40             :     case IrOpcode::kCheckedTaggedToInt32:
      41             :     case IrOpcode::kCheckedUint32ToInt32:
      42      843019 :       return ReduceCheckNode(node);
      43             :     case IrOpcode::kSpeculativeNumberAdd:
      44             :     case IrOpcode::kSpeculativeNumberSubtract:
      45             :     case IrOpcode::kSpeculativeSafeIntegerAdd:
      46             :     case IrOpcode::kSpeculativeSafeIntegerSubtract:
      47             :       // For increments and decrements by a constant, try to learn from the last
      48             :       // bounds check.
      49      363936 :       return TryReuseBoundsCheckForFirstInput(node);
      50             :     case IrOpcode::kEffectPhi:
      51     1633063 :       return ReduceEffectPhi(node);
      52             :     case IrOpcode::kDead:
      53             :       break;
      54             :     case IrOpcode::kStart:
      55      886704 :       return ReduceStart(node);
      56             :     default:
      57    73085859 :       return ReduceOtherNode(node);
      58             :   }
      59             :   return NoChange();
      60             : }
      61             : 
      62             : // static
      63             : RedundancyElimination::EffectPathChecks*
      64     1070726 : RedundancyElimination::EffectPathChecks::Copy(Zone* zone,
      65             :                                               EffectPathChecks const* checks) {
      66     1070726 :   return new (zone->New(sizeof(EffectPathChecks))) EffectPathChecks(*checks);
      67             : }
      68             : 
      69             : // static
      70             : RedundancyElimination::EffectPathChecks const*
      71           0 : RedundancyElimination::EffectPathChecks::Empty(Zone* zone) {
      72      886703 :   return new (zone->New(sizeof(EffectPathChecks))) EffectPathChecks(nullptr, 0);
      73             : }
      74             : 
      75           0 : bool RedundancyElimination::EffectPathChecks::Equals(
      76             :     EffectPathChecks const* that) const {
      77           0 :   if (this->size_ != that->size_) return false;
      78           0 :   Check* this_head = this->head_;
      79           0 :   Check* that_head = that->head_;
      80           0 :   while (this_head != that_head) {
      81           0 :     if (this_head->node != that_head->node) return false;
      82           0 :     this_head = this_head->next;
      83           0 :     that_head = that_head->next;
      84             :   }
      85             :   return true;
      86             : }
      87             : 
      88     1358360 : void RedundancyElimination::EffectPathChecks::Merge(
      89             :     EffectPathChecks const* that) {
      90             :   // Change the current check list to a longest common tail of this check
      91             :   // list and the other list.
      92             : 
      93             :   // First, we throw away the prefix of the longer list, so that
      94             :   // we have lists of the same length.
      95     1358360 :   Check* that_head = that->head_;
      96     1358360 :   size_t that_size = that->size_;
      97     2805566 :   while (that_size > size_) {
      98       88846 :     that_head = that_head->next;
      99       88846 :     that_size--;
     100             :   }
     101     1400534 :   while (size_ > that_size) {
     102       42174 :     head_ = head_->next;
     103       42174 :     size_--;
     104             :   }
     105             : 
     106             :   // Then we go through both lists in lock-step until we find
     107             :   // the common tail.
     108     1362977 :   while (head_ != that_head) {
     109             :     DCHECK_LT(0u, size_);
     110             :     DCHECK_NOT_NULL(head_);
     111        4617 :     size_--;
     112        4617 :     head_ = head_->next;
     113        4617 :     that_head = that_head->next;
     114             :   }
     115     1358360 : }
     116             : 
     117             : RedundancyElimination::EffectPathChecks const*
     118      336326 : RedundancyElimination::EffectPathChecks::AddCheck(Zone* zone,
     119             :                                                   Node* node) const {
     120      336326 :   Check* head = new (zone->New(sizeof(Check))) Check(node, head_);
     121             :   return new (zone->New(sizeof(EffectPathChecks)))
     122      672647 :       EffectPathChecks(head, size_ + 1);
     123             : }
     124             : 
     125             : namespace {
     126             : 
     127     4774346 : bool IsCompatibleCheck(Node const* a, Node const* b) {
     128     4774346 :   if (a->op() != b->op()) {
     129     2377361 :     if (a->opcode() == IrOpcode::kCheckInternalizedString &&
     130             :         b->opcode() == IrOpcode::kCheckString) {
     131             :       // CheckInternalizedString(node) implies CheckString(node)
     132             :     } else {
     133             :       return false;
     134             :     }
     135             :   }
     136     7747303 :   for (int i = a->op()->ValueInputCount(); --i >= 0;) {
     137     2696347 :     if (a->InputAt(i) != b->InputAt(i)) return false;
     138             :   }
     139             :   return true;
     140             : }
     141             : 
     142             : }  // namespace
     143             : 
     144      585901 : Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const {
     145     5111402 :   for (Check const* check = head_; check != nullptr; check = check->next) {
     146     4774315 :     if (IsCompatibleCheck(check->node, node)) {
     147             :       DCHECK(!check->node->IsDead());
     148             :       return check->node;
     149             :     }
     150             :   }
     151             :   return nullptr;
     152             : }
     153             : 
     154      165637 : Node* RedundancyElimination::EffectPathChecks::LookupBoundsCheckFor(
     155             :     Node* node) const {
     156      464534 :   for (Check const* check = head_; check != nullptr; check = check->next) {
     157      675692 :     if (check->node->opcode() == IrOpcode::kCheckBounds &&
     158             :         check->node->InputAt(0) == node) {
     159             :       return check->node;
     160             :     }
     161             :   }
     162             :   return nullptr;
     163             : }
     164             : 
     165             : RedundancyElimination::EffectPathChecks const*
     166   139372099 : RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const {
     167   139372099 :   size_t const id = node->id();
     168   375812262 :   if (id < info_for_node_.size()) return info_for_node_[id];
     169             :   return nullptr;
     170             : }
     171             : 
     172    21741737 : void RedundancyElimination::PathChecksForEffectNodes::Set(
     173    21741737 :     Node* node, EffectPathChecks const* checks) {
     174    21741737 :   size_t const id = node->id();
     175    43483474 :   if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr);
     176    21741744 :   info_for_node_[id] = checks;
     177    21741744 : }
     178             : 
     179     1179344 : Reduction RedundancyElimination::ReduceCheckNode(Node* node) {
     180      843018 :   Node* const effect = NodeProperties::GetEffectInput(node);
     181             :   EffectPathChecks const* checks = node_checks_.Get(effect);
     182             :   // If we do not know anything about the predecessor, do not propagate just yet
     183             :   // because we will have to recompute anyway once we compute the predecessor.
     184      843108 :   if (checks == nullptr) return NoChange();
     185             :   // See if we have another check that dominates us.
     186      585902 :   if (Node* check = checks->LookupCheck(node)) {
     187      249653 :     ReplaceWithValue(node, check);
     188             :     return Replace(check);
     189             :   }
     190             : 
     191             :   // Learn from this check.
     192      336326 :   return UpdateChecks(node, checks->AddCheck(zone(), node));
     193             : }
     194             : 
     195      363944 : Reduction RedundancyElimination::TryReuseBoundsCheckForFirstInput(Node* node) {
     196             :   DCHECK(node->opcode() == IrOpcode::kSpeculativeNumberAdd ||
     197             :          node->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
     198             :          node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd ||
     199             :          node->opcode() == IrOpcode::kSpeculativeSafeIntegerSubtract);
     200             : 
     201             :   DCHECK_EQ(1, node->op()->EffectInputCount());
     202             :   DCHECK_EQ(1, node->op()->EffectOutputCount());
     203             : 
     204      363944 :   Node* const effect = NodeProperties::GetEffectInput(node);
     205             :   EffectPathChecks const* checks = node_checks_.Get(effect);
     206             : 
     207             :   // If we do not know anything about the predecessor, do not propagate just yet
     208             :   // because we will have to recompute anyway once we compute the predecessor.
     209      363956 :   if (checks == nullptr) return NoChange();
     210             : 
     211             :   Node* left = node->InputAt(0);
     212      239562 :   Node* right = node->InputAt(1);
     213             :   // Only use bounds checks for increments/decrements by a constant.
     214      239562 :   if (right->opcode() == IrOpcode::kNumberConstant) {
     215      165637 :     if (Node* bounds_check = checks->LookupBoundsCheckFor(left)) {
     216             :       // Only use the bounds checked type if it is better.
     217        7546 :       if (NodeProperties::GetType(bounds_check)
     218             :               ->Is(NodeProperties::GetType(left))) {
     219        5613 :         node->ReplaceInput(0, bounds_check);
     220             :       }
     221             :     }
     222             :   }
     223             : 
     224      239561 :   return UpdateChecks(node, checks);
     225             : }
     226             : 
     227     4229926 : Reduction RedundancyElimination::ReduceEffectPhi(Node* node) {
     228     1633056 :   Node* const control = NodeProperties::GetControlInput(node);
     229     1633031 :   if (control->opcode() == IrOpcode::kLoop) {
     230             :     // Here we rely on having only reducible loops:
     231             :     // The loop entry edge always dominates the header, so we can just use
     232             :     // the information from the loop entry edge.
     233      106889 :     return TakeChecksFromFirstEffect(node);
     234             :   }
     235             :   DCHECK_EQ(IrOpcode::kMerge, control->opcode());
     236             : 
     237             :   // Shortcut for the case when we do not know anything about some input.
     238     1526142 :   int const input_count = node->op()->EffectInputCount();
     239     5121264 :   for (int i = 0; i < input_count; ++i) {
     240     4050536 :     Node* const effect = NodeProperties::GetEffectInput(node, i);
     241     4050570 :     if (node_checks_.Get(effect) == nullptr) return NoChange();
     242             :   }
     243             : 
     244             :   // Make a copy of the first input's checks and merge with the checks
     245             :   // from other inputs.
     246             :   EffectPathChecks* checks = EffectPathChecks::Copy(
     247     2141456 :       zone(), node_checks_.Get(NodeProperties::GetEffectInput(node, 0)));
     248     2429085 :   for (int i = 1; i < input_count; ++i) {
     249     1358357 :     Node* const input = NodeProperties::GetEffectInput(node, i);
     250     1358358 :     checks->Merge(node_checks_.Get(input));
     251             :   }
     252     1070728 :   return UpdateChecks(node, checks);
     253             : }
     254             : 
     255      886703 : Reduction RedundancyElimination::ReduceStart(Node* node) {
     256      886708 :   return UpdateChecks(node, EffectPathChecks::Empty(zone()));
     257             : }
     258             : 
     259    73088802 : Reduction RedundancyElimination::ReduceOtherNode(Node* node) {
     260    73088802 :   if (node->op()->EffectInputCount() == 1) {
     261    23790123 :     if (node->op()->EffectOutputCount() == 1) {
     262    22237068 :       return TakeChecksFromFirstEffect(node);
     263             :     } else {
     264             :       // Effect terminators should be handled specially.
     265             :       return NoChange();
     266             :     }
     267             :   }
     268             :   DCHECK_EQ(0, node->op()->EffectInputCount());
     269             :   DCHECK_EQ(0, node->op()->EffectOutputCount());
     270             :   return NoChange();
     271             : }
     272             : 
     273    22343950 : Reduction RedundancyElimination::TakeChecksFromFirstEffect(Node* node) {
     274             :   DCHECK_EQ(1, node->op()->EffectOutputCount());
     275    22343950 :   Node* const effect = NodeProperties::GetEffectInput(node);
     276             :   EffectPathChecks const* checks = node_checks_.Get(effect);
     277             :   // If we do not know anything about the predecessor, do not propagate just yet
     278             :   // because we will have to recompute anyway once we compute the predecessor.
     279    22344004 :   if (checks == nullptr) return NoChange();
     280             :   // We just propagate the information from the effect input (ideally,
     281             :   // we would only revisit effect uses if there is change).
     282    19208707 :   return UpdateChecks(node, checks);
     283             : }
     284             : 
     285    21741725 : Reduction RedundancyElimination::UpdateChecks(Node* node,
     286             :                                               EffectPathChecks const* checks) {
     287             :   EffectPathChecks const* original = node_checks_.Get(node);
     288             :   // Only signal that the {node} has Changed, if the information about {checks}
     289             :   // has changed wrt. the {original}.
     290    21741725 :   if (checks != original) {
     291    21741723 :     if (original == nullptr || !checks->Equals(original)) {
     292    21741725 :       node_checks_.Set(node, checks);
     293             :       return Changed(node);
     294             :     }
     295             :   }
     296             :   return NoChange();
     297             : }
     298             : 
     299             : }  // namespace compiler
     300             : }  // namespace internal
     301             : }  // namespace v8

Generated by: LCOV version 1.10