[turbofan] Use "leal" in even more situations
authordanno <danno@chromium.org>
Fri, 5 Dec 2014 10:54:27 +0000 (02:54 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 5 Dec 2014 10:54:40 +0000 (10:54 +0000)
Achieve more than parity with modes currently handled on ia32 in preparation for
porting the entire mechanism to ia32, including supporting mul of constants 3,
5 and 9 with "leal" instructions.

TEST=unittests

Review URL: https://codereview.chromium.org/774193003

Cr-Commit-Position: refs/heads/master@{#25677}

src/compiler/node-matchers.h
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-selector-x64.cc
test/unittests/compiler/node-matchers-unittest.cc
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 6636794b377565839926860aa9e934cee9553d92..13f7e1911e754454c603c9ec1e18d22e389cdf99 100644 (file)
@@ -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
index fd02916fa22257b2c6ace4ded72d6d1aa9ff01c1..f2679b0391b01f25dca742d011352471dbee4c7a 100644 (file)
@@ -93,8 +93,14 @@ class X64OperandConverter : public InstructionOperandConverter {
         int32_t disp = InputInt32(NextOffset(offset));
         return Operand(base, index, scale, disp);
       }
-      case kMode_M1:
+      case kMode_M1: {
+        Register base = InputRegister(NextOffset(offset));
+        int32_t disp = 0;
+        return Operand(base, disp);
+      }
       case kMode_M2:
+        UNREACHABLE();  // Should use kModeMR with more compact encoding instead
+        return Operand(no_reg, 0);
       case kMode_M4:
       case kMode_M8: {
         Register index = InputRegister(NextOffset(offset));
@@ -737,17 +743,26 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       break;
     case kX64Lea32: {
       AddressingMode mode = AddressingModeField::decode(instr->opcode());
-      // Shorten "leal" to "addl" or "subl" if the register allocation just
-      // happens to work out for operations with immediate operands where the
-      // non-constant input register is the same as output register. The
-      // "addl"/"subl" forms in these cases are faster based on empirical
-      // measurements.
-      if (mode == kMode_MRI && i.InputRegister(0).is(i.OutputRegister())) {
-        int32_t constant_summand = i.InputInt32(1);
-        if (constant_summand > 0) {
-          __ addl(i.OutputRegister(), Immediate(constant_summand));
-        } else if (constant_summand < 0) {
-          __ subl(i.OutputRegister(), Immediate(-constant_summand));
+      // Shorten "leal" to "addl", "subl" or "shll" if the register allocation
+      // and addressing mode just happens to work out. The "addl"/"subl" forms
+      // in these cases are faster based on measurements.
+      if (i.InputRegister(0).is(i.OutputRegister())) {
+        if (mode == kMode_MRI) {
+          int32_t constant_summand = i.InputInt32(1);
+          if (constant_summand > 0) {
+            __ addl(i.OutputRegister(), Immediate(constant_summand));
+          } else if (constant_summand < 0) {
+            __ subl(i.OutputRegister(), Immediate(-constant_summand));
+          }
+        } else if (mode == kMode_MR1 || mode == kMode_M2) {
+          // Using "addl %r1, %r1" is generally faster than "shll %r1, 1"
+          __ addl(i.OutputRegister(), i.InputRegister(1));
+        } else if (mode == kMode_M4) {
+          __ shll(i.OutputRegister(), Immediate(2));
+        } else if (mode == kMode_M8) {
+          __ shll(i.OutputRegister(), Immediate(3));
+        } else {
+          __ leal(i.OutputRegister(), i.MemoryOperand());
         }
       } else {
         __ leal(i.OutputRegister(), i.MemoryOperand());
index 4aa8b50bf37861e44b325ab79be40be4c90bb3c8..95ba8973ea1aa62cac352760b5013d2e7cfbe4d0 100644 (file)
@@ -33,6 +33,56 @@ class X64OperandGenerator FINAL : public OperandGenerator {
     }
   }
 
+  AddressingMode GenerateMemoryOperandInputs(Node* index, int scale_exponent,
+                                             Node* base, Node* displacement,
+                                             InstructionOperand* inputs[],
+                                             size_t* input_count) {
+    AddressingMode mode = kMode_MRI;
+    if (base != NULL) {
+      inputs[(*input_count)++] = UseRegister(base);
+      if (index != NULL) {
+        DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
+        inputs[(*input_count)++] = UseRegister(index);
+        if (displacement != NULL) {
+          inputs[(*input_count)++] = UseImmediate(displacement);
+          static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
+                                                       kMode_MR4I, kMode_MR8I};
+          mode = kMRnI_modes[scale_exponent];
+        } else {
+          static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
+                                                      kMode_MR4, kMode_MR8};
+          mode = kMRn_modes[scale_exponent];
+        }
+      } else {
+        if (displacement == NULL) {
+          mode = kMode_MR;
+        } else {
+          inputs[(*input_count)++] = UseImmediate(displacement);
+          mode = kMode_MRI;
+        }
+      }
+    } else {
+      DCHECK(index != NULL);
+      DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
+      inputs[(*input_count)++] = UseRegister(index);
+      if (displacement != NULL) {
+        inputs[(*input_count)++] = UseImmediate(displacement);
+        static const AddressingMode kMnI_modes[] = {kMode_M1I, kMode_M2I,
+                                                    kMode_M4I, kMode_M8I};
+        mode = kMnI_modes[scale_exponent];
+      } else {
+        static const AddressingMode kMn_modes[] = {kMode_M1, kMode_MR1,
+                                                   kMode_M4, kMode_M8};
+        mode = kMn_modes[scale_exponent];
+        if (mode == kMode_MR1) {
+          // [%r1 + %r1*1] has a smaller encoding than [%r1*2+0]
+          inputs[(*input_count)++] = UseRegister(index);
+        }
+      }
+    }
+    return mode;
+  }
+
   bool CanBeBetterLeftOperand(Node* node) const {
     return !selector()->IsLive(node);
   }
@@ -408,10 +458,39 @@ void VisitWord64Shift(InstructionSelector* selector, Node* node,
   }
 }
 
+
+void EmitLea(InstructionSelector* selector, InstructionCode opcode,
+             Node* result, Node* index, int scale, Node* base,
+             Node* displacement) {
+  X64OperandGenerator g(selector);
+
+  InstructionOperand* inputs[4];
+  size_t input_count = 0;
+  AddressingMode mode = g.GenerateMemoryOperandInputs(
+      index, scale, base, displacement, inputs, &input_count);
+
+  DCHECK_NE(0, static_cast<int>(input_count));
+  DCHECK_GE(arraysize(inputs), input_count);
+
+  InstructionOperand* outputs[1];
+  outputs[0] = g.DefineAsRegister(result);
+
+  opcode = AddressingModeField::encode(mode) | opcode;
+
+  selector->Emit(opcode, 1, outputs, input_count, inputs);
+}
+
 }  // namespace
 
 
 void InstructionSelector::VisitWord32Shl(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+    return;
+  }
   VisitWord32Shift(this, node, kX64Shl32);
 }
 
@@ -474,84 +553,19 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
 }
 
 
-namespace {
-
-AddressingMode GenerateMemoryOperandInputs(X64OperandGenerator* g, Node* scaled,
-                                           int scale_exponent, Node* offset,
-                                           Node* constant,
-                                           InstructionOperand* inputs[],
-                                           size_t* input_count) {
-  AddressingMode mode = kMode_MRI;
-  if (offset != NULL) {
-    inputs[(*input_count)++] = g->UseRegister(offset);
-    if (scaled != NULL) {
-      DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
-      inputs[(*input_count)++] = g->UseRegister(scaled);
-      if (constant != NULL) {
-        inputs[(*input_count)++] = g->UseImmediate(constant);
-        static const AddressingMode kMRnI_modes[] = {kMode_MR1I, kMode_MR2I,
-                                                     kMode_MR4I, kMode_MR8I};
-        mode = kMRnI_modes[scale_exponent];
-      } else {
-        static const AddressingMode kMRn_modes[] = {kMode_MR1, kMode_MR2,
-                                                    kMode_MR4, kMode_MR8};
-        mode = kMRn_modes[scale_exponent];
-      }
-    } else {
-      if (constant == NULL) {
-        mode = kMode_MR;
-      } else {
-        inputs[(*input_count)++] = g->UseImmediate(constant);
-        mode = kMode_MRI;
-      }
-    }
-  } else {
-    DCHECK(scaled != NULL);
-    DCHECK(scale_exponent >= 0 && scale_exponent <= 3);
-    inputs[(*input_count)++] = g->UseRegister(scaled);
-    if (constant != NULL) {
-      inputs[(*input_count)++] = g->UseImmediate(constant);
-      static const AddressingMode kMnI_modes[] = {kMode_M1I, kMode_M2I,
-                                                  kMode_M4I, kMode_M8I};
-      mode = kMnI_modes[scale_exponent];
-    } else {
-      static const AddressingMode kMn_modes[] = {kMode_M1, kMode_M2, kMode_M4,
-                                                 kMode_M8};
-      mode = kMn_modes[scale_exponent];
-    }
-  }
-  return mode;
-}
-
-}  // namespace
-
-
 void InstructionSelector::VisitInt32Add(Node* node) {
-  // Try to match the Add to a leal pattern
-  ScaledWithOffset32Matcher m(node);
   X64OperandGenerator g(this);
-  // It's possible to use a "leal", but it may not be smaller/cheaper. In the
-  // case that there are only two operands to the add and one of them isn't
-  // live, use a plain "addl".
-  if (m.matches() && (m.constant() == NULL || g.CanBeImmediate(m.constant()))) {
-    InstructionOperand* inputs[4];
-    size_t input_count = 0;
-    AddressingMode mode = GenerateMemoryOperandInputs(
-        &g, m.scaled(), m.scale_exponent(), m.offset(), m.constant(), inputs,
-        &input_count);
 
-    DCHECK_NE(0, static_cast<int>(input_count));
-    DCHECK_GE(arraysize(inputs), input_count);
-
-    InstructionOperand* outputs[1];
-    outputs[0] = g.DefineAsRegister(node);
-
-    InstructionCode opcode = AddressingModeField::encode(mode) | kX64Lea32;
-
-    Emit(opcode, 1, outputs, input_count, inputs);
+  // Try to match the Add to a leal pattern
+  BaseWithIndexAndDisplacement32Matcher m(node);
+  if (m.matches() &&
+      (m.displacement() == NULL || g.CanBeImmediate(m.displacement()))) {
+    EmitLea(this, kX64Lea32, node, m.index(), m.scale(), m.base(),
+            m.displacement());
     return;
   }
 
+  // No leal pattern match, use addl
   VisitBinop(this, node, kX64Add32);
 }
 
@@ -646,6 +660,13 @@ void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
 
 
 void InstructionSelector::VisitInt32Mul(Node* node) {
+  Int32ScaleMatcher m(node, true);
+  if (m.matches()) {
+    Node* index = node->InputAt(0);
+    Node* base = m.power_of_two_plus_one() ? index : NULL;
+    EmitLea(this, kX64Lea32, node, index, m.scale(), base, NULL);
+    return;
+  }
   VisitMul(this, node, kX64Imul32);
 }
 
index 937c0869074ec99c4a31a3b51ca02ad2398e0789..5969cb424ad2ceca710c2a8e973d2b573ac15afa 100644 (file)
@@ -30,14 +30,13 @@ class NodeMatcherTest : public GraphTest {
 namespace {
 
 template <class Matcher>
-void CheckScaledWithOffsetMatch(Matcher* matcher, Node* scaled,
-                                int scale_exponent, Node* offset,
-                                Node* constant) {
+void CheckBaseWithIndexAndDisplacement(Matcher* matcher, Node* index, int scale,
+                                       Node* base, Node* displacement) {
   EXPECT_TRUE(matcher->matches());
-  EXPECT_EQ(scaled, matcher->scaled());
-  EXPECT_EQ(scale_exponent, matcher->scale_exponent());
-  EXPECT_EQ(offset, matcher->offset());
-  EXPECT_EQ(constant, matcher->constant());
+  EXPECT_EQ(index, matcher->index());
+  EXPECT_EQ(scale, matcher->scale());
+  EXPECT_EQ(base, matcher->base());
+  EXPECT_EQ(displacement, matcher->displacement());
 }
 };
 
@@ -45,34 +44,43 @@ void CheckScaledWithOffsetMatch(Matcher* matcher, Node* scaled,
 TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
   graph()->SetStart(graph()->NewNode(common()->Start(0)));
 
-  const Operator* c0_op = common()->Int32Constant(0);
-  Node* c0 = graph()->NewNode(c0_op);
-  USE(c0);
-  const Operator* c1_op = common()->Int32Constant(1);
-  Node* c1 = graph()->NewNode(c1_op);
-  USE(c1);
-  const Operator* c2_op = common()->Int32Constant(2);
-  Node* c2 = graph()->NewNode(c2_op);
-  USE(c2);
-  const Operator* c3_op = common()->Int32Constant(3);
-  Node* c3 = graph()->NewNode(c3_op);
-  USE(c3);
-  const Operator* c4_op = common()->Int32Constant(4);
-  Node* c4 = graph()->NewNode(c4_op);
-  USE(c4);
-  const Operator* c8_op = common()->Int32Constant(8);
-  Node* c8 = graph()->NewNode(c8_op);
-  USE(c8);
-  const Operator* c15_op = common()->Int32Constant(15);
-  Node* c15 = graph()->NewNode(c15_op);
-  USE(c15);
-
-  const Operator* o0_op = common()->Parameter(0);
-  Node* o0 = graph()->NewNode(o0_op, graph()->start());
-  USE(o0);
-  const Operator* o1_op = common()->Parameter(1);
-  Node* o1 = graph()->NewNode(o1_op, graph()->start());
-  USE(o0);
+  const Operator* d0_op = common()->Int32Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int32Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int32Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int32Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int32Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int32Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int32Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d4);
+  const Operator* d8_op = common()->Int32Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int32Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d9);
+  const Operator* d15_op = common()->Int32Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
 
   const Operator* p1_op = common()->Parameter(3);
   Node* p1 = graph()->NewNode(p1_op, graph()->start());
@@ -82,23 +90,29 @@ TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
   USE(a_op);
 
   const Operator* m_op = machine()->Int32Mul();
-  Node* m1 = graph()->NewNode(m_op, p1, c1);
-  Node* m2 = graph()->NewNode(m_op, p1, c2);
-  Node* m4 = graph()->NewNode(m_op, p1, c4);
-  Node* m8 = graph()->NewNode(m_op, p1, c8);
-  Node* m3 = graph()->NewNode(m_op, p1, c3);
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
   USE(m1);
   USE(m2);
+  USE(m3);
   USE(m4);
+  USE(m5);
+  USE(m7);
   USE(m8);
-  USE(m3);
+  USE(m9);
 
   const Operator* s_op = machine()->Word32Shl();
-  Node* s0 = graph()->NewNode(s_op, p1, c0);
-  Node* s1 = graph()->NewNode(s_op, p1, c1);
-  Node* s2 = graph()->NewNode(s_op, p1, c2);
-  Node* s3 = graph()->NewNode(s_op, p1, c3);
-  Node* s4 = graph()->NewNode(s_op, p1, c4);
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
   USE(s0);
   USE(s1);
   USE(s2);
@@ -107,257 +121,282 @@ TEST_F(NodeMatcherTest, ScaledWithOffset32Matcher) {
 
   // 1 INPUT
 
-  // Only relevant test cases is checking for non-match.
-  ScaledWithOffset32Matcher match0(c15);
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement32Matcher match0(d15);
   EXPECT_FALSE(match0.matches());
 
   // 2 INPUT
 
-  // (O0 + O1) -> [O0, 0, O1, NULL]
-  ScaledWithOffset32Matcher match1(graph()->NewNode(a_op, o0, o1));
-  CheckScaledWithOffsetMatch(&match1, o1, 0, o0, NULL);
-
-  // (O0 + C15) -> [NULL, 0, O0, C15]
-  ScaledWithOffset32Matcher match2(graph()->NewNode(a_op, o0, c15));
-  CheckScaledWithOffsetMatch(&match2, NULL, 0, o0, c15);
-
-  // (C15 + O0) -> [NULL, 0, O0, C15]
-  ScaledWithOffset32Matcher match3(graph()->NewNode(a_op, c15, o0));
-  CheckScaledWithOffsetMatch(&match3, NULL, 0, o0, c15);
-
-  // (O0 + M1) -> [p1, 0, O0, NULL]
-  ScaledWithOffset32Matcher match4(graph()->NewNode(a_op, o0, m1));
-  CheckScaledWithOffsetMatch(&match4, p1, 0, o0, NULL);
-
-  // (M1 + O0) -> [p1, 0, O0, NULL]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset32Matcher match5(graph()->NewNode(a_op, m1, o0));
-  CheckScaledWithOffsetMatch(&match5, p1, 0, o0, NULL);
-
-  // (C15 + M1) -> [P1, 0, NULL, C15]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset32Matcher match6(graph()->NewNode(a_op, c15, m1));
-  CheckScaledWithOffsetMatch(&match6, p1, 0, NULL, c15);
-
-  // (M1 + C15) -> [P1, 0, NULL, C15]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset32Matcher match7(graph()->NewNode(a_op, m1, c15));
-  CheckScaledWithOffsetMatch(&match7, p1, 0, NULL, c15);
-
-  // (O0 + S0) -> [p1, 0, O0, NULL]
-  ScaledWithOffset32Matcher match8(graph()->NewNode(a_op, o0, s0));
-  CheckScaledWithOffsetMatch(&match8, p1, 0, o0, NULL);
-
-  // (S0 + O0) -> [p1, 0, O0, NULL]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset32Matcher match9(graph()->NewNode(a_op, s0, o0));
-  CheckScaledWithOffsetMatch(&match9, p1, 0, o0, NULL);
-
-  // (C15 + S0) -> [P1, 0, NULL, C15]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset32Matcher match10(graph()->NewNode(a_op, c15, s0));
-  CheckScaledWithOffsetMatch(&match10, p1, 0, NULL, c15);
-
-  // (S0 + C15) -> [P1, 0, NULL, C15]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset32Matcher match11(graph()->NewNode(a_op, s0, c15));
-  CheckScaledWithOffsetMatch(&match11, p1, 0, NULL, c15);
-
-  // (O0 + M2) -> [p1, 1, O0, NULL]
-  ScaledWithOffset32Matcher match12(graph()->NewNode(a_op, o0, m2));
-  CheckScaledWithOffsetMatch(&match12, p1, 1, o0, NULL);
-
-  // (M2 + O0) -> [p1, 1, O0, NULL]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset32Matcher match13(graph()->NewNode(a_op, m2, o0));
-  CheckScaledWithOffsetMatch(&match13, p1, 1, o0, NULL);
-
-  // (C15 + M2) -> [P1, 1, NULL, C15]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset32Matcher match14(graph()->NewNode(a_op, c15, m2));
-  CheckScaledWithOffsetMatch(&match14, p1, 1, NULL, c15);
-
-  // (M2 + C15) -> [P1, 1, NULL, C15]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset32Matcher match15(graph()->NewNode(a_op, m2, c15));
-  CheckScaledWithOffsetMatch(&match15, p1, 1, NULL, c15);
-
-  // (O0 + S1) -> [p1, 1, O0, NULL]
-  ScaledWithOffset32Matcher match16(graph()->NewNode(a_op, o0, s1));
-  CheckScaledWithOffsetMatch(&match16, p1, 1, o0, NULL);
-
-  // (S1 + O0) -> [p1, 1, O0, NULL]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset32Matcher match17(graph()->NewNode(a_op, s1, o0));
-  CheckScaledWithOffsetMatch(&match17, p1, 1, o0, NULL);
-
-  // (C15 + S1) -> [P1, 1, NULL, C15]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset32Matcher match18(graph()->NewNode(a_op, c15, s1));
-  CheckScaledWithOffsetMatch(&match18, p1, 1, NULL, c15);
-
-  // (S1 + C15) -> [P1, 1, NULL, C15]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset32Matcher match19(graph()->NewNode(a_op, s1, c15));
-  CheckScaledWithOffsetMatch(&match19, p1, 1, NULL, c15);
-
-  // (O0 + M4) -> [p1, 2, O0, NULL]
-  ScaledWithOffset32Matcher match20(graph()->NewNode(a_op, o0, m4));
-  CheckScaledWithOffsetMatch(&match20, p1, 2, o0, NULL);
-
-  // (M4 + O0) -> [p1, 2, O0, NULL]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset32Matcher match21(graph()->NewNode(a_op, m4, o0));
-  CheckScaledWithOffsetMatch(&match21, p1, 2, o0, NULL);
-
-  // (C15 + M4) -> [p1, 2, NULL, C15]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset32Matcher match22(graph()->NewNode(a_op, c15, m4));
-  CheckScaledWithOffsetMatch(&match22, p1, 2, NULL, c15);
-
-  // (M4 + C15) -> [p1, 2, NULL, C15]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset32Matcher match23(graph()->NewNode(a_op, m4, c15));
-  CheckScaledWithOffsetMatch(&match23, p1, 2, NULL, c15);
-
-  // (O0 + S2) -> [p1, 2, O0, NULL]
-  ScaledWithOffset32Matcher match24(graph()->NewNode(a_op, o0, s2));
-  CheckScaledWithOffsetMatch(&match24, p1, 2, o0, NULL);
-
-  // (S2 + O0) -> [p1, 2, O0, NULL]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset32Matcher match25(graph()->NewNode(a_op, s2, o0));
-  CheckScaledWithOffsetMatch(&match25, p1, 2, o0, NULL);
-
-  // (C15 + S2) -> [p1, 2, NULL, C15]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset32Matcher match26(graph()->NewNode(a_op, c15, s2));
-  CheckScaledWithOffsetMatch(&match26, p1, 2, NULL, c15);
-
-  // (S2 + C15) -> [p1, 2, NULL, C15]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset32Matcher match27(graph()->NewNode(a_op, s2, c15));
-  CheckScaledWithOffsetMatch(&match27, p1, 2, NULL, c15);
-
-  // (O0 + M8) -> [p1, 2, O0, NULL]
-  ScaledWithOffset32Matcher match28(graph()->NewNode(a_op, o0, m8));
-  CheckScaledWithOffsetMatch(&match28, p1, 3, o0, NULL);
-
-  // (M8 + O0) -> [p1, 2, O0, NULL]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset32Matcher match29(graph()->NewNode(a_op, m8, o0));
-  CheckScaledWithOffsetMatch(&match29, p1, 3, o0, NULL);
-
-  // (C15 + M8) -> [p1, 2, NULL, C15]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset32Matcher match30(graph()->NewNode(a_op, c15, m8));
-  CheckScaledWithOffsetMatch(&match30, p1, 3, NULL, c15);
-
-  // (M8 + C15) -> [p1, 2, NULL, C15]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset32Matcher match31(graph()->NewNode(a_op, m8, c15));
-  CheckScaledWithOffsetMatch(&match31, p1, 3, NULL, c15);
-
-  // (O0 + S3) -> [p1, 2, O0, NULL]
-  ScaledWithOffset32Matcher match32(graph()->NewNode(a_op, o0, s3));
-  CheckScaledWithOffsetMatch(&match32, p1, 3, o0, NULL);
-
-  // (S3 + O0) -> [p1, 2, O0, NULL]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match33(graph()->NewNode(a_op, s3, o0));
-  CheckScaledWithOffsetMatch(&match33, p1, 3, o0, NULL);
-
-  // (C15 + S3) -> [p1, 2, NULL, C15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match34(graph()->NewNode(a_op, c15, s3));
-  CheckScaledWithOffsetMatch(&match34, p1, 3, NULL, c15);
-
-  // (S3 + C15) -> [p1, 2, NULL, C15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match35(graph()->NewNode(a_op, s3, c15));
-  CheckScaledWithOffsetMatch(&match35, p1, 3, NULL, c15);
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement32Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement32Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement32Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement32Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement32Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement32Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement32Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement32Matcher match32(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match32, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
 
   // 2 INPUT - NEGATIVE CASES
 
-  // (M3 + O1) -> [O0, 0, M3, NULL]
-  ScaledWithOffset32Matcher match36(graph()->NewNode(a_op, o1, m3));
-  CheckScaledWithOffsetMatch(&match36, m3, 0, o1, NULL);
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement32Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
 
-  // (S4 + O1) -> [O0, 0, S4, NULL]
-  ScaledWithOffset32Matcher match37(graph()->NewNode(a_op, o1, s4));
-  CheckScaledWithOffsetMatch(&match37, s4, 0, o1, NULL);
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement32Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
 
   // 3 INPUT
 
-  // (C15 + S3) + O0 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match38(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, c15, s3), o0));
-  CheckScaledWithOffsetMatch(&match38, p1, 3, o0, c15);
-
-  // (O0 + C15) + S3 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match39(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, o0, c15), s3));
-  CheckScaledWithOffsetMatch(&match39, p1, 3, o0, c15);
-
-  // (S3 + O0) + C15 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match40(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, o0), c15));
-  CheckScaledWithOffsetMatch(&match40, p1, 3, o0, c15);
-
-  // C15 + (S3 + O0) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match41(
-      graph()->NewNode(a_op, c15, graph()->NewNode(a_op, s3, o0)));
-  CheckScaledWithOffsetMatch(&match41, p1, 3, o0, c15);
-
-  // O0 + (C15 + S3) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match42(
-      graph()->NewNode(a_op, o0, graph()->NewNode(a_op, c15, s3)));
-  CheckScaledWithOffsetMatch(&match42, p1, 3, o0, c15);
-
-  // S3 + (O0 + C15) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset32Matcher match43(
-      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, o0, c15)));
-  CheckScaledWithOffsetMatch(&match43, p1, 3, o0, c15);
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement32Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // Check that scales that require using the base address work dorrectly.
 }
 
 
 TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
   graph()->SetStart(graph()->NewNode(common()->Start(0)));
 
-  const Operator* c0_op = common()->Int64Constant(0);
-  Node* c0 = graph()->NewNode(c0_op);
-  USE(c0);
-  const Operator* c1_op = common()->Int64Constant(1);
-  Node* c1 = graph()->NewNode(c1_op);
-  USE(c1);
-  const Operator* c2_op = common()->Int64Constant(2);
-  Node* c2 = graph()->NewNode(c2_op);
-  USE(c2);
-  const Operator* c3_op = common()->Int64Constant(3);
-  Node* c3 = graph()->NewNode(c3_op);
-  USE(c3);
-  const Operator* c4_op = common()->Int64Constant(4);
-  Node* c4 = graph()->NewNode(c4_op);
-  USE(c4);
-  const Operator* c8_op = common()->Int64Constant(8);
-  Node* c8 = graph()->NewNode(c8_op);
-  USE(c8);
-  const Operator* c15_op = common()->Int64Constant(15);
-  Node* c15 = graph()->NewNode(c15_op);
-  USE(c15);
-
-  const Operator* o0_op = common()->Parameter(0);
-  Node* o0 = graph()->NewNode(o0_op, graph()->start());
-  USE(o0);
-  const Operator* o1_op = common()->Parameter(1);
-  Node* o1 = graph()->NewNode(o1_op, graph()->start());
-  USE(o0);
+  const Operator* d0_op = common()->Int64Constant(0);
+  Node* d0 = graph()->NewNode(d0_op);
+  USE(d0);
+  const Operator* d1_op = common()->Int64Constant(1);
+  Node* d1 = graph()->NewNode(d1_op);
+  USE(d1);
+  const Operator* d2_op = common()->Int64Constant(2);
+  Node* d2 = graph()->NewNode(d2_op);
+  USE(d2);
+  const Operator* d3_op = common()->Int64Constant(3);
+  Node* d3 = graph()->NewNode(d3_op);
+  USE(d3);
+  const Operator* d4_op = common()->Int64Constant(4);
+  Node* d4 = graph()->NewNode(d4_op);
+  USE(d4);
+  const Operator* d5_op = common()->Int64Constant(5);
+  Node* d5 = graph()->NewNode(d5_op);
+  USE(d5);
+  const Operator* d7_op = common()->Int64Constant(7);
+  Node* d7 = graph()->NewNode(d7_op);
+  USE(d7);
+  const Operator* d8_op = common()->Int64Constant(8);
+  Node* d8 = graph()->NewNode(d8_op);
+  USE(d8);
+  const Operator* d9_op = common()->Int64Constant(9);
+  Node* d9 = graph()->NewNode(d9_op);
+  USE(d8);
+  const Operator* d15_op = common()->Int64Constant(15);
+  Node* d15 = graph()->NewNode(d15_op);
+  USE(d15);
+
+  const Operator* b0_op = common()->Parameter(0);
+  Node* b0 = graph()->NewNode(b0_op, graph()->start());
+  USE(b0);
+  const Operator* b1_op = common()->Parameter(1);
+  Node* b1 = graph()->NewNode(b1_op, graph()->start());
+  USE(b0);
 
   const Operator* p1_op = common()->Parameter(3);
   Node* p1 = graph()->NewNode(p1_op, graph()->start());
@@ -367,23 +406,29 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
   USE(a_op);
 
   const Operator* m_op = machine()->Int64Mul();
-  Node* m1 = graph()->NewNode(m_op, p1, c1);
-  Node* m2 = graph()->NewNode(m_op, p1, c2);
-  Node* m4 = graph()->NewNode(m_op, p1, c4);
-  Node* m8 = graph()->NewNode(m_op, p1, c8);
-  Node* m3 = graph()->NewNode(m_op, p1, c3);
+  Node* m1 = graph()->NewNode(m_op, p1, d1);
+  Node* m2 = graph()->NewNode(m_op, p1, d2);
+  Node* m3 = graph()->NewNode(m_op, p1, d3);
+  Node* m4 = graph()->NewNode(m_op, p1, d4);
+  Node* m5 = graph()->NewNode(m_op, p1, d5);
+  Node* m7 = graph()->NewNode(m_op, p1, d7);
+  Node* m8 = graph()->NewNode(m_op, p1, d8);
+  Node* m9 = graph()->NewNode(m_op, p1, d9);
   USE(m1);
   USE(m2);
+  USE(m3);
   USE(m4);
+  USE(m5);
+  USE(m7);
   USE(m8);
-  USE(m3);
+  USE(m9);
 
   const Operator* s_op = machine()->Word64Shl();
-  Node* s0 = graph()->NewNode(s_op, p1, c0);
-  Node* s1 = graph()->NewNode(s_op, p1, c1);
-  Node* s2 = graph()->NewNode(s_op, p1, c2);
-  Node* s3 = graph()->NewNode(s_op, p1, c3);
-  Node* s4 = graph()->NewNode(s_op, p1, c4);
+  Node* s0 = graph()->NewNode(s_op, p1, d0);
+  Node* s1 = graph()->NewNode(s_op, p1, d1);
+  Node* s2 = graph()->NewNode(s_op, p1, d2);
+  Node* s3 = graph()->NewNode(s_op, p1, d3);
+  Node* s4 = graph()->NewNode(s_op, p1, d4);
   USE(s0);
   USE(s1);
   USE(s2);
@@ -392,223 +437,287 @@ TEST_F(NodeMatcherTest, ScaledWithOffset64Matcher) {
 
   // 1 INPUT
 
-  // Only relevant test cases is checking for non-match.
-  ScaledWithOffset64Matcher match0(c15);
+  // Only relevant test dases is Checking for non-match.
+  BaseWithIndexAndDisplacement64Matcher match0(d15);
   EXPECT_FALSE(match0.matches());
 
   // 2 INPUT
 
-  // (O0 + O1) -> [O0, 0, O1, NULL]
-  ScaledWithOffset64Matcher match1(graph()->NewNode(a_op, o0, o1));
-  CheckScaledWithOffsetMatch(&match1, o1, 0, o0, NULL);
-
-  // (O0 + C15) -> [NULL, 0, O0, C15]
-  ScaledWithOffset64Matcher match2(graph()->NewNode(a_op, o0, c15));
-  CheckScaledWithOffsetMatch(&match2, NULL, 0, o0, c15);
-
-  // (C15 + O0) -> [NULL, 0, O0, C15]
-  ScaledWithOffset64Matcher match3(graph()->NewNode(a_op, c15, o0));
-  CheckScaledWithOffsetMatch(&match3, NULL, 0, o0, c15);
-
-  // (O0 + M1) -> [p1, 0, O0, NULL]
-  ScaledWithOffset64Matcher match4(graph()->NewNode(a_op, o0, m1));
-  CheckScaledWithOffsetMatch(&match4, p1, 0, o0, NULL);
-
-  // (M1 + O0) -> [p1, 0, O0, NULL]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset64Matcher match5(graph()->NewNode(a_op, m1, o0));
-  CheckScaledWithOffsetMatch(&match5, p1, 0, o0, NULL);
-
-  // (C15 + M1) -> [P1, 0, NULL, C15]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset64Matcher match6(graph()->NewNode(a_op, c15, m1));
-  CheckScaledWithOffsetMatch(&match6, p1, 0, NULL, c15);
-
-  // (M1 + C15) -> [P1, 0, NULL, C15]
-  m1 = graph()->NewNode(m_op, p1, c1);
-  ScaledWithOffset64Matcher match7(graph()->NewNode(a_op, m1, c15));
-  CheckScaledWithOffsetMatch(&match7, p1, 0, NULL, c15);
-
-  // (O0 + S0) -> [p1, 0, O0, NULL]
-  ScaledWithOffset64Matcher match8(graph()->NewNode(a_op, o0, s0));
-  CheckScaledWithOffsetMatch(&match8, p1, 0, o0, NULL);
-
-  // (S0 + O0) -> [p1, 0, O0, NULL]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset64Matcher match9(graph()->NewNode(a_op, s0, o0));
-  CheckScaledWithOffsetMatch(&match9, p1, 0, o0, NULL);
-
-  // (C15 + S0) -> [P1, 0, NULL, C15]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset64Matcher match10(graph()->NewNode(a_op, c15, s0));
-  CheckScaledWithOffsetMatch(&match10, p1, 0, NULL, c15);
-
-  // (S0 + C15) -> [P1, 0, NULL, C15]
-  s0 = graph()->NewNode(s_op, p1, c0);
-  ScaledWithOffset64Matcher match11(graph()->NewNode(a_op, s0, c15));
-  CheckScaledWithOffsetMatch(&match11, p1, 0, NULL, c15);
-
-  // (O0 + M2) -> [p1, 1, O0, NULL]
-  ScaledWithOffset64Matcher match12(graph()->NewNode(a_op, o0, m2));
-  CheckScaledWithOffsetMatch(&match12, p1, 1, o0, NULL);
-
-  // (M2 + O0) -> [p1, 1, O0, NULL]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset64Matcher match13(graph()->NewNode(a_op, m2, o0));
-  CheckScaledWithOffsetMatch(&match13, p1, 1, o0, NULL);
-
-  // (C15 + M2) -> [P1, 1, NULL, C15]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset64Matcher match14(graph()->NewNode(a_op, c15, m2));
-  CheckScaledWithOffsetMatch(&match14, p1, 1, NULL, c15);
-
-  // (M2 + C15) -> [P1, 1, NULL, C15]
-  m2 = graph()->NewNode(m_op, p1, c2);
-  ScaledWithOffset64Matcher match15(graph()->NewNode(a_op, m2, c15));
-  CheckScaledWithOffsetMatch(&match15, p1, 1, NULL, c15);
-
-  // (O0 + S1) -> [p1, 1, O0, NULL]
-  ScaledWithOffset64Matcher match16(graph()->NewNode(a_op, o0, s1));
-  CheckScaledWithOffsetMatch(&match16, p1, 1, o0, NULL);
-
-  // (S1 + O0) -> [p1, 1, O0, NULL]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset64Matcher match17(graph()->NewNode(a_op, s1, o0));
-  CheckScaledWithOffsetMatch(&match17, p1, 1, o0, NULL);
-
-  // (C15 + S1) -> [P1, 1, NULL, C15]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset64Matcher match18(graph()->NewNode(a_op, c15, s1));
-  CheckScaledWithOffsetMatch(&match18, p1, 1, NULL, c15);
-
-  // (S1 + C15) -> [P1, 1, NULL, C15]
-  s1 = graph()->NewNode(s_op, p1, c1);
-  ScaledWithOffset64Matcher match19(graph()->NewNode(a_op, s1, c15));
-  CheckScaledWithOffsetMatch(&match19, p1, 1, NULL, c15);
-
-  // (O0 + M4) -> [p1, 2, O0, NULL]
-  ScaledWithOffset64Matcher match20(graph()->NewNode(a_op, o0, m4));
-  CheckScaledWithOffsetMatch(&match20, p1, 2, o0, NULL);
-
-  // (M4 + O0) -> [p1, 2, O0, NULL]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset64Matcher match21(graph()->NewNode(a_op, m4, o0));
-  CheckScaledWithOffsetMatch(&match21, p1, 2, o0, NULL);
-
-  // (C15 + M4) -> [p1, 2, NULL, C15]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset64Matcher match22(graph()->NewNode(a_op, c15, m4));
-  CheckScaledWithOffsetMatch(&match22, p1, 2, NULL, c15);
-
-  // (M4 + C15) -> [p1, 2, NULL, C15]
-  m4 = graph()->NewNode(m_op, p1, c4);
-  ScaledWithOffset64Matcher match23(graph()->NewNode(a_op, m4, c15));
-  CheckScaledWithOffsetMatch(&match23, p1, 2, NULL, c15);
-
-  // (O0 + S2) -> [p1, 2, O0, NULL]
-  ScaledWithOffset64Matcher match24(graph()->NewNode(a_op, o0, s2));
-  CheckScaledWithOffsetMatch(&match24, p1, 2, o0, NULL);
-
-  // (S2 + O0) -> [p1, 2, O0, NULL]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset64Matcher match25(graph()->NewNode(a_op, s2, o0));
-  CheckScaledWithOffsetMatch(&match25, p1, 2, o0, NULL);
-
-  // (C15 + S2) -> [p1, 2, NULL, C15]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset64Matcher match26(graph()->NewNode(a_op, c15, s2));
-  CheckScaledWithOffsetMatch(&match26, p1, 2, NULL, c15);
-
-  // (S2 + C15) -> [p1, 2, NULL, C15]
-  s2 = graph()->NewNode(s_op, p1, c2);
-  ScaledWithOffset64Matcher match27(graph()->NewNode(a_op, s2, c15));
-  CheckScaledWithOffsetMatch(&match27, p1, 2, NULL, c15);
-
-  // (O0 + M8) -> [p1, 2, O0, NULL]
-  ScaledWithOffset64Matcher match28(graph()->NewNode(a_op, o0, m8));
-  CheckScaledWithOffsetMatch(&match28, p1, 3, o0, NULL);
-
-  // (M8 + O0) -> [p1, 2, O0, NULL]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset64Matcher match29(graph()->NewNode(a_op, m8, o0));
-  CheckScaledWithOffsetMatch(&match29, p1, 3, o0, NULL);
-
-  // (C15 + M8) -> [p1, 2, NULL, C15]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset64Matcher match30(graph()->NewNode(a_op, c15, m8));
-  CheckScaledWithOffsetMatch(&match30, p1, 3, NULL, c15);
-
-  // (M8 + C15) -> [p1, 2, NULL, C15]
-  m8 = graph()->NewNode(m_op, p1, c8);
-  ScaledWithOffset64Matcher match31(graph()->NewNode(a_op, m8, c15));
-  CheckScaledWithOffsetMatch(&match31, p1, 3, NULL, c15);
-
-  // (O0 + S3) -> [p1, 2, O0, NULL]
-  ScaledWithOffset64Matcher match64(graph()->NewNode(a_op, o0, s3));
-  CheckScaledWithOffsetMatch(&match64, p1, 3, o0, NULL);
-
-  // (S3 + O0) -> [p1, 2, O0, NULL]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match33(graph()->NewNode(a_op, s3, o0));
-  CheckScaledWithOffsetMatch(&match33, p1, 3, o0, NULL);
-
-  // (C15 + S3) -> [p1, 2, NULL, C15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match34(graph()->NewNode(a_op, c15, s3));
-  CheckScaledWithOffsetMatch(&match34, p1, 3, NULL, c15);
-
-  // (S3 + C15) -> [p1, 2, NULL, C15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match35(graph()->NewNode(a_op, s3, c15));
-  CheckScaledWithOffsetMatch(&match35, p1, 3, NULL, c15);
+  // (B0 + B1) -> [B0, 0, B1, NULL]
+  BaseWithIndexAndDisplacement64Matcher match1(graph()->NewNode(a_op, b0, b1));
+  CheckBaseWithIndexAndDisplacement(&match1, b1, 0, b0, NULL);
+
+  // (B0 + D15) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match2(graph()->NewNode(a_op, b0, d15));
+  CheckBaseWithIndexAndDisplacement(&match2, NULL, 0, b0, d15);
+
+  // (D15 + B0) -> [NULL, 0, B0, D15]
+  BaseWithIndexAndDisplacement64Matcher match3(graph()->NewNode(a_op, d15, b0));
+  CheckBaseWithIndexAndDisplacement(&match3, NULL, 0, b0, d15);
+
+  // (B0 + M1) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match4(graph()->NewNode(a_op, b0, m1));
+  CheckBaseWithIndexAndDisplacement(&match4, p1, 0, b0, NULL);
+
+  // (M1 + B0) -> [p1, 0, B0, NULL]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match5(graph()->NewNode(a_op, m1, b0));
+  CheckBaseWithIndexAndDisplacement(&match5, p1, 0, b0, NULL);
+
+  // (D15 + M1) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match6(graph()->NewNode(a_op, d15, m1));
+  CheckBaseWithIndexAndDisplacement(&match6, p1, 0, NULL, d15);
+
+  // (M1 + D15) -> [P1, 0, NULL, D15]
+  m1 = graph()->NewNode(m_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match7(graph()->NewNode(a_op, m1, d15));
+  CheckBaseWithIndexAndDisplacement(&match7, p1, 0, NULL, d15);
+
+  // (B0 + S0) -> [p1, 0, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match8(graph()->NewNode(a_op, b0, s0));
+  CheckBaseWithIndexAndDisplacement(&match8, p1, 0, b0, NULL);
+
+  // (S0 + B0) -> [p1, 0, B0, NULL]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match9(graph()->NewNode(a_op, s0, b0));
+  CheckBaseWithIndexAndDisplacement(&match9, p1, 0, b0, NULL);
+
+  // (D15 + S0) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match10(
+      graph()->NewNode(a_op, d15, s0));
+  CheckBaseWithIndexAndDisplacement(&match10, p1, 0, NULL, d15);
+
+  // (S0 + D15) -> [P1, 0, NULL, D15]
+  s0 = graph()->NewNode(s_op, p1, d0);
+  BaseWithIndexAndDisplacement64Matcher match11(
+      graph()->NewNode(a_op, s0, d15));
+  CheckBaseWithIndexAndDisplacement(&match11, p1, 0, NULL, d15);
+
+  // (B0 + M2) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match12(graph()->NewNode(a_op, b0, m2));
+  CheckBaseWithIndexAndDisplacement(&match12, p1, 1, b0, NULL);
+
+  // (M2 + B0) -> [p1, 1, B0, NULL]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match13(graph()->NewNode(a_op, m2, b0));
+  CheckBaseWithIndexAndDisplacement(&match13, p1, 1, b0, NULL);
+
+  // (D15 + M2) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match14(
+      graph()->NewNode(a_op, d15, m2));
+  CheckBaseWithIndexAndDisplacement(&match14, p1, 1, NULL, d15);
+
+  // (M2 + D15) -> [P1, 1, NULL, D15]
+  m2 = graph()->NewNode(m_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match15(
+      graph()->NewNode(a_op, m2, d15));
+  CheckBaseWithIndexAndDisplacement(&match15, p1, 1, NULL, d15);
+
+  // (B0 + S1) -> [p1, 1, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match16(graph()->NewNode(a_op, b0, s1));
+  CheckBaseWithIndexAndDisplacement(&match16, p1, 1, b0, NULL);
+
+  // (S1 + B0) -> [p1, 1, B0, NULL]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match17(graph()->NewNode(a_op, s1, b0));
+  CheckBaseWithIndexAndDisplacement(&match17, p1, 1, b0, NULL);
+
+  // (D15 + S1) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match18(
+      graph()->NewNode(a_op, d15, s1));
+  CheckBaseWithIndexAndDisplacement(&match18, p1, 1, NULL, d15);
+
+  // (S1 + D15) -> [P1, 1, NULL, D15]
+  s1 = graph()->NewNode(s_op, p1, d1);
+  BaseWithIndexAndDisplacement64Matcher match19(
+      graph()->NewNode(a_op, s1, d15));
+  CheckBaseWithIndexAndDisplacement(&match19, p1, 1, NULL, d15);
+
+  // (B0 + M4) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match20(graph()->NewNode(a_op, b0, m4));
+  CheckBaseWithIndexAndDisplacement(&match20, p1, 2, b0, NULL);
+
+  // (M4 + B0) -> [p1, 2, B0, NULL]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match21(graph()->NewNode(a_op, m4, b0));
+  CheckBaseWithIndexAndDisplacement(&match21, p1, 2, b0, NULL);
+
+  // (D15 + M4) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match22(
+      graph()->NewNode(a_op, d15, m4));
+  CheckBaseWithIndexAndDisplacement(&match22, p1, 2, NULL, d15);
+
+  // (M4 + D15) -> [p1, 2, NULL, D15]
+  m4 = graph()->NewNode(m_op, p1, d4);
+  BaseWithIndexAndDisplacement64Matcher match23(
+      graph()->NewNode(a_op, m4, d15));
+  CheckBaseWithIndexAndDisplacement(&match23, p1, 2, NULL, d15);
+
+  // (B0 + S2) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match24(graph()->NewNode(a_op, b0, s2));
+  CheckBaseWithIndexAndDisplacement(&match24, p1, 2, b0, NULL);
+
+  // (S2 + B0) -> [p1, 2, B0, NULL]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match25(graph()->NewNode(a_op, s2, b0));
+  CheckBaseWithIndexAndDisplacement(&match25, p1, 2, b0, NULL);
+
+  // (D15 + S2) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match26(
+      graph()->NewNode(a_op, d15, s2));
+  CheckBaseWithIndexAndDisplacement(&match26, p1, 2, NULL, d15);
+
+  // (S2 + D15) -> [p1, 2, NULL, D15]
+  s2 = graph()->NewNode(s_op, p1, d2);
+  BaseWithIndexAndDisplacement64Matcher match27(
+      graph()->NewNode(a_op, s2, d15));
+  CheckBaseWithIndexAndDisplacement(&match27, p1, 2, NULL, d15);
+
+  // (B0 + M8) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match28(graph()->NewNode(a_op, b0, m8));
+  CheckBaseWithIndexAndDisplacement(&match28, p1, 3, b0, NULL);
+
+  // (M8 + B0) -> [p1, 2, B0, NULL]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match29(graph()->NewNode(a_op, m8, b0));
+  CheckBaseWithIndexAndDisplacement(&match29, p1, 3, b0, NULL);
+
+  // (D15 + M8) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match30(
+      graph()->NewNode(a_op, d15, m8));
+  CheckBaseWithIndexAndDisplacement(&match30, p1, 3, NULL, d15);
+
+  // (M8 + D15) -> [p1, 2, NULL, D15]
+  m8 = graph()->NewNode(m_op, p1, d8);
+  BaseWithIndexAndDisplacement64Matcher match31(
+      graph()->NewNode(a_op, m8, d15));
+  CheckBaseWithIndexAndDisplacement(&match31, p1, 3, NULL, d15);
+
+  // (B0 + S3) -> [p1, 2, B0, NULL]
+  BaseWithIndexAndDisplacement64Matcher match64(graph()->NewNode(a_op, b0, s3));
+  CheckBaseWithIndexAndDisplacement(&match64, p1, 3, b0, NULL);
+
+  // (S3 + B0) -> [p1, 2, B0, NULL]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match33(graph()->NewNode(a_op, s3, b0));
+  CheckBaseWithIndexAndDisplacement(&match33, p1, 3, b0, NULL);
+
+  // (D15 + S3) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match34(
+      graph()->NewNode(a_op, d15, s3));
+  CheckBaseWithIndexAndDisplacement(&match34, p1, 3, NULL, d15);
+
+  // (S3 + D15) -> [p1, 2, NULL, D15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match35(
+      graph()->NewNode(a_op, s3, d15));
+  CheckBaseWithIndexAndDisplacement(&match35, p1, 3, NULL, d15);
 
   // 2 INPUT - NEGATIVE CASES
 
-  // (M3 + O1) -> [O0, 0, M3, NULL]
-  ScaledWithOffset64Matcher match36(graph()->NewNode(a_op, o1, m3));
-  CheckScaledWithOffsetMatch(&match36, m3, 0, o1, NULL);
+  // (M3 + B1) -> [B0, 0, M3, NULL]
+  BaseWithIndexAndDisplacement64Matcher match36(graph()->NewNode(a_op, b1, m3));
+  CheckBaseWithIndexAndDisplacement(&match36, m3, 0, b1, NULL);
 
-  // (S4 + O1) -> [O0, 0, S4, NULL]
-  ScaledWithOffset64Matcher match37(graph()->NewNode(a_op, o1, s4));
-  CheckScaledWithOffsetMatch(&match37, s4, 0, o1, NULL);
+  // (S4 + B1) -> [B0, 0, S4, NULL]
+  BaseWithIndexAndDisplacement64Matcher match37(graph()->NewNode(a_op, b1, s4));
+  CheckBaseWithIndexAndDisplacement(&match37, s4, 0, b1, NULL);
 
   // 3 INPUT
 
-  // (C15 + S3) + O0 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match38(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, c15, s3), o0));
-  CheckScaledWithOffsetMatch(&match38, p1, 3, o0, c15);
-
-  // (O0 + C15) + S3 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match39(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, o0, c15), s3));
-  CheckScaledWithOffsetMatch(&match39, p1, 3, o0, c15);
-
-  // (S3 + O0) + C15 -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match40(
-      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, o0), c15));
-  CheckScaledWithOffsetMatch(&match40, p1, 3, o0, c15);
-
-  // C15 + (S3 + O0) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match41(
-      graph()->NewNode(a_op, c15, graph()->NewNode(a_op, s3, o0)));
-  CheckScaledWithOffsetMatch(&match41, p1, 3, o0, c15);
-
-  // O0 + (C15 + S3) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match42(
-      graph()->NewNode(a_op, o0, graph()->NewNode(a_op, c15, s3)));
-  CheckScaledWithOffsetMatch(&match42, p1, 3, o0, c15);
-
-  // S3 + (O0 + C15) -> [p1, 2, o0, c15]
-  s3 = graph()->NewNode(s_op, p1, c3);
-  ScaledWithOffset64Matcher match43(
-      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, o0, c15)));
-  CheckScaledWithOffsetMatch(&match43, p1, 3, o0, c15);
+  // (D15 + S3) + B0 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match38(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, d15, s3), b0));
+  CheckBaseWithIndexAndDisplacement(&match38, p1, 3, b0, d15);
+
+  // (B0 + D15) + S3 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match39(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, b0, d15), s3));
+  CheckBaseWithIndexAndDisplacement(&match39, p1, 3, b0, d15);
+
+  // (S3 + B0) + D15 -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match40(
+      graph()->NewNode(a_op, graph()->NewNode(a_op, s3, b0), d15));
+  CheckBaseWithIndexAndDisplacement(&match40, p1, 3, b0, d15);
+
+  // D15 + (S3 + B0) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match41(
+      graph()->NewNode(a_op, d15, graph()->NewNode(a_op, s3, b0)));
+  CheckBaseWithIndexAndDisplacement(&match41, p1, 3, b0, d15);
+
+  // B0 + (D15 + S3) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match42(
+      graph()->NewNode(a_op, b0, graph()->NewNode(a_op, d15, s3)));
+  CheckBaseWithIndexAndDisplacement(&match42, p1, 3, b0, d15);
+
+  // S3 + (B0 + D15) -> [p1, 2, b0, d15]
+  s3 = graph()->NewNode(s_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match43(
+      graph()->NewNode(a_op, s3, graph()->NewNode(a_op, b0, d15)));
+  CheckBaseWithIndexAndDisplacement(&match43, p1, 3, b0, d15);
+
+  // 2 INPUT with non-power of 2 scale
+
+  // (M3 + D15) -> [p1, 1, p1, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  BaseWithIndexAndDisplacement64Matcher match44(
+      graph()->NewNode(a_op, m3, d15));
+  CheckBaseWithIndexAndDisplacement(&match44, p1, 1, p1, d15);
+
+  // (M5 + D15) -> [p1, 2, p1, D15]
+  m5 = graph()->NewNode(m_op, p1, d5);
+  BaseWithIndexAndDisplacement64Matcher match45(
+      graph()->NewNode(a_op, m5, d15));
+  CheckBaseWithIndexAndDisplacement(&match45, p1, 2, p1, d15);
+
+  // (M9 + D15) -> [p1, 3, p1, D15]
+  m9 = graph()->NewNode(m_op, p1, d9);
+  BaseWithIndexAndDisplacement64Matcher match46(
+      graph()->NewNode(a_op, m9, d15));
+  CheckBaseWithIndexAndDisplacement(&match46, p1, 3, p1, d15);
+
+  // 3 INPUT negative cases: non-power of 2 scale but with a base
+
+  // ((M3 + B0) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  Node* temp = graph()->NewNode(a_op, m3, b0);
+  BaseWithIndexAndDisplacement64Matcher match47(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match47, m3, 0, b0, d15);
+
+  // (M3 + (B0 + D15)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, d15, b0);
+  BaseWithIndexAndDisplacement64Matcher match48(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match48, m3, 0, b0, d15);
+
+  // ((B0 + M3) + D15) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, m3);
+  BaseWithIndexAndDisplacement64Matcher match49(
+      graph()->NewNode(a_op, temp, d15));
+  CheckBaseWithIndexAndDisplacement(&match49, m3, 0, b0, d15);
+
+  // (M3 + (D15 + B0)) -> [m3, 0, b0, D15]
+  m3 = graph()->NewNode(m_op, p1, d3);
+  temp = graph()->NewNode(a_op, b0, d15);
+  BaseWithIndexAndDisplacement64Matcher match50(
+      graph()->NewNode(a_op, m3, temp));
+  CheckBaseWithIndexAndDisplacement(&match50, m3, 0, b0, d15);
 }
 
 
index 808bfbcdc065e4e002cb40952e974e2f2dad8ac4..9ef0fa58ca97709c9366ea2acba28cd44370c9db 100644 (file)
@@ -846,6 +846,150 @@ TEST_F(InstructionSelectorTest, Uint32MulHigh) {
 }
 
 
+TEST_F(InstructionSelectorTest, Int32Mul2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul3BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR2, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(4);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul5BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(5);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR4, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul8BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(8);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Mul9BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(9);
+  Node* const n = m.Int32Mul(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR8, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Word32Shl.
+
+
+TEST_F(InstructionSelectorTest, Int32Shl1BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(1);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_MR1, s[0]->addressing_mode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl2BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(2);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M4, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const c1 = m.Int32Constant(3);
+  Node* const n = m.Word32Shl(p0, c1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+  EXPECT_EQ(kMode_M8, s[0]->addressing_mode());
+  ASSERT_EQ(1U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+}
+
+
 // -----------------------------------------------------------------------------
 // Word64Shl.