[turbofan] IA: support better left operand for commutative binops
authorbmeurer@chromium.org <bmeurer@chromium.org>
Thu, 25 Sep 2014 07:41:25 +0000 (07:41 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Thu, 25 Sep 2014 07:41:25 +0000 (07:41 +0000)
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

src/compiler/ia32/instruction-selector-ia32-unittest.cc
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.h
src/compiler/x64/instruction-selector-x64-unittest.cc
src/compiler/x64/instruction-selector-x64.cc

index 447f562..50e1358 100644 (file)
@@ -101,6 +101,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
 
 namespace {
index dfdf233..d72f0dc 100644 (file)
@@ -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));
   }
index a86e156..264f737 100644 (file)
@@ -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;
 
index 7204abd..d94c73f 100644 (file)
@@ -62,6 +62,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
 
 namespace {
index a3172e5..0447b79 100644 (file)
@@ -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));
   }