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 |