Index: src/compiler/redundancy-elimination.cc |
diff --git a/src/compiler/redundancy-elimination.cc b/src/compiler/redundancy-elimination.cc |
index 6dcf2bf4cf0c111da9c018c0feb8e946d22ad061..acd051ac4408bb2b0d4bd05bba4166752e13d306 100644 |
--- a/src/compiler/redundancy-elimination.cc |
+++ b/src/compiler/redundancy-elimination.cc |
@@ -36,6 +36,11 @@ Reduction RedundancyElimination::Reduce(Node* node) { |
case IrOpcode::kCheckedTaggedToInt32: |
case IrOpcode::kCheckedUint32ToInt32: |
return ReduceCheckNode(node); |
+ case IrOpcode::kSpeculativeNumberAdd: |
+ case IrOpcode::kSpeculativeNumberSubtract: |
+ // For increments and decrements by a constant, try to learn from the last |
+ // bounds check. |
+ return TryReuseBoundsCheckForFirstInput(node); |
case IrOpcode::kEffectPhi: |
return ReduceEffectPhi(node); |
case IrOpcode::kDead: |
@@ -133,6 +138,17 @@ Node* RedundancyElimination::EffectPathChecks::LookupCheck(Node* node) const { |
return nullptr; |
} |
+Node* RedundancyElimination::EffectPathChecks::LookupBoundsCheckFor( |
+ Node* node) const { |
+ for (Check const* check = head_; check != nullptr; check = check->next) { |
+ if (check->node->opcode() == IrOpcode::kCheckBounds && |
+ check->node->InputAt(0) == node) { |
+ return check->node; |
+ } |
+ } |
+ return nullptr; |
+} |
+ |
RedundancyElimination::EffectPathChecks const* |
RedundancyElimination::PathChecksForEffectNodes::Get(Node* node) const { |
size_t const id = node->id(); |
@@ -158,10 +174,41 @@ Reduction RedundancyElimination::ReduceCheckNode(Node* node) { |
ReplaceWithValue(node, check); |
return Replace(check); |
} |
+ |
// Learn from this check. |
return UpdateChecks(node, checks->AddCheck(zone(), node)); |
} |
+Reduction RedundancyElimination::TryReuseBoundsCheckForFirstInput(Node* node) { |
+ DCHECK(node->opcode() == IrOpcode::kSpeculativeNumberAdd || |
+ node->opcode() == IrOpcode::kSpeculativeNumberSubtract); |
+ |
+ DCHECK_EQ(1, node->op()->EffectInputCount()); |
+ DCHECK_EQ(1, node->op()->EffectOutputCount()); |
+ |
+ Node* const effect = NodeProperties::GetEffectInput(node); |
+ EffectPathChecks const* checks = node_checks_.Get(effect); |
+ |
+ // 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 (checks == nullptr) return NoChange(); |
+ |
+ Node* left = node->InputAt(0); |
+ Node* right = node->InputAt(1); |
+ // Only use bounds checks for increments/decrements by a constant. |
+ if (right->opcode() == IrOpcode::kNumberConstant) { |
+ if (Node* bounds_check = checks->LookupBoundsCheckFor(left)) { |
+ // Only use the bounds checked type if it is better. |
+ if (NodeProperties::GetType(bounds_check) |
+ ->Is(NodeProperties::GetType(left))) { |
+ node->ReplaceInput(0, bounds_check); |
+ } |
+ } |
+ } |
+ |
+ return UpdateChecks(node, checks); |
+} |
+ |
Reduction RedundancyElimination::ReduceEffectPhi(Node* node) { |
Node* const control = NodeProperties::GetControlInput(node); |
if (control->opcode() == IrOpcode::kLoop) { |