From: bmeurer@chromium.org Date: Wed, 20 Aug 2014 09:16:30 +0000 (+0000) Subject: [turbofan] Add support for Finish to the InstructionSelector. X-Git-Tag: upstream/4.7.83~7535 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=98293ab8d29b9bd394fcf95ca0947ac8385d4064;p=platform%2Fupstream%2Fv8.git [turbofan] Add support for Finish to the InstructionSelector. 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 --- diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index bec9f5d..78bcc96 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -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(node); - MachineType rep = linkage() - ->GetIncomingDescriptor() - ->GetInputLocation(index) - .representation(); - MarkAsRepresentation(rep, node); + LinkageLocation location = + linkage()->GetParameterLocation(OpParameter(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( diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h index e283322..5c00592 100644 --- a/src/compiler/instruction-selector.h +++ b/src/compiler/instruction-selector.h @@ -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); diff --git a/test/compiler-unittests/instruction-selector-unittest.cc b/test/compiler-unittests/instruction-selector-unittest.cc index d6fef2e..2724189 100644 --- a/test/compiler-unittests/instruction-selector-unittest.cc +++ b/test/compiler-unittests/instruction-selector-unittest.cc @@ -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 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::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 + 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 + 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 diff --git a/test/compiler-unittests/instruction-selector-unittest.h b/test/compiler-unittests/instruction-selector-unittest.h index 124bc42..42aac9f 100644 --- a/test/compiler-unittests/instruction-selector-unittest.h +++ b/test/compiler-unittests/instruction-selector-unittest.h @@ -6,7 +6,7 @@ #define V8_COMPILER_UNITTESTS_INSTRUCTION_SELECTOR_UNITTEST_H_ #include -#include // NOLINT(readability/streams) +#include #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 instructions_; + std::set doubles_; + std::set references_; }; base::RandomNumberGenerator rng_;