[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
This commit is contained in:
dcarney@chromium.org 2014-09-30 11:22:14 +00:00
parent 900df59f41
commit 912cea172e
4 changed files with 126 additions and 26 deletions

View File

@ -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));

View File

@ -50,6 +50,7 @@ namespace compiler {
V(IA32Movl) \
V(IA32Movss) \
V(IA32Movsd) \
V(IA32Lea) \
V(IA32Push) \
V(IA32StoreWriteBarrier)

View File

@ -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<MultParam> 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

View File

@ -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<AddressingMode>(static_cast<int>(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<AddressingMode>(static_cast<int>(one) + power);
}
size_t SetInputs(InstructionOperand** inputs) {
size_t input_count = 0;
// Compute inputs_ and input_count.
@ -386,6 +385,26 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
void InstructionSelector::VisitInt32Mul(Node* node) {
IA32OperandGenerator g(this);
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 {
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
@ -400,6 +419,7 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
g.Use(right));
}
}
}
static inline void VisitDiv(InstructionSelector* selector, Node* node,