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.
6 #include "test/cctest/cctest.h"
8 #include "src/base/bits.h"
9 #include "src/compiler/common-operator.h"
10 #include "src/compiler/control-reducer.h"
11 #include "src/compiler/graph.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/node-properties.h"
15 using namespace v8::internal;
16 using namespace v8::internal::compiler;
18 static const size_t kNumLeafs = 4;
20 enum Decision { kFalse, kUnknown, kTrue };
22 // TODO(titzer): convert this whole file into unit tests.
24 static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL,
27 if (i2 == NULL) count = 2;
28 if (i1 == NULL) count = 1;
29 if (i0 == NULL) count = 0;
30 CHECK_EQ(count, node->InputCount());
31 if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0));
32 if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1));
33 if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2));
38 static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL,
40 CHECK_EQ(IrOpcode::kMerge, node->opcode());
41 int count = CheckInputs(node, i0, i1, i2);
42 CHECK_EQ(count, node->op()->ControlInputCount());
47 static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
49 CHECK_EQ(IrOpcode::kLoop, node->opcode());
50 int count = CheckInputs(node, i0, i1, i2);
51 CHECK_EQ(count, node->op()->ControlInputCount());
56 bool IsUsedBy(Node* a, Node* b) {
57 auto const uses = a->uses();
58 return std::find(uses.begin(), uses.end(), b) != uses.end();
62 // A helper for all tests dealing with ControlTester.
63 class ControlReducerTester : HandleAndZoneScope {
65 ControlReducerTester()
66 : isolate(main_isolate()),
69 jsgraph(main_isolate(), &graph, &common, NULL, NULL),
70 start(graph.NewNode(common.Start(1))),
71 end(graph.NewNode(common.End(), start)),
72 p0(graph.NewNode(common.Parameter(0), start)),
73 zero(jsgraph.Int32Constant(0)),
74 one(jsgraph.OneConstant()),
75 half(jsgraph.Constant(0.5)),
76 self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
77 dead(graph.NewNode(common.Dead())) {
79 graph.SetStart(start);
87 CommonOperatorBuilder common;
98 Node* leaf[kNumLeafs];
101 return SetSelfReferences(graph.NewNode(op(1, false), a, start));
104 Node* Phi(Node* a, Node* b) {
105 return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
108 Node* Phi(Node* a, Node* b, Node* c) {
109 return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
112 Node* Phi(Node* a, Node* b, Node* c, Node* d) {
113 return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
116 Node* EffectPhi(Node* a) {
117 return SetSelfReferences(graph.NewNode(op(1, true), a, start));
120 Node* EffectPhi(Node* a, Node* b) {
121 return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
124 Node* EffectPhi(Node* a, Node* b, Node* c) {
125 return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
128 Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
129 return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
132 Node* SetSelfReferences(Node* node) {
133 for (Edge edge : node->input_edges()) {
134 if (edge.to() == self) node->ReplaceInput(edge.index(), node);
139 const Operator* op(int count, bool effect) {
140 return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
143 void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); }
146 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
149 // Checks one-step reduction of a phi.
150 void ReducePhi(Node* expect, Node* phi) {
151 Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi);
152 CHECK_EQ(expect, result);
153 ReducePhiIterative(expect, phi); // iterative should give the same result.
156 // Checks one-step reduction of a phi.
157 void ReducePhiNonIterative(Node* expect, Node* phi) {
158 Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi);
159 CHECK_EQ(expect, result);
162 void ReducePhiIterative(Node* expect, Node* phi) {
163 p0->ReplaceInput(0, start); // hack: parameters may be trimmed.
164 Node* ret = graph.NewNode(common.Return(), phi, start, start);
165 Node* end = graph.NewNode(common.End(), ret);
167 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
168 CheckInputs(end, ret);
169 CheckInputs(ret, expect, start, start);
172 void ReduceMerge(Node* expect, Node* merge) {
173 Node* result = ControlReducer::ReduceMerge(&jsgraph, &common, merge);
174 CHECK_EQ(expect, result);
177 void ReduceMergeIterative(Node* expect, Node* merge) {
178 p0->ReplaceInput(0, start); // hack: parameters may be trimmed.
179 Node* end = graph.NewNode(common.End(), merge);
182 CheckInputs(end, expect);
185 void ReduceBranch(Decision expected, Node* branch) {
186 Node* control = branch->InputAt(1);
187 for (Node* use : branch->uses()) {
188 if (use->opcode() == IrOpcode::kIfTrue) {
190 ControlReducer::ReduceIfNodeForTesting(&jsgraph, &common, use);
191 if (expected == kTrue) CHECK_EQ(control, result);
192 if (expected == kFalse) CHECK_EQ(IrOpcode::kDead, result->opcode());
193 if (expected == kUnknown) CHECK_EQ(use, result);
194 } else if (use->opcode() == IrOpcode::kIfFalse) {
196 ControlReducer::ReduceIfNodeForTesting(&jsgraph, &common, use);
197 if (expected == kFalse) CHECK_EQ(control, result);
198 if (expected == kTrue) CHECK_EQ(IrOpcode::kDead, result->opcode());
199 if (expected == kUnknown) CHECK_EQ(use, result);
206 Node* Return(Node* val, Node* effect, Node* control) {
207 Node* ret = graph.NewNode(common.Return(), val, effect, control);
208 end->ReplaceInput(0, ret);
215 ControlReducerTester T;
216 CHECK(IsUsedBy(T.start, T.p0));
217 T.graph.SetEnd(T.p0);
219 CHECK(IsUsedBy(T.start, T.p0));
220 CheckInputs(T.p0, T.start);
225 ControlReducerTester T;
226 CHECK(IsUsedBy(T.start, T.p0));
228 CHECK(!IsUsedBy(T.start, T.p0));
229 CHECK(!T.p0->InputAt(0));
234 ControlReducerTester T;
236 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
237 CHECK(IsUsedBy(T.one, phi));
238 CHECK(IsUsedBy(T.half, phi));
239 CHECK(IsUsedBy(T.start, phi));
242 CHECK(IsUsedBy(T.one, phi));
243 CHECK(IsUsedBy(T.half, phi));
244 CHECK(IsUsedBy(T.start, phi));
245 CheckInputs(phi, T.one, T.half, T.start);
250 ControlReducerTester T;
252 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
253 CHECK(IsUsedBy(T.one, phi));
254 CHECK(IsUsedBy(T.half, phi));
255 CHECK(IsUsedBy(T.start, phi));
257 CHECK(!IsUsedBy(T.one, phi));
258 CHECK(!IsUsedBy(T.half, phi));
259 CHECK(!IsUsedBy(T.start, phi));
260 CHECK(!phi->InputAt(0));
261 CHECK(!phi->InputAt(1));
262 CHECK(!phi->InputAt(2));
267 ControlReducerTester T;
268 const int kDepth = 15;
272 for (int i = 0; i < kDepth; i++) {
273 live[i] = end = T.graph.NewNode(T.common.Merge(1), end);
274 dead[i] = T.graph.NewNode(T.common.Merge(1), end);
276 // end -> live[last] -> live[last-1] -> ... -> start
277 // dead[last] ^ dead[last-1] ^ ... ^
280 for (int i = 0; i < kDepth; i++) {
281 CHECK(!IsUsedBy(live[i], dead[i]));
282 CHECK(!dead[i]->InputAt(0));
283 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
289 ControlReducerTester T;
290 const int kDepth = 15;
295 for (int i = 0; i < kDepth; i++) {
296 live[i] = l = T.graph.NewNode(T.common.Merge(1), l);
297 dead[i] = d = T.graph.NewNode(T.common.Merge(1), d);
299 // end -> live[last] -> live[last-1] -> ... -> start
300 // dead[last] -> dead[last-1] -> ... -> start
303 CHECK(!IsUsedBy(T.start, dead[0]));
304 for (int i = 0; i < kDepth; i++) {
305 CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0));
306 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
312 ControlReducerTester T;
313 Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start);
314 loop->ReplaceInput(1, loop);
315 Node* end = T.graph.NewNode(T.common.End(), loop);
318 CHECK(IsUsedBy(T.start, loop));
319 CHECK(IsUsedBy(loop, end));
320 CHECK(IsUsedBy(loop, loop));
324 // nothing should have happened to the loop itself.
325 CHECK(IsUsedBy(T.start, loop));
326 CHECK(IsUsedBy(loop, end));
327 CHECK(IsUsedBy(loop, loop));
328 CheckInputs(loop, T.start, loop);
329 CheckInputs(end, loop);
334 ControlReducerTester T;
335 Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start);
336 loop->ReplaceInput(1, loop);
337 Node* end = T.graph.NewNode(T.common.End(), loop);
339 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop);
342 CHECK(IsUsedBy(T.start, loop));
343 CHECK(IsUsedBy(loop, end));
344 CHECK(IsUsedBy(loop, loop));
345 CHECK(IsUsedBy(loop, phi));
346 CHECK(IsUsedBy(T.one, phi));
347 CHECK(IsUsedBy(T.half, phi));
351 // nothing should have happened to the loop itself.
352 CHECK(IsUsedBy(T.start, loop));
353 CHECK(IsUsedBy(loop, end));
354 CHECK(IsUsedBy(loop, loop));
355 CheckInputs(loop, T.start, loop);
356 CheckInputs(end, loop);
358 // phi should have been trimmed away.
359 CHECK(!IsUsedBy(loop, phi));
360 CHECK(!IsUsedBy(T.one, phi));
361 CHECK(!IsUsedBy(T.half, phi));
362 CHECK(!phi->InputAt(0));
363 CHECK(!phi->InputAt(1));
364 CHECK(!phi->InputAt(2));
368 void CheckTrimConstant(ControlReducerTester* T, Node* k) {
369 Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start);
370 CHECK(IsUsedBy(k, phi));
372 CHECK(!IsUsedBy(k, phi));
373 CHECK(!phi->InputAt(0));
374 CHECK(!phi->InputAt(1));
378 TEST(Trim_constants) {
379 ControlReducerTester T;
380 int32_t int32_constants[] = {
381 0, -1, -2, 2, 2, 3, 3, 4, 4, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8, 9,
382 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9};
384 for (size_t i = 0; i < arraysize(int32_constants); i++) {
385 CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i]));
386 CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i]));
387 CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i]));
390 Node* other_constants[] = {
391 T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(),
392 T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(),
393 T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(),
394 T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(),
395 T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)};
397 for (size_t i = 0; i < arraysize(other_constants); i++) {
398 CheckTrimConstant(&T, other_constants[i]);
404 ControlReducerTester R;
406 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0]));
407 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1]));
408 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2]));
409 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3]));
413 TEST(CReducePhi1_dead) {
414 ControlReducerTester R;
416 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead));
417 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead));
418 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead));
419 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead));
421 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0]));
422 R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1]));
423 R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2]));
424 R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3]));
428 TEST(CReducePhi1_dead2) {
429 ControlReducerTester R;
431 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead));
432 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead));
433 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0]));
438 ControlReducerTester R;
440 for (size_t i = 0; i < kNumLeafs; i++) {
442 R.ReducePhi(a, R.Phi(a, a));
448 ControlReducerTester R;
450 for (size_t i = 0; i < kNumLeafs; i++) {
452 R.ReducePhi(a, R.Phi(R.self, a));
453 R.ReducePhi(a, R.Phi(a, R.self));
459 ControlReducerTester R;
461 for (size_t i = 1; i < kNumLeafs; i++) {
462 Node* a = R.leaf[i], *b = R.leaf[0];
463 Node* phi1 = R.Phi(b, a);
464 R.ReducePhi(phi1, phi1);
466 Node* phi2 = R.Phi(a, b);
467 R.ReducePhi(phi2, phi2);
472 TEST(CReducePhi2_dead) {
473 ControlReducerTester R;
475 for (size_t i = 0; i < kNumLeafs; i++) {
477 R.ReducePhi(a, R.Phi(a, a, R.dead));
478 R.ReducePhi(a, R.Phi(a, R.dead, a));
479 R.ReducePhi(a, R.Phi(R.dead, a, a));
482 for (size_t i = 0; i < kNumLeafs; i++) {
484 R.ReducePhi(a, R.Phi(R.self, a));
485 R.ReducePhi(a, R.Phi(a, R.self));
486 R.ReducePhi(a, R.Phi(R.self, a, R.dead));
487 R.ReducePhi(a, R.Phi(a, R.self, R.dead));
490 for (size_t i = 1; i < kNumLeafs; i++) {
491 Node* a = R.leaf[i], *b = R.leaf[0];
492 Node* phi1 = R.Phi(b, a, R.dead);
493 R.ReducePhiNonIterative(phi1, phi1);
495 Node* phi2 = R.Phi(a, b, R.dead);
496 R.ReducePhiNonIterative(phi2, phi2);
502 ControlReducerTester R;
504 for (size_t i = 0; i < kNumLeafs; i++) {
506 R.ReducePhi(a, R.Phi(a, a, a));
509 for (size_t i = 0; i < kNumLeafs; i++) {
511 R.ReducePhi(a, R.Phi(R.self, a, a));
512 R.ReducePhi(a, R.Phi(a, R.self, a));
513 R.ReducePhi(a, R.Phi(a, a, R.self));
516 for (size_t i = 1; i < kNumLeafs; i++) {
517 Node* a = R.leaf[i], *b = R.leaf[0];
518 Node* phi1 = R.Phi(b, a, a);
519 R.ReducePhi(phi1, phi1);
521 Node* phi2 = R.Phi(a, b, a);
522 R.ReducePhi(phi2, phi2);
524 Node* phi3 = R.Phi(a, a, b);
525 R.ReducePhi(phi3, phi3);
531 ControlReducerTester R;
533 for (size_t i = 0; i < kNumLeafs; i++) {
535 R.ReducePhi(a, R.Phi(a, a, a, a));
538 for (size_t i = 0; i < kNumLeafs; i++) {
540 R.ReducePhi(a, R.Phi(R.self, a, a, a));
541 R.ReducePhi(a, R.Phi(a, R.self, a, a));
542 R.ReducePhi(a, R.Phi(a, a, R.self, a));
543 R.ReducePhi(a, R.Phi(a, a, a, R.self));
545 R.ReducePhi(a, R.Phi(R.self, R.self, a, a));
546 R.ReducePhi(a, R.Phi(a, R.self, R.self, a));
547 R.ReducePhi(a, R.Phi(a, a, R.self, R.self));
548 R.ReducePhi(a, R.Phi(R.self, a, a, R.self));
551 for (size_t i = 1; i < kNumLeafs; i++) {
552 Node* a = R.leaf[i], *b = R.leaf[0];
553 Node* phi1 = R.Phi(b, a, a, a);
554 R.ReducePhi(phi1, phi1);
556 Node* phi2 = R.Phi(a, b, a, a);
557 R.ReducePhi(phi2, phi2);
559 Node* phi3 = R.Phi(a, a, b, a);
560 R.ReducePhi(phi3, phi3);
562 Node* phi4 = R.Phi(a, a, a, b);
563 R.ReducePhi(phi4, phi4);
568 TEST(CReducePhi_iterative1) {
569 ControlReducerTester R;
571 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0])));
572 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0]));
576 TEST(CReducePhi_iterative2) {
577 ControlReducerTester R;
579 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0])));
583 TEST(CReducePhi_iterative3) {
584 ControlReducerTester R;
586 R.ReducePhiIterative(R.leaf[0],
587 R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0])));
588 R.ReducePhiIterative(R.leaf[0],
589 R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0]));
593 TEST(CReducePhi_iterative4) {
594 ControlReducerTester R;
596 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]),
597 R.Phi(R.leaf[0], R.leaf[0])));
599 Node* p1 = R.Phi(R.leaf[0], R.leaf[0]);
600 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
602 Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
603 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2));
605 Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
606 R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0]));
610 TEST(CReducePhi_iterative_self1) {
611 ControlReducerTester R;
613 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self)));
614 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0]));
618 TEST(CReducePhi_iterative_self2) {
619 ControlReducerTester R;
621 R.ReducePhiIterative(
622 R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self)));
623 R.ReducePhiIterative(
624 R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0])));
626 Node* p1 = R.Phi(R.leaf[0], R.self);
627 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
629 Node* p2 = R.Phi(R.self, R.leaf[0]);
630 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2));
635 ControlReducerTester R;
637 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0]));
638 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1]));
639 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2]));
640 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3]));
644 TEST(EReducePhi1_dead) {
645 ControlReducerTester R;
647 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead));
648 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead));
649 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead));
650 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead));
652 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0]));
653 R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1]));
654 R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2]));
655 R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3]));
659 TEST(EReducePhi1_dead2) {
660 ControlReducerTester R;
662 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead));
663 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead));
664 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0]));
668 TEST(CMergeReduce_simple1) {
669 ControlReducerTester R;
671 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
672 R.ReduceMerge(R.start, merge);
676 TEST(CMergeReduce_simple2) {
677 ControlReducerTester R;
679 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
680 Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1);
681 R.ReduceMerge(merge1, merge2);
682 R.ReduceMergeIterative(R.start, merge2);
686 TEST(CMergeReduce_none1) {
687 ControlReducerTester R;
689 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start);
690 R.ReduceMerge(merge, merge);
694 TEST(CMergeReduce_none2) {
695 ControlReducerTester R;
697 Node* t1 = R.graph.NewNode(R.common.IfTrue(), R.start);
698 Node* t2 = R.graph.NewNode(R.common.IfTrue(), R.start);
699 Node* merge = R.graph.NewNode(R.common.Merge(2), t1, t2);
700 R.ReduceMerge(merge, merge);
704 TEST(CMergeReduce_self3) {
705 ControlReducerTester R;
708 R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self));
709 R.ReduceMerge(merge, merge);
713 TEST(CMergeReduce_dead1) {
714 ControlReducerTester R;
716 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead);
717 R.ReduceMerge(R.start, merge);
721 TEST(CMergeReduce_dead2) {
722 ControlReducerTester R;
724 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
725 Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead);
726 R.ReduceMerge(merge1, merge2);
727 R.ReduceMergeIterative(R.start, merge2);
731 TEST(CMergeReduce_dead_rm1a) {
732 ControlReducerTester R;
734 for (int i = 0; i < 3; i++) {
735 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
736 merge->ReplaceInput(i, R.dead);
737 R.ReduceMerge(merge, merge);
738 CheckMerge(merge, R.start, R.start);
743 TEST(CMergeReduce_dead_rm1b) {
744 ControlReducerTester R;
746 Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
747 Node* f = R.graph.NewNode(R.common.IfTrue(), R.start);
748 for (int i = 0; i < 2; i++) {
749 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
750 for (int j = i + 1; j < 3; j++) {
751 merge->ReplaceInput(i, t);
752 merge->ReplaceInput(j, f);
753 R.ReduceMerge(merge, merge);
754 CheckMerge(merge, t, f);
760 TEST(CMergeReduce_dead_rm2) {
761 ControlReducerTester R;
763 for (int i = 0; i < 3; i++) {
764 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
765 merge->ReplaceInput(i, R.start);
766 R.ReduceMerge(R.start, merge);
771 TEST(CLoopReduce_dead_rm1) {
772 ControlReducerTester R;
774 for (int i = 0; i < 3; i++) {
775 Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start);
776 R.ReduceMerge(loop, loop);
777 CheckLoop(loop, R.start, R.start);
782 TEST(CMergeReduce_edit_phi1) {
783 ControlReducerTester R;
785 for (int i = 0; i < 3; i++) {
786 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
787 merge->ReplaceInput(i, R.dead);
788 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
789 R.leaf[1], R.leaf[2], merge);
790 R.ReduceMerge(merge, merge);
791 CHECK_EQ(IrOpcode::kPhi, phi->opcode());
792 CHECK_EQ(2, phi->op()->ValueInputCount());
793 CHECK_EQ(3, phi->InputCount());
794 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
795 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
796 CHECK_EQ(merge, phi->InputAt(2));
801 TEST(CMergeReduce_edit_effect_phi1) {
802 ControlReducerTester R;
804 for (int i = 0; i < 3; i++) {
805 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
806 merge->ReplaceInput(i, R.dead);
807 Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1],
809 R.ReduceMerge(merge, merge);
810 CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode());
811 CHECK_EQ(0, phi->op()->ValueInputCount());
812 CHECK_EQ(2, phi->op()->EffectInputCount());
813 CHECK_EQ(3, phi->InputCount());
814 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
815 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
816 CHECK_EQ(merge, phi->InputAt(2));
821 static const int kSelectorSize = 4;
823 // Helper to select K of N nodes according to a mask, useful for the test below.
827 explicit Selector(int m) {
829 count = v8::base::bits::CountPopulation32(m);
831 bool is_selected(int i) { return (mask & (1 << i)) != 0; }
832 void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs,
834 CHECK_EQ(opcode, node->opcode());
835 CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount());
837 for (int i = 0; i < kSelectorSize; i++) {
838 if (mask & (1 << i)) {
839 CHECK_EQ(inputs[i], node->InputAt(index++));
842 CHECK_EQ(count, index);
843 if (control != NULL) CHECK_EQ(control, node->InputAt(index++));
847 return WhichPowerOf2(mask);
852 TEST(CMergeReduce_exhaustive_4) {
853 ControlReducerTester R;
855 R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)),
856 R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))};
857 Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22),
858 R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)};
860 R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4),
861 R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)};
863 for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) {
864 // Reduce a single merge with a given mask.
865 Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1],
866 controls[2], controls[3]);
867 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0],
868 values[1], values[2], values[3], merge);
869 Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1],
870 effects[2], effects[3], merge);
873 R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start);
874 Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start);
876 Selector selector(mask);
878 for (int i = 0; i < kSelectorSize; i++) { // set up dead merge inputs.
879 if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead);
882 Node* result = ControlReducer::ReduceMerge(&R.jsgraph, &R.common, merge);
884 int count = selector.count;
886 // result should be dead.
887 CHECK_EQ(IrOpcode::kDead, result->opcode());
888 } else if (count == 1) {
889 // merge should be replaced with one of the controls.
890 CHECK_EQ(controls[selector.single_index()], result);
891 // Phis should have been directly replaced.
892 CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0));
893 CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0));
895 // Otherwise, nodes should be edited in place.
896 CHECK_EQ(merge, result);
897 selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL);
898 selector.CheckNode(phi, IrOpcode::kPhi, values, merge);
899 selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge);
900 CHECK_EQ(phi, phi_use->InputAt(0));
901 CHECK_EQ(ephi, ephi_use->InputAt(0));
902 CHECK_EQ(count, phi->op()->ValueInputCount());
903 CHECK_EQ(count + 1, phi->InputCount());
904 CHECK_EQ(count, ephi->op()->EffectInputCount());
905 CHECK_EQ(count + 1, ephi->InputCount());
911 TEST(CMergeReduce_edit_many_phis1) {
912 ControlReducerTester R;
914 const int kPhiCount = 10;
915 Node* phis[kPhiCount];
917 for (int i = 0; i < 3; i++) {
918 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
919 merge->ReplaceInput(i, R.dead);
920 for (int j = 0; j < kPhiCount; j++) {
921 phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
922 R.leaf[1], R.leaf[2], merge);
924 R.ReduceMerge(merge, merge);
925 for (int j = 0; j < kPhiCount; j++) {
927 CHECK_EQ(IrOpcode::kPhi, phi->opcode());
928 CHECK_EQ(2, phi->op()->ValueInputCount());
929 CHECK_EQ(3, phi->InputCount());
930 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
931 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
932 CHECK_EQ(merge, phi->InputAt(2));
938 TEST(CMergeReduce_simple_chain1) {
939 ControlReducerTester R;
940 for (int i = 0; i < 5; i++) {
941 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
942 for (int j = 0; j < i; j++) {
943 merge = R.graph.NewNode(R.common.Merge(1), merge);
945 R.ReduceMergeIterative(R.start, merge);
950 TEST(CMergeReduce_dead_chain1) {
951 ControlReducerTester R;
952 for (int i = 0; i < 5; i++) {
953 Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead);
954 for (int j = 0; j < i; j++) {
955 merge = R.graph.NewNode(R.common.Merge(1), merge);
957 Node* end = R.graph.NewNode(R.common.End(), merge);
960 CHECK(merge->IsDead());
961 CHECK(!end->InputAt(0)); // end dies.
966 TEST(CMergeReduce_dead_chain2) {
967 ControlReducerTester R;
968 for (int i = 0; i < 5; i++) {
969 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
970 for (int j = 0; j < i; j++) {
971 merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead);
973 R.ReduceMergeIterative(R.start, merge);
983 Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) {
984 if (control == NULL) control = R.start;
985 branch = R.graph.NewNode(R.common.Branch(), cond, control);
986 if_true = R.graph.NewNode(R.common.IfTrue(), branch);
987 if_false = R.graph.NewNode(R.common.IfFalse(), branch);
992 // TODO(titzer): use the diamonds from src/compiler/diamond.h here.
1000 Diamond(ControlReducerTester& R, Node* cond) {
1001 branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
1002 if_true = R.graph.NewNode(R.common.IfTrue(), branch);
1003 if_false = R.graph.NewNode(R.common.IfFalse(), branch);
1004 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
1008 Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) {
1009 branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
1010 if_true = R.graph.NewNode(R.common.IfTrue(), branch);
1011 if_false = R.graph.NewNode(R.common.IfFalse(), branch);
1012 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
1013 phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge);
1016 void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
1018 // Nest {this} into either the if_true or if_false branch of {that}.
1019 void nest(Diamond& that, bool if_true) {
1021 branch->ReplaceInput(1, that.if_true);
1022 that.merge->ReplaceInput(0, merge);
1024 branch->ReplaceInput(1, that.if_false);
1025 that.merge->ReplaceInput(1, merge);
1037 While(ControlReducerTester& R, Node* cond) {
1038 loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
1039 branch = R.graph.NewNode(R.common.Branch(), cond, loop);
1040 if_true = R.graph.NewNode(R.common.IfTrue(), branch);
1041 exit = R.graph.NewNode(R.common.IfFalse(), branch);
1042 loop->ReplaceInput(1, if_true);
1045 void chain(Node* control) { loop->ReplaceInput(0, control); }
1049 TEST(CBranchReduce_none1) {
1050 ControlReducerTester R;
1052 R.ReduceBranch(kUnknown, d.branch);
1056 TEST(CBranchReduce_none2) {
1057 ControlReducerTester R;
1058 Diamond d1(R, R.p0);
1059 Diamond d2(R, R.p0);
1061 R.ReduceBranch(kUnknown, d2.branch);
1065 TEST(CBranchReduce_true) {
1066 ControlReducerTester R;
1067 Node* true_values[] = {
1068 R.one, R.jsgraph.Int32Constant(2),
1069 R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0),
1070 R.jsgraph.Constant(22.1), R.jsgraph.TrueConstant()};
1072 for (size_t i = 0; i < arraysize(true_values); i++) {
1073 Diamond d(R, true_values[i]);
1074 R.ReduceBranch(kTrue, d.branch);
1079 TEST(CBranchReduce_false) {
1080 ControlReducerTester R;
1081 Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0),
1082 R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()};
1084 for (size_t i = 0; i < arraysize(false_values); i++) {
1085 Diamond d(R, false_values[i]);
1086 R.ReduceBranch(kFalse, d.branch);
1091 TEST(CDiamondReduce_true) {
1092 ControlReducerTester R;
1093 Diamond d1(R, R.one);
1094 R.ReduceMergeIterative(R.start, d1.merge);
1098 TEST(CDiamondReduce_false) {
1099 ControlReducerTester R;
1100 Diamond d2(R, R.zero);
1101 R.ReduceMergeIterative(R.start, d2.merge);
1105 TEST(CChainedDiamondsReduce_true_false) {
1106 ControlReducerTester R;
1107 Diamond d1(R, R.one);
1108 Diamond d2(R, R.zero);
1111 R.ReduceMergeIterative(R.start, d2.merge);
1115 TEST(CChainedDiamondsReduce_x_false) {
1116 ControlReducerTester R;
1117 Diamond d1(R, R.p0);
1118 Diamond d2(R, R.zero);
1121 R.ReduceMergeIterative(R.start, d2.merge);
1125 TEST(CChainedDiamondsReduce_false_x) {
1126 ControlReducerTester R;
1127 Diamond d1(R, R.zero);
1128 Diamond d2(R, R.p0);
1131 R.ReduceMergeIterative(R.start, d2.merge);
1135 TEST(CChainedDiamondsReduce_phi1) {
1136 ControlReducerTester R;
1137 Diamond d1(R, R.zero, R.one, R.zero); // foldable branch, phi.
1138 Diamond d2(R, d1.phi);
1141 R.ReduceMergeIterative(R.start, d2.merge);
1145 TEST(CChainedDiamondsReduce_phi2) {
1146 ControlReducerTester R;
1147 Diamond d1(R, R.p0, R.one, R.one); // redundant phi.
1148 Diamond d2(R, d1.phi);
1151 R.ReduceMergeIterative(d1.merge, d2.merge);
1155 TEST(CNestedDiamondsReduce_true_true_false) {
1156 ControlReducerTester R;
1157 Diamond d1(R, R.one);
1158 Diamond d2(R, R.zero);
1161 R.ReduceMergeIterative(R.start, d1.merge);
1165 TEST(CNestedDiamondsReduce_false_true_false) {
1166 ControlReducerTester R;
1167 Diamond d1(R, R.one);
1168 Diamond d2(R, R.zero);
1171 R.ReduceMergeIterative(R.start, d1.merge);
1175 TEST(CNestedDiamonds_xyz) {
1176 ControlReducerTester R;
1178 for (int a = 0; a < 2; a++) {
1179 for (int b = 0; b < 2; b++) {
1180 for (int c = 0; c < 2; c++) {
1181 Diamond d1(R, R.jsgraph.Int32Constant(a));
1182 Diamond d2(R, R.jsgraph.Int32Constant(b));
1185 R.ReduceMergeIterative(R.start, d1.merge);
1192 TEST(CUnusedDiamond1) {
1193 ControlReducerTester R;
1194 // if (p0) { } else { }
1195 Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start);
1196 Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch);
1197 Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch);
1198 Node* merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
1199 R.ReduceMergeIterative(R.start, merge);
1203 TEST(CUnusedDiamond2) {
1204 ControlReducerTester R;
1205 // if (p0) { } else { }
1206 Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start);
1207 Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch);
1208 Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch);
1209 Node* merge = R.graph.NewNode(R.common.Merge(2), if_false, if_true);
1210 R.ReduceMergeIterative(R.start, merge);
1215 ControlReducerTester R;
1217 Node* loop = R.graph.NewNode(R.common.Loop(1), R.start);
1218 Branch b(R, R.p0, loop);
1219 loop->ReplaceInput(0, b.if_true); // loop is not connected to start.
1220 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false);
1221 R.ReduceMergeIterative(R.start, merge);
1222 CHECK(b.if_true->IsDead());
1223 CHECK(b.if_false->IsDead());
1228 ControlReducerTester R;
1231 Diamond d(R, R.zero);
1232 // if (0) { while (p0) ; } else { }
1233 w.branch->ReplaceInput(1, d.if_true);
1234 d.merge->ReplaceInput(0, w.exit);
1236 R.ReduceMergeIterative(R.start, d.merge);
1237 CHECK(d.if_true->IsDead());
1238 CHECK(d.if_false->IsDead());
1243 ControlReducerTester R;
1244 Node* ret = R.Return(R.one, R.start, R.start);
1246 CheckInputs(R.graph.end(), ret);
1247 CheckInputs(ret, R.one, R.start, R.start);
1252 ControlReducerTester R;
1253 Diamond d(R, R.one);
1254 Node* ret = R.Return(R.half, R.start, d.merge);
1256 CHECK(d.branch->IsDead());
1257 CHECK(d.if_true->IsDead());
1258 CHECK(d.if_false->IsDead());
1259 CHECK(d.merge->IsDead());
1261 CheckInputs(R.graph.end(), ret);
1262 CheckInputs(ret, R.half, R.start, R.start);
1266 TEST(Return_true1) {
1267 ControlReducerTester R;
1268 Diamond d(R, R.one, R.half, R.zero);
1269 Node* ret = R.Return(d.phi, R.start, d.merge);
1271 CHECK(d.branch->IsDead());
1272 CHECK(d.if_true->IsDead());
1273 CHECK(d.if_false->IsDead());
1274 CHECK(d.merge->IsDead());
1275 CHECK(d.phi->IsDead());
1277 CheckInputs(R.graph.end(), ret);
1278 CheckInputs(ret, R.half, R.start, R.start);
1282 TEST(Return_false1) {
1283 ControlReducerTester R;
1284 Diamond d(R, R.zero, R.one, R.half);
1285 Node* ret = R.Return(d.phi, R.start, d.merge);
1287 CHECK(d.branch->IsDead());
1288 CHECK(d.if_true->IsDead());
1289 CHECK(d.if_false->IsDead());
1290 CHECK(d.merge->IsDead());
1291 CHECK(d.phi->IsDead());
1293 CheckInputs(R.graph.end(), ret);
1294 CheckInputs(ret, R.half, R.start, R.start);
1298 void CheckDeadDiamond(Diamond& d) {
1299 CHECK(d.branch->IsDead());
1300 CHECK(d.if_true->IsDead());
1301 CHECK(d.if_false->IsDead());
1302 CHECK(d.merge->IsDead());
1303 if (d.phi != NULL) CHECK(d.phi->IsDead());
1307 void CheckLiveDiamond(Diamond& d, bool live_phi = true) {
1308 CheckInputs(d.merge, d.if_true, d.if_false);
1309 CheckInputs(d.if_true, d.branch);
1310 CheckInputs(d.if_false, d.branch);
1311 if (d.phi != NULL) {
1313 CHECK_EQ(3, d.phi->InputCount());
1314 CHECK_EQ(d.merge, d.phi->InputAt(2));
1316 CHECK(d.phi->IsDead());
1322 TEST(Return_effect1) {
1323 ControlReducerTester R;
1324 Diamond d(R, R.one);
1325 Node* e1 = R.jsgraph.Float64Constant(-100.1);
1326 Node* e2 = R.jsgraph.Float64Constant(+100.1);
1327 Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge);
1328 Node* ret = R.Return(R.p0, effect, d.merge);
1330 CheckDeadDiamond(d);
1331 CHECK(effect->IsDead());
1333 CheckInputs(R.graph.end(), ret);
1334 CheckInputs(ret, R.p0, e1, R.start);
1338 TEST(Return_nested_diamonds1) {
1339 ControlReducerTester R;
1340 Diamond d1(R, R.p0, R.one, R.zero);
1341 Diamond d2(R, R.p0);
1342 Diamond d3(R, R.p0);
1347 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1349 R.ReduceGraph(); // nothing should happen.
1351 CheckInputs(ret, d1.phi, R.start, d1.merge);
1352 CheckInputs(d1.phi, R.one, R.zero, d1.merge);
1353 CheckInputs(d1.merge, d1.if_true, d1.if_false);
1357 TEST(Return_nested_diamonds_true1) {
1358 ControlReducerTester R;
1359 Diamond d1(R, R.one, R.one, R.zero);
1360 Diamond d2(R, R.p0);
1361 Diamond d3(R, R.p0);
1366 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1368 R.ReduceGraph(); // d1 gets folded true.
1370 CheckInputs(ret, R.one, R.start, R.start);
1374 TEST(Return_nested_diamonds_false1) {
1375 ControlReducerTester R;
1376 Diamond d1(R, R.zero, R.one, R.zero);
1377 Diamond d2(R, R.p0);
1378 Diamond d3(R, R.p0);
1383 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1385 R.ReduceGraph(); // d1 gets folded false.
1387 CheckInputs(ret, R.zero, R.start, R.start);
1391 TEST(Return_nested_diamonds_true_true1) {
1392 ControlReducerTester R;
1393 Diamond d1(R, R.one, R.one, R.zero);
1394 Diamond d2(R, R.one);
1395 Diamond d3(R, R.p0);
1400 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1402 R.ReduceGraph(); // d1 and d2 both get folded true.
1404 CheckInputs(ret, R.one, R.start, R.start);
1405 CheckDeadDiamond(d1);
1406 CheckDeadDiamond(d2);
1407 CheckDeadDiamond(d3);
1411 TEST(Return_nested_diamonds_true_false1) {
1412 ControlReducerTester R;
1413 Diamond d1(R, R.one, R.one, R.zero);
1414 Diamond d2(R, R.zero);
1415 Diamond d3(R, R.p0);
1420 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1422 R.ReduceGraph(); // d1 gets folded true and d2 gets folded false.
1424 CheckInputs(ret, R.one, R.start, R.start);
1425 CheckDeadDiamond(d1);
1426 CheckDeadDiamond(d2);
1427 CheckDeadDiamond(d3);
1431 TEST(Return_nested_diamonds2) {
1432 ControlReducerTester R;
1433 Node* x2 = R.jsgraph.Float64Constant(11.1);
1434 Node* y2 = R.jsgraph.Float64Constant(22.2);
1435 Node* x3 = R.jsgraph.Float64Constant(33.3);
1436 Node* y3 = R.jsgraph.Float64Constant(44.4);
1438 Diamond d2(R, R.p0, x2, y2);
1439 Diamond d3(R, R.p0, x3, y3);
1440 Diamond d1(R, R.p0, d2.phi, d3.phi);
1445 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1447 R.ReduceGraph(); // nothing should happen.
1449 CheckInputs(ret, d1.phi, R.start, d1.merge);
1450 CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge);
1451 CheckInputs(d1.merge, d2.merge, d3.merge);
1452 CheckLiveDiamond(d2);
1453 CheckLiveDiamond(d3);
1457 TEST(Return_nested_diamonds_true2) {
1458 ControlReducerTester R;
1459 Node* x2 = R.jsgraph.Float64Constant(11.1);
1460 Node* y2 = R.jsgraph.Float64Constant(22.2);
1461 Node* x3 = R.jsgraph.Float64Constant(33.3);
1462 Node* y3 = R.jsgraph.Float64Constant(44.4);
1464 Diamond d2(R, R.p0, x2, y2);
1465 Diamond d3(R, R.p0, x3, y3);
1466 Diamond d1(R, R.one, d2.phi, d3.phi);
1471 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1473 R.ReduceGraph(); // d1 gets folded true.
1475 CheckInputs(ret, d2.phi, R.start, d2.merge);
1476 CheckInputs(d2.branch, R.p0, R.start);
1477 CheckDeadDiamond(d1);
1478 CheckLiveDiamond(d2);
1479 CheckDeadDiamond(d3);
1483 TEST(Return_nested_diamonds_true_true2) {
1484 ControlReducerTester R;
1485 Node* x2 = R.jsgraph.Float64Constant(11.1);
1486 Node* y2 = R.jsgraph.Float64Constant(22.2);
1487 Node* x3 = R.jsgraph.Float64Constant(33.3);
1488 Node* y3 = R.jsgraph.Float64Constant(44.4);
1490 Diamond d2(R, R.one, x2, y2);
1491 Diamond d3(R, R.p0, x3, y3);
1492 Diamond d1(R, R.one, d2.phi, d3.phi);
1497 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1499 R.ReduceGraph(); // d1 gets folded true.
1501 CheckInputs(ret, x2, R.start, R.start);
1502 CheckDeadDiamond(d1);
1503 CheckDeadDiamond(d2);
1504 CheckDeadDiamond(d3);
1508 TEST(Return_nested_diamonds_true_false2) {
1509 ControlReducerTester R;
1510 Node* x2 = R.jsgraph.Float64Constant(11.1);
1511 Node* y2 = R.jsgraph.Float64Constant(22.2);
1512 Node* x3 = R.jsgraph.Float64Constant(33.3);
1513 Node* y3 = R.jsgraph.Float64Constant(44.4);
1515 Diamond d2(R, R.zero, x2, y2);
1516 Diamond d3(R, R.p0, x3, y3);
1517 Diamond d1(R, R.one, d2.phi, d3.phi);
1522 Node* ret = R.Return(d1.phi, R.start, d1.merge);
1524 R.ReduceGraph(); // d1 gets folded true.
1526 CheckInputs(ret, y2, R.start, R.start);
1527 CheckDeadDiamond(d1);
1528 CheckDeadDiamond(d2);
1529 CheckDeadDiamond(d3);