Index: src/compiler/node-matchers.h |
diff --git a/src/compiler/node-matchers.h b/src/compiler/node-matchers.h |
index a55e7bf0a22b529ac36304b3458ae426ece9eead..b1147a7369f9801a75e24f22a2442347fbbfdf70 100644 |
--- a/src/compiler/node-matchers.h |
+++ b/src/compiler/node-matchers.h |
@@ -5,6 +5,8 @@ |
#ifndef V8_COMPILER_NODE_MATCHERS_H_ |
#define V8_COMPILER_NODE_MATCHERS_H_ |
+#include "src/compiler/generic-node.h" |
+#include "src/compiler/generic-node-inl.h" |
#include "src/compiler/node.h" |
#include "src/compiler/operator.h" |
#include "src/unique.h" |
@@ -116,7 +118,7 @@ struct HeapObjectMatcher FINAL |
// right hand sides of a binary operation and can put constants on the right |
// if they appear on the left hand side of a commutative operation. |
template <typename Left, typename Right> |
-struct BinopMatcher FINAL : public NodeMatcher { |
+struct BinopMatcher : public NodeMatcher { |
explicit BinopMatcher(Node* node) |
: NodeMatcher(node), left_(InputAt(0)), right_(InputAt(1)) { |
if (HasProperty(Operator::kCommutative)) PutConstantOnRight(); |
@@ -128,12 +130,17 @@ struct BinopMatcher FINAL : public NodeMatcher { |
bool IsFoldable() const { return left().HasValue() && right().HasValue(); } |
bool LeftEqualsRight() const { return left().node() == right().node(); } |
+ protected: |
+ void SwapInputs() { |
+ std::swap(left_, right_); |
+ node()->ReplaceInput(0, left().node()); |
+ node()->ReplaceInput(1, right().node()); |
+ } |
+ |
private: |
void PutConstantOnRight() { |
if (left().HasValue() && !right().HasValue()) { |
- std::swap(left_, right_); |
- node()->ReplaceInput(0, left().node()); |
- node()->ReplaceInput(1, right().node()); |
+ SwapInputs(); |
} |
} |
@@ -150,6 +157,189 @@ typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher; |
typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; |
typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher; |
+struct Int32AddMatcher : public Int32BinopMatcher { |
+ explicit Int32AddMatcher(Node* node) |
+ : Int32BinopMatcher(node), scale_exponent_(-1) { |
+ PutScaledInputOnLeft(); |
+ } |
+ |
+ bool HasScaledInput() const { return scale_exponent_ != -1; } |
+ Node* ScaledInput() const { |
+ DCHECK(HasScaledInput()); |
+ return left().node()->InputAt(0); |
+ } |
+ int ScaleExponent() const { |
+ DCHECK(HasScaledInput()); |
+ return scale_exponent_; |
+ } |
+ |
+ private: |
+ int GetInputScaleExponent(Node* node) const { |
+ if (node->opcode() == IrOpcode::kWord32Shl) { |
+ Int32BinopMatcher m(node); |
+ if (m.right().HasValue()) { |
+ int32_t value = m.right().Value(); |
+ if (value >= 0 && value <= 3) { |
+ return value; |
+ } |
+ } |
+ } else if (node->opcode() == IrOpcode::kInt32Mul) { |
+ Int32BinopMatcher m(node); |
+ if (m.right().HasValue()) { |
+ int32_t value = m.right().Value(); |
+ if (value == 1) { |
+ return 0; |
+ } else if (value == 2) { |
+ return 1; |
+ } else if (value == 4) { |
+ return 2; |
+ } else if (value == 8) { |
+ return 3; |
+ } |
+ } |
+ } |
+ return -1; |
+ } |
+ |
+ void PutScaledInputOnLeft() { |
+ scale_exponent_ = GetInputScaleExponent(right().node()); |
+ if (scale_exponent_ >= 0) { |
+ int left_scale_exponent = GetInputScaleExponent(left().node()); |
+ if (left_scale_exponent == -1) { |
+ SwapInputs(); |
+ } else { |
+ scale_exponent_ = left_scale_exponent; |
+ } |
+ } else { |
+ scale_exponent_ = GetInputScaleExponent(left().node()); |
+ if (scale_exponent_ == -1) { |
+ if (right().opcode() == IrOpcode::kInt32Add && |
+ left().opcode() != IrOpcode::kInt32Add) { |
+ SwapInputs(); |
+ } |
+ } |
+ } |
+ } |
+ |
+ int scale_exponent_; |
+}; |
+ |
+struct ScaledWithOffsetMatcher { |
+ explicit ScaledWithOffsetMatcher(Node* node) |
+ : matches_(false), |
+ scaled_(NULL), |
+ scale_exponent_(0), |
+ offset_(NULL), |
+ constant_(NULL) { |
+ if (node->opcode() != IrOpcode::kInt32Add) return; |
+ |
+ // The Int32AddMatcher 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) |
+ Int32AddMatcher 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(); |
+ if (right->opcode() == IrOpcode::kInt32Add && right->OwnedBy(node)) { |
+ Int32AddMatcher right_matcher(right); |
+ if (right_matcher.right().HasValue()) { |
+ // (S + (O + C)) |
+ offset_ = right_matcher.left().node(); |
+ constant_ = right_matcher.right().node(); |
+ } else { |
+ // (S + (O + O)) |
+ offset_ = right; |
+ } |
+ } else if (base_matcher.right().HasValue()) { |
+ // (S + C) |
+ constant_ = right; |
+ } else { |
+ // (S + O) |
+ offset_ = right; |
+ } |
+ } else { |
+ if (left->opcode() == IrOpcode::kInt32Add && left->OwnedBy(node)) { |
+ Int32AddMatcher 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)) { |
+ scaled_ = left_matcher.ScaledInput(); |
+ scale_exponent_ = left_matcher.ScaleExponent(); |
+ if (left_matcher.right().HasValue()) { |
+ // ((S + C) + O) |
+ constant_ = left_right; |
+ offset_ = right; |
+ } else if (base_matcher.right().HasValue()) { |
+ // ((S + O) + C) |
+ offset_ = left_right; |
+ constant_ = right; |
+ } else { |
+ // (O + O) |
+ scaled_ = left; |
+ offset_ = 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; |
+ } else { |
+ // (O + O) |
+ scaled_ = left; |
+ offset_ = right; |
+ } |
+ } |
+ } else { |
+ if (base_matcher.right().HasValue()) { |
+ // (O + C) |
+ offset_ = left; |
+ constant_ = right; |
+ } else { |
+ // (O + O) |
+ offset_ = left; |
+ scaled_ = right; |
+ } |
+ } |
+ } |
+ 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_; } |
+ |
+ private: |
+ bool matches_; |
+ |
+ protected: |
+ Node* scaled_; |
+ int scale_exponent_; |
+ Node* offset_; |
+ Node* constant_; |
+}; |
+ |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |