// -----------------------------------------------------------------------------
+// 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
namespace {
return false;
}
}
+
+ bool CanBeBetterLeftOperand(Node* node) const {
+ return !selector()->IsLive(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()) {
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));
}
return Features(CpuFeatures::SupportedFeatures());
}
+ // Checks if {node} is currently live.
+ bool IsLive(Node* node) const { return !IsDefined(node) && IsUsed(node); }
+
private:
friend class OperandGenerator;
// -----------------------------------------------------------------------------
+// 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
namespace {
return false;
}
}
+
+ bool CanBeBetterLeftOperand(Node* node) const {
+ return !selector()->IsLive(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()) {
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));
}