summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/branch-elimination.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/branch-elimination.cc')
-rw-r--r--deps/v8/src/compiler/branch-elimination.cc287
1 files changed, 92 insertions, 195 deletions
diff --git a/deps/v8/src/compiler/branch-elimination.cc b/deps/v8/src/compiler/branch-elimination.cc
index 53c3435b55..3d71e98a12 100644
--- a/deps/v8/src/compiler/branch-elimination.cc
+++ b/deps/v8/src/compiler/branch-elimination.cc
@@ -16,7 +16,8 @@ BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
Zone* zone)
: AdvancedReducer(editor),
jsgraph_(js_graph),
- node_conditions_(zone, js_graph->graph()->NodeCount()),
+ node_conditions_(js_graph->graph()->NodeCount(), zone),
+ reduced_(js_graph->graph()->NodeCount(), zone),
zone_(zone),
dead_(js_graph->Dead()) {}
@@ -55,26 +56,32 @@ Reduction BranchElimination::Reduce(Node* node) {
Reduction BranchElimination::ReduceBranch(Node* node) {
Node* condition = node->InputAt(0);
Node* control_input = NodeProperties::GetControlInput(node, 0);
- const ControlPathConditions* from_input = node_conditions_.Get(control_input);
- if (from_input != nullptr) {
- Maybe<bool> condition_value = from_input->LookupCondition(condition);
- // If we know the condition we can discard the branch.
- if (condition_value.IsJust()) {
- bool known_value = condition_value.FromJust();
- for (Node* const use : node->uses()) {
- switch (use->opcode()) {
- case IrOpcode::kIfTrue:
- Replace(use, known_value ? control_input : dead());
- break;
- case IrOpcode::kIfFalse:
- Replace(use, known_value ? dead() : control_input);
- break;
- default:
- UNREACHABLE();
- }
+ ControlPathConditions from_input = node_conditions_.Get(control_input);
+ Node* branch;
+ bool condition_value;
+ // If we know the condition we can discard the branch.
+ if (from_input.LookupCondition(condition, &branch, &condition_value)) {
+ // Mark the branch as a safety check.
+ // Check if {branch} is dead because we might have a stale side-table entry.
+ if (IsSafetyCheckOf(node->op()) == IsSafetyCheck::kSafetyCheck &&
+ !branch->IsDead()) {
+ NodeProperties::ChangeOp(branch,
+ common()->MarkAsSafetyCheck(branch->op()));
+ }
+
+ for (Node* const use : node->uses()) {
+ switch (use->opcode()) {
+ case IrOpcode::kIfTrue:
+ Replace(use, condition_value ? control_input : dead());
+ break;
+ case IrOpcode::kIfFalse:
+ Replace(use, condition_value ? dead() : control_input);
+ break;
+ default:
+ UNREACHABLE();
}
- return Replace(dead());
}
+ return Replace(dead());
}
return TakeConditionsFromFirstControl(node);
}
@@ -88,45 +95,53 @@ Reduction BranchElimination::ReduceDeoptimizeConditional(Node* node) {
Node* frame_state = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
- ControlPathConditions const* conditions = node_conditions_.Get(control);
// If we do not know anything about the predecessor, do not propagate just
// yet because we will have to recompute anyway once we compute the
// predecessor.
- if (conditions == nullptr) {
- return UpdateConditions(node, conditions);
- }
- Maybe<bool> condition_value = conditions->LookupCondition(condition);
- if (condition_value.IsJust()) {
+ if (!reduced_.Get(control)) {
+ return NoChange();
+ }
+
+ ControlPathConditions conditions = node_conditions_.Get(control);
+ bool condition_value;
+ Node* branch;
+ if (conditions.LookupCondition(condition, &branch, &condition_value)) {
+ // Mark the branch as a safety check.
+ if (p.is_safety_check() == IsSafetyCheck::kSafetyCheck) {
+ NodeProperties::ChangeOp(branch,
+ common()->MarkAsSafetyCheck(branch->op()));
+ }
+
// If we know the condition we can discard the branch.
- if (condition_is_true == condition_value.FromJust()) {
+ if (condition_is_true == condition_value) {
// We don't update the conditions here, because we're replacing {node}
// with the {control} node that already contains the right information.
ReplaceWithValue(node, dead(), effect, control);
} else {
control = graph()->NewNode(
- common()->Deoptimize(p.kind(), p.reason(), VectorSlotPair()),
- frame_state, effect, control);
+ common()->Deoptimize(p.kind(), p.reason(), p.feedback()), frame_state,
+ effect, control);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), control);
Revisit(graph()->end());
}
return Replace(dead());
}
- return UpdateConditions(node, conditions, condition, condition_is_true);
+ return UpdateConditions(node, conditions, condition, node, condition_is_true);
}
Reduction BranchElimination::ReduceIf(Node* node, bool is_true_branch) {
// Add the condition to the list arriving from the input branch.
Node* branch = NodeProperties::GetControlInput(node, 0);
- const ControlPathConditions* from_branch = node_conditions_.Get(branch);
+ ControlPathConditions from_branch = node_conditions_.Get(branch);
// If we do not know anything about the predecessor, do not propagate just
// yet because we will have to recompute anyway once we compute the
// predecessor.
- if (from_branch == nullptr) {
- return UpdateConditions(node, nullptr);
+ if (!reduced_.Get(branch)) {
+ return NoChange();
}
Node* condition = branch->InputAt(0);
- return UpdateConditions(node, from_branch, condition, is_true_branch);
+ return UpdateConditions(node, from_branch, condition, branch, is_true_branch);
}
@@ -143,8 +158,8 @@ Reduction BranchElimination::ReduceMerge(Node* node) {
// input.
Node::Inputs inputs = node->inputs();
for (Node* input : inputs) {
- if (node_conditions_.Get(input) == nullptr) {
- return UpdateConditions(node, nullptr);
+ if (!reduced_.Get(input)) {
+ return NoChange();
}
}
@@ -152,42 +167,23 @@ Reduction BranchElimination::ReduceMerge(Node* node) {
DCHECK_GT(inputs.count(), 0);
- const ControlPathConditions* first = node_conditions_.Get(*input_it);
+ ControlPathConditions conditions = node_conditions_.Get(*input_it);
++input_it;
- // Make a copy of the first input's conditions and merge with the conditions
- // from other inputs.
- ControlPathConditions* conditions =
- new (zone_->New(sizeof(ControlPathConditions)))
- ControlPathConditions(*first);
+ // Merge the first input's conditions with the conditions from the other
+ // inputs.
auto input_end = inputs.end();
for (; input_it != input_end; ++input_it) {
- conditions->Merge(*(node_conditions_.Get(*input_it)));
+ // Change the current condition list to a longest common tail
+ // of this condition list and the other list. (The common tail
+ // should correspond to the list from the common dominator.)
+ conditions.ResetToCommonAncestor(node_conditions_.Get(*input_it));
}
-
return UpdateConditions(node, conditions);
}
Reduction BranchElimination::ReduceStart(Node* node) {
- return UpdateConditions(node, ControlPathConditions::Empty(zone_));
-}
-
-const BranchElimination::ControlPathConditions*
-BranchElimination::PathConditionsForControlNodes::Get(Node* node) const {
- if (static_cast<size_t>(node->id()) < info_for_node_.size()) {
- return info_for_node_[node->id()];
- }
- return nullptr;
-}
-
-
-void BranchElimination::PathConditionsForControlNodes::Set(
- Node* node, const ControlPathConditions* conditions) {
- size_t index = static_cast<size_t>(node->id());
- if (index >= info_for_node_.size()) {
- info_for_node_.resize(index + 1, nullptr);
- }
- info_for_node_[index] = conditions;
+ return UpdateConditions(node, {});
}
@@ -200,157 +196,58 @@ Reduction BranchElimination::ReduceOtherControl(Node* node) {
Reduction BranchElimination::TakeConditionsFromFirstControl(Node* node) {
// We just propagate the information from the control input (ideally,
// we would only revisit control uses if there is change).
- const ControlPathConditions* from_input =
- node_conditions_.Get(NodeProperties::GetControlInput(node, 0));
- return UpdateConditions(node, from_input);
+ Node* input = NodeProperties::GetControlInput(node, 0);
+ if (!reduced_.Get(input)) return NoChange();
+ return UpdateConditions(node, node_conditions_.Get(input));
}
-
Reduction BranchElimination::UpdateConditions(
- Node* node, const ControlPathConditions* conditions) {
- const ControlPathConditions* original = node_conditions_.Get(node);
+ Node* node, ControlPathConditions conditions) {
// Only signal that the node has Changed if the condition information has
// changed.
- if (conditions != original) {
- if (conditions == nullptr || original == nullptr ||
- *conditions != *original) {
- node_conditions_.Set(node, conditions);
- return Changed(node);
- }
+ if (reduced_.Set(node, true) | node_conditions_.Set(node, conditions)) {
+ return Changed(node);
}
return NoChange();
}
Reduction BranchElimination::UpdateConditions(
- Node* node, const ControlPathConditions* prev_conditions,
- Node* current_condition, bool is_true_branch) {
- const ControlPathConditions* original = node_conditions_.Get(node);
- DCHECK(prev_conditions != nullptr && current_condition != nullptr);
+ Node* node, ControlPathConditions prev_conditions, Node* current_condition,
+ Node* current_branch, bool is_true_branch) {
+ ControlPathConditions original = node_conditions_.Get(node);
// The control path for the node is the path obtained by appending the
- // current_condition to the prev_conditions. Check if this new control path
- // would be the same as the already recorded path (original).
- if (original == nullptr || !prev_conditions->EqualsAfterAddingCondition(
- original, current_condition, is_true_branch)) {
- // If this is the first visit or if the control path is different from the
- // recorded path create the new control path and record it.
- const ControlPathConditions* new_condition =
- prev_conditions->AddCondition(zone_, current_condition, is_true_branch);
- node_conditions_.Set(node, new_condition);
- return Changed(node);
- }
- return NoChange();
-}
-
-// static
-const BranchElimination::ControlPathConditions*
-BranchElimination::ControlPathConditions::Empty(Zone* zone) {
- return new (zone->New(sizeof(ControlPathConditions)))
- ControlPathConditions(nullptr, 0);
-}
-
-
-void BranchElimination::ControlPathConditions::Merge(
- const ControlPathConditions& other) {
- // Change the current condition list to a longest common tail
- // of this condition list and the other list. (The common tail
- // should correspond to the list from the common dominator.)
-
- // First, we throw away the prefix of the longer list, so that
- // we have lists of the same length.
- size_t other_size = other.condition_count_;
- BranchCondition* other_condition = other.head_;
- while (other_size > condition_count_) {
- other_condition = other_condition->next;
- other_size--;
- }
- while (condition_count_ > other_size) {
- head_ = head_->next;
- condition_count_--;
- }
-
- // Then we go through both lists in lock-step until we find
- // the common tail.
- while (head_ != other_condition) {
- DCHECK_LT(0, condition_count_);
- condition_count_--;
- other_condition = other_condition->next;
- head_ = head_->next;
- }
-}
-
-
-const BranchElimination::ControlPathConditions*
-BranchElimination::ControlPathConditions::AddCondition(Zone* zone,
- Node* condition,
- bool is_true) const {
- DCHECK(LookupCondition(condition).IsNothing());
-
- BranchCondition* new_head = new (zone->New(sizeof(BranchCondition)))
- BranchCondition(condition, is_true, head_);
-
- ControlPathConditions* conditions =
- new (zone->New(sizeof(ControlPathConditions)))
- ControlPathConditions(new_head, condition_count_ + 1);
- return conditions;
-}
-
-
-Maybe<bool> BranchElimination::ControlPathConditions::LookupCondition(
- Node* condition) const {
- for (BranchCondition* current = head_; current != nullptr;
- current = current->next) {
- if (current->condition == condition) {
- return Just<bool>(current->is_true);
+ // current_condition to the prev_conditions. Use the original control path as
+ // a hint to avoid allocations.
+ prev_conditions.AddCondition(zone_, current_condition, current_branch,
+ is_true_branch, original);
+ return UpdateConditions(node, prev_conditions);
+}
+
+void BranchElimination::ControlPathConditions::AddCondition(
+ Zone* zone, Node* condition, Node* branch, bool is_true,
+ ControlPathConditions hint) {
+ DCHECK_EQ(false, LookupCondition(condition, nullptr, nullptr));
+ PushFront({condition, branch, is_true}, zone, hint);
+}
+
+bool BranchElimination::ControlPathConditions::LookupCondition(
+ Node* condition, Node** branch, bool* is_true) const {
+ for (BranchCondition element : *this) {
+ if (element.condition == condition) {
+ *is_true = element.is_true;
+ *branch = element.branch;
+ return true;
}
}
- return Nothing<bool>();
-}
-
-bool BranchElimination::ControlPathConditions::IsSamePath(
- BranchCondition* this_condition, BranchCondition* other_condition) const {
- while (true) {
- if (this_condition == other_condition) return true;
- if (this_condition->condition != other_condition->condition ||
- this_condition->is_true != other_condition->is_true) {
- return false;
- }
- this_condition = this_condition->next;
- other_condition = other_condition->next;
+ return false;
}
- UNREACHABLE();
-}
-bool BranchElimination::ControlPathConditions::operator==(
- const ControlPathConditions& other) const {
- if (condition_count_ != other.condition_count_) return false;
- return IsSamePath(head_, other.head_);
-}
+ Graph* BranchElimination::graph() const { return jsgraph()->graph(); }
-bool BranchElimination::ControlPathConditions::EqualsAfterAddingCondition(
- const ControlPathConditions* other, const Node* new_condition,
- bool new_branch_direction) const {
- // When an extra condition is added to the current chain, the count of
- // the resulting chain would increase by 1. Quick check to see if counts
- // match.
- if (other->condition_count_ != condition_count_ + 1) return false;
-
- // Check if the head of the other chain is same as the new condition that
- // would be added.
- if (other->head_->condition != new_condition ||
- other->head_->is_true != new_branch_direction) {
- return false;
+ CommonOperatorBuilder* BranchElimination::common() const {
+ return jsgraph()->common();
}
- // Check if the rest of the path is the same as the prev_condition.
- return IsSamePath(other->head_->next, head_);
-}
-
-Graph* BranchElimination::graph() const { return jsgraph()->graph(); }
-
-CommonOperatorBuilder* BranchElimination::common() const {
- return jsgraph()->common();
-}
-
} // namespace compiler
} // namespace internal
} // namespace v8