Commit 8b4ad709 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] IA: support better left operand for commutative binops

R=bmeurer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24205 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1257f35c
......@@ -100,6 +100,39 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
}
// -----------------------------------------------------------------------------
// Better left operand for commutative binops
TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* param1 = m.Parameter(0);
Node* param2 = m.Parameter(1);
Node* add = m.Int32Add(param1, param2);
m.Return(m.Int32Add(add, param1));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kIA32Add, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0)));
}
TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* param1 = m.Parameter(0);
Node* param2 = m.Parameter(1);
Node* mul = m.Int32Mul(param1, param2);
m.Return(m.Int32Mul(mul, param1));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kIA32Imul, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0)));
}
// -----------------------------------------------------------------------------
// Loads and stores
......
......@@ -37,6 +37,10 @@ class IA32OperandGenerator FINAL : public OperandGenerator {
return false;
}
}
bool CanBeBetterLeftOperand(Node* node) const {
return !selector()->IsLive(node);
}
};
......@@ -166,20 +170,24 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) {
IA32OperandGenerator g(selector);
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
InstructionOperand* inputs[4];
size_t input_count = 0;
InstructionOperand* outputs[2];
size_t output_count = 0;
// TODO(turbofan): match complex addressing modes.
// TODO(turbofan): if commutative, pick the non-live-in operand as the left as
// this might be the last use and therefore its register can be reused.
if (g.CanBeImmediate(m.right().node())) {
inputs[input_count++] = g.Use(m.left().node());
inputs[input_count++] = g.UseImmediate(m.right().node());
if (g.CanBeImmediate(right)) {
inputs[input_count++] = g.Use(left);
inputs[input_count++] = g.UseImmediate(right);
} else {
inputs[input_count++] = g.UseRegister(m.left().node());
inputs[input_count++] = g.Use(m.right().node());
if (node->op()->HasProperty(Operator::kCommutative) &&
g.CanBeBetterLeftOperand(right)) {
std::swap(left, right);
}
inputs[input_count++] = g.UseRegister(left);
inputs[input_count++] = g.Use(right);
}
if (cont->IsBranch()) {
......@@ -296,16 +304,16 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
void InstructionSelector::VisitInt32Mul(Node* node) {
IA32OperandGenerator g(this);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
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.CanBeImmediate(left)) {
Emit(kIA32Imul, g.DefineAsRegister(node), g.Use(right),
g.UseImmediate(left));
} else {
// TODO(turbofan): select better left operand.
if (g.CanBeBetterLeftOperand(right)) {
std::swap(left, right);
}
Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(left),
g.Use(right));
}
......
......@@ -84,6 +84,9 @@ class InstructionSelector FINAL {
return Features(CpuFeatures::SupportedFeatures());
}
// Checks if {node} is currently live.
bool IsLive(Node* node) const { return !IsDefined(node) && IsUsed(node); }
private:
friend class OperandGenerator;
......
......@@ -61,6 +61,39 @@ TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
}
// -----------------------------------------------------------------------------
// Better left operand for commutative binops
TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* param1 = m.Parameter(0);
Node* param2 = m.Parameter(1);
Node* add = m.Int32Add(param1, param2);
m.Return(m.Int32Add(add, param1));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kX64Add32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0)));
}
TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
Node* param1 = m.Parameter(0);
Node* param2 = m.Parameter(1);
Node* mul = m.Int32Mul(param1, param2);
m.Return(m.Int32Mul(mul, param1));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kX64Imul32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
ASSERT_TRUE(s[0]->InputAt(0)->IsUnallocated());
EXPECT_EQ(param2->id(), s.ToVreg(s[0]->InputAt(0)));
}
// -----------------------------------------------------------------------------
// Loads and stores
......
......@@ -52,6 +52,10 @@ class X64OperandGenerator FINAL : public OperandGenerator {
return false;
}
}
bool CanBeBetterLeftOperand(Node* node) const {
return !selector()->IsLive(node);
}
};
......@@ -178,20 +182,24 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) {
X64OperandGenerator g(selector);
Int32BinopMatcher m(node);
Node* left = m.left().node();
Node* right = m.right().node();
InstructionOperand* inputs[4];
size_t input_count = 0;
InstructionOperand* outputs[2];
size_t output_count = 0;
// TODO(turbofan): match complex addressing modes.
// TODO(turbofan): if commutative, pick the non-live-in operand as the left as
// this might be the last use and therefore its register can be reused.
if (g.CanBeImmediate(m.right().node())) {
inputs[input_count++] = g.Use(m.left().node());
inputs[input_count++] = g.UseImmediate(m.right().node());
if (g.CanBeImmediate(right)) {
inputs[input_count++] = g.Use(left);
inputs[input_count++] = g.UseImmediate(right);
} else {
inputs[input_count++] = g.UseRegister(m.left().node());
inputs[input_count++] = g.Use(m.right().node());
if (node->op()->HasProperty(Operator::kCommutative) &&
g.CanBeBetterLeftOperand(right)) {
std::swap(left, right);
}
inputs[input_count++] = g.UseRegister(left);
inputs[input_count++] = g.Use(right);
}
if (cont->IsBranch()) {
......@@ -392,16 +400,16 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
static void VisitMul(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
X64OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
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.CanBeImmediate(left)) {
selector->Emit(opcode, g.DefineAsRegister(node), g.Use(right),
g.UseImmediate(left));
} else {
// TODO(turbofan): select better left operand.
if (g.CanBeBetterLeftOperand(right)) {
std::swap(left, right);
}
selector->Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(left),
g.Use(right));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment