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