| 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 |
| 214 } // namespace |
| 203 | 215 |
| 204 } // namespace | 216 |
| 217 class AdvancedReducerTest : public TestWithZone { |
| 218 public: |
| 219 AdvancedReducerTest() : graph_(zone()) {} |
| 220 |
| 221 protected: |
| 222 Graph* graph() { return &graph_; } |
| 223 |
| 224 private: |
| 225 Graph graph_; |
| 226 }; |
| 227 |
| 228 |
| 229 TEST_F(AdvancedReducerTest, Replace) { |
| 230 struct DummyReducer final : public AdvancedReducer { |
| 231 explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {} |
| 232 Reduction Reduce(Node* node) final { |
| 233 Replace(node, node); |
| 234 return NoChange(); |
| 235 } |
| 236 }; |
| 237 StrictMock<MockAdvancedReducerEditor> e; |
| 238 DummyReducer r(&e); |
| 239 Node* node0 = graph()->NewNode(&kOpA0); |
| 240 Node* node1 = graph()->NewNode(&kOpA1, node0); |
| 241 EXPECT_CALL(e, Replace(node0, node0)); |
| 242 EXPECT_CALL(e, Replace(node1, node1)); |
| 243 EXPECT_FALSE(r.Reduce(node0).Changed()); |
| 244 EXPECT_FALSE(r.Reduce(node1).Changed()); |
| 245 } |
| 246 |
| 247 |
| 248 TEST_F(AdvancedReducerTest, Revisit) { |
| 249 struct DummyReducer final : public AdvancedReducer { |
| 250 explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {} |
| 251 Reduction Reduce(Node* node) final { |
| 252 Revisit(node); |
| 253 return NoChange(); |
| 254 } |
| 255 }; |
| 256 StrictMock<MockAdvancedReducerEditor> e; |
| 257 DummyReducer r(&e); |
| 258 Node* node0 = graph()->NewNode(&kOpA0); |
| 259 Node* node1 = graph()->NewNode(&kOpA1, node0); |
| 260 EXPECT_CALL(e, Revisit(node0)); |
| 261 EXPECT_CALL(e, Revisit(node1)); |
| 262 EXPECT_FALSE(r.Reduce(node0).Changed()); |
| 263 EXPECT_FALSE(r.Reduce(node1).Changed()); |
| 264 } |
| 205 | 265 |
| 206 | 266 |
| 207 class GraphReducerTest : public TestWithZone { | 267 class GraphReducerTest : public TestWithZone { |
| 208 public: | 268 public: |
| 209 GraphReducerTest() : graph_(zone()) {} | 269 GraphReducerTest() : graph_(zone()) {} |
| 210 | 270 |
| 211 static void SetUpTestCase() { | 271 static void SetUpTestCase() { |
| 212 TestWithZone::SetUpTestCase(); | 272 TestWithZone::SetUpTestCase(); |
| 213 DefaultValue<Reduction>::Set(Reducer::NoChange()); | 273 DefaultValue<Reduction>::Set(Reducer::NoChange()); |
| 214 } | 274 } |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 EXPECT_EQ(&kOpA0, n1->op()); | 626 EXPECT_EQ(&kOpA0, n1->op()); |
| 567 EXPECT_EQ(&kOpA1, n2->op()); | 627 EXPECT_EQ(&kOpA1, n2->op()); |
| 568 EXPECT_EQ(&kOpA1, n3->op()); | 628 EXPECT_EQ(&kOpA1, n3->op()); |
| 569 EXPECT_EQ(&kOpA2, end->op()); | 629 EXPECT_EQ(&kOpA2, end->op()); |
| 570 EXPECT_EQ(end, graph()->end()); | 630 EXPECT_EQ(end, graph()->end()); |
| 571 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id()); | 631 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id()); |
| 572 } | 632 } |
| 573 } | 633 } |
| 574 | 634 |
| 575 | 635 |
| 636 namespace { |
| 637 |
| 576 // Generate a node graph with the given permutations. | 638 // Generate a node graph with the given permutations. |
| 577 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { | 639 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { |
| 578 Node* level4 = graph->NewNode(&kOpA0); | 640 Node* level4 = graph->NewNode(&kOpA0); |
| 579 Node* level3[] = {graph->NewNode(&kOpA1, level4), | 641 Node* level3[] = {graph->NewNode(&kOpA1, level4), |
| 580 graph->NewNode(&kOpA1, level4)}; | 642 graph->NewNode(&kOpA1, level4)}; |
| 581 | 643 |
| 582 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]), | 644 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]), |
| 583 graph->NewNode(&kOpA1, level3[p3[1]]), | 645 graph->NewNode(&kOpA1, level3[p3[1]]), |
| 584 graph->NewNode(&kOpA1, level3[p3[0]]), | 646 graph->NewNode(&kOpA1, level3[p3[0]]), |
| 585 graph->NewNode(&kOpA1, level3[p3[1]])}; | 647 graph->NewNode(&kOpA1, level3[p3[1]])}; |
| 586 | 648 |
| 587 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]), | 649 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]), |
| 588 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])}; | 650 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])}; |
| 589 | 651 |
| 590 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]); | 652 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]); |
| 591 graph->SetEnd(end); | 653 graph->SetEnd(end); |
| 592 } | 654 } |
| 593 | 655 |
| 656 } // namespace |
| 657 |
| 594 | 658 |
| 595 TEST_F(GraphReducerTest, SortForwardReduce) { | 659 TEST_F(GraphReducerTest, SortForwardReduce) { |
| 596 // Tests combined reductions on a series of DAGs. | 660 // Tests combined reductions on a series of DAGs. |
| 597 for (int j = 0; j < 2; j++) { | 661 for (int j = 0; j < 2; j++) { |
| 598 int p3[] = {j, 1 - j}; | 662 int p3[] = {j, 1 - j}; |
| 599 for (int m = 0; m < 2; m++) { | 663 for (int m = 0; m < 2; m++) { |
| 600 int p1[] = {m, 1 - m}; | 664 int p1[] = {m, 1 - m}; |
| 601 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 | 665 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 |
| 602 int p2[] = {-1, -1, -1, -1}; | 666 int p2[] = {-1, -1, -1, -1}; |
| 603 int n = k; | 667 int n = k; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 } | 724 } |
| 661 | 725 |
| 662 EXPECT_EQ(before, graph()->NodeCount()); | 726 EXPECT_EQ(before, graph()->NodeCount()); |
| 663 EXPECT_EQ(&kOpC0, n1->op()); | 727 EXPECT_EQ(&kOpC0, n1->op()); |
| 664 EXPECT_EQ(&kOpC1, end->op()); | 728 EXPECT_EQ(&kOpC1, end->op()); |
| 665 EXPECT_EQ(n1, end->InputAt(0)); | 729 EXPECT_EQ(n1, end->InputAt(0)); |
| 666 } | 730 } |
| 667 } | 731 } |
| 668 } | 732 } |
| 669 | 733 |
| 670 | |
| 671 } // namespace compiler | 734 } // namespace compiler |
| 672 } // namespace internal | 735 } // namespace internal |
| 673 } // namespace v8 | 736 } // namespace v8 |
| OLD | NEW |