Chromium Code Reviews| 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 "src/compiler/graph.h" | 5 #include "src/compiler/graph.h" |
| 6 #include "src/compiler/graph-reducer.h" | 6 #include "src/compiler/graph-reducer.h" |
| 7 #include "src/compiler/node.h" | 7 #include "src/compiler/node.h" |
| 8 #include "src/compiler/operator.h" | 8 #include "src/compiler/operator.h" |
| 9 #include "test/unittests/test-utils.h" | 9 #include "test/unittests/test-utils.h" |
| 10 #include "testing/gmock/include/gmock/gmock.h" | 10 #include "testing/gmock/include/gmock/gmock.h" |
| 11 | 11 |
| 12 using testing::_; | 12 using testing::_; |
| 13 using testing::DefaultValue; | 13 using testing::DefaultValue; |
| 14 using testing::Return; | 14 using testing::Return; |
| 15 using testing::Sequence; | 15 using testing::Sequence; |
| 16 using testing::StrictMock; | 16 using testing::StrictMock; |
| 17 | 17 |
| 18 namespace v8 { | 18 namespace v8 { |
| 19 namespace internal { | 19 namespace internal { |
| 20 namespace compiler { | 20 namespace compiler { |
| 21 | 21 |
| 22 namespace { | |
| 23 | |
| 22 struct TestOperator : public Operator { | 24 struct TestOperator : public Operator { |
| 23 TestOperator(Operator::Opcode opcode, Operator::Properties properties, | 25 TestOperator(Operator::Opcode opcode, Operator::Properties properties, |
| 24 size_t value_in, size_t value_out) | 26 const char* op_name, size_t value_in, size_t value_out) |
| 25 : Operator(opcode, properties, "TestOp", value_in, 0, 0, value_out, 0, | 27 : Operator(opcode, properties, op_name, value_in, 0, 0, value_out, 0, 0) { |
| 26 0) {} | 28 } |
| 27 }; | 29 }; |
| 28 | 30 |
| 29 | 31 |
| 30 namespace { | 32 const uint8_t kOpcodeA0 = 10; |
| 33 const uint8_t kOpcodeA1 = 11; | |
| 34 const uint8_t kOpcodeA2 = 12; | |
| 35 const uint8_t kOpcodeB0 = 20; | |
| 36 const uint8_t kOpcodeB1 = 21; | |
| 37 const uint8_t kOpcodeB2 = 22; | |
| 38 const uint8_t kOpcodeC0 = 30; | |
| 39 const uint8_t kOpcodeC1 = 31; | |
| 40 const uint8_t kOpcodeC2 = 32; | |
| 31 | 41 |
| 32 TestOperator OP0(0, Operator::kNoWrite, 0, 1); | 42 static TestOperator kOpA0(kOpcodeA0, Operator::kNoWrite, "opa1", 0, 1); |
| 33 TestOperator OP1(1, Operator::kNoProperties, 1, 1); | 43 static TestOperator kOpA1(kOpcodeA1, Operator::kNoProperties, "opa2", 1, 1); |
| 34 | 44 static TestOperator kOpA2(kOpcodeA2, Operator::kNoProperties, "opa3", 2, 1); |
| 45 static TestOperator kOpB0(kOpcodeB0, Operator::kNoWrite, "opa0", 0, 0); | |
| 46 static TestOperator kOpB1(kOpcodeB1, Operator::kNoWrite, "opa1", 1, 0); | |
| 47 static TestOperator kOpB2(kOpcodeB2, Operator::kNoWrite, "opa2", 2, 0); | |
| 48 static TestOperator kOpC0(kOpcodeC0, Operator::kNoWrite, "opc0", 0, 0); | |
| 49 static TestOperator kOpC1(kOpcodeC1, Operator::kNoWrite, "opc1", 1, 0); | |
| 50 static TestOperator kOpC2(kOpcodeC2, Operator::kNoWrite, "opc2", 2, 0); | |
| 35 | 51 |
| 36 struct MockReducer : public Reducer { | 52 struct MockReducer : public Reducer { |
| 37 MOCK_METHOD1(Reduce, Reduction(Node*)); | 53 MOCK_METHOD1(Reduce, Reduction(Node*)); |
| 38 }; | 54 }; |
| 39 | 55 |
| 56 | |
| 57 // Replaces all "A" operators with "B" operators without creating new nodes. | |
| 58 class InPlaceABReducer : public Reducer { | |
| 59 public: | |
| 60 virtual Reduction Reduce(Node* node) { | |
| 61 switch (node->op()->opcode()) { | |
| 62 case kOpcodeA0: | |
| 63 EXPECT_EQ(0, node->InputCount()); | |
| 64 node->set_op(&kOpB0); | |
| 65 return Replace(node); | |
| 66 case kOpcodeA1: | |
| 67 EXPECT_EQ(1, node->InputCount()); | |
| 68 node->set_op(&kOpB1); | |
| 69 return Replace(node); | |
| 70 case kOpcodeA2: | |
| 71 EXPECT_EQ(2, node->InputCount()); | |
| 72 node->set_op(&kOpB2); | |
| 73 return Replace(node); | |
| 74 } | |
| 75 return NoChange(); | |
| 76 } | |
| 77 }; | |
| 78 | |
| 79 | |
| 80 // Replaces all "A" operators with "B" operators by allocating new nodes. | |
| 81 class NewABReducer : public Reducer { | |
| 82 public: | |
| 83 explicit NewABReducer(Graph* graph) : graph_(graph) {} | |
| 84 virtual Reduction Reduce(Node* node) { | |
| 85 switch (node->op()->opcode()) { | |
| 86 case kOpcodeA0: | |
| 87 EXPECT_EQ(0, node->InputCount()); | |
| 88 return Replace(graph_->NewNode(&kOpB0)); | |
| 89 case kOpcodeA1: | |
| 90 EXPECT_EQ(1, node->InputCount()); | |
| 91 return Replace(graph_->NewNode(&kOpB1, node->InputAt(0))); | |
| 92 case kOpcodeA2: | |
| 93 EXPECT_EQ(2, node->InputCount()); | |
| 94 return Replace( | |
| 95 graph_->NewNode(&kOpB2, node->InputAt(0), node->InputAt(1))); | |
| 96 } | |
| 97 return NoChange(); | |
| 98 } | |
| 99 Graph* graph_; | |
| 100 }; | |
| 101 | |
| 102 | |
| 103 // Wraps all "kOpA0" nodes in "kOpB1" operators by allocating new nodes. | |
| 104 class A0Wrapper FINAL : public Reducer { | |
| 105 public: | |
| 106 explicit A0Wrapper(Graph* graph) : graph_(graph) {} | |
| 107 virtual Reduction Reduce(Node* node) OVERRIDE { | |
| 108 switch (node->op()->opcode()) { | |
| 109 case kOpcodeA0: | |
| 110 EXPECT_EQ(0, node->InputCount()); | |
| 111 return Replace(graph_->NewNode(&kOpB1, node)); | |
| 112 } | |
| 113 return NoChange(); | |
| 114 } | |
| 115 Graph* graph_; | |
| 116 }; | |
| 117 | |
| 118 | |
| 119 // Wraps all "kOpB0" nodes in two "kOpC1" operators by allocating new nodes. | |
| 120 class B0Wrapper FINAL : public Reducer { | |
| 121 public: | |
| 122 explicit B0Wrapper(Graph* graph) : graph_(graph) {} | |
| 123 virtual Reduction Reduce(Node* node) OVERRIDE { | |
| 124 switch (node->op()->opcode()) { | |
| 125 case kOpcodeB0: | |
| 126 EXPECT_EQ(0, node->InputCount()); | |
| 127 return Replace(graph_->NewNode(&kOpC1, graph_->NewNode(&kOpC1, node))); | |
| 128 } | |
| 129 return NoChange(); | |
| 130 } | |
| 131 Graph* graph_; | |
| 132 }; | |
| 133 | |
| 134 | |
| 135 // Replaces all "kOpA1" nodes with the first input. | |
| 136 class A1Forwarder : public Reducer { | |
| 137 virtual Reduction Reduce(Node* node) { | |
| 138 switch (node->op()->opcode()) { | |
| 139 case kOpcodeA1: | |
| 140 EXPECT_EQ(1, node->InputCount()); | |
| 141 return Replace(node->InputAt(0)); | |
| 142 } | |
| 143 return NoChange(); | |
| 144 } | |
| 145 }; | |
| 146 | |
| 147 | |
| 148 // Replaces all "kOpB1" nodes with the first input. | |
| 149 class B1Forwarder : public Reducer { | |
| 150 virtual Reduction Reduce(Node* node) { | |
| 151 switch (node->op()->opcode()) { | |
| 152 case kOpcodeB1: | |
| 153 EXPECT_EQ(1, node->InputCount()); | |
| 154 return Replace(node->InputAt(0)); | |
| 155 } | |
| 156 return NoChange(); | |
| 157 } | |
| 158 }; | |
| 159 | |
| 160 | |
| 161 // Replaces all "B" operators with "C" operators without creating new nodes. | |
| 162 class InPlaceBCReducer : public Reducer { | |
| 163 public: | |
| 164 virtual Reduction Reduce(Node* node) { | |
| 165 switch (node->op()->opcode()) { | |
| 166 case kOpcodeB0: | |
| 167 EXPECT_EQ(0, node->InputCount()); | |
| 168 node->set_op(&kOpC0); | |
| 169 return Replace(node); | |
| 170 case kOpcodeB1: | |
| 171 EXPECT_EQ(1, node->InputCount()); | |
| 172 node->set_op(&kOpC1); | |
| 173 return Replace(node); | |
| 174 case kOpcodeB2: | |
| 175 EXPECT_EQ(2, node->InputCount()); | |
| 176 node->set_op(&kOpC2); | |
| 177 return Replace(node); | |
| 178 } | |
| 179 return NoChange(); | |
| 180 } | |
| 181 }; | |
| 182 | |
| 183 | |
| 184 // Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids. | |
| 185 class AB2Sorter : public Reducer { | |
| 186 virtual Reduction Reduce(Node* node) { | |
| 187 switch (node->op()->opcode()) { | |
| 188 case kOpcodeA2: | |
| 189 case kOpcodeB2: | |
| 190 EXPECT_EQ(2, node->InputCount()); | |
| 191 Node* x = node->InputAt(0); | |
| 192 Node* y = node->InputAt(1); | |
| 193 if (x->id() > y->id()) { | |
| 194 node->ReplaceInput(0, y); | |
| 195 node->ReplaceInput(1, x); | |
| 196 return Replace(node); | |
| 197 } | |
| 198 } | |
| 199 return NoChange(); | |
| 200 } | |
| 201 }; | |
| 202 | |
| 203 | |
| 40 } // namespace | 204 } // namespace |
| 41 | 205 |
| 42 | 206 |
| 43 class GraphReducerTest : public TestWithZone { | 207 class GraphReducerTest : public TestWithZone { |
| 44 public: | 208 public: |
| 45 GraphReducerTest() : graph_(zone()) {} | 209 GraphReducerTest() : graph_(zone()) {} |
| 46 | 210 |
| 47 static void SetUpTestCase() { | 211 static void SetUpTestCase() { |
| 48 TestWithZone::SetUpTestCase(); | 212 TestWithZone::SetUpTestCase(); |
| 49 DefaultValue<Reduction>::Set(Reducer::NoChange()); | 213 DefaultValue<Reduction>::Set(Reducer::NoChange()); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 69 } | 233 } |
| 70 | 234 |
| 71 void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) { | 235 void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) { |
| 72 GraphReducer reducer(graph(), zone()); | 236 GraphReducer reducer(graph(), zone()); |
| 73 reducer.AddReducer(r1); | 237 reducer.AddReducer(r1); |
| 74 reducer.AddReducer(r2); | 238 reducer.AddReducer(r2); |
| 75 reducer.AddReducer(r3); | 239 reducer.AddReducer(r3); |
| 76 reducer.ReduceNode(node); | 240 reducer.ReduceNode(node); |
| 77 } | 241 } |
| 78 | 242 |
| 243 void ReduceGraph(Reducer* r1) { | |
| 244 GraphReducer reducer(graph(), zone()); | |
| 245 reducer.AddReducer(r1); | |
| 246 reducer.ReduceGraph(); | |
| 247 } | |
| 248 | |
| 249 void ReduceGraph(Reducer* r1, Reducer* r2) { | |
| 250 GraphReducer reducer(graph(), zone()); | |
| 251 reducer.AddReducer(r1); | |
| 252 reducer.AddReducer(r2); | |
| 253 reducer.ReduceGraph(); | |
| 254 } | |
| 255 | |
| 256 void ReduceGraph(Reducer* r1, Reducer* r2, Reducer* r3) { | |
| 257 GraphReducer reducer(graph(), zone()); | |
| 258 reducer.AddReducer(r1); | |
| 259 reducer.AddReducer(r2); | |
| 260 reducer.AddReducer(r3); | |
| 261 reducer.ReduceGraph(); | |
| 262 } | |
| 263 | |
| 79 Graph* graph() { return &graph_; } | 264 Graph* graph() { return &graph_; } |
| 80 | 265 |
| 81 private: | 266 private: |
| 82 Graph graph_; | 267 Graph graph_; |
| 83 }; | 268 }; |
| 84 | 269 |
| 85 | 270 |
| 86 TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) { | 271 TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) { |
| 87 StrictMock<MockReducer> r; | 272 StrictMock<MockReducer> r; |
| 88 Node* node0 = graph()->NewNode(&OP0); | 273 Node* node0 = graph()->NewNode(&kOpA0); |
| 89 Node* node1 = graph()->NewNode(&OP1, node0); | 274 Node* node1 = graph()->NewNode(&kOpA1, node0); |
| 90 Node* node2 = graph()->NewNode(&OP1, node0); | 275 Node* node2 = graph()->NewNode(&kOpA1, node0); |
| 91 EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange())); | 276 EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange())); |
| 92 EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2))); | 277 EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2))); |
| 93 ReduceNode(node1, &r); | 278 ReduceNode(node1, &r); |
| 94 EXPECT_FALSE(node0->IsDead()); | 279 EXPECT_FALSE(node0->IsDead()); |
| 95 EXPECT_TRUE(node1->IsDead()); | 280 EXPECT_TRUE(node1->IsDead()); |
| 96 EXPECT_FALSE(node2->IsDead()); | 281 EXPECT_FALSE(node2->IsDead()); |
| 97 } | 282 } |
| 98 | 283 |
| 99 | 284 |
| 100 TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) { | 285 TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) { |
| 101 StrictMock<MockReducer> r1, r2; | 286 StrictMock<MockReducer> r1, r2; |
| 102 Node* node0 = graph()->NewNode(&OP0); | 287 Node* node0 = graph()->NewNode(&kOpA0); |
| 103 EXPECT_CALL(r1, Reduce(node0)); | 288 EXPECT_CALL(r1, Reduce(node0)); |
| 104 EXPECT_CALL(r2, Reduce(node0)); | 289 EXPECT_CALL(r2, Reduce(node0)); |
| 105 ReduceNode(node0, &r1, &r2); | 290 ReduceNode(node0, &r1, &r2); |
| 106 } | 291 } |
| 107 | 292 |
| 108 | 293 |
| 109 TEST_F(GraphReducerTest, ReduceAgainAfterChanged) { | 294 TEST_F(GraphReducerTest, ReduceAgainAfterChanged) { |
| 110 Sequence s1, s2, s3; | 295 Sequence s1, s2, s3; |
| 111 StrictMock<MockReducer> r1, r2, r3; | 296 StrictMock<MockReducer> r1, r2, r3; |
| 112 Node* node0 = graph()->NewNode(&OP0); | 297 Node* node0 = graph()->NewNode(&kOpA0); |
| 113 EXPECT_CALL(r1, Reduce(node0)); | 298 EXPECT_CALL(r1, Reduce(node0)); |
| 114 EXPECT_CALL(r2, Reduce(node0)); | 299 EXPECT_CALL(r2, Reduce(node0)); |
| 115 EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2, s3).WillOnce( | 300 EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2, s3).WillOnce( |
| 116 Return(Reducer::Changed(node0))); | 301 Return(Reducer::Changed(node0))); |
| 117 EXPECT_CALL(r1, Reduce(node0)).InSequence(s1); | 302 EXPECT_CALL(r1, Reduce(node0)).InSequence(s1); |
| 118 EXPECT_CALL(r2, Reduce(node0)).InSequence(s2); | 303 EXPECT_CALL(r2, Reduce(node0)).InSequence(s2); |
| 119 ReduceNode(node0, &r1, &r2, &r3); | 304 ReduceNode(node0, &r1, &r2, &r3); |
| 120 } | 305 } |
| 121 | 306 |
| 307 | |
| 308 TEST_F(GraphReducerTest, ReduceGraphFromEnd1) { | |
| 309 StrictMock<MockReducer> r1; | |
| 310 Node* n = graph()->NewNode(&kOpA0); | |
| 311 Node* end = graph()->NewNode(&kOpA1, n); | |
| 312 graph()->SetEnd(end); | |
| 313 Sequence s; | |
| 314 EXPECT_CALL(r1, Reduce(n)); | |
| 315 EXPECT_CALL(r1, Reduce(end)); | |
| 316 ReduceGraph(&r1); | |
| 317 } | |
| 318 | |
| 319 | |
| 320 TEST_F(GraphReducerTest, ReduceGraphFromEnd2) { | |
| 321 StrictMock<MockReducer> r1; | |
| 322 Node* n1 = graph()->NewNode(&kOpA0); | |
| 323 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 324 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 325 Node* end = graph()->NewNode(&kOpA2, n2, n3); | |
| 326 graph()->SetEnd(end); | |
| 327 Sequence s1, s2; | |
| 328 EXPECT_CALL(r1, Reduce(n1)).InSequence(s1, s2); | |
| 329 EXPECT_CALL(r1, Reduce(n2)).InSequence(s1); | |
| 330 EXPECT_CALL(r1, Reduce(n3)).InSequence(s2); | |
| 331 EXPECT_CALL(r1, Reduce(end)).InSequence(s1, s2); | |
| 332 ReduceGraph(&r1); | |
| 333 } | |
| 334 | |
| 335 | |
| 336 TEST_F(GraphReducerTest, ReduceInPlace1) { | |
| 337 Node* n1 = graph()->NewNode(&kOpA0); | |
| 338 Node* end = graph()->NewNode(&kOpA1, n1); | |
| 339 graph()->SetEnd(end); | |
| 340 | |
| 341 // Tests A* => B* with in-place updates. | |
| 342 InPlaceABReducer r; | |
| 343 for (int i = 0; i < 3; i++) { | |
| 344 int before = graph()->NodeCount(); | |
| 345 ReduceGraph(&r); | |
| 346 EXPECT_EQ(before, graph()->NodeCount()); | |
| 347 EXPECT_EQ(&kOpB0, n1->op()); | |
| 348 EXPECT_EQ(&kOpB1, end->op()); | |
| 349 EXPECT_EQ(n1, end->InputAt(0)); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 | |
| 354 TEST_F(GraphReducerTest, ReduceInPlace2) { | |
| 355 Node* n1 = graph()->NewNode(&kOpA0); | |
| 356 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 357 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 358 Node* end = graph()->NewNode(&kOpA2, n2, n3); | |
| 359 graph()->SetEnd(end); | |
| 360 | |
| 361 // Tests A* => B* with in-place updates. | |
| 362 InPlaceABReducer r; | |
| 363 for (int i = 0; i < 3; i++) { | |
| 364 int before = graph()->NodeCount(); | |
| 365 ReduceGraph(&r); | |
| 366 EXPECT_EQ(before, graph()->NodeCount()); | |
|
titzer
2015/01/22 14:01:24
We can also start to use the NodeMatcher infrastru
| |
| 367 EXPECT_EQ(&kOpB0, n1->op()); | |
| 368 EXPECT_EQ(&kOpB1, n2->op()); | |
| 369 EXPECT_EQ(n1, n2->InputAt(0)); | |
| 370 EXPECT_EQ(&kOpB1, n3->op()); | |
| 371 EXPECT_EQ(n1, n3->InputAt(0)); | |
| 372 EXPECT_EQ(&kOpB2, end->op()); | |
| 373 EXPECT_EQ(n2, end->InputAt(0)); | |
| 374 EXPECT_EQ(n3, end->InputAt(1)); | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 | |
| 379 TEST_F(GraphReducerTest, ReduceNew1) { | |
| 380 Node* n1 = graph()->NewNode(&kOpA0); | |
| 381 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 382 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 383 Node* end = graph()->NewNode(&kOpA2, n2, n3); | |
| 384 graph()->SetEnd(end); | |
| 385 | |
| 386 NewABReducer r(graph()); | |
| 387 // Tests A* => B* while creating new nodes. | |
| 388 for (int i = 0; i < 3; i++) { | |
| 389 int before = graph()->NodeCount(); | |
| 390 ReduceGraph(&r); | |
| 391 if (i == 0) { | |
| 392 EXPECT_NE(before, graph()->NodeCount()); | |
| 393 } else { | |
| 394 EXPECT_EQ(before, graph()->NodeCount()); | |
| 395 } | |
| 396 Node* nend = graph()->end(); | |
| 397 EXPECT_NE(end, nend); // end() should be updated too. | |
| 398 | |
| 399 Node* nn2 = nend->InputAt(0); | |
| 400 Node* nn3 = nend->InputAt(1); | |
| 401 Node* nn1 = nn2->InputAt(0); | |
| 402 | |
| 403 EXPECT_EQ(nn1, nn3->InputAt(0)); | |
| 404 | |
| 405 EXPECT_EQ(&kOpB0, nn1->op()); | |
| 406 EXPECT_EQ(&kOpB1, nn2->op()); | |
| 407 EXPECT_EQ(&kOpB1, nn3->op()); | |
| 408 EXPECT_EQ(&kOpB2, nend->op()); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 | |
| 413 TEST_F(GraphReducerTest, Wrapping1) { | |
| 414 Node* end = graph()->NewNode(&kOpA0); | |
| 415 graph()->SetEnd(end); | |
| 416 EXPECT_EQ(1, graph()->NodeCount()); | |
| 417 | |
| 418 A0Wrapper r(graph()); | |
| 419 | |
| 420 ReduceGraph(&r); | |
| 421 EXPECT_EQ(2, graph()->NodeCount()); | |
| 422 | |
| 423 Node* nend = graph()->end(); | |
| 424 EXPECT_NE(end, nend); | |
| 425 EXPECT_EQ(&kOpB1, nend->op()); | |
| 426 EXPECT_EQ(1, nend->InputCount()); | |
| 427 EXPECT_EQ(end, nend->InputAt(0)); | |
| 428 } | |
| 429 | |
| 430 | |
| 431 TEST_F(GraphReducerTest, Wrapping2) { | |
| 432 Node* end = graph()->NewNode(&kOpB0); | |
| 433 graph()->SetEnd(end); | |
| 434 EXPECT_EQ(1, graph()->NodeCount()); | |
| 435 | |
| 436 B0Wrapper r(graph()); | |
| 437 | |
| 438 ReduceGraph(&r); | |
| 439 EXPECT_EQ(3, graph()->NodeCount()); | |
| 440 | |
| 441 Node* nend = graph()->end(); | |
| 442 EXPECT_NE(end, nend); | |
| 443 EXPECT_EQ(&kOpC1, nend->op()); | |
| 444 EXPECT_EQ(1, nend->InputCount()); | |
| 445 | |
| 446 Node* n1 = nend->InputAt(0); | |
| 447 EXPECT_NE(end, n1); | |
| 448 EXPECT_EQ(&kOpC1, n1->op()); | |
| 449 EXPECT_EQ(1, n1->InputCount()); | |
| 450 EXPECT_EQ(end, n1->InputAt(0)); | |
| 451 } | |
| 452 | |
| 453 | |
| 454 TEST_F(GraphReducerTest, Forwarding1) { | |
| 455 Node* n1 = graph()->NewNode(&kOpA0); | |
| 456 Node* end = graph()->NewNode(&kOpA1, n1); | |
| 457 graph()->SetEnd(end); | |
| 458 | |
| 459 A1Forwarder r; | |
| 460 | |
| 461 // Tests A1(x) => x | |
| 462 for (int i = 0; i < 3; i++) { | |
| 463 int before = graph()->NodeCount(); | |
| 464 ReduceGraph(&r); | |
| 465 EXPECT_EQ(before, graph()->NodeCount()); | |
| 466 EXPECT_EQ(&kOpA0, n1->op()); | |
| 467 EXPECT_EQ(n1, graph()->end()); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 | |
| 472 TEST_F(GraphReducerTest, Forwarding2) { | |
| 473 Node* n1 = graph()->NewNode(&kOpA0); | |
| 474 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 475 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 476 Node* end = graph()->NewNode(&kOpA2, n2, n3); | |
| 477 graph()->SetEnd(end); | |
| 478 | |
| 479 A1Forwarder r; | |
| 480 | |
| 481 // Tests reducing A2(A1(x), A1(y)) => A2(x, y). | |
| 482 for (int i = 0; i < 3; i++) { | |
| 483 int before = graph()->NodeCount(); | |
| 484 ReduceGraph(&r); | |
| 485 EXPECT_EQ(before, graph()->NodeCount()); | |
| 486 EXPECT_EQ(&kOpA0, n1->op()); | |
| 487 EXPECT_EQ(n1, end->InputAt(0)); | |
| 488 EXPECT_EQ(n1, end->InputAt(1)); | |
| 489 EXPECT_EQ(&kOpA2, end->op()); | |
| 490 EXPECT_EQ(0, n2->UseCount()); | |
| 491 EXPECT_EQ(0, n3->UseCount()); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 | |
| 496 TEST_F(GraphReducerTest, Forwarding3) { | |
| 497 // Tests reducing a chain of A1(A1(A1(A1(x)))) => x. | |
| 498 for (int i = 0; i < 8; i++) { | |
| 499 Node* n1 = graph()->NewNode(&kOpA0); | |
| 500 Node* end = n1; | |
| 501 for (int j = 0; j < i; j++) { | |
| 502 end = graph()->NewNode(&kOpA1, end); | |
| 503 } | |
| 504 graph()->SetEnd(end); | |
| 505 | |
| 506 A1Forwarder r; | |
| 507 | |
| 508 for (int i = 0; i < 3; i++) { | |
| 509 int before = graph()->NodeCount(); | |
| 510 ReduceGraph(&r); | |
| 511 EXPECT_EQ(before, graph()->NodeCount()); | |
| 512 EXPECT_EQ(&kOpA0, n1->op()); | |
| 513 EXPECT_EQ(n1, graph()->end()); | |
| 514 } | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 | |
| 519 TEST_F(GraphReducerTest, ReduceForward1) { | |
| 520 Node* n1 = graph()->NewNode(&kOpA0); | |
| 521 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 522 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 523 Node* end = graph()->NewNode(&kOpA2, n2, n3); | |
| 524 graph()->SetEnd(end); | |
| 525 | |
| 526 InPlaceABReducer r; | |
| 527 B1Forwarder f; | |
| 528 | |
| 529 // Tests first reducing A => B, then B1(x) => x. | |
| 530 for (int i = 0; i < 3; i++) { | |
| 531 int before = graph()->NodeCount(); | |
| 532 ReduceGraph(&r, &f); | |
| 533 EXPECT_EQ(before, graph()->NodeCount()); | |
| 534 EXPECT_EQ(&kOpB0, n1->op()); | |
| 535 EXPECT_TRUE(n2->IsDead()); | |
| 536 EXPECT_EQ(n1, end->InputAt(0)); | |
| 537 EXPECT_TRUE(n3->IsDead()); | |
| 538 EXPECT_EQ(n1, end->InputAt(0)); | |
| 539 EXPECT_EQ(&kOpB2, end->op()); | |
| 540 EXPECT_EQ(0, n2->UseCount()); | |
| 541 EXPECT_EQ(0, n3->UseCount()); | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 | |
| 546 TEST_F(GraphReducerTest, Sorter1) { | |
| 547 AB2Sorter r; | |
| 548 for (int i = 0; i < 6; i++) { | |
| 549 Node* n1 = graph()->NewNode(&kOpA0); | |
| 550 Node* n2 = graph()->NewNode(&kOpA1, n1); | |
| 551 Node* n3 = graph()->NewNode(&kOpA1, n1); | |
| 552 Node* end = NULL; // Initialize to please the compiler. | |
| 553 | |
| 554 if (i == 0) end = graph()->NewNode(&kOpA2, n2, n3); | |
| 555 if (i == 1) end = graph()->NewNode(&kOpA2, n3, n2); | |
| 556 if (i == 2) end = graph()->NewNode(&kOpA2, n2, n1); | |
| 557 if (i == 3) end = graph()->NewNode(&kOpA2, n1, n2); | |
| 558 if (i == 4) end = graph()->NewNode(&kOpA2, n3, n1); | |
| 559 if (i == 5) end = graph()->NewNode(&kOpA2, n1, n3); | |
| 560 | |
| 561 graph()->SetEnd(end); | |
| 562 | |
| 563 int before = graph()->NodeCount(); | |
| 564 ReduceGraph(&r); | |
| 565 EXPECT_EQ(before, graph()->NodeCount()); | |
| 566 EXPECT_EQ(&kOpA0, n1->op()); | |
| 567 EXPECT_EQ(&kOpA1, n2->op()); | |
| 568 EXPECT_EQ(&kOpA1, n3->op()); | |
| 569 EXPECT_EQ(&kOpA2, end->op()); | |
| 570 EXPECT_EQ(end, graph()->end()); | |
| 571 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id()); | |
| 572 } | |
| 573 } | |
| 574 | |
| 575 | |
| 576 // Generate a node graph with the given permutations. | |
| 577 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { | |
| 578 Node* level4 = graph->NewNode(&kOpA0); | |
| 579 Node* level3[] = {graph->NewNode(&kOpA1, level4), | |
| 580 graph->NewNode(&kOpA1, level4)}; | |
| 581 | |
| 582 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]), | |
| 583 graph->NewNode(&kOpA1, level3[p3[1]]), | |
| 584 graph->NewNode(&kOpA1, level3[p3[0]]), | |
| 585 graph->NewNode(&kOpA1, level3[p3[1]])}; | |
| 586 | |
| 587 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]), | |
| 588 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])}; | |
| 589 | |
| 590 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]); | |
| 591 graph->SetEnd(end); | |
| 592 } | |
| 593 | |
| 594 | |
| 595 TEST_F(GraphReducerTest, SortForwardReduce) { | |
| 596 // Tests combined reductions on a series of DAGs. | |
| 597 for (int j = 0; j < 2; j++) { | |
| 598 int p3[] = {j, 1 - j}; | |
| 599 for (int m = 0; m < 2; m++) { | |
| 600 int p1[] = {m, 1 - m}; | |
| 601 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 | |
| 602 int p2[] = {-1, -1, -1, -1}; | |
| 603 int n = k; | |
| 604 for (int d = 4; d >= 1; d--) { // Construct permutation. | |
| 605 int p = n % d; | |
| 606 for (int z = 0; z < 4; z++) { | |
| 607 if (p2[z] == -1) { | |
| 608 if (p == 0) p2[z] = d - 1; | |
| 609 p--; | |
| 610 } | |
| 611 } | |
| 612 n = n / d; | |
| 613 } | |
| 614 | |
| 615 GenDAG(graph(), p3, p2, p1); | |
| 616 | |
| 617 AB2Sorter r1; | |
| 618 A1Forwarder r2; | |
| 619 InPlaceABReducer r3; | |
| 620 | |
| 621 ReduceGraph(&r1, &r2, &r3); | |
| 622 | |
| 623 Node* end = graph()->end(); | |
| 624 EXPECT_EQ(&kOpB2, end->op()); | |
| 625 Node* n1 = end->InputAt(0); | |
| 626 Node* n2 = end->InputAt(1); | |
| 627 EXPECT_NE(n1, n2); | |
| 628 EXPECT_LT(n1->id(), n2->id()); | |
| 629 EXPECT_EQ(&kOpB2, n1->op()); | |
| 630 EXPECT_EQ(&kOpB2, n2->op()); | |
| 631 Node* n4 = n1->InputAt(0); | |
| 632 EXPECT_EQ(&kOpB0, n4->op()); | |
| 633 EXPECT_EQ(n4, n1->InputAt(1)); | |
| 634 EXPECT_EQ(n4, n2->InputAt(0)); | |
| 635 EXPECT_EQ(n4, n2->InputAt(1)); | |
| 636 } | |
| 637 } | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 | |
| 642 TEST_F(GraphReducerTest, Order) { | |
| 643 // Test that the order of reducers doesn't matter, as they should be | |
| 644 // rerun for changed nodes. | |
| 645 for (int i = 0; i < 2; i++) { | |
| 646 Node* n1 = graph()->NewNode(&kOpA0); | |
| 647 Node* end = graph()->NewNode(&kOpA1, n1); | |
| 648 graph()->SetEnd(end); | |
| 649 | |
| 650 InPlaceABReducer abr; | |
| 651 InPlaceBCReducer bcr; | |
| 652 | |
| 653 // Tests A* => C* with in-place updates. | |
| 654 for (int j = 0; j < 3; j++) { | |
| 655 int before = graph()->NodeCount(); | |
| 656 if (i == 0) { | |
| 657 ReduceGraph(&abr, &bcr); | |
| 658 } else { | |
| 659 ReduceGraph(&bcr, &abr); | |
| 660 } | |
| 661 | |
| 662 EXPECT_EQ(before, graph()->NodeCount()); | |
| 663 EXPECT_EQ(&kOpC0, n1->op()); | |
| 664 EXPECT_EQ(&kOpC1, end->op()); | |
| 665 EXPECT_EQ(n1, end->InputAt(0)); | |
| 666 } | |
| 667 } | |
| 668 } | |
| 669 | |
| 670 | |
| 122 } // namespace compiler | 671 } // namespace compiler |
| 123 } // namespace internal | 672 } // namespace internal |
| 124 } // namespace v8 | 673 } // namespace v8 |
| OLD | NEW |