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