Index: src/compiler/node-matchers.h |
diff --git a/src/compiler/node-matchers.h b/src/compiler/node-matchers.h |
index 6636794b377565839926860aa9e934cee9553d92..13f7e1911e754454c603c9ec1e18d22e389cdf99 100644 |
--- a/src/compiler/node-matchers.h |
+++ b/src/compiler/node-matchers.h |
@@ -171,76 +171,111 @@ typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; |
typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher; |
-template <class BinopMatcher, IrOpcode::Value kAddOpcode, |
- IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode> |
-struct AddMatcher : public BinopMatcher { |
- static const IrOpcode::Value kOpcode = kAddOpcode; |
- |
- explicit AddMatcher(Node* node) : BinopMatcher(node), scale_exponent_(-1) { |
- if (this->HasProperty(Operator::kCommutative)) PutScaledInputOnLeft(); |
- } |
- |
- bool HasScaledInput() const { return scale_exponent_ != -1; } |
- Node* ScaledInput() const { |
- DCHECK(HasScaledInput()); |
- return this->left().node()->InputAt(0); |
- } |
- int ScaleExponent() const { |
- DCHECK(HasScaledInput()); |
- return scale_exponent_; |
- } |
- |
- private: |
- int GetInputScaleExponent(Node* node) const { |
+template <class BinopMatcher, IrOpcode::Value kMulOpcode, |
+ IrOpcode::Value kShiftOpcode> |
+struct ScaleMatcher { |
+ explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false) |
+ : scale_(-1), power_of_two_plus_one_(false) { |
+ if (node->InputCount() < 2) return; |
+ BinopMatcher m(node); |
if (node->opcode() == kShiftOpcode) { |
- BinopMatcher m(node); |
if (m.right().HasValue()) { |
typename BinopMatcher::RightMatcher::ValueType value = |
m.right().Value(); |
if (value >= 0 && value <= 3) { |
- return static_cast<int>(value); |
+ scale_ = static_cast<int>(value); |
} |
} |
} else if (node->opcode() == kMulOpcode) { |
- BinopMatcher m(node); |
if (m.right().HasValue()) { |
typename BinopMatcher::RightMatcher::ValueType value = |
m.right().Value(); |
if (value == 1) { |
- return 0; |
+ scale_ = 0; |
} else if (value == 2) { |
- return 1; |
+ scale_ = 1; |
} else if (value == 4) { |
- return 2; |
+ scale_ = 2; |
} else if (value == 8) { |
- return 3; |
+ scale_ = 3; |
+ } else if (allow_power_of_two_plus_one) { |
+ if (value == 3) { |
+ scale_ = 1; |
+ power_of_two_plus_one_ = true; |
+ } else if (value == 5) { |
+ scale_ = 2; |
+ power_of_two_plus_one_ = true; |
+ } else if (value == 9) { |
+ scale_ = 3; |
+ power_of_two_plus_one_ = true; |
+ } |
} |
} |
} |
- return -1; |
} |
- void PutScaledInputOnLeft() { |
- scale_exponent_ = GetInputScaleExponent(this->right().node()); |
- if (scale_exponent_ >= 0) { |
- int left_scale_exponent = GetInputScaleExponent(this->left().node()); |
- if (left_scale_exponent == -1) { |
- this->SwapInputs(); |
- } else { |
- scale_exponent_ = left_scale_exponent; |
- } |
- } else { |
- scale_exponent_ = GetInputScaleExponent(this->left().node()); |
- if (scale_exponent_ == -1) { |
- if (this->right().opcode() == kAddOpcode && |
- this->left().opcode() != kAddOpcode) { |
- this->SwapInputs(); |
- } |
- } |
+ bool matches() const { return scale_ != -1; } |
+ int scale() const { return scale_; } |
+ bool power_of_two_plus_one() const { return power_of_two_plus_one_; } |
+ |
+ private: |
+ int scale_; |
+ bool power_of_two_plus_one_; |
+}; |
+ |
+typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul, |
+ IrOpcode::kWord32Shl> Int32ScaleMatcher; |
+typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul, |
+ IrOpcode::kWord64Shl> Int64ScaleMatcher; |
+ |
+ |
+template <class BinopMatcher, IrOpcode::Value kAddOpcode, |
+ IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode> |
+struct AddMatcher : public BinopMatcher { |
+ static const IrOpcode::Value kOpcode = kAddOpcode; |
+ typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher; |
+ |
+ explicit AddMatcher(Node* node) |
+ : BinopMatcher(node), scale_(-1), power_of_two_plus_one_(false) { |
+ Matcher left_matcher(this->left().node(), true); |
+ if (left_matcher.matches()) { |
+ scale_ = left_matcher.scale(); |
+ power_of_two_plus_one_ = left_matcher.power_of_two_plus_one(); |
+ return; |
+ } |
+ |
+ if (!this->HasProperty(Operator::kCommutative)) { |
+ return; |
+ } |
+ |
+ Matcher right_matcher(this->right().node(), true); |
+ if (right_matcher.matches()) { |
+ scale_ = right_matcher.scale(); |
+ power_of_two_plus_one_ = right_matcher.power_of_two_plus_one(); |
+ this->SwapInputs(); |
+ return; |
} |
+ |
+ if (this->right().opcode() == kAddOpcode && |
+ this->left().opcode() != kAddOpcode) { |
+ this->SwapInputs(); |
+ } |
+ } |
+ |
+ bool HasIndexInput() const { return scale_ != -1; } |
+ Node* IndexInput() const { |
+ DCHECK(HasIndexInput()); |
+ return this->left().node()->InputAt(0); |
+ } |
+ int scale() const { |
+ DCHECK(HasIndexInput()); |
+ return scale_; |
} |
+ bool power_of_two_plus_one() const { return power_of_two_plus_one_; } |
- int scale_exponent_; |
+ private: |
+ int scale_; |
+ bool power_of_two_plus_one_; |
}; |
typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul, |
@@ -248,115 +283,128 @@ typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul, |
typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul, |
IrOpcode::kWord64Shl> Int64AddMatcher; |
+ |
template <class AddMatcher> |
-struct ScaledWithOffsetMatcher { |
- explicit ScaledWithOffsetMatcher(Node* node) |
+struct BaseWithIndexAndDisplacementMatcher { |
+ explicit BaseWithIndexAndDisplacementMatcher(Node* node) |
: matches_(false), |
- scaled_(NULL), |
- scale_exponent_(0), |
- offset_(NULL), |
- constant_(NULL) { |
- // The ScaledWithOffsetMatcher canonicalizes the order of constants and |
- // scale factors that are used as inputs, so instead of enumerating all |
- // possible patterns by brute force, checking for node clusters using the |
- // following templates in the following order suffices to find all of the |
- // interesting cases (S = scaled input, O = offset input, C = constant |
- // input): |
- // (S + (O + C)) |
- // (S + (O + O)) |
- // (S + C) |
- // (S + O) |
- // ((S + C) + O) |
- // ((S + O) + C) |
- // ((O + C) + O) |
- // ((O + O) + C) |
- // (O + C) |
- // (O + O) |
+ index_(NULL), |
+ scale_(0), |
+ base_(NULL), |
+ displacement_(NULL) { |
+ // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of |
+ // displacements and scale factors that are used as inputs, so instead of |
+ // enumerating all possible patterns by brute force, checking for node |
+ // clusters using the following templates in the following order suffices to |
+ // find all of the interesting cases (S = index * scale, B = base input, D = |
+ // displacement input): |
+ // (S + (B + D)) |
+ // (S + (B + B)) |
+ // (S + D) |
+ // (S + B) |
+ // ((S + D) + B) |
+ // ((S + B) + D) |
+ // ((B + D) + B) |
+ // ((B + B) + D) |
+ // (B + D) |
+ // (B + B) |
if (node->InputCount() < 2) return; |
- AddMatcher base_matcher(node); |
- Node* left = base_matcher.left().node(); |
- Node* right = base_matcher.right().node(); |
- if (base_matcher.HasScaledInput() && left->OwnedBy(node)) { |
- scaled_ = base_matcher.ScaledInput(); |
- scale_exponent_ = base_matcher.ScaleExponent(); |
+ AddMatcher m(node); |
+ Node* left = m.left().node(); |
+ Node* right = m.right().node(); |
+ Node* displacement = NULL; |
+ Node* base = NULL; |
+ Node* index = NULL; |
+ Node* scale_expression = NULL; |
+ bool power_of_two_plus_one = false; |
+ int scale = 0; |
+ if (m.HasIndexInput() && left->OwnedBy(node)) { |
+ index = m.IndexInput(); |
+ scale = m.scale(); |
+ scale_expression = left; |
+ power_of_two_plus_one = m.power_of_two_plus_one(); |
if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) { |
AddMatcher right_matcher(right); |
if (right_matcher.right().HasValue()) { |
- // (S + (O + C)) |
- offset_ = right_matcher.left().node(); |
- constant_ = right_matcher.right().node(); |
+ // (S + (B + D)) |
+ base = right_matcher.left().node(); |
+ displacement = right_matcher.right().node(); |
} else { |
- // (S + (O + O)) |
- offset_ = right; |
+ // (S + (B + B)) |
+ base = right; |
} |
- } else if (base_matcher.right().HasValue()) { |
- // (S + C) |
- constant_ = right; |
+ } else if (m.right().HasValue()) { |
+ // (S + D) |
+ displacement = right; |
} else { |
- // (S + O) |
- offset_ = right; |
+ // (S + B) |
+ base = right; |
} |
} else { |
if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) { |
AddMatcher left_matcher(left); |
Node* left_left = left_matcher.left().node(); |
Node* left_right = left_matcher.right().node(); |
- if (left_matcher.HasScaledInput() && left_left->OwnedBy(left)) { |
+ if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) { |
if (left_matcher.right().HasValue()) { |
- // ((S + C) + O) |
- scaled_ = left_matcher.ScaledInput(); |
- scale_exponent_ = left_matcher.ScaleExponent(); |
- constant_ = left_right; |
- offset_ = right; |
- } else if (base_matcher.right().HasValue()) { |
- // ((S + O) + C) |
- scaled_ = left_matcher.ScaledInput(); |
- scale_exponent_ = left_matcher.ScaleExponent(); |
- offset_ = left_right; |
- constant_ = right; |
+ // ((S + D) + B) |
+ index = left_matcher.IndexInput(); |
+ scale = left_matcher.scale(); |
+ scale_expression = left_left; |
+ power_of_two_plus_one = left_matcher.power_of_two_plus_one(); |
+ displacement = left_right; |
+ base = right; |
+ } else if (m.right().HasValue()) { |
+ // ((S + B) + D) |
+ index = left_matcher.IndexInput(); |
+ scale = left_matcher.scale(); |
+ scale_expression = left_left; |
+ power_of_two_plus_one = left_matcher.power_of_two_plus_one(); |
+ base = left_right; |
+ displacement = right; |
} else { |
- // (O + O) |
- scaled_ = left; |
- offset_ = right; |
+ // (B + B) |
+ index = left; |
+ base = right; |
} |
} else { |
if (left_matcher.right().HasValue()) { |
- // ((O + C) + O) |
- scaled_ = left_left; |
- constant_ = left_right; |
- offset_ = right; |
- } else if (base_matcher.right().HasValue()) { |
- // ((O + O) + C) |
- scaled_ = left_left; |
- offset_ = left_right; |
- constant_ = right; |
+ // ((B + D) + B) |
+ index = left_left; |
+ displacement = left_right; |
+ base = right; |
+ } else if (m.right().HasValue()) { |
+ // ((B + B) + D) |
+ index = left_left; |
+ base = left_right; |
+ displacement = right; |
} else { |
- // (O + O) |
- scaled_ = left; |
- offset_ = right; |
+ // (B + B) |
+ index = left; |
+ base = right; |
} |
} |
} else { |
- if (base_matcher.right().HasValue()) { |
- // (O + C) |
- offset_ = left; |
- constant_ = right; |
+ if (m.right().HasValue()) { |
+ // (B + D) |
+ base = left; |
+ displacement = right; |
} else { |
- // (O + O) |
- offset_ = left; |
- scaled_ = right; |
+ // (B + B) |
+ base = left; |
+ index = right; |
} |
} |
} |
int64_t value = 0; |
- if (constant_ != NULL) { |
- switch (constant_->opcode()) { |
+ if (displacement != NULL) { |
+ switch (displacement->opcode()) { |
case IrOpcode::kInt32Constant: { |
- value = OpParameter<int32_t>(constant_); |
+ value = OpParameter<int32_t>(displacement); |
break; |
} |
case IrOpcode::kInt64Constant: { |
- value = OpParameter<int64_t>(constant_); |
+ value = OpParameter<int64_t>(displacement); |
break; |
} |
default: |
@@ -364,30 +412,48 @@ struct ScaledWithOffsetMatcher { |
break; |
} |
if (value == 0) { |
- constant_ = NULL; |
+ displacement = NULL; |
+ } |
+ } |
+ if (power_of_two_plus_one) { |
+ if (base != NULL) { |
+ // If the scale requires explicitly using the index as the base, but a |
+ // base is already part of the match, then the (1 << N + 1) scale factor |
+ // can't be folded into the match and the entire index * scale |
+ // calculation must be computed separately. |
+ index = scale_expression; |
+ scale = 0; |
+ } else { |
+ base = index; |
} |
} |
+ base_ = base; |
+ displacement_ = displacement; |
+ index_ = index; |
+ scale_ = scale; |
matches_ = true; |
} |
bool matches() const { return matches_; } |
- Node* scaled() const { return scaled_; } |
- int scale_exponent() const { return scale_exponent_; } |
- Node* offset() const { return offset_; } |
- Node* constant() const { return constant_; } |
+ Node* index() const { return index_; } |
+ int scale() const { return scale_; } |
+ Node* base() const { return base_; } |
+ Node* displacement() const { return displacement_; } |
private: |
bool matches_; |
protected: |
- Node* scaled_; |
- int scale_exponent_; |
- Node* offset_; |
- Node* constant_; |
+ Node* index_; |
+ int scale_; |
+ Node* base_; |
+ Node* displacement_; |
}; |
-typedef ScaledWithOffsetMatcher<Int32AddMatcher> ScaledWithOffset32Matcher; |
-typedef ScaledWithOffsetMatcher<Int64AddMatcher> ScaledWithOffset64Matcher; |
+typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher> |
+ BaseWithIndexAndDisplacement32Matcher; |
+typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher> |
+ BaseWithIndexAndDisplacement64Matcher; |
} // namespace compiler |
} // namespace internal |