LCOV - code coverage report
Current view: top level - src/compiler - branch-elimination.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 103 122 84.4 %
Date: 2017-10-20 Functions: 16 25 64.0 %

          Line data    Source code
       1             : // Copyright 2015 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/branch-elimination.h"
       6             : 
       7             : #include "src/compiler/js-graph.h"
       8             : #include "src/compiler/node-properties.h"
       9             : #include "src/compiler/simplified-operator.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : namespace compiler {
      14             : 
      15     3546844 : BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
      16             :                                      Zone* zone)
      17             :     : AdvancedReducer(editor),
      18             :       jsgraph_(js_graph),
      19             :       node_conditions_(zone, js_graph->graph()->NodeCount()),
      20             :       zone_(zone),
      21     4433556 :       dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) {
      22             :   NodeProperties::SetType(dead_, Type::None());
      23      886712 : }
      24             : 
      25     1773406 : BranchElimination::~BranchElimination() {}
      26             : 
      27             : 
      28   100493885 : Reduction BranchElimination::Reduce(Node* node) {
      29   100493885 :   switch (node->opcode()) {
      30             :     case IrOpcode::kDead:
      31             :       return NoChange();
      32             :     case IrOpcode::kDeoptimizeIf:
      33             :     case IrOpcode::kDeoptimizeUnless:
      34      381784 :       return ReduceDeoptimizeConditional(node);
      35             :     case IrOpcode::kMerge:
      36     2149507 :       return ReduceMerge(node);
      37             :     case IrOpcode::kLoop:
      38             :       return ReduceLoop(node);
      39             :     case IrOpcode::kBranch:
      40     2833004 :       return ReduceBranch(node);
      41             :     case IrOpcode::kIfFalse:
      42     2756159 :       return ReduceIf(node, false);
      43             :     case IrOpcode::kIfTrue:
      44     2766107 :       return ReduceIf(node, true);
      45             :     case IrOpcode::kStart:
      46     1773405 :       return ReduceStart(node);
      47             :     default:
      48   175234344 :       if (node->op()->ControlOutputCount() > 0) {
      49             :         return ReduceOtherControl(node);
      50             :       }
      51             :       break;
      52             :   }
      53             :   return NoChange();
      54             : }
      55             : 
      56             : 
      57     2868375 : Reduction BranchElimination::ReduceBranch(Node* node) {
      58             :   Node* condition = node->InputAt(0);
      59     2833021 :   Node* control_input = NodeProperties::GetControlInput(node, 0);
      60             :   const ControlPathConditions* from_input = node_conditions_.Get(control_input);
      61     2833016 :   if (from_input != nullptr) {
      62             :     Maybe<bool> condition_value = from_input->LookupCondition(condition);
      63             :     // If we know the condition we can discard the branch.
      64     2464282 :     if (condition_value.IsJust()) {
      65             :       bool known_value = condition_value.FromJust();
      66       88385 :       for (Node* const use : node->uses()) {
      67       35354 :         switch (use->opcode()) {
      68             :           case IrOpcode::kIfTrue:
      69       53031 :             Replace(use, known_value ? control_input : dead());
      70             :             break;
      71             :           case IrOpcode::kIfFalse:
      72       17677 :             Replace(use, known_value ? dead() : control_input);
      73             :             break;
      74             :           default:
      75           0 :             UNREACHABLE();
      76             :         }
      77             :       }
      78             :       return Replace(dead());
      79             :     }
      80             :   }
      81     2815339 :   return TakeConditionsFromFirstControl(node);
      82             : }
      83             : 
      84      409245 : Reduction BranchElimination::ReduceDeoptimizeConditional(Node* node) {
      85             :   DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
      86             :          node->opcode() == IrOpcode::kDeoptimizeUnless);
      87      381781 :   bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
      88      381781 :   DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
      89      381783 :   Node* condition = NodeProperties::GetValueInput(node, 0);
      90      381782 :   Node* frame_state = NodeProperties::GetValueInput(node, 1);
      91      381781 :   Node* effect = NodeProperties::GetEffectInput(node);
      92      381781 :   Node* control = NodeProperties::GetControlInput(node);
      93             :   ControlPathConditions const* conditions = node_conditions_.Get(control);
      94             :   // If we do not know anything about the predecessor, do not propagate just
      95             :   // yet because we will have to recompute anyway once we compute the
      96             :   // predecessor.
      97      381783 :   if (conditions == nullptr) {
      98       62202 :     return UpdateConditions(node, conditions);
      99             :   }
     100             :   Maybe<bool> condition_value = conditions->LookupCondition(condition);
     101      319581 :   if (condition_value.IsJust()) {
     102             :     // If we know the condition we can discard the branch.
     103       13732 :     if (condition_is_true == condition_value.FromJust()) {
     104             :       // We don't update the conditions here, because we're replacing {node}
     105             :       // with the {control} node that already contains the right information.
     106       13732 :       ReplaceWithValue(node, dead(), effect, control);
     107             :     } else {
     108             :       control = graph()->NewNode(common()->Deoptimize(p.kind(), p.reason()),
     109           0 :                                  frame_state, effect, control);
     110             :       // TODO(bmeurer): This should be on the AdvancedReducer somehow.
     111           0 :       NodeProperties::MergeControlToEnd(graph(), common(), control);
     112           0 :       Revisit(graph()->end());
     113             :     }
     114             :     return Replace(dead());
     115             :   }
     116      305849 :   return UpdateConditions(node, conditions, condition, condition_is_true);
     117             : }
     118             : 
     119     5522183 : Reduction BranchElimination::ReduceIf(Node* node, bool is_true_branch) {
     120             :   // Add the condition to the list arriving from the input branch.
     121     5522183 :   Node* branch = NodeProperties::GetControlInput(node, 0);
     122             :   const ControlPathConditions* from_branch = node_conditions_.Get(branch);
     123             :   // If we do not know anything about the predecessor, do not propagate just
     124             :   // yet because we will have to recompute anyway once we compute the
     125             :   // predecessor.
     126     5522238 :   if (from_branch == nullptr) {
     127      709500 :     return UpdateConditions(node, nullptr);
     128             :   }
     129             :   Node* condition = branch->InputAt(0);
     130     4812738 :   return UpdateConditions(node, from_branch, condition, is_true_branch);
     131             : }
     132             : 
     133             : 
     134           0 : Reduction BranchElimination::ReduceLoop(Node* node) {
     135             :   // Here we rely on having only reducible loops:
     136             :   // The loop entry edge always dominates the header, so we can just use
     137             :   // the information from the loop entry edge.
     138      199869 :   return TakeConditionsFromFirstControl(node);
     139             : }
     140             : 
     141             : 
     142     2149476 : Reduction BranchElimination::ReduceMerge(Node* node) {
     143             :   // Shortcut for the case when we do not know anything about some
     144             :   // input.
     145             :   Node::Inputs inputs = node->inputs();
     146     7477094 :   for (Node* input : inputs) {
     147     5741717 :     if (node_conditions_.Get(input) == nullptr) {
     148      414099 :       return UpdateConditions(node, nullptr);
     149             :     }
     150             :   }
     151             : 
     152             :   auto input_it = inputs.begin();
     153             : 
     154             :   DCHECK_GT(inputs.count(), 0);
     155             : 
     156             :   const ControlPathConditions* first = node_conditions_.Get(*input_it);
     157             :   ++input_it;
     158             :   // Make a copy of the first input's conditions and merge with the conditions
     159             :   // from other inputs.
     160             :   ControlPathConditions* conditions =
     161     1735377 :       new (zone_->New(sizeof(ControlPathConditions)))
     162     1735377 :           ControlPathConditions(*first);
     163             :   auto input_end = inputs.end();
     164     4283100 :   for (; input_it != input_end; ++input_it) {
     165     2547722 :     conditions->Merge(*(node_conditions_.Get(*input_it)));
     166             :   }
     167             : 
     168     1735378 :   return UpdateConditions(node, conditions);
     169             : }
     170             : 
     171             : 
     172     1773404 : Reduction BranchElimination::ReduceStart(Node* node) {
     173     3546812 :   return UpdateConditions(node, ControlPathConditions::Empty(zone_));
     174             : }
     175             : 
     176             : const BranchElimination::ControlPathConditions*
     177    63435671 : BranchElimination::PathConditionsForControlNodes::Get(Node* node) const {
     178   126871342 :   if (static_cast<size_t>(node->id()) < info_for_node_.size()) {
     179    63331718 :     return info_for_node_[node->id()];
     180             :   }
     181             :   return nullptr;
     182             : }
     183             : 
     184             : 
     185    17709665 : void BranchElimination::PathConditionsForControlNodes::Set(
     186    17709665 :     Node* node, const ControlPathConditions* conditions) {
     187    17709665 :   size_t index = static_cast<size_t>(node->id());
     188    53128995 :   if (index >= info_for_node_.size()) {
     189       71087 :     info_for_node_.resize(index + 1, nullptr);
     190             :   }
     191    17709665 :   info_for_node_[index] = conditions;
     192    17709665 : }
     193             : 
     194             : 
     195           0 : Reduction BranchElimination::ReduceOtherControl(Node* node) {
     196             :   DCHECK_EQ(1, node->op()->ControlInputCount());
     197    14415238 :   return TakeConditionsFromFirstControl(node);
     198             : }
     199             : 
     200             : 
     201    17430402 : Reduction BranchElimination::TakeConditionsFromFirstControl(Node* node) {
     202             :   // We just propagate the information from the control input (ideally,
     203             :   // we would only revisit control uses if there is change).
     204             :   const ControlPathConditions* from_input =
     205    17430402 :       node_conditions_.Get(NodeProperties::GetControlInput(node, 0));
     206    17430364 :   return UpdateConditions(node, from_input);
     207             : }
     208             : 
     209             : 
     210    22124918 : Reduction BranchElimination::UpdateConditions(
     211             :     Node* node, const ControlPathConditions* conditions) {
     212             :   const ControlPathConditions* original = node_conditions_.Get(node);
     213             :   // Only signal that the node has Changed if the condition information has
     214             :   // changed.
     215    22124918 :   if (conditions != original) {
     216    14471157 :     if (conditions == nullptr || original == nullptr ||
     217             :         *conditions != *original) {
     218    12591822 :       node_conditions_.Set(node, conditions);
     219             :       return Changed(node);
     220             :     }
     221             :   }
     222             :   return NoChange();
     223             : }
     224             : 
     225     5118536 : Reduction BranchElimination::UpdateConditions(
     226             :     Node* node, const ControlPathConditions* prev_conditions,
     227             :     Node* current_condition, bool is_true_branch) {
     228             :   const ControlPathConditions* original = node_conditions_.Get(node);
     229             :   DCHECK(prev_conditions != nullptr && current_condition != nullptr);
     230             :   // The control path for the node is the path obtained by appending the
     231             :   // current_condition to the prev_conditions. Check if this new control path
     232             :   // would be the same as the already recorded path (original).
     233     5118578 :   if (original == nullptr || !prev_conditions->EqualsAfterAddingCondition(
     234          42 :                                  original, current_condition, is_true_branch)) {
     235             :     // If this is the first visit or if the control path is different from the
     236             :     // recorded path create the new control path and record it.
     237             :     const ControlPathConditions* new_condition =
     238     5118536 :         prev_conditions->AddCondition(zone_, current_condition, is_true_branch);
     239     5118352 :     node_conditions_.Set(node, new_condition);
     240             :     return Changed(node);
     241             :   }
     242             :   return NoChange();
     243             : }
     244             : 
     245             : // static
     246             : const BranchElimination::ControlPathConditions*
     247           0 : BranchElimination::ControlPathConditions::Empty(Zone* zone) {
     248             :   return new (zone->New(sizeof(ControlPathConditions)))
     249     1773404 :       ControlPathConditions(nullptr, 0);
     250             : }
     251             : 
     252             : 
     253     2547734 : void BranchElimination::ControlPathConditions::Merge(
     254             :     const ControlPathConditions& other) {
     255             :   // Change the current condition list to a longest common tail
     256             :   // of this condition list and the other list. (The common tail
     257             :   // should correspond to the list from the common dominator.)
     258             : 
     259             :   // First, we throw away the prefix of the longer list, so that
     260             :   // we have lists of the same length.
     261     2547734 :   size_t other_size = other.condition_count_;
     262     2547734 :   BranchCondition* other_condition = other.head_;
     263     7915048 :   while (other_size > condition_count_) {
     264     2819580 :     other_condition = other_condition->next;
     265     2819580 :     other_size--;
     266             :   }
     267     2903735 :   while (condition_count_ > other_size) {
     268      356001 :     head_ = head_->next;
     269      356001 :     condition_count_--;
     270             :   }
     271             : 
     272             :   // Then we go through both lists in lock-step until we find
     273             :   // the common tail.
     274     4217929 :   while (head_ != other_condition) {
     275             :     DCHECK_LT(0, condition_count_);
     276     1670195 :     condition_count_--;
     277     1670195 :     other_condition = other_condition->next;
     278     1670195 :     head_ = head_->next;
     279             :   }
     280     2547734 : }
     281             : 
     282             : 
     283             : const BranchElimination::ControlPathConditions*
     284     5118535 : BranchElimination::ControlPathConditions::AddCondition(Zone* zone,
     285             :                                                        Node* condition,
     286             :                                                        bool is_true) const {
     287             :   DCHECK(LookupCondition(condition).IsNothing());
     288             : 
     289             :   BranchCondition* new_head = new (zone->New(sizeof(BranchCondition)))
     290     5118535 :       BranchCondition(condition, is_true, head_);
     291             : 
     292             :   ControlPathConditions* conditions =
     293             :       new (zone->New(sizeof(ControlPathConditions)))
     294     5118512 :           ControlPathConditions(new_head, condition_count_ + 1);
     295     5118337 :   return conditions;
     296             : }
     297             : 
     298             : 
     299           0 : Maybe<bool> BranchElimination::ControlPathConditions::LookupCondition(
     300             :     Node* condition) const {
     301    16541633 :   for (BranchCondition* current = head_; current != nullptr;
     302             :        current = current->next) {
     303    13789182 :     if (current->condition == condition) {
     304       31412 :       return Just<bool>(current->is_true);
     305             :     }
     306             :   }
     307             :   return Nothing<bool>();
     308             : }
     309             : 
     310           0 : bool BranchElimination::ControlPathConditions::IsSamePath(
     311             :     BranchCondition* this_condition, BranchCondition* other_condition) const {
     312             :   while (true) {
     313      939644 :     if (this_condition == other_condition) return true;
     314           0 :     if (this_condition->condition != other_condition->condition ||
     315           0 :         this_condition->is_true != other_condition->is_true) {
     316             :       return false;
     317             :     }
     318           0 :     this_condition = this_condition->next;
     319           0 :     other_condition = other_condition->next;
     320             :   }
     321             :   UNREACHABLE();
     322             : }
     323             : 
     324      939691 : bool BranchElimination::ControlPathConditions::operator==(
     325             :     const ControlPathConditions& other) const {
     326      939691 :   if (condition_count_ != other.condition_count_) return false;
     327     1879288 :   return IsSamePath(head_, other.head_);
     328             : }
     329             : 
     330          42 : bool BranchElimination::ControlPathConditions::EqualsAfterAddingCondition(
     331             :     const ControlPathConditions* other, const Node* new_condition,
     332             :     bool new_branch_direction) const {
     333             :   // When an extra condition is added to the current chain, the count of
     334             :   // the resulting chain would increase by 1. Quick check to see if counts
     335             :   // match.
     336          42 :   if (other->condition_count_ != condition_count_ + 1) return false;
     337             : 
     338             :   // Check if the head of the other chain is same as the new condition that
     339             :   // would be added.
     340           0 :   if (other->head_->condition != new_condition ||
     341           0 :       other->head_->is_true != new_branch_direction) {
     342             :     return false;
     343             :   }
     344             : 
     345             :   // Check if the rest of the path is the same as the prev_condition.
     346           0 :   return IsSamePath(other->head_->next, head_);
     347             : }
     348             : 
     349           0 : Graph* BranchElimination::graph() const { return jsgraph()->graph(); }
     350             : 
     351           0 : CommonOperatorBuilder* BranchElimination::common() const {
     352           0 :   return jsgraph()->common();
     353             : }
     354             : 
     355             : }  // namespace compiler
     356             : }  // namespace internal
     357             : }  // namespace v8

Generated by: LCOV version 1.10