| Index: src/compiler/node-matchers.h
|
| diff --git a/src/compiler/node-matchers.h b/src/compiler/node-matchers.h
|
| index a55e7bf0a22b529ac36304b3458ae426ece9eead..f8f3c0387329751c642ea65389d19ce1281f7103 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_factor_(-1) {
|
| + PutScaledInputOnLeft();
|
| + }
|
| +
|
| + bool HasScaledInput() const { return scale_factor_ != -1; }
|
| + Node* ScaledInput() const {
|
| + DCHECK(HasScaledInput());
|
| + return left().node()->InputAt(0);
|
| + }
|
| + int ScaleFactor() const {
|
| + DCHECK(HasScaledInput());
|
| + return scale_factor_;
|
| + }
|
| +
|
| + private:
|
| + int GetInputScaleFactor(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_factor_ = GetInputScaleFactor(right().node());
|
| + if (scale_factor_ >= 0) {
|
| + int left_scale_factor = GetInputScaleFactor(left().node());
|
| + if (left_scale_factor == -1) {
|
| + SwapInputs();
|
| + } else {
|
| + scale_factor_ = left_scale_factor;
|
| + }
|
| + } else {
|
| + scale_factor_ = GetInputScaleFactor(left().node());
|
| + if (scale_factor_ == -1) {
|
| + if (right().opcode() == IrOpcode::kInt32Add &&
|
| + left().opcode() != IrOpcode::kInt32Add) {
|
| + SwapInputs();
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + int scale_factor_;
|
| +};
|
| +
|
| +struct ScaledWithOffsetMatcher {
|
| + explicit ScaledWithOffsetMatcher(Node* node)
|
| + : matches_(false),
|
| + scaled_(NULL),
|
| + scale_factor_(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_factor_ = base_matcher.ScaleFactor();
|
| + 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_factor_ = left_matcher.ScaleFactor();
|
| + 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_factor() const { return scale_factor_; }
|
| + Node* offset() const { return offset_; }
|
| + Node* constant() const { return constant_; }
|
| +
|
| + private:
|
| + bool matches_;
|
| +
|
| + protected:
|
| + Node* scaled_;
|
| + int scale_factor_;
|
| + Node* offset_;
|
| + Node* constant_;
|
| +};
|
| +
|
| } // namespace compiler
|
| } // namespace internal
|
| } // namespace v8
|
|
|