OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "test/compiler-unittests/instruction-selector-unittest.h" | 5 #include "test/compiler-unittests/instruction-selector-unittest.h" |
6 | 6 |
7 #include "src/flags.h" | 7 #include "src/flags.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
11 namespace compiler { | 11 namespace compiler { |
12 | 12 |
| 13 namespace { |
| 14 |
| 15 typedef RawMachineAssembler::Label MLabel; |
| 16 |
| 17 } // namespace |
| 18 |
| 19 |
13 InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {} | 20 InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {} |
14 | 21 |
15 | 22 |
16 InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( | 23 InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( |
17 InstructionSelector::Features features, | 24 InstructionSelector::Features features, |
18 InstructionSelectorTest::StreamBuilderMode mode) { | 25 InstructionSelectorTest::StreamBuilderMode mode) { |
19 Schedule* schedule = Export(); | 26 Schedule* schedule = Export(); |
20 if (FLAG_trace_turbo) { | 27 if (FLAG_trace_turbo) { |
21 OFStream out(stdout); | 28 OFStream out(stdout); |
22 out << "=== Schedule before instruction selection ===" << endl << *schedule; | 29 out << "=== Schedule before instruction selection ===" << endl << *schedule; |
23 } | 30 } |
24 EXPECT_NE(0, graph()->NodeCount()); | 31 EXPECT_NE(0, graph()->NodeCount()); |
25 CompilationInfo info(test_->isolate(), test_->zone()); | 32 CompilationInfo info(test_->isolate(), test_->zone()); |
26 Linkage linkage(&info, call_descriptor()); | 33 Linkage linkage(&info, call_descriptor()); |
27 InstructionSequence sequence(&linkage, graph(), schedule); | 34 InstructionSequence sequence(&linkage, graph(), schedule); |
28 SourcePositionTable source_position_table(graph()); | 35 SourcePositionTable source_position_table(graph()); |
29 InstructionSelector selector(&sequence, &source_position_table, features); | 36 InstructionSelector selector(&sequence, &source_position_table, features); |
30 selector.SelectInstructions(); | 37 selector.SelectInstructions(); |
31 if (FLAG_trace_turbo) { | 38 if (FLAG_trace_turbo) { |
32 OFStream out(stdout); | 39 OFStream out(stdout); |
33 out << "=== Code sequence after instruction selection ===" << endl | 40 out << "=== Code sequence after instruction selection ===" << endl |
34 << sequence; | 41 << sequence; |
35 } | 42 } |
36 Stream s; | 43 Stream s; |
| 44 std::set<int> virtual_registers; |
37 for (InstructionSequence::const_iterator i = sequence.begin(); | 45 for (InstructionSequence::const_iterator i = sequence.begin(); |
38 i != sequence.end(); ++i) { | 46 i != sequence.end(); ++i) { |
39 Instruction* instr = *i; | 47 Instruction* instr = *i; |
40 if (instr->opcode() < 0) continue; | 48 if (instr->opcode() < 0) continue; |
41 if (mode == kTargetInstructions) { | 49 if (mode == kTargetInstructions) { |
42 switch (instr->arch_opcode()) { | 50 switch (instr->arch_opcode()) { |
43 #define CASE(Name) \ | 51 #define CASE(Name) \ |
44 case k##Name: \ | 52 case k##Name: \ |
45 break; | 53 break; |
46 TARGET_ARCH_OPCODE_LIST(CASE) | 54 TARGET_ARCH_OPCODE_LIST(CASE) |
47 #undef CASE | 55 #undef CASE |
48 default: | 56 default: |
49 continue; | 57 continue; |
50 } | 58 } |
51 } | 59 } |
52 for (size_t i = 0; i < instr->OutputCount(); ++i) { | 60 for (size_t i = 0; i < instr->OutputCount(); ++i) { |
53 InstructionOperand* output = instr->OutputAt(i); | 61 InstructionOperand* output = instr->OutputAt(i); |
54 EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind()); | 62 EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind()); |
55 if (output->IsConstant()) { | 63 if (output->IsConstant()) { |
56 s.constants_.insert(std::make_pair( | 64 s.constants_.insert(std::make_pair( |
57 output->index(), sequence.GetConstant(output->index()))); | 65 output->index(), sequence.GetConstant(output->index()))); |
| 66 virtual_registers.insert(output->index()); |
| 67 } else if (output->IsUnallocated()) { |
| 68 virtual_registers.insert( |
| 69 UnallocatedOperand::cast(output)->virtual_register()); |
58 } | 70 } |
59 } | 71 } |
60 for (size_t i = 0; i < instr->InputCount(); ++i) { | 72 for (size_t i = 0; i < instr->InputCount(); ++i) { |
61 InstructionOperand* input = instr->InputAt(i); | 73 InstructionOperand* input = instr->InputAt(i); |
62 EXPECT_NE(InstructionOperand::CONSTANT, input->kind()); | 74 EXPECT_NE(InstructionOperand::CONSTANT, input->kind()); |
63 if (input->IsImmediate()) { | 75 if (input->IsImmediate()) { |
64 s.immediates_.insert(std::make_pair( | 76 s.immediates_.insert(std::make_pair( |
65 input->index(), sequence.GetImmediate(input->index()))); | 77 input->index(), sequence.GetImmediate(input->index()))); |
| 78 } else if (input->IsUnallocated()) { |
| 79 virtual_registers.insert( |
| 80 UnallocatedOperand::cast(input)->virtual_register()); |
66 } | 81 } |
67 } | 82 } |
68 s.instructions_.push_back(instr); | 83 s.instructions_.push_back(instr); |
69 } | 84 } |
| 85 for (std::set<int>::const_iterator i = virtual_registers.begin(); |
| 86 i != virtual_registers.end(); ++i) { |
| 87 int virtual_register = *i; |
| 88 if (sequence.IsDouble(virtual_register)) { |
| 89 EXPECT_FALSE(sequence.IsReference(virtual_register)); |
| 90 s.doubles_.insert(virtual_register); |
| 91 } |
| 92 if (sequence.IsReference(virtual_register)) { |
| 93 EXPECT_FALSE(sequence.IsDouble(virtual_register)); |
| 94 s.references_.insert(virtual_register); |
| 95 } |
| 96 } |
70 return s; | 97 return s; |
71 } | 98 } |
72 | 99 |
73 | 100 |
74 // ----------------------------------------------------------------------------- | 101 // ----------------------------------------------------------------------------- |
75 // Return. | 102 // Return. |
76 | 103 |
77 | 104 |
78 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { | 105 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) { |
79 StreamBuilder m(this, kMachInt32, kMachInt32); | 106 StreamBuilder m(this, kMachInt32, kMachInt32); |
(...skipping 30 matching lines...) Expand all Loading... |
110 m.Return(m.TruncateFloat64ToInt32(m.Parameter(0))); | 137 m.Return(m.TruncateFloat64ToInt32(m.Parameter(0))); |
111 Stream s = m.Build(kAllInstructions); | 138 Stream s = m.Build(kAllInstructions); |
112 ASSERT_EQ(3U, s.size()); | 139 ASSERT_EQ(3U, s.size()); |
113 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); | 140 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); |
114 EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode()); | 141 EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode()); |
115 EXPECT_EQ(1U, s[1]->InputCount()); | 142 EXPECT_EQ(1U, s[1]->InputCount()); |
116 EXPECT_EQ(1U, s[1]->OutputCount()); | 143 EXPECT_EQ(1U, s[1]->OutputCount()); |
117 EXPECT_EQ(kArchRet, s[2]->arch_opcode()); | 144 EXPECT_EQ(kArchRet, s[2]->arch_opcode()); |
118 } | 145 } |
119 | 146 |
| 147 |
| 148 // ----------------------------------------------------------------------------- |
| 149 // Parameters. |
| 150 |
| 151 |
| 152 TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) { |
| 153 StreamBuilder m(this, kMachFloat64, kMachFloat64); |
| 154 Node* param = m.Parameter(0); |
| 155 m.Return(param); |
| 156 Stream s = m.Build(kAllInstructions); |
| 157 EXPECT_TRUE(s.IsDouble(param->id())); |
| 158 } |
| 159 |
| 160 |
| 161 TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) { |
| 162 StreamBuilder m(this, kMachAnyTagged, kMachAnyTagged); |
| 163 Node* param = m.Parameter(0); |
| 164 m.Return(param); |
| 165 Stream s = m.Build(kAllInstructions); |
| 166 EXPECT_TRUE(s.IsReference(param->id())); |
| 167 } |
| 168 |
| 169 |
| 170 // ----------------------------------------------------------------------------- |
| 171 // Finish. |
| 172 |
| 173 |
| 174 typedef InstructionSelectorTestWithParam<MachineType> |
| 175 InstructionSelectorFinishTest; |
| 176 |
| 177 |
| 178 TARGET_TEST_P(InstructionSelectorFinishTest, Parameter) { |
| 179 const MachineType type = GetParam(); |
| 180 StreamBuilder m(this, type, type); |
| 181 Node* param = m.Parameter(0); |
| 182 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start()); |
| 183 m.Return(finish); |
| 184 Stream s = m.Build(kAllInstructions); |
| 185 ASSERT_EQ(3U, s.size()); |
| 186 EXPECT_EQ(kArchNop, s[0]->arch_opcode()); |
| 187 ASSERT_EQ(1U, s[0]->OutputCount()); |
| 188 ASSERT_TRUE(s[0]->Output()->IsUnallocated()); |
| 189 EXPECT_EQ(param->id(), |
| 190 UnallocatedOperand::cast(s[0]->Output())->virtual_register()); |
| 191 EXPECT_EQ(kArchNop, s[1]->arch_opcode()); |
| 192 ASSERT_EQ(1U, s[1]->InputCount()); |
| 193 ASSERT_TRUE(s[1]->InputAt(0)->IsUnallocated()); |
| 194 EXPECT_EQ(param->id(), |
| 195 UnallocatedOperand::cast(s[1]->InputAt(0))->virtual_register()); |
| 196 ASSERT_EQ(1U, s[1]->OutputCount()); |
| 197 ASSERT_TRUE(s[1]->Output()->IsUnallocated()); |
| 198 EXPECT_TRUE(UnallocatedOperand::cast(s[1]->Output())->HasSameAsInputPolicy()); |
| 199 EXPECT_EQ(finish->id(), |
| 200 UnallocatedOperand::cast(s[1]->Output())->virtual_register()); |
| 201 } |
| 202 |
| 203 |
| 204 TARGET_TEST_P(InstructionSelectorFinishTest, PropagateDoubleness) { |
| 205 const MachineType type = GetParam(); |
| 206 StreamBuilder m(this, type, type); |
| 207 Node* param = m.Parameter(0); |
| 208 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start()); |
| 209 m.Return(finish); |
| 210 Stream s = m.Build(kAllInstructions); |
| 211 EXPECT_EQ(s.IsDouble(param->id()), s.IsDouble(finish->id())); |
| 212 } |
| 213 |
| 214 |
| 215 TARGET_TEST_P(InstructionSelectorFinishTest, PropagateReferenceness) { |
| 216 const MachineType type = GetParam(); |
| 217 StreamBuilder m(this, type, type); |
| 218 Node* param = m.Parameter(0); |
| 219 Node* finish = m.NewNode(m.common()->Finish(1), param, m.graph()->start()); |
| 220 m.Return(finish); |
| 221 Stream s = m.Build(kAllInstructions); |
| 222 EXPECT_EQ(s.IsReference(param->id()), s.IsReference(finish->id())); |
| 223 } |
| 224 |
| 225 |
| 226 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorFinishTest, |
| 227 ::testing::Values(kMachFloat64, kMachInt8, kMachUint8, |
| 228 kMachInt16, kMachUint16, kMachInt32, |
| 229 kMachUint32, kMachInt64, kMachUint64, |
| 230 kMachPtr, kMachAnyTagged)); |
| 231 |
| 232 |
| 233 // ----------------------------------------------------------------------------- |
| 234 // Finish. |
| 235 |
| 236 |
| 237 typedef InstructionSelectorTestWithParam<MachineType> |
| 238 InstructionSelectorPhiTest; |
| 239 |
| 240 |
| 241 TARGET_TEST_P(InstructionSelectorPhiTest, PropagateDoubleness) { |
| 242 const MachineType type = GetParam(); |
| 243 StreamBuilder m(this, type, type, type); |
| 244 Node* param0 = m.Parameter(0); |
| 245 Node* param1 = m.Parameter(1); |
| 246 MLabel a, b, c; |
| 247 m.Branch(m.Int32Constant(0), &a, &b); |
| 248 m.Bind(&a); |
| 249 m.Goto(&c); |
| 250 m.Bind(&b); |
| 251 m.Goto(&c); |
| 252 m.Bind(&c); |
| 253 Node* phi = m.Phi(param0, param1); |
| 254 m.Return(phi); |
| 255 Stream s = m.Build(kAllInstructions); |
| 256 EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param0->id())); |
| 257 EXPECT_EQ(s.IsDouble(phi->id()), s.IsDouble(param1->id())); |
| 258 } |
| 259 |
| 260 |
| 261 TARGET_TEST_P(InstructionSelectorPhiTest, PropagateReferenceness) { |
| 262 const MachineType type = GetParam(); |
| 263 StreamBuilder m(this, type, type, type); |
| 264 Node* param0 = m.Parameter(0); |
| 265 Node* param1 = m.Parameter(1); |
| 266 MLabel a, b, c; |
| 267 m.Branch(m.Int32Constant(1), &a, &b); |
| 268 m.Bind(&a); |
| 269 m.Goto(&c); |
| 270 m.Bind(&b); |
| 271 m.Goto(&c); |
| 272 m.Bind(&c); |
| 273 Node* phi = m.Phi(param0, param1); |
| 274 m.Return(phi); |
| 275 Stream s = m.Build(kAllInstructions); |
| 276 EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param0->id())); |
| 277 EXPECT_EQ(s.IsReference(phi->id()), s.IsReference(param1->id())); |
| 278 } |
| 279 |
| 280 |
| 281 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorPhiTest, |
| 282 ::testing::Values(kMachFloat64, kMachInt8, kMachUint8, |
| 283 kMachInt16, kMachUint16, kMachInt32, |
| 284 kMachUint32, kMachInt64, kMachUint64, |
| 285 kMachPtr, kMachAnyTagged)); |
| 286 |
| 287 |
| 288 // ----------------------------------------------------------------------------- |
| 289 // ValueEffect. |
| 290 |
| 291 |
| 292 TARGET_TEST_F(InstructionSelectorTest, ValueEffect) { |
| 293 StreamBuilder m1(this, kMachInt32, kMachPtr); |
| 294 Node* p1 = m1.Parameter(0); |
| 295 m1.Return(m1.Load(kMachInt32, p1, m1.Int32Constant(0))); |
| 296 Stream s1 = m1.Build(kAllInstructions); |
| 297 StreamBuilder m2(this, kMachInt32, kMachPtr); |
| 298 Node* p2 = m2.Parameter(0); |
| 299 m2.Return(m2.NewNode(m2.machine()->Load(kMachInt32), p2, m2.Int32Constant(0), |
| 300 m2.NewNode(m2.common()->ValueEffect(1), p2))); |
| 301 Stream s2 = m2.Build(kAllInstructions); |
| 302 EXPECT_LE(3U, s1.size()); |
| 303 ASSERT_EQ(s1.size(), s2.size()); |
| 304 TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) { |
| 305 const Instruction* i1 = s1[i]; |
| 306 const Instruction* i2 = s2[i]; |
| 307 EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode()); |
| 308 EXPECT_EQ(i1->InputCount(), i2->InputCount()); |
| 309 EXPECT_EQ(i1->OutputCount(), i2->OutputCount()); |
| 310 } |
| 311 } |
| 312 |
120 } // namespace compiler | 313 } // namespace compiler |
121 } // namespace internal | 314 } // namespace internal |
122 } // namespace v8 | 315 } // namespace v8 |
OLD | NEW |