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 |