| 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" | |
| 7 #include "src/compiler/node.h" | 6 #include "src/compiler/node.h" |
| 8 #include "src/compiler/operator.h" | 7 #include "src/compiler/operator.h" |
| 8 #include "test/unittests/compiler/graph-reducer-unittest.h" |
| 9 #include "test/unittests/test-utils.h" | 9 #include "test/unittests/test-utils.h" |
| 10 #include "testing/gmock/include/gmock/gmock.h" | |
| 11 | 10 |
| 12 using testing::_; | 11 using testing::_; |
| 13 using testing::DefaultValue; | 12 using testing::DefaultValue; |
| 14 using testing::Return; | 13 using testing::Return; |
| 15 using testing::Sequence; | 14 using testing::Sequence; |
| 16 using testing::StrictMock; | 15 using testing::StrictMock; |
| 17 | 16 |
| 18 namespace v8 { | 17 namespace v8 { |
| 19 namespace internal { | 18 namespace internal { |
| 20 namespace compiler { | 19 namespace compiler { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 48 static TestOperator kOpC0(kOpcodeC0, Operator::kNoWrite, "opc0", 0, 0); | 47 static TestOperator kOpC0(kOpcodeC0, Operator::kNoWrite, "opc0", 0, 0); |
| 49 static TestOperator kOpC1(kOpcodeC1, Operator::kNoWrite, "opc1", 1, 0); | 48 static TestOperator kOpC1(kOpcodeC1, Operator::kNoWrite, "opc1", 1, 0); |
| 50 static TestOperator kOpC2(kOpcodeC2, Operator::kNoWrite, "opc2", 2, 0); | 49 static TestOperator kOpC2(kOpcodeC2, Operator::kNoWrite, "opc2", 2, 0); |
| 51 | 50 |
| 52 struct MockReducer : public Reducer { | 51 struct MockReducer : public Reducer { |
| 53 MOCK_METHOD1(Reduce, Reduction(Node*)); | 52 MOCK_METHOD1(Reduce, Reduction(Node*)); |
| 54 }; | 53 }; |
| 55 | 54 |
| 56 | 55 |
| 57 // Replaces all "A" operators with "B" operators without creating new nodes. | 56 // Replaces all "A" operators with "B" operators without creating new nodes. |
| 58 class InPlaceABReducer : public Reducer { | 57 class InPlaceABReducer final : public Reducer { |
| 59 public: | 58 public: |
| 60 virtual Reduction Reduce(Node* node) { | 59 Reduction Reduce(Node* node) final { |
| 61 switch (node->op()->opcode()) { | 60 switch (node->op()->opcode()) { |
| 62 case kOpcodeA0: | 61 case kOpcodeA0: |
| 63 EXPECT_EQ(0, node->InputCount()); | 62 EXPECT_EQ(0, node->InputCount()); |
| 64 node->set_op(&kOpB0); | 63 node->set_op(&kOpB0); |
| 65 return Replace(node); | 64 return Replace(node); |
| 66 case kOpcodeA1: | 65 case kOpcodeA1: |
| 67 EXPECT_EQ(1, node->InputCount()); | 66 EXPECT_EQ(1, node->InputCount()); |
| 68 node->set_op(&kOpB1); | 67 node->set_op(&kOpB1); |
| 69 return Replace(node); | 68 return Replace(node); |
| 70 case kOpcodeA2: | 69 case kOpcodeA2: |
| 71 EXPECT_EQ(2, node->InputCount()); | 70 EXPECT_EQ(2, node->InputCount()); |
| 72 node->set_op(&kOpB2); | 71 node->set_op(&kOpB2); |
| 73 return Replace(node); | 72 return Replace(node); |
| 74 } | 73 } |
| 75 return NoChange(); | 74 return NoChange(); |
| 76 } | 75 } |
| 77 }; | 76 }; |
| 78 | 77 |
| 79 | 78 |
| 80 // Replaces all "A" operators with "B" operators by allocating new nodes. | 79 // Replaces all "A" operators with "B" operators by allocating new nodes. |
| 81 class NewABReducer : public Reducer { | 80 class NewABReducer final : public Reducer { |
| 82 public: | 81 public: |
| 83 explicit NewABReducer(Graph* graph) : graph_(graph) {} | 82 explicit NewABReducer(Graph* graph) : graph_(graph) {} |
| 84 virtual Reduction Reduce(Node* node) { | 83 |
| 84 Reduction Reduce(Node* node) final { |
| 85 switch (node->op()->opcode()) { | 85 switch (node->op()->opcode()) { |
| 86 case kOpcodeA0: | 86 case kOpcodeA0: |
| 87 EXPECT_EQ(0, node->InputCount()); | 87 EXPECT_EQ(0, node->InputCount()); |
| 88 return Replace(graph_->NewNode(&kOpB0)); | 88 return Replace(graph_->NewNode(&kOpB0)); |
| 89 case kOpcodeA1: | 89 case kOpcodeA1: |
| 90 EXPECT_EQ(1, node->InputCount()); | 90 EXPECT_EQ(1, node->InputCount()); |
| 91 return Replace(graph_->NewNode(&kOpB1, node->InputAt(0))); | 91 return Replace(graph_->NewNode(&kOpB1, node->InputAt(0))); |
| 92 case kOpcodeA2: | 92 case kOpcodeA2: |
| 93 EXPECT_EQ(2, node->InputCount()); | 93 EXPECT_EQ(2, node->InputCount()); |
| 94 return Replace( | 94 return Replace( |
| 95 graph_->NewNode(&kOpB2, node->InputAt(0), node->InputAt(1))); | 95 graph_->NewNode(&kOpB2, node->InputAt(0), node->InputAt(1))); |
| 96 } | 96 } |
| 97 return NoChange(); | 97 return NoChange(); |
| 98 } | 98 } |
| 99 Graph* graph_; | 99 |
| 100 private: |
| 101 Graph* const graph_; |
| 100 }; | 102 }; |
| 101 | 103 |
| 102 | 104 |
| 103 // Wraps all "kOpA0" nodes in "kOpB1" operators by allocating new nodes. | 105 // Wraps all "kOpA0" nodes in "kOpB1" operators by allocating new nodes. |
| 104 class A0Wrapper final : public Reducer { | 106 class A0Wrapper final : public Reducer { |
| 105 public: | 107 public: |
| 106 explicit A0Wrapper(Graph* graph) : graph_(graph) {} | 108 explicit A0Wrapper(Graph* graph) : graph_(graph) {} |
| 107 virtual Reduction Reduce(Node* node) override { | 109 |
| 110 Reduction Reduce(Node* node) final { |
| 108 switch (node->op()->opcode()) { | 111 switch (node->op()->opcode()) { |
| 109 case kOpcodeA0: | 112 case kOpcodeA0: |
| 110 EXPECT_EQ(0, node->InputCount()); | 113 EXPECT_EQ(0, node->InputCount()); |
| 111 return Replace(graph_->NewNode(&kOpB1, node)); | 114 return Replace(graph_->NewNode(&kOpB1, node)); |
| 112 } | 115 } |
| 113 return NoChange(); | 116 return NoChange(); |
| 114 } | 117 } |
| 115 Graph* graph_; | 118 |
| 119 private: |
| 120 Graph* const graph_; |
| 116 }; | 121 }; |
| 117 | 122 |
| 118 | 123 |
| 119 // Wraps all "kOpB0" nodes in two "kOpC1" operators by allocating new nodes. | 124 // Wraps all "kOpB0" nodes in two "kOpC1" operators by allocating new nodes. |
| 120 class B0Wrapper final : public Reducer { | 125 class B0Wrapper final : public Reducer { |
| 121 public: | 126 public: |
| 122 explicit B0Wrapper(Graph* graph) : graph_(graph) {} | 127 explicit B0Wrapper(Graph* graph) : graph_(graph) {} |
| 123 virtual Reduction Reduce(Node* node) override { | 128 |
| 129 Reduction Reduce(Node* node) final { |
| 124 switch (node->op()->opcode()) { | 130 switch (node->op()->opcode()) { |
| 125 case kOpcodeB0: | 131 case kOpcodeB0: |
| 126 EXPECT_EQ(0, node->InputCount()); | 132 EXPECT_EQ(0, node->InputCount()); |
| 127 return Replace(graph_->NewNode(&kOpC1, graph_->NewNode(&kOpC1, node))); | 133 return Replace(graph_->NewNode(&kOpC1, graph_->NewNode(&kOpC1, node))); |
| 128 } | 134 } |
| 129 return NoChange(); | 135 return NoChange(); |
| 130 } | 136 } |
| 131 Graph* graph_; | 137 |
| 138 private: |
| 139 Graph* const graph_; |
| 132 }; | 140 }; |
| 133 | 141 |
| 134 | 142 |
| 135 // Replaces all "kOpA1" nodes with the first input. | 143 // Replaces all "kOpA1" nodes with the first input. |
| 136 class A1Forwarder : public Reducer { | 144 class A1Forwarder final : public Reducer { |
| 137 virtual Reduction Reduce(Node* node) { | 145 public: |
| 146 Reduction Reduce(Node* node) final { |
| 138 switch (node->op()->opcode()) { | 147 switch (node->op()->opcode()) { |
| 139 case kOpcodeA1: | 148 case kOpcodeA1: |
| 140 EXPECT_EQ(1, node->InputCount()); | 149 EXPECT_EQ(1, node->InputCount()); |
| 141 return Replace(node->InputAt(0)); | 150 return Replace(node->InputAt(0)); |
| 142 } | 151 } |
| 143 return NoChange(); | 152 return NoChange(); |
| 144 } | 153 } |
| 145 }; | 154 }; |
| 146 | 155 |
| 147 | 156 |
| 148 // Replaces all "kOpB1" nodes with the first input. | 157 // Replaces all "kOpB1" nodes with the first input. |
| 149 class B1Forwarder : public Reducer { | 158 class B1Forwarder final : public Reducer { |
| 150 virtual Reduction Reduce(Node* node) { | 159 public: |
| 160 Reduction Reduce(Node* node) final { |
| 151 switch (node->op()->opcode()) { | 161 switch (node->op()->opcode()) { |
| 152 case kOpcodeB1: | 162 case kOpcodeB1: |
| 153 EXPECT_EQ(1, node->InputCount()); | 163 EXPECT_EQ(1, node->InputCount()); |
| 154 return Replace(node->InputAt(0)); | 164 return Replace(node->InputAt(0)); |
| 155 } | 165 } |
| 156 return NoChange(); | 166 return NoChange(); |
| 157 } | 167 } |
| 158 }; | 168 }; |
| 159 | 169 |
| 160 | 170 |
| 161 // Replaces all "B" operators with "C" operators without creating new nodes. | 171 // Replaces all "B" operators with "C" operators without creating new nodes. |
| 162 class InPlaceBCReducer : public Reducer { | 172 class InPlaceBCReducer final : public Reducer { |
| 163 public: | 173 public: |
| 164 virtual Reduction Reduce(Node* node) { | 174 Reduction Reduce(Node* node) final { |
| 165 switch (node->op()->opcode()) { | 175 switch (node->op()->opcode()) { |
| 166 case kOpcodeB0: | 176 case kOpcodeB0: |
| 167 EXPECT_EQ(0, node->InputCount()); | 177 EXPECT_EQ(0, node->InputCount()); |
| 168 node->set_op(&kOpC0); | 178 node->set_op(&kOpC0); |
| 169 return Replace(node); | 179 return Replace(node); |
| 170 case kOpcodeB1: | 180 case kOpcodeB1: |
| 171 EXPECT_EQ(1, node->InputCount()); | 181 EXPECT_EQ(1, node->InputCount()); |
| 172 node->set_op(&kOpC1); | 182 node->set_op(&kOpC1); |
| 173 return Replace(node); | 183 return Replace(node); |
| 174 case kOpcodeB2: | 184 case kOpcodeB2: |
| 175 EXPECT_EQ(2, node->InputCount()); | 185 EXPECT_EQ(2, node->InputCount()); |
| 176 node->set_op(&kOpC2); | 186 node->set_op(&kOpC2); |
| 177 return Replace(node); | 187 return Replace(node); |
| 178 } | 188 } |
| 179 return NoChange(); | 189 return NoChange(); |
| 180 } | 190 } |
| 181 }; | 191 }; |
| 182 | 192 |
| 183 | 193 |
| 184 // Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids. | 194 // Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids. |
| 185 class AB2Sorter : public Reducer { | 195 class AB2Sorter final : public Reducer { |
| 186 virtual Reduction Reduce(Node* node) { | 196 public: |
| 197 Reduction Reduce(Node* node) final { |
| 187 switch (node->op()->opcode()) { | 198 switch (node->op()->opcode()) { |
| 188 case kOpcodeA2: | 199 case kOpcodeA2: |
| 189 case kOpcodeB2: | 200 case kOpcodeB2: |
| 190 EXPECT_EQ(2, node->InputCount()); | 201 EXPECT_EQ(2, node->InputCount()); |
| 191 Node* x = node->InputAt(0); | 202 Node* x = node->InputAt(0); |
| 192 Node* y = node->InputAt(1); | 203 Node* y = node->InputAt(1); |
| 193 if (x->id() > y->id()) { | 204 if (x->id() > y->id()) { |
| 194 node->ReplaceInput(0, y); | 205 node->ReplaceInput(0, y); |
| 195 node->ReplaceInput(1, x); | 206 node->ReplaceInput(1, x); |
| 196 return Replace(node); | 207 return Replace(node); |
| 197 } | 208 } |
| 198 } | 209 } |
| 199 return NoChange(); | 210 return NoChange(); |
| 200 } | 211 } |
| 201 }; | 212 }; |
| 202 | 213 |
| 203 | |
| 204 } // namespace | 214 } // namespace |
| 205 | 215 |
| 206 | 216 |
| 207 class GraphReducerTest : public TestWithZone { | 217 class GraphReducerTest : public TestWithZone { |
| 208 public: | 218 public: |
| 209 GraphReducerTest() : graph_(zone()) {} | 219 GraphReducerTest() : graph_(zone()) {} |
| 210 | 220 |
| 211 static void SetUpTestCase() { | 221 static void SetUpTestCase() { |
| 212 TestWithZone::SetUpTestCase(); | 222 TestWithZone::SetUpTestCase(); |
| 213 DefaultValue<Reduction>::Set(Reducer::NoChange()); | 223 DefaultValue<Reduction>::Set(Reducer::NoChange()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 reducer.ReduceGraph(); | 271 reducer.ReduceGraph(); |
| 262 } | 272 } |
| 263 | 273 |
| 264 Graph* graph() { return &graph_; } | 274 Graph* graph() { return &graph_; } |
| 265 | 275 |
| 266 private: | 276 private: |
| 267 Graph graph_; | 277 Graph graph_; |
| 268 }; | 278 }; |
| 269 | 279 |
| 270 | 280 |
| 281 TEST_F(GraphReducerTest, AddReducerSetsObserver) { |
| 282 StrictMock<MockReducer> r; |
| 283 GraphReducer gr(graph(), zone()); |
| 284 gr.AddReducer(&r); |
| 285 EXPECT_EQ(&gr, r.observer()); |
| 286 } |
| 287 |
| 288 |
| 289 TEST_F(GraphReducerTest, DestructorResetsObserver) { |
| 290 StrictMock<MockReducer> r; |
| 291 { |
| 292 GraphReducer gr(graph(), zone()); |
| 293 gr.AddReducer(&r); |
| 294 } |
| 295 EXPECT_EQ(nullptr, r.observer()); |
| 296 } |
| 297 |
| 298 |
| 271 TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) { | 299 TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) { |
| 272 StrictMock<MockReducer> r; | 300 StrictMock<MockReducer> r; |
| 273 Node* node0 = graph()->NewNode(&kOpA0); | 301 Node* node0 = graph()->NewNode(&kOpA0); |
| 274 Node* node1 = graph()->NewNode(&kOpA1, node0); | 302 Node* node1 = graph()->NewNode(&kOpA1, node0); |
| 275 Node* node2 = graph()->NewNode(&kOpA1, node0); | 303 Node* node2 = graph()->NewNode(&kOpA1, node0); |
| 276 EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange())); | 304 EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange())); |
| 277 EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2))); | 305 EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2))); |
| 278 ReduceNode(node1, &r); | 306 ReduceNode(node1, &r); |
| 279 EXPECT_FALSE(node0->IsDead()); | 307 EXPECT_FALSE(node0->IsDead()); |
| 280 EXPECT_TRUE(node1->IsDead()); | 308 EXPECT_TRUE(node1->IsDead()); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 EXPECT_EQ(&kOpA0, n1->op()); | 594 EXPECT_EQ(&kOpA0, n1->op()); |
| 567 EXPECT_EQ(&kOpA1, n2->op()); | 595 EXPECT_EQ(&kOpA1, n2->op()); |
| 568 EXPECT_EQ(&kOpA1, n3->op()); | 596 EXPECT_EQ(&kOpA1, n3->op()); |
| 569 EXPECT_EQ(&kOpA2, end->op()); | 597 EXPECT_EQ(&kOpA2, end->op()); |
| 570 EXPECT_EQ(end, graph()->end()); | 598 EXPECT_EQ(end, graph()->end()); |
| 571 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id()); | 599 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id()); |
| 572 } | 600 } |
| 573 } | 601 } |
| 574 | 602 |
| 575 | 603 |
| 604 namespace { |
| 605 |
| 576 // Generate a node graph with the given permutations. | 606 // Generate a node graph with the given permutations. |
| 577 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { | 607 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { |
| 578 Node* level4 = graph->NewNode(&kOpA0); | 608 Node* level4 = graph->NewNode(&kOpA0); |
| 579 Node* level3[] = {graph->NewNode(&kOpA1, level4), | 609 Node* level3[] = {graph->NewNode(&kOpA1, level4), |
| 580 graph->NewNode(&kOpA1, level4)}; | 610 graph->NewNode(&kOpA1, level4)}; |
| 581 | 611 |
| 582 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]), | 612 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]), |
| 583 graph->NewNode(&kOpA1, level3[p3[1]]), | 613 graph->NewNode(&kOpA1, level3[p3[1]]), |
| 584 graph->NewNode(&kOpA1, level3[p3[0]]), | 614 graph->NewNode(&kOpA1, level3[p3[0]]), |
| 585 graph->NewNode(&kOpA1, level3[p3[1]])}; | 615 graph->NewNode(&kOpA1, level3[p3[1]])}; |
| 586 | 616 |
| 587 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]), | 617 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]), |
| 588 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])}; | 618 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])}; |
| 589 | 619 |
| 590 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]); | 620 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]); |
| 591 graph->SetEnd(end); | 621 graph->SetEnd(end); |
| 592 } | 622 } |
| 593 | 623 |
| 624 } // namespace |
| 625 |
| 594 | 626 |
| 595 TEST_F(GraphReducerTest, SortForwardReduce) { | 627 TEST_F(GraphReducerTest, SortForwardReduce) { |
| 596 // Tests combined reductions on a series of DAGs. | 628 // Tests combined reductions on a series of DAGs. |
| 597 for (int j = 0; j < 2; j++) { | 629 for (int j = 0; j < 2; j++) { |
| 598 int p3[] = {j, 1 - j}; | 630 int p3[] = {j, 1 - j}; |
| 599 for (int m = 0; m < 2; m++) { | 631 for (int m = 0; m < 2; m++) { |
| 600 int p1[] = {m, 1 - m}; | 632 int p1[] = {m, 1 - m}; |
| 601 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 | 633 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 |
| 602 int p2[] = {-1, -1, -1, -1}; | 634 int p2[] = {-1, -1, -1, -1}; |
| 603 int n = k; | 635 int n = k; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 } | 692 } |
| 661 | 693 |
| 662 EXPECT_EQ(before, graph()->NodeCount()); | 694 EXPECT_EQ(before, graph()->NodeCount()); |
| 663 EXPECT_EQ(&kOpC0, n1->op()); | 695 EXPECT_EQ(&kOpC0, n1->op()); |
| 664 EXPECT_EQ(&kOpC1, end->op()); | 696 EXPECT_EQ(&kOpC1, end->op()); |
| 665 EXPECT_EQ(n1, end->InputAt(0)); | 697 EXPECT_EQ(n1, end->InputAt(0)); |
| 666 } | 698 } |
| 667 } | 699 } |
| 668 } | 700 } |
| 669 | 701 |
| 670 | |
| 671 } // namespace compiler | 702 } // namespace compiler |
| 672 } // namespace internal | 703 } // namespace internal |
| 673 } // namespace v8 | 704 } // namespace v8 |
| OLD | NEW |