OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <set> | |
6 | |
7 #include "src/v8.h" | |
8 | |
9 #include "graph-tester.h" | |
10 #include "src/compiler/graph-reducer.h" | |
11 #include "src/compiler/node.h" | |
12 #include "src/compiler/operator.h" | |
13 | |
14 using namespace v8::internal; | |
15 using namespace v8::internal::compiler; | |
16 | |
17 const uint8_t OPCODE_A0 = 10; | |
18 const uint8_t OPCODE_A1 = 11; | |
19 const uint8_t OPCODE_A2 = 12; | |
20 const uint8_t OPCODE_B0 = 20; | |
21 const uint8_t OPCODE_B1 = 21; | |
22 const uint8_t OPCODE_B2 = 22; | |
23 const uint8_t OPCODE_C0 = 30; | |
24 const uint8_t OPCODE_C1 = 31; | |
25 const uint8_t OPCODE_C2 = 32; | |
26 | |
27 static Operator OPA0(OPCODE_A0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0); | |
28 static Operator OPA1(OPCODE_A1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0); | |
29 static Operator OPA2(OPCODE_A2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0); | |
30 static Operator OPB0(OPCODE_B0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0); | |
31 static Operator OPB1(OPCODE_B1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0); | |
32 static Operator OPB2(OPCODE_B2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0); | |
33 static Operator OPC0(OPCODE_C0, Operator::kNoWrite, "opc0", 0, 0, 0, 0, 0, 0); | |
34 static Operator OPC1(OPCODE_C1, Operator::kNoWrite, "opc1", 1, 0, 0, 0, 0, 0); | |
35 static Operator OPC2(OPCODE_C2, Operator::kNoWrite, "opc2", 2, 0, 0, 0, 0, 0); | |
36 | |
37 | |
38 // Replaces all "A" operators with "B" operators without creating new nodes. | |
39 class InPlaceABReducer : public Reducer { | |
40 public: | |
41 virtual Reduction Reduce(Node* node) { | |
42 switch (node->op()->opcode()) { | |
43 case OPCODE_A0: | |
44 CHECK_EQ(0, node->InputCount()); | |
45 node->set_op(&OPB0); | |
46 return Replace(node); | |
47 case OPCODE_A1: | |
48 CHECK_EQ(1, node->InputCount()); | |
49 node->set_op(&OPB1); | |
50 return Replace(node); | |
51 case OPCODE_A2: | |
52 CHECK_EQ(2, node->InputCount()); | |
53 node->set_op(&OPB2); | |
54 return Replace(node); | |
55 } | |
56 return NoChange(); | |
57 } | |
58 }; | |
59 | |
60 | |
61 // Replaces all "A" operators with "B" operators by allocating new nodes. | |
62 class NewABReducer : public Reducer { | |
63 public: | |
64 explicit NewABReducer(Graph* graph) : graph_(graph) {} | |
65 virtual Reduction Reduce(Node* node) { | |
66 switch (node->op()->opcode()) { | |
67 case OPCODE_A0: | |
68 CHECK_EQ(0, node->InputCount()); | |
69 return Replace(graph_->NewNode(&OPB0)); | |
70 case OPCODE_A1: | |
71 CHECK_EQ(1, node->InputCount()); | |
72 return Replace(graph_->NewNode(&OPB1, node->InputAt(0))); | |
73 case OPCODE_A2: | |
74 CHECK_EQ(2, node->InputCount()); | |
75 return Replace( | |
76 graph_->NewNode(&OPB2, node->InputAt(0), node->InputAt(1))); | |
77 } | |
78 return NoChange(); | |
79 } | |
80 Graph* graph_; | |
81 }; | |
82 | |
83 | |
84 // Replaces all "B" operators with "C" operators without creating new nodes. | |
85 class InPlaceBCReducer : public Reducer { | |
86 public: | |
87 virtual Reduction Reduce(Node* node) { | |
88 switch (node->op()->opcode()) { | |
89 case OPCODE_B0: | |
90 CHECK_EQ(0, node->InputCount()); | |
91 node->set_op(&OPC0); | |
92 return Replace(node); | |
93 case OPCODE_B1: | |
94 CHECK_EQ(1, node->InputCount()); | |
95 node->set_op(&OPC1); | |
96 return Replace(node); | |
97 case OPCODE_B2: | |
98 CHECK_EQ(2, node->InputCount()); | |
99 node->set_op(&OPC2); | |
100 return Replace(node); | |
101 } | |
102 return NoChange(); | |
103 } | |
104 }; | |
105 | |
106 | |
107 // Wraps all "OPA0" nodes in "OPB1" operators by allocating new nodes. | |
108 class A0Wrapper FINAL : public Reducer { | |
109 public: | |
110 explicit A0Wrapper(Graph* graph) : graph_(graph) {} | |
111 virtual Reduction Reduce(Node* node) OVERRIDE { | |
112 switch (node->op()->opcode()) { | |
113 case OPCODE_A0: | |
114 CHECK_EQ(0, node->InputCount()); | |
115 return Replace(graph_->NewNode(&OPB1, node)); | |
116 } | |
117 return NoChange(); | |
118 } | |
119 Graph* graph_; | |
120 }; | |
121 | |
122 | |
123 // Wraps all "OPB0" nodes in two "OPC1" operators by allocating new nodes. | |
124 class B0Wrapper FINAL : public Reducer { | |
125 public: | |
126 explicit B0Wrapper(Graph* graph) : graph_(graph) {} | |
127 virtual Reduction Reduce(Node* node) OVERRIDE { | |
128 switch (node->op()->opcode()) { | |
129 case OPCODE_B0: | |
130 CHECK_EQ(0, node->InputCount()); | |
131 return Replace(graph_->NewNode(&OPC1, graph_->NewNode(&OPC1, node))); | |
132 } | |
133 return NoChange(); | |
134 } | |
135 Graph* graph_; | |
136 }; | |
137 | |
138 | |
139 // Replaces all "OPA1" nodes with the first input. | |
140 class A1Forwarder : public Reducer { | |
141 virtual Reduction Reduce(Node* node) { | |
142 switch (node->op()->opcode()) { | |
143 case OPCODE_A1: | |
144 CHECK_EQ(1, node->InputCount()); | |
145 return Replace(node->InputAt(0)); | |
146 } | |
147 return NoChange(); | |
148 } | |
149 }; | |
150 | |
151 | |
152 // Replaces all "OPB1" nodes with the first input. | |
153 class B1Forwarder : public Reducer { | |
154 virtual Reduction Reduce(Node* node) { | |
155 switch (node->op()->opcode()) { | |
156 case OPCODE_B1: | |
157 CHECK_EQ(1, node->InputCount()); | |
158 return Replace(node->InputAt(0)); | |
159 } | |
160 return NoChange(); | |
161 } | |
162 }; | |
163 | |
164 | |
165 // Swaps the inputs to "OP2A" and "OP2B" nodes based on ids. | |
166 class AB2Sorter : public Reducer { | |
167 virtual Reduction Reduce(Node* node) { | |
168 switch (node->op()->opcode()) { | |
169 case OPCODE_A2: | |
170 case OPCODE_B2: | |
171 CHECK_EQ(2, node->InputCount()); | |
172 Node* x = node->InputAt(0); | |
173 Node* y = node->InputAt(1); | |
174 if (x->id() > y->id()) { | |
175 node->ReplaceInput(0, y); | |
176 node->ReplaceInput(1, x); | |
177 return Replace(node); | |
178 } | |
179 } | |
180 return NoChange(); | |
181 } | |
182 }; | |
183 | |
184 | |
185 // Simply records the nodes visited. | |
186 class ReducerRecorder : public Reducer { | |
187 public: | |
188 typedef std::set<Node*, std::less<Node*>, zone_allocator<Node*>> NodeSet; | |
189 explicit ReducerRecorder(Zone* zone) | |
190 : set(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {} | |
191 virtual Reduction Reduce(Node* node) { | |
192 set.insert(node); | |
193 return NoChange(); | |
194 } | |
195 void CheckContains(Node* node) { | |
196 CHECK_EQ(1, static_cast<int>(set.count(node))); | |
197 } | |
198 NodeSet set; | |
199 }; | |
200 | |
201 | |
202 TEST(ReduceGraphFromEnd1) { | |
203 GraphTester graph; | |
204 | |
205 Node* n1 = graph.NewNode(&OPA0); | |
206 Node* end = graph.NewNode(&OPA1, n1); | |
207 graph.SetEnd(end); | |
208 | |
209 GraphReducer reducer(&graph, graph.zone()); | |
210 ReducerRecorder recorder(graph.zone()); | |
211 reducer.AddReducer(&recorder); | |
212 reducer.ReduceGraph(); | |
213 recorder.CheckContains(n1); | |
214 recorder.CheckContains(end); | |
215 } | |
216 | |
217 | |
218 TEST(ReduceGraphFromEnd2) { | |
219 GraphTester graph; | |
220 | |
221 Node* n1 = graph.NewNode(&OPA0); | |
222 Node* n2 = graph.NewNode(&OPA1, n1); | |
223 Node* n3 = graph.NewNode(&OPA1, n1); | |
224 Node* end = graph.NewNode(&OPA2, n2, n3); | |
225 graph.SetEnd(end); | |
226 | |
227 GraphReducer reducer(&graph, graph.zone()); | |
228 ReducerRecorder recorder(graph.zone()); | |
229 reducer.AddReducer(&recorder); | |
230 reducer.ReduceGraph(); | |
231 recorder.CheckContains(n1); | |
232 recorder.CheckContains(n2); | |
233 recorder.CheckContains(n3); | |
234 recorder.CheckContains(end); | |
235 } | |
236 | |
237 | |
238 TEST(ReduceInPlace1) { | |
239 GraphTester graph; | |
240 | |
241 Node* n1 = graph.NewNode(&OPA0); | |
242 Node* end = graph.NewNode(&OPA1, n1); | |
243 graph.SetEnd(end); | |
244 | |
245 GraphReducer reducer(&graph, graph.zone()); | |
246 InPlaceABReducer r; | |
247 reducer.AddReducer(&r); | |
248 | |
249 // Tests A* => B* with in-place updates. | |
250 for (int i = 0; i < 3; i++) { | |
251 int before = graph.NodeCount(); | |
252 reducer.ReduceGraph(); | |
253 CHECK_EQ(before, graph.NodeCount()); | |
254 CHECK_EQ(&OPB0, n1->op()); | |
255 CHECK_EQ(&OPB1, end->op()); | |
256 CHECK_EQ(n1, end->InputAt(0)); | |
257 } | |
258 } | |
259 | |
260 | |
261 TEST(ReduceInPlace2) { | |
262 GraphTester graph; | |
263 | |
264 Node* n1 = graph.NewNode(&OPA0); | |
265 Node* n2 = graph.NewNode(&OPA1, n1); | |
266 Node* n3 = graph.NewNode(&OPA1, n1); | |
267 Node* end = graph.NewNode(&OPA2, n2, n3); | |
268 graph.SetEnd(end); | |
269 | |
270 GraphReducer reducer(&graph, graph.zone()); | |
271 InPlaceABReducer r; | |
272 reducer.AddReducer(&r); | |
273 | |
274 // Tests A* => B* with in-place updates. | |
275 for (int i = 0; i < 3; i++) { | |
276 int before = graph.NodeCount(); | |
277 reducer.ReduceGraph(); | |
278 CHECK_EQ(before, graph.NodeCount()); | |
279 CHECK_EQ(&OPB0, n1->op()); | |
280 CHECK_EQ(&OPB1, n2->op()); | |
281 CHECK_EQ(n1, n2->InputAt(0)); | |
282 CHECK_EQ(&OPB1, n3->op()); | |
283 CHECK_EQ(n1, n3->InputAt(0)); | |
284 CHECK_EQ(&OPB2, end->op()); | |
285 CHECK_EQ(n2, end->InputAt(0)); | |
286 CHECK_EQ(n3, end->InputAt(1)); | |
287 } | |
288 } | |
289 | |
290 | |
291 TEST(ReduceNew1) { | |
292 GraphTester graph; | |
293 | |
294 Node* n1 = graph.NewNode(&OPA0); | |
295 Node* n2 = graph.NewNode(&OPA1, n1); | |
296 Node* n3 = graph.NewNode(&OPA1, n1); | |
297 Node* end = graph.NewNode(&OPA2, n2, n3); | |
298 graph.SetEnd(end); | |
299 | |
300 GraphReducer reducer(&graph, graph.zone()); | |
301 NewABReducer r(&graph); | |
302 reducer.AddReducer(&r); | |
303 | |
304 // Tests A* => B* while creating new nodes. | |
305 for (int i = 0; i < 3; i++) { | |
306 int before = graph.NodeCount(); | |
307 reducer.ReduceGraph(); | |
308 if (i == 0) { | |
309 CHECK_NE(before, graph.NodeCount()); | |
310 } else { | |
311 CHECK_EQ(before, graph.NodeCount()); | |
312 } | |
313 Node* nend = graph.end(); | |
314 CHECK_NE(end, nend); // end() should be updated too. | |
315 | |
316 Node* nn2 = nend->InputAt(0); | |
317 Node* nn3 = nend->InputAt(1); | |
318 Node* nn1 = nn2->InputAt(0); | |
319 | |
320 CHECK_EQ(nn1, nn3->InputAt(0)); | |
321 | |
322 CHECK_EQ(&OPB0, nn1->op()); | |
323 CHECK_EQ(&OPB1, nn2->op()); | |
324 CHECK_EQ(&OPB1, nn3->op()); | |
325 CHECK_EQ(&OPB2, nend->op()); | |
326 } | |
327 } | |
328 | |
329 | |
330 TEST(Wrapping1) { | |
331 GraphTester graph; | |
332 | |
333 Node* end = graph.NewNode(&OPA0); | |
334 graph.SetEnd(end); | |
335 CHECK_EQ(1, graph.NodeCount()); | |
336 | |
337 GraphReducer reducer(&graph, graph.zone()); | |
338 A0Wrapper r(&graph); | |
339 reducer.AddReducer(&r); | |
340 | |
341 reducer.ReduceGraph(); | |
342 CHECK_EQ(2, graph.NodeCount()); | |
343 | |
344 Node* nend = graph.end(); | |
345 CHECK_NE(end, nend); | |
346 CHECK_EQ(&OPB1, nend->op()); | |
347 CHECK_EQ(1, nend->InputCount()); | |
348 CHECK_EQ(end, nend->InputAt(0)); | |
349 } | |
350 | |
351 | |
352 TEST(Wrapping2) { | |
353 GraphTester graph; | |
354 | |
355 Node* end = graph.NewNode(&OPB0); | |
356 graph.SetEnd(end); | |
357 CHECK_EQ(1, graph.NodeCount()); | |
358 | |
359 GraphReducer reducer(&graph, graph.zone()); | |
360 B0Wrapper r(&graph); | |
361 reducer.AddReducer(&r); | |
362 | |
363 reducer.ReduceGraph(); | |
364 CHECK_EQ(3, graph.NodeCount()); | |
365 | |
366 Node* nend = graph.end(); | |
367 CHECK_NE(end, nend); | |
368 CHECK_EQ(&OPC1, nend->op()); | |
369 CHECK_EQ(1, nend->InputCount()); | |
370 | |
371 Node* n1 = nend->InputAt(0); | |
372 CHECK_NE(end, n1); | |
373 CHECK_EQ(&OPC1, n1->op()); | |
374 CHECK_EQ(1, n1->InputCount()); | |
375 CHECK_EQ(end, n1->InputAt(0)); | |
376 } | |
377 | |
378 | |
379 TEST(Forwarding1) { | |
380 GraphTester graph; | |
381 | |
382 Node* n1 = graph.NewNode(&OPA0); | |
383 Node* end = graph.NewNode(&OPA1, n1); | |
384 graph.SetEnd(end); | |
385 | |
386 GraphReducer reducer(&graph, graph.zone()); | |
387 A1Forwarder r; | |
388 reducer.AddReducer(&r); | |
389 | |
390 // Tests A1(x) => x | |
391 for (int i = 0; i < 3; i++) { | |
392 int before = graph.NodeCount(); | |
393 reducer.ReduceGraph(); | |
394 CHECK_EQ(before, graph.NodeCount()); | |
395 CHECK_EQ(&OPA0, n1->op()); | |
396 CHECK_EQ(n1, graph.end()); | |
397 } | |
398 } | |
399 | |
400 | |
401 TEST(Forwarding2) { | |
402 GraphTester graph; | |
403 | |
404 Node* n1 = graph.NewNode(&OPA0); | |
405 Node* n2 = graph.NewNode(&OPA1, n1); | |
406 Node* n3 = graph.NewNode(&OPA1, n1); | |
407 Node* end = graph.NewNode(&OPA2, n2, n3); | |
408 graph.SetEnd(end); | |
409 | |
410 GraphReducer reducer(&graph, graph.zone()); | |
411 A1Forwarder r; | |
412 reducer.AddReducer(&r); | |
413 | |
414 // Tests reducing A2(A1(x), A1(y)) => A2(x, y). | |
415 for (int i = 0; i < 3; i++) { | |
416 int before = graph.NodeCount(); | |
417 reducer.ReduceGraph(); | |
418 CHECK_EQ(before, graph.NodeCount()); | |
419 CHECK_EQ(&OPA0, n1->op()); | |
420 CHECK_EQ(n1, end->InputAt(0)); | |
421 CHECK_EQ(n1, end->InputAt(1)); | |
422 CHECK_EQ(&OPA2, end->op()); | |
423 CHECK_EQ(0, n2->UseCount()); | |
424 CHECK_EQ(0, n3->UseCount()); | |
425 } | |
426 } | |
427 | |
428 | |
429 TEST(Forwarding3) { | |
430 // Tests reducing a chain of A1(A1(A1(A1(x)))) => x. | |
431 for (int i = 0; i < 8; i++) { | |
432 GraphTester graph; | |
433 | |
434 Node* n1 = graph.NewNode(&OPA0); | |
435 Node* end = n1; | |
436 for (int j = 0; j < i; j++) { | |
437 end = graph.NewNode(&OPA1, end); | |
438 } | |
439 graph.SetEnd(end); | |
440 | |
441 GraphReducer reducer(&graph, graph.zone()); | |
442 A1Forwarder r; | |
443 reducer.AddReducer(&r); | |
444 | |
445 for (int i = 0; i < 3; i++) { | |
446 int before = graph.NodeCount(); | |
447 reducer.ReduceGraph(); | |
448 CHECK_EQ(before, graph.NodeCount()); | |
449 CHECK_EQ(&OPA0, n1->op()); | |
450 CHECK_EQ(n1, graph.end()); | |
451 } | |
452 } | |
453 } | |
454 | |
455 | |
456 TEST(ReduceForward1) { | |
457 GraphTester graph; | |
458 | |
459 Node* n1 = graph.NewNode(&OPA0); | |
460 Node* n2 = graph.NewNode(&OPA1, n1); | |
461 Node* n3 = graph.NewNode(&OPA1, n1); | |
462 Node* end = graph.NewNode(&OPA2, n2, n3); | |
463 graph.SetEnd(end); | |
464 | |
465 GraphReducer reducer(&graph, graph.zone()); | |
466 InPlaceABReducer r; | |
467 B1Forwarder f; | |
468 reducer.AddReducer(&r); | |
469 reducer.AddReducer(&f); | |
470 | |
471 // Tests first reducing A => B, then B1(x) => x. | |
472 for (int i = 0; i < 3; i++) { | |
473 int before = graph.NodeCount(); | |
474 reducer.ReduceGraph(); | |
475 CHECK_EQ(before, graph.NodeCount()); | |
476 CHECK_EQ(&OPB0, n1->op()); | |
477 CHECK(n2->IsDead()); | |
478 CHECK_EQ(n1, end->InputAt(0)); | |
479 CHECK(n3->IsDead()); | |
480 CHECK_EQ(n1, end->InputAt(0)); | |
481 CHECK_EQ(&OPB2, end->op()); | |
482 CHECK_EQ(0, n2->UseCount()); | |
483 CHECK_EQ(0, n3->UseCount()); | |
484 } | |
485 } | |
486 | |
487 | |
488 TEST(Sorter1) { | |
489 HandleAndZoneScope scope; | |
490 AB2Sorter r; | |
491 for (int i = 0; i < 6; i++) { | |
492 GraphTester graph; | |
493 | |
494 Node* n1 = graph.NewNode(&OPA0); | |
495 Node* n2 = graph.NewNode(&OPA1, n1); | |
496 Node* n3 = graph.NewNode(&OPA1, n1); | |
497 Node* end = NULL; // Initialize to please the compiler. | |
498 | |
499 if (i == 0) end = graph.NewNode(&OPA2, n2, n3); | |
500 if (i == 1) end = graph.NewNode(&OPA2, n3, n2); | |
501 if (i == 2) end = graph.NewNode(&OPA2, n2, n1); | |
502 if (i == 3) end = graph.NewNode(&OPA2, n1, n2); | |
503 if (i == 4) end = graph.NewNode(&OPA2, n3, n1); | |
504 if (i == 5) end = graph.NewNode(&OPA2, n1, n3); | |
505 | |
506 graph.SetEnd(end); | |
507 | |
508 GraphReducer reducer(&graph, graph.zone()); | |
509 reducer.AddReducer(&r); | |
510 | |
511 int before = graph.NodeCount(); | |
512 reducer.ReduceGraph(); | |
513 CHECK_EQ(before, graph.NodeCount()); | |
514 CHECK_EQ(&OPA0, n1->op()); | |
515 CHECK_EQ(&OPA1, n2->op()); | |
516 CHECK_EQ(&OPA1, n3->op()); | |
517 CHECK_EQ(&OPA2, end->op()); | |
518 CHECK_EQ(end, graph.end()); | |
519 CHECK(end->InputAt(0)->id() <= end->InputAt(1)->id()); | |
520 } | |
521 } | |
522 | |
523 | |
524 // Generate a node graph with the given permutations. | |
525 void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { | |
526 Node* level4 = graph->NewNode(&OPA0); | |
527 Node* level3[] = {graph->NewNode(&OPA1, level4), | |
528 graph->NewNode(&OPA1, level4)}; | |
529 | |
530 Node* level2[] = {graph->NewNode(&OPA1, level3[p3[0]]), | |
531 graph->NewNode(&OPA1, level3[p3[1]]), | |
532 graph->NewNode(&OPA1, level3[p3[0]]), | |
533 graph->NewNode(&OPA1, level3[p3[1]])}; | |
534 | |
535 Node* level1[] = {graph->NewNode(&OPA2, level2[p2[0]], level2[p2[1]]), | |
536 graph->NewNode(&OPA2, level2[p2[2]], level2[p2[3]])}; | |
537 | |
538 Node* end = graph->NewNode(&OPA2, level1[p1[0]], level1[p1[1]]); | |
539 graph->SetEnd(end); | |
540 } | |
541 | |
542 | |
543 TEST(SortForwardReduce) { | |
544 GraphTester graph; | |
545 | |
546 // Tests combined reductions on a series of DAGs. | |
547 for (int j = 0; j < 2; j++) { | |
548 int p3[] = {j, 1 - j}; | |
549 for (int m = 0; m < 2; m++) { | |
550 int p1[] = {m, 1 - m}; | |
551 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 | |
552 int p2[] = {-1, -1, -1, -1}; | |
553 int n = k; | |
554 for (int d = 4; d >= 1; d--) { // Construct permutation. | |
555 int p = n % d; | |
556 for (int z = 0; z < 4; z++) { | |
557 if (p2[z] == -1) { | |
558 if (p == 0) p2[z] = d - 1; | |
559 p--; | |
560 } | |
561 } | |
562 n = n / d; | |
563 } | |
564 | |
565 GenDAG(&graph, p3, p2, p1); | |
566 | |
567 GraphReducer reducer(&graph, graph.zone()); | |
568 AB2Sorter r1; | |
569 A1Forwarder r2; | |
570 InPlaceABReducer r3; | |
571 reducer.AddReducer(&r1); | |
572 reducer.AddReducer(&r2); | |
573 reducer.AddReducer(&r3); | |
574 | |
575 reducer.ReduceGraph(); | |
576 | |
577 Node* end = graph.end(); | |
578 CHECK_EQ(&OPB2, end->op()); | |
579 Node* n1 = end->InputAt(0); | |
580 Node* n2 = end->InputAt(1); | |
581 CHECK_NE(n1, n2); | |
582 CHECK(n1->id() < n2->id()); | |
583 CHECK_EQ(&OPB2, n1->op()); | |
584 CHECK_EQ(&OPB2, n2->op()); | |
585 Node* n4 = n1->InputAt(0); | |
586 CHECK_EQ(&OPB0, n4->op()); | |
587 CHECK_EQ(n4, n1->InputAt(1)); | |
588 CHECK_EQ(n4, n2->InputAt(0)); | |
589 CHECK_EQ(n4, n2->InputAt(1)); | |
590 } | |
591 } | |
592 } | |
593 } | |
594 | |
595 | |
596 TEST(Order) { | |
597 // Test that the order of reducers doesn't matter, as they should be | |
598 // rerun for changed nodes. | |
599 for (int i = 0; i < 2; i++) { | |
600 GraphTester graph; | |
601 | |
602 Node* n1 = graph.NewNode(&OPA0); | |
603 Node* end = graph.NewNode(&OPA1, n1); | |
604 graph.SetEnd(end); | |
605 | |
606 GraphReducer reducer(&graph, graph.zone()); | |
607 InPlaceABReducer abr; | |
608 InPlaceBCReducer bcr; | |
609 if (i == 0) { | |
610 reducer.AddReducer(&abr); | |
611 reducer.AddReducer(&bcr); | |
612 } else { | |
613 reducer.AddReducer(&bcr); | |
614 reducer.AddReducer(&abr); | |
615 } | |
616 | |
617 // Tests A* => C* with in-place updates. | |
618 for (int i = 0; i < 3; i++) { | |
619 int before = graph.NodeCount(); | |
620 reducer.ReduceGraph(); | |
621 CHECK_EQ(before, graph.NodeCount()); | |
622 CHECK_EQ(&OPC0, n1->op()); | |
623 CHECK_EQ(&OPC1, end->op()); | |
624 CHECK_EQ(n1, end->InputAt(0)); | |
625 } | |
626 } | |
627 } | |
OLD | NEW |