[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:
parent
900df59f41
commit
912cea172e
@ -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));
|
||||
|
@ -50,6 +50,7 @@ namespace compiler {
|
||||
V(IA32Movl) \
|
||||
V(IA32Movss) \
|
||||
V(IA32Movsd) \
|
||||
V(IA32Lea) \
|
||||
V(IA32Push) \
|
||||
V(IA32StoreWriteBarrier)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,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));
|
||||
} else {
|
||||
if (g.CanBeBetterLeftOperand(right)) {
|
||||
std::swap(left, 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 {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user