[turbofan] intel lea add multiply matchers

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
This commit is contained in:
dcarney@chromium.org 2014-10-01 10:47:14 +00:00
parent c1d79db81b
commit b3d426889d
6 changed files with 326 additions and 71 deletions

View 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));
}
}

View 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);
}

View File

@ -1258,6 +1258,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(

View 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,

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

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