From 912cea172ed1331af334b8b90208f2efbbf3b2b1 Mon Sep 17 00:00:00 2001 From: "dcarney@chromium.org" Date: Tue, 30 Sep 2014 11:22:14 +0000 Subject: [PATCH] [turbofan] ia32 lea multiplication matching R=bmeurer@chromium.org BUG= Review URL: https://codereview.chromium.org/616833002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24326 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler/ia32/code-generator-ia32.cc | 3 + src/compiler/ia32/instruction-codes-ia32.h | 1 + .../ia32/instruction-selector-ia32-unittest.cc | 84 ++++++++++++++++++++-- src/compiler/ia32/instruction-selector-ia32.cc | 62 ++++++++++------ 4 files changed, 125 insertions(+), 25 deletions(-) diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index a99beed..4bb7500 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -435,6 +435,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { __ movss(operand, i.InputDoubleRegister(index)); } break; + case kIA32Lea: + __ lea(i.OutputRegister(), i.MemoryOperand()); + break; case kIA32Push: if (HasImmediateInput(instr, 0)) { __ push(i.InputImmediate(0)); diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index 268a59d..91844c4 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h @@ -50,6 +50,7 @@ namespace compiler { V(IA32Movl) \ V(IA32Movss) \ V(IA32Movsd) \ + V(IA32Lea) \ V(IA32Push) \ V(IA32StoreWriteBarrier) diff --git a/src/compiler/ia32/instruction-selector-ia32-unittest.cc b/src/compiler/ia32/instruction-selector-ia32-unittest.cc index 1aab75c..9e50276 100644 --- a/src/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/src/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -388,12 +388,12 @@ TEST_F(AddressingModeUnitTest, AddressingMode_MRNI) { TEST_F(AddressingModeUnitTest, AddressingMode_M1) { Node* base = null_ptr; Node* index = index_reg; - Run(base, index, kMode_MR); + Run(base, index, kMode_M1); } TEST_F(AddressingModeUnitTest, AddressingMode_MN) { - AddressingMode expected[] = {kMode_MR, kMode_M2, kMode_M4, kMode_M8}; + AddressingMode expected[] = {kMode_M1, kMode_M2, kMode_M4, kMode_M8}; for (size_t i = 0; i < arraysize(scales); ++i) { Reset(); Node* base = null_ptr; @@ -406,12 +406,12 @@ TEST_F(AddressingModeUnitTest, AddressingMode_MN) { TEST_F(AddressingModeUnitTest, AddressingMode_M1I) { Node* base = null_ptr; Node* index = m->Int32Add(index_reg, non_zero); - Run(base, index, kMode_MRI); + Run(base, index, kMode_M1I); } TEST_F(AddressingModeUnitTest, AddressingMode_MNI) { - AddressingMode expected[] = {kMode_MRI, kMode_M2I, kMode_M4I, kMode_M8I}; + AddressingMode expected[] = {kMode_M1I, kMode_M2I, kMode_M4I, kMode_M8I}; for (size_t i = 0; i < arraysize(scales); ++i) { Reset(); Node* base = null_ptr; @@ -434,6 +434,82 @@ TEST_F(AddressingModeUnitTest, AddressingMode_MI) { } } + +// ----------------------------------------------------------------------------- +// Multiplication. + +namespace { + +struct MultParam { + int value; + bool lea_expected; + AddressingMode addressing_mode; +}; + + +std::ostream& operator<<(std::ostream& os, const MultParam& m) { + return os << m.value << "." << m.lea_expected << "." << m.addressing_mode; +} + + +const MultParam kMultParams[] = {{-1, false, kMode_None}, + {0, false, kMode_None}, + {1, true, kMode_M1}, + {2, true, kMode_M2}, + {3, true, kMode_MR2}, + {4, true, kMode_M4}, + {5, true, kMode_MR4}, + {6, false, kMode_None}, + {7, false, kMode_None}, + {8, true, kMode_M8}, + {9, true, kMode_MR8}, + {10, false, kMode_None}, + {11, false, kMode_None}}; + +} // namespace + + +typedef InstructionSelectorTestWithParam InstructionSelectorMultTest; + + +static unsigned InputCountForLea(AddressingMode mode) { + switch (mode) { + case kMode_MR1: + case kMode_MR2: + case kMode_MR4: + case kMode_MR8: + return 2U; + case kMode_M1: + case kMode_M2: + case kMode_M4: + case kMode_M8: + return 1U; + default: + UNREACHABLE(); + return 0U; + } +} + + +TEST_P(InstructionSelectorMultTest, Mult32) { + const MultParam m_param = GetParam(); + StreamBuilder m(this, kMachInt32, kMachInt32); + Node* param = m.Parameter(0); + Node* mult = m.Int32Mul(param, m.Int32Constant(m_param.value)); + m.Return(mult); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(m_param.addressing_mode, s[0]->addressing_mode()); + if (m_param.lea_expected) { + EXPECT_EQ(kIA32Lea, s[0]->arch_opcode()); + ASSERT_EQ(InputCountForLea(s[0]->addressing_mode()), s[0]->InputCount()); + } else { + EXPECT_EQ(kIA32Lea, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + } + EXPECT_EQ(param->id(), s.ToVreg(s[0]->InputAt(0))); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 0f5c7b2..b252e71 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -44,6 +44,15 @@ class IA32OperandGenerator FINAL : public OperandGenerator { }; +// Get the AddressingMode of scale factor N from the AddressingMode of scale +// factor 1. +static AddressingMode AdjustAddressingMode(AddressingMode base_mode, + int power) { + DCHECK(0 <= power && power < 4); + return static_cast(static_cast(base_mode) + power); +} + + class AddressingModeMatcher { public: AddressingModeMatcher(IA32OperandGenerator* g, Node* base, Node* index) @@ -104,21 +113,11 @@ class AddressingModeMatcher { } } // Adjust mode to actual scale factor. - mode_ = GetMode(mode_, matcher.power()); - // Don't emit instructions with scale factor 1 if there's no base. - if (mode_ == kMode_M1) { - mode_ = kMode_MR; - } else if (mode_ == kMode_M1I) { - mode_ = kMode_MRI; - } + mode_ = AdjustAddressingMode(mode_, matcher.power()); } DCHECK_NE(kMode_None, mode_); } - AddressingMode GetMode(AddressingMode one, int power) { - return static_cast(static_cast(one) + power); - } - size_t SetInputs(InstructionOperand** inputs) { size_t input_count = 0; // Compute inputs_ and input_count. @@ -386,18 +385,39 @@ void InstructionSelector::VisitInt32Sub(Node* node) { void InstructionSelector::VisitInt32Mul(Node* node) { 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)); + 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); } else { - if (g.CanBeBetterLeftOperand(right)) { - std::swap(left, right); + 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)); } - Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left), - g.Use(right)); } } -- 2.7.4