[turbofan] Add support for Finish to the InstructionSelector.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 09:16:30 +0000 (09:16 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 09:16:30 +0000 (09:16 +0000)
Also fix an off-by-one bug in the handling of Parameter nodes, and
improve test coverage for pointer map computation.

TEST=compiler-unittest
R=titzer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23219 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/instruction-selector.cc
src/compiler/instruction-selector.h
test/compiler-unittests/instruction-selector-unittest.cc
test/compiler-unittests/instruction-selector-unittest.h

index bec9f5d..78bcc96 100644 (file)
@@ -199,12 +199,18 @@ void InstructionSelector::MarkAsDouble(Node* node) {
   DCHECK(!IsReference(node));
   sequence()->MarkAsDouble(node->id());
 
-  // Propagate "doubleness" throughout phis.
+  // Propagate "doubleness" throughout Finish/Phi nodes.
   for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
     Node* user = *i;
-    if (user->opcode() != IrOpcode::kPhi) continue;
-    if (IsDouble(user)) continue;
-    MarkAsDouble(user);
+    switch (user->opcode()) {
+      case IrOpcode::kFinish:
+      case IrOpcode::kPhi:
+        if (IsDouble(user)) continue;
+        MarkAsDouble(user);
+        break;
+      default:
+        break;
+    }
   }
 }
 
@@ -220,12 +226,18 @@ void InstructionSelector::MarkAsReference(Node* node) {
   DCHECK(!IsDouble(node));
   sequence()->MarkAsReference(node->id());
 
-  // Propagate "referenceness" throughout phis.
+  // Propagate "referenceness" throughout Finish/Phi nodes.
   for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
     Node* user = *i;
-    if (user->opcode() != IrOpcode::kPhi) continue;
-    if (IsReference(user)) continue;
-    MarkAsReference(user);
+    switch (user->opcode()) {
+      case IrOpcode::kFinish:
+      case IrOpcode::kPhi:
+        if (IsReference(user)) continue;
+        MarkAsReference(user);
+        break;
+      default:
+        break;
+    }
   }
 }
 
@@ -464,13 +476,12 @@ void InstructionSelector::VisitNode(Node* node) {
     case IrOpcode::kContinuation:
       // No code needed for these graph artifacts.
       return;
+    case IrOpcode::kFinish:
+      return VisitFinish(node);
     case IrOpcode::kParameter: {
-      int index = OpParameter<int>(node);
-      MachineType rep = linkage()
-                            ->GetIncomingDescriptor()
-                            ->GetInputLocation(index)
-                            .representation();
-      MarkAsRepresentation(rep, node);
+      LinkageLocation location =
+          linkage()->GetParameterLocation(OpParameter<int>(node));
+      MarkAsRepresentation(location.representation(), node);
       return VisitParameter(node);
     }
     case IrOpcode::kPhi:
@@ -797,6 +808,13 @@ void InstructionSelector::VisitWord64Compare(Node* node,
 #endif  // V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
 
 
+void InstructionSelector::VisitFinish(Node* node) {
+  OperandGenerator g(this);
+  Node* value = node->InputAt(0);
+  Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
+}
+
+
 void InstructionSelector::VisitParameter(Node* node) {
   OperandGenerator g(this);
   Emit(kArchNop, g.DefineAsLocation(node, linkage()->GetParameterLocation(
index e283322..5c00592 100644 (file)
@@ -169,6 +169,7 @@ class InstructionSelector V8_FINAL {
   void VisitWord64Compare(Node* node, FlagsContinuation* cont);
   void VisitFloat64Compare(Node* node, FlagsContinuation* cont);
 
+  void VisitFinish(Node* node);
   void VisitParameter(Node* node);
   void VisitPhi(Node* node);
   void VisitProjection(Node* node);
index d6fef2e..2724189 100644 (file)
@@ -10,6 +10,13 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+}  // namespace
+
+
 InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
 
 
@@ -34,6 +41,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
         << sequence;
   }
   Stream s;
+  std::set<int> virtual_registers;
   for (InstructionSequence::const_iterator i = sequence.begin();
        i != sequence.end(); ++i) {
     Instruction* instr = *i;
@@ -55,6 +63,10 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
       if (output->IsConstant()) {
         s.constants_.insert(std::make_pair(
             output->index(), sequence.GetConstant(output->index())));
+        virtual_registers.insert(output->index());
+      } else if (output->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(output)->virtual_register());
       }
     }
     for (size_t i = 0; i < instr->InputCount(); ++i) {
@@ -63,10 +75,25 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
       if (input->IsImmediate()) {
         s.immediates_.insert(std::make_pair(
             input->index(), sequence.GetImmediate(input->index())));
+      } else if (input->IsUnallocated()) {
+        virtual_registers.insert(
+            UnallocatedOperand::cast(input)->virtual_register());
       }
     }
     s.instructions_.push_back(instr);
   }
+  for (std::set<int>::const_iterator i = virtual_registers.begin();
+       i != virtual_registers.end(); ++i) {
+    int virtual_register = *i;
+    if (sequence.IsDouble(virtual_register)) {
+      EXPECT_FALSE(sequence.IsReference(virtual_register));
+      s.doubles_.insert(virtual_register);
+    }
+    if (sequence.IsReference(virtual_register)) {
+      EXPECT_FALSE(sequence.IsDouble(virtual_register));
+      s.references_.insert(virtual_register);
+    }
+  }
   return s;
 }
 
@@ -117,6 +144,172 @@ TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
   EXPECT_EQ(kArchRet, s[2]->arch_opcode());
 }
 
+
+// -----------------------------------------------------------------------------
+// Parameters.
+
+
+TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
+  StreamBuilder m(this, kMachFloat64, kMachFloat64);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsDouble(param->id()));
+}
+
+
+TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
+  StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged);
+  Node* param = m.Parameter(0);
+  m.Return(param);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_TRUE(s.IsReference(param->id()));
+}
+
+
+// -----------------------------------------------------------------------------
+// Finish.
+
+
+typedef InstructionSelectorTestWithParam<MachineType>
+    InstructionSelectorFinishTest;
+
+
+TARGET_TEST_P(InstructionSelectorFinishTest, Parameter) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type);
+  Node* param = m.Parameter(0);
+  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
+  m.Return(finish);
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_TRUE(s[0]->Output()->IsUnallocated());
+  EXPECT_EQ(param->id(),
+            UnallocatedOperand::cast(s[0]->Output())->virtual_register());
+  EXPECT_EQ(kArchNop, s[1]->arch_opcode());
+  ASSERT_EQ(1U, s[1]->InputCount());
+  ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated());
+  EXPECT_EQ(param->id(),
+            UnallocatedOperand::cast(s[1]->InputAt(0))->virtual_register());
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  ASSERT_TRUE(s[1]->Output()->IsUnallocated());
+  EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy());
+  EXPECT_EQ(finish->id(),
+            UnallocatedOperand::cast(s[1]->Output())->virtual_register());
+}
+
+
+TARGET_TEST_P(InstructionSelectorFinishTest, PropagateDoubleness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type);
+  Node* param = m.Parameter(0);
+  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
+  m.Return(finish);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsDouble(param->id()), s.IsDouble(finish->id()));
+}
+
+
+TARGET_TEST_P(InstructionSelectorFinishTest, PropagateReferenceness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type);
+  Node* param = m.Parameter(0);
+  Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start());
+  m.Return(finish);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsReference(param->id()), s.IsReference(finish->id()));
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFinishTest,
+                        ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
+                                          kMachInt16, kMachUint16, kMachInt32,
+                                          kMachUint32, kMachInt64, kMachUint64,
+                                          kMachPtr, kMachAnyTagged));
+
+
+// -----------------------------------------------------------------------------
+// Finish.
+
+
+typedef InstructionSelectorTestWithParam<MachineType>
+    InstructionSelectorPhiTest;
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, PropagateDoubleness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(0), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param0->id()));
+  EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param1->id()));
+}
+
+
+TARGET_TEST_P(InstructionSelectorPhiTest, PropagateReferenceness) {
+  const MachineType type = GetParam();
+  StreamBuilder m(this, type, type, type);
+  Node* param0 = m.Parameter(0);
+  Node* param1 = m.Parameter(1);
+  MLabel a, b, c;
+  m.Branch(m.Int32Constant(1), &a, &b);
+  m.Bind(&a);
+  m.Goto(&c);
+  m.Bind(&b);
+  m.Goto(&c);
+  m.Bind(&c);
+  Node* phi = m.Phi(param0, param1);
+  m.Return(phi);
+  Stream s = m.Build(kAllInstructions);
+  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param0->id()));
+  EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param1->id()));
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest,
+                        ::testing::Values(kMachFloat64, kMachInt8, kMachUint8,
+                                          kMachInt16, kMachUint16, kMachInt32,
+                                          kMachUint32, kMachInt64, kMachUint64,
+                                          kMachPtr, kMachAnyTagged));
+
+
+// -----------------------------------------------------------------------------
+// ValueEffect.
+
+
+TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
+  StreamBuilder m1(this, kMachInt32, kMachPtr);
+  Node* p1 = m1.Parameter(0);
+  m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0)));
+  Stream s1 = m1.Build(kAllInstructions);
+  StreamBuilder m2(this, kMachInt32, kMachPtr);
+  Node* p2 = m2.Parameter(0);
+  m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0),
+                       m2.NewNode(m2.common()->ValueEffect(1), p2)));
+  Stream s2 = m2.Build(kAllInstructions);
+  EXPECT_LE(3U, s1.size());
+  ASSERT_EQ(s1.size(), s2.size());
+  TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
+    const Instruction* i1 = s1[i];
+    const Instruction* i2 = s2[i];
+    EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
+    EXPECT_EQ(i1->InputCount(), i2->InputCount());
+    EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
+  }
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 124bc42..42aac9f 100644 (file)
@@ -6,7 +6,7 @@
 #define V8_COMPILER_UNITTESTS_INSTRUCTION_SELECTOR_UNITTEST_H_
 
 #include <deque>
-#include <ostream>  // NOLINT(readability/streams)
+#include <set>
 
 #include "src/base/utils/random-number-generator.h"
 #include "src/compiler/instruction-selector.h"
@@ -116,6 +116,14 @@ class InstructionSelectorTest : public CompilerTest {
       return instructions_[index];
     }
 
+    bool IsDouble(int virtual_register) const {
+      return doubles_.find(virtual_register) != doubles_.end();
+    }
+
+    bool IsReference(int virtual_register) const {
+      return references_.find(virtual_register) != references_.end();
+    }
+
     int32_t ToInt32(const InstructionOperand* operand) const {
       return ToConstant(operand).ToInt32();
     }
@@ -147,6 +155,8 @@ class InstructionSelectorTest : public CompilerTest {
     ConstantMap constants_;
     ConstantMap immediates_;
     std::deque<Instruction*> instructions_;
+    std::set<int> doubles_;
+    std::set<int> references_;
   };
 
   base::RandomNumberGenerator rng_;