[turbofan] intel lea add multiply matchers
authordcarney@chromium.org <dcarney@chromium.org>
Wed, 1 Oct 2014 10:47:14 +0000 (10:47 +0000)
committerdcarney@chromium.org <dcarney@chromium.org>
Wed, 1 Oct 2014 10:47:14 +0000 (10:47 +0000)
R=bmeurer@chromium.org

BUG=

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24357 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/x64/instruction-selector-x64.cc
test/cctest/compiler/test-run-machops.cc
test/cctest/compiler/value-helper.h
test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 35d674d..4ee05d2 100644 (file)
@@ -367,7 +367,37 @@ void InstructionSelector::VisitWord32Ror(Node* node) {
 }
 
 
+static bool TryEmitLeaMultAdd(InstructionSelector* selector, Node* node) {
+  Int32BinopMatcher m(node);
+  if (!m.right().HasValue()) return false;
+  int32_t displacement_value = m.right().Value();
+  Node* left = m.left().node();
+  LeaMultiplyMatcher lmm(left);
+  if (!lmm.Matches()) return false;
+  AddressingMode mode;
+  size_t input_count;
+  IA32OperandGenerator g(selector);
+  InstructionOperand* index = g.UseRegister(lmm.Left());
+  InstructionOperand* displacement = g.TempImmediate(displacement_value);
+  InstructionOperand* inputs[] = {index, displacement, displacement};
+  if (lmm.Displacement() != 0) {
+    input_count = 3;
+    inputs[1] = index;
+    mode = kMode_MR1I;
+  } else {
+    input_count = 2;
+    mode = kMode_M1I;
+  }
+  mode = AdjustAddressingMode(mode, lmm.Power());
+  InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
+  selector->Emit(kIA32Lea | AddressingModeField::encode(mode), 1, outputs,
+                 input_count, inputs);
+  return true;
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
+  if (TryEmitLeaMultAdd(this, node)) return;
   VisitBinop(this, node, kIA32Add);
 }
 
@@ -383,41 +413,45 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
 }
 
 
-void InstructionSelector::VisitInt32Mul(Node* node) {
-  IA32OperandGenerator g(this);
+static bool TryEmitLeaMult(InstructionSelector* selector, Node* node) {
   LeaMultiplyMatcher lea(node);
   // Try to match lea.
-  if (lea.Matches()) {
-    ArchOpcode opcode = kIA32Lea;
-    AddressingMode mode;
-    size_t input_count;
-    InstructionOperand* left = g.UseRegister(lea.Left());
-    InstructionOperand* inputs[] = {left, left};
-    if (lea.Displacement() != 0) {
-      input_count = 2;
-      mode = kMode_MR1;
-    } else {
-      input_count = 1;
-      mode = kMode_M1;
-    }
-    mode = AdjustAddressingMode(mode, lea.Power());
-    InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
-    Emit(opcode | AddressingModeField::encode(mode), 1, outputs, input_count,
-         inputs);
+  if (!lea.Matches()) return false;
+  AddressingMode mode;
+  size_t input_count;
+  IA32OperandGenerator g(selector);
+  InstructionOperand* left = g.UseRegister(lea.Left());
+  InstructionOperand* inputs[] = {left, left};
+  if (lea.Displacement() != 0) {
+    input_count = 2;
+    mode = kMode_MR1;
   } else {
-    Int32BinopMatcher m(node);
-    Node* left = m.left().node();
-    Node* right = m.right().node();
-    if (g.CanBeImmediate(right)) {
-      Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
-           g.UseImmediate(right));
-    } else {
-      if (g.CanBeBetterLeftOperand(right)) {
-        std::swap(left, right);
-      }
-      Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
-           g.Use(right));
+    input_count = 1;
+    mode = kMode_M1;
+  }
+  mode = AdjustAddressingMode(mode, lea.Power());
+  InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
+  selector->Emit(kIA32Lea | AddressingModeField::encode(mode), 1, outputs,
+                 input_count, inputs);
+  return true;
+}
+
+
+void InstructionSelector::VisitInt32Mul(Node* node) {
+  if (TryEmitLeaMult(this, node)) return;
+  IA32OperandGenerator g(this);
+  Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
+  if (g.CanBeImmediate(right)) {
+    Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(left),
+         g.UseImmediate(right));
+  } else {
+    if (g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
     }
+    Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
+         g.Use(right));
   }
 }
 
index 9215cbe..8f52606 100644 (file)
@@ -434,12 +434,57 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
 }
 
 
+static bool TryEmitLeaMultAdd(InstructionSelector* selector, Node* node,
+                              ArchOpcode opcode) {
+  int32_t displacement_value;
+  Node* left;
+  {
+    Int32BinopMatcher m32(node);
+    left = m32.left().node();
+    if (m32.right().HasValue()) {
+      displacement_value = m32.right().Value();
+    } else {
+      Int64BinopMatcher m64(node);
+      if (!m64.right().HasValue()) {
+        return false;
+      }
+      int64_t value_64 = m64.right().Value();
+      displacement_value = static_cast<int32_t>(value_64);
+      if (displacement_value != value_64) return false;
+    }
+  }
+  LeaMultiplyMatcher lmm(left);
+  if (!lmm.Matches()) return false;
+  AddressingMode mode;
+  size_t input_count;
+  X64OperandGenerator g(selector);
+  InstructionOperand* index = g.UseRegister(lmm.Left());
+  InstructionOperand* displacement = g.TempImmediate(displacement_value);
+  InstructionOperand* inputs[] = {index, displacement, displacement};
+  if (lmm.Displacement() != 0) {
+    input_count = 3;
+    inputs[1] = index;
+    mode = kMode_MR1I;
+  } else {
+    input_count = 2;
+    mode = kMode_M1I;
+  }
+  mode = AdjustAddressingMode(mode, lmm.Power());
+  InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
+  selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs,
+                 input_count, inputs);
+  return true;
+}
+
+
 void InstructionSelector::VisitInt32Add(Node* node) {
+  if (TryEmitLeaMultAdd(this, node, kX64Lea32)) return;
   VisitBinop(this, node, kX64Add32);
 }
 
 
 void InstructionSelector::VisitInt64Add(Node* node) {
+  if (TryEmitLeaMultAdd(this, node, kX64Lea)) return;
   VisitBinop(this, node, kX64Add);
 }
 
@@ -466,61 +511,58 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
 }
 
 
+static bool TryEmitLeaMult(InstructionSelector* selector, Node* node,
+                           ArchOpcode opcode) {
+  LeaMultiplyMatcher lea(node);
+  // Try to match lea.
+  if (!lea.Matches()) return false;
+  AddressingMode mode;
+  size_t input_count;
+  X64OperandGenerator g(selector);
+  InstructionOperand* left = g.UseRegister(lea.Left());
+  InstructionOperand* inputs[] = {left, left};
+  if (lea.Displacement() != 0) {
+    input_count = 2;
+    mode = kMode_MR1;
+  } else {
+    input_count = 1;
+    mode = kMode_M1;
+  }
+  mode = AdjustAddressingMode(mode, lea.Power());
+  InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
+  selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs,
+                 input_count, inputs);
+  return true;
+}
+
+
 static void VisitMul(InstructionSelector* selector, Node* node,
                      ArchOpcode opcode) {
   X64OperandGenerator g(selector);
-  LeaMultiplyMatcher lea(node);
-  // Try to match lea.
-  if (lea.Matches()) {
-    switch (opcode) {
-      case kX64Imul32:
-        opcode = kX64Lea32;
-        break;
-      case kX64Imul:
-        opcode = kX64Lea;
-        break;
-      default:
-        UNREACHABLE();
-    }
-    AddressingMode mode;
-    size_t input_count;
-    InstructionOperand* left = g.UseRegister(lea.Left());
-    InstructionOperand* inputs[] = {left, left};
-    if (lea.Displacement() != 0) {
-      input_count = 2;
-      mode = kMode_MR1;
-    } else {
-      input_count = 1;
-      mode = kMode_M1;
-    }
-    mode = AdjustAddressingMode(mode, lea.Power());
-    InstructionOperand* outputs[] = {g.DefineAsRegister(node)};
-    selector->Emit(opcode | AddressingModeField::encode(mode), 1, outputs,
-                   input_count, inputs);
+  Int32BinopMatcher m(node);
+  Node* left = m.left().node();
+  Node* right = m.right().node();
+  if (g.CanBeImmediate(right)) {
+    selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
+                   g.UseImmediate(right));
   } else {
-    Int32BinopMatcher m(node);
-    Node* left = m.left().node();
-    Node* right = m.right().node();
-    if (g.CanBeImmediate(right)) {
-      selector->Emit(opcode, g.DefineAsRegister(node), g.Use(left),
-                     g.UseImmediate(right));
-    } else {
-      if (g.CanBeBetterLeftOperand(right)) {
-        std::swap(left, right);
-      }
-      selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
-                     g.Use(right));
+    if (g.CanBeBetterLeftOperand(right)) {
+      std::swap(left, right);
     }
+    selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
+                   g.Use(right));
   }
 }
 
 
 void InstructionSelector::VisitInt32Mul(Node* node) {
+  if (TryEmitLeaMult(this, node, kX64Lea32)) return;
   VisitMul(this, node, kX64Imul32);
 }
 
 
 void InstructionSelector::VisitInt64Mul(Node* node) {
+  if (TryEmitLeaMult(this, node, kX64Lea)) return;
   VisitMul(this, node, kX64Imul);
 }
 
index d925448..55a8ae7 100644 (file)
@@ -1259,6 +1259,22 @@ TEST(RunInt32MulImm) {
 
 TEST(RunInt32MulAndInt32AddP) {
   {
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        RawMachineAssemblerTester<int32_t> m(kMachInt32);
+        int32_t p0 = *i;
+        int32_t p1 = *j;
+        m.Return(m.Int32Add(m.Int32Constant(p0),
+                            m.Int32Mul(m.Parameter(0), m.Int32Constant(p1))));
+        FOR_INT32_INPUTS(k) {
+          int32_t p2 = *k;
+          int expected = p0 + static_cast<int32_t>(p1 * p2);
+          CHECK_EQ(expected, m.Call(p2));
+        }
+      }
+    }
+  }
+  {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
     m.Return(
         m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
index 7d7c11e..218a773 100644 (file)
@@ -121,6 +121,8 @@ class ValueHelper {
   static const std::vector<uint32_t> uint32_vector() {
     static const uint32_t kValues[] = {
         0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+        // This row is useful for testing lea optimizations on intel.
+        0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
         0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
         0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
         0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
index a5c4201..5147728 100644 (file)
@@ -474,6 +474,16 @@ typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
 
 static unsigned InputCountForLea(AddressingMode mode) {
   switch (mode) {
+    case kMode_MR1I:
+    case kMode_MR2I:
+    case kMode_MR4I:
+    case kMode_MR8I:
+      return 3U;
+    case kMode_M1I:
+    case kMode_M2I:
+    case kMode_M4I:
+    case kMode_M8I:
+      return 2U;
     case kMode_MR1:
     case kMode_MR2:
     case kMode_MR4:
@@ -491,6 +501,31 @@ static unsigned InputCountForLea(AddressingMode mode) {
 }
 
 
+static AddressingMode AddressingModeForAddMult(const MultParam& m) {
+  switch (m.addressing_mode) {
+    case kMode_MR1:
+      return kMode_MR1I;
+    case kMode_MR2:
+      return kMode_MR2I;
+    case kMode_MR4:
+      return kMode_MR4I;
+    case kMode_MR8:
+      return kMode_MR8I;
+    case kMode_M1:
+      return kMode_M1I;
+    case kMode_M2:
+      return kMode_M2I;
+    case kMode_M4:
+      return kMode_M4I;
+    case kMode_M8:
+      return kMode_M8I;
+    default:
+      UNREACHABLE();
+      return kMode_None;
+  }
+}
+
+
 TEST_P(InstructionSelectorMultTest, Mult32) {
   const MultParam m_param = GetParam();
   StreamBuilder m(this, kMachInt32, kMachInt32);
@@ -511,6 +546,33 @@ TEST_P(InstructionSelectorMultTest, Mult32) {
 }
 
 
+TEST_P(InstructionSelectorMultTest, MultAdd32) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    const MultParam m_param = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* param = m.Parameter(0);
+    Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)),
+                            m.Int32Constant(imm));
+    m.Return(mult);
+    Stream s = m.Build();
+    if (m_param.lea_expected) {
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kIA32Lea, s[0]->arch_opcode());
+      EXPECT_EQ(AddressingModeForAddMult(m_param), s[0]->addressing_mode());
+      unsigned input_count = InputCountForLea(s[0]->addressing_mode());
+      ASSERT_EQ(input_count, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE,
+                s[0]->InputAt(input_count - 1)->kind());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
+    } else {
+      ASSERT_EQ(2U, s.size());
+      EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
+      EXPECT_EQ(kIA32Add, s[1]->arch_opcode());
+    }
+  }
+}
+
+
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
                         ::testing::ValuesIn(kMultParams));
 
index 7f52e44..5488e1c 100644 (file)
@@ -10,6 +10,16 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+namespace {
+
+// Immediates (random subset).
+static const int32_t kImmediates[] = {
+    kMinInt, -42, -1, 0,  1,  2,    3,      4,          5,
+    6,       7,   8,  16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt};
+
+}  // namespace
+
+
 // -----------------------------------------------------------------------------
 // Conversions.
 
@@ -337,6 +347,16 @@ typedef InstructionSelectorTestWithParam<MultParam> InstructionSelectorMultTest;
 
 static unsigned InputCountForLea(AddressingMode mode) {
   switch (mode) {
+    case kMode_MR1I:
+    case kMode_MR2I:
+    case kMode_MR4I:
+    case kMode_MR8I:
+      return 3U;
+    case kMode_M1I:
+    case kMode_M2I:
+    case kMode_M4I:
+    case kMode_M8I:
+      return 2U;
     case kMode_MR1:
     case kMode_MR2:
     case kMode_MR4:
@@ -354,6 +374,31 @@ static unsigned InputCountForLea(AddressingMode mode) {
 }
 
 
+static AddressingMode AddressingModeForAddMult(const MultParam& m) {
+  switch (m.addressing_mode) {
+    case kMode_MR1:
+      return kMode_MR1I;
+    case kMode_MR2:
+      return kMode_MR2I;
+    case kMode_MR4:
+      return kMode_MR4I;
+    case kMode_MR8:
+      return kMode_MR8I;
+    case kMode_M1:
+      return kMode_M1I;
+    case kMode_M2:
+      return kMode_M2I;
+    case kMode_M4:
+      return kMode_M4I;
+    case kMode_M8:
+      return kMode_M8I;
+    default:
+      UNREACHABLE();
+      return kMode_None;
+  }
+}
+
+
 TEST_P(InstructionSelectorMultTest, Mult32) {
   const MultParam m_param = GetParam();
   StreamBuilder m(this, kMachInt32, kMachInt32);
@@ -396,6 +441,60 @@ TEST_P(InstructionSelectorMultTest, Mult64) {
 }
 
 
+TEST_P(InstructionSelectorMultTest, MultAdd32) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    const MultParam m_param = GetParam();
+    StreamBuilder m(this, kMachInt32, kMachInt32);
+    Node* param = m.Parameter(0);
+    Node* mult = m.Int32Add(m.Int32Mul(param, m.Int32Constant(m_param.value)),
+                            m.Int32Constant(imm));
+    m.Return(mult);
+    Stream s = m.Build();
+    if (m_param.lea_expected) {
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kX64Lea32, s[0]->arch_opcode());
+      EXPECT_EQ(AddressingModeForAddMult(m_param), s[0]->addressing_mode());
+      unsigned input_count = InputCountForLea(s[0]->addressing_mode());
+      ASSERT_EQ(input_count, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE,
+                s[0]->InputAt(input_count - 1)->kind());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
+    } else {
+      ASSERT_EQ(2U, s.size());
+      EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
+      EXPECT_EQ(kX64Add32, s[1]->arch_opcode());
+    }
+  }
+}
+
+
+TEST_P(InstructionSelectorMultTest, MultAdd64) {
+  TRACED_FOREACH(int32_t, imm, kImmediates) {
+    const MultParam m_param = GetParam();
+    StreamBuilder m(this, kMachInt64, kMachInt64);
+    Node* param = m.Parameter(0);
+    Node* mult = m.Int64Add(m.Int64Mul(param, m.Int64Constant(m_param.value)),
+                            m.Int64Constant(imm));
+    m.Return(mult);
+    Stream s = m.Build();
+    if (m_param.lea_expected) {
+      ASSERT_EQ(1U, s.size());
+      EXPECT_EQ(kX64Lea, s[0]->arch_opcode());
+      EXPECT_EQ(AddressingModeForAddMult(m_param), s[0]->addressing_mode());
+      unsigned input_count = InputCountForLea(s[0]->addressing_mode());
+      ASSERT_EQ(input_count, s[0]->InputCount());
+      ASSERT_EQ(InstructionOperand::IMMEDIATE,
+                s[0]->InputAt(input_count - 1)->kind());
+      EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(input_count - 1)));
+    } else {
+      ASSERT_EQ(2U, s.size());
+      EXPECT_EQ(kX64Imul, s[0]->arch_opcode());
+      EXPECT_EQ(kX64Add, s[1]->arch_opcode());
+    }
+  }
+}
+
+
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
                         ::testing::ValuesIn(kMultParams));