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;
+ }
}
}
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;
+ }
}
}
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:
#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(
namespace internal {
namespace compiler {
+namespace {
+
+typedef RawMachineAssembler::Label MLabel;
+
+} // namespace
+
+
InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
<< sequence;
}
Stream s;
+ std::set<int> virtual_registers;
for (InstructionSequence::const_iterator i = sequence.begin();
i != sequence.end(); ++i) {
Instruction* instr = *i;
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) {
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;
}
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