Index: test/cctest/compiler/test-control-reducer.cc |
diff --git a/test/cctest/compiler/test-control-reducer.cc b/test/cctest/compiler/test-control-reducer.cc |
index fb877e323c92443ba0d289ffdd5782e14ea3a399..e969e271062fdde5b2f386c8a4756bd02b55b01c 100644 |
--- a/test/cctest/compiler/test-control-reducer.cc |
+++ b/test/cctest/compiler/test-control-reducer.cc |
@@ -6,6 +6,7 @@ |
#include "test/cctest/cctest.h" |
#include "src/base/bits.h" |
+#include "src/compiler/all-nodes.h" |
#include "src/compiler/common-operator.h" |
#include "src/compiler/control-reducer.h" |
#include "src/compiler/graph.h" |
@@ -142,20 +143,18 @@ class ControlReducerTester : HandleAndZoneScope { |
void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } |
- void ReduceGraph() { |
- ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
- } |
+ void ReduceGraph() { ControlReducer::ReduceGraph(main_zone(), &jsgraph); } |
// Checks one-step reduction of a phi. |
void ReducePhi(Node* expect, Node* phi) { |
- Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi); |
+ Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, phi); |
CHECK_EQ(expect, result); |
ReducePhiIterative(expect, phi); // iterative should give the same result. |
} |
// Checks one-step reduction of a phi. |
void ReducePhiNonIterative(Node* expect, Node* phi) { |
- Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi); |
+ Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, phi); |
CHECK_EQ(expect, result); |
} |
@@ -164,13 +163,13 @@ class ControlReducerTester : HandleAndZoneScope { |
Node* ret = graph.NewNode(common.Return(), phi, start, start); |
Node* end = graph.NewNode(common.End(), ret); |
graph.SetEnd(end); |
- ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
+ ControlReducer::ReduceGraph(main_zone(), &jsgraph); |
CheckInputs(end, ret); |
CheckInputs(ret, expect, start, start); |
} |
void ReduceMerge(Node* expect, Node* merge) { |
- Node* result = ControlReducer::ReduceMerge(&jsgraph, &common, merge); |
+ Node* result = ControlReducer::ReduceMerge(&jsgraph, merge); |
CHECK_EQ(expect, result); |
} |
@@ -186,14 +185,12 @@ class ControlReducerTester : HandleAndZoneScope { |
Node* control = branch->InputAt(1); |
for (Node* use : branch->uses()) { |
if (use->opcode() == IrOpcode::kIfTrue) { |
- Node* result = |
- ControlReducer::ReduceIfNodeForTesting(&jsgraph, &common, use); |
+ Node* result = ControlReducer::ReduceIfNodeForTesting(&jsgraph, use); |
if (expected == kTrue) CHECK_EQ(control, result); |
if (expected == kFalse) CHECK_EQ(IrOpcode::kDead, result->opcode()); |
if (expected == kUnknown) CHECK_EQ(use, result); |
} else if (use->opcode() == IrOpcode::kIfFalse) { |
- Node* result = |
- ControlReducer::ReduceIfNodeForTesting(&jsgraph, &common, use); |
+ Node* result = ControlReducer::ReduceIfNodeForTesting(&jsgraph, use); |
if (expected == kFalse) CHECK_EQ(control, result); |
if (expected == kTrue) CHECK_EQ(IrOpcode::kDead, result->opcode()); |
if (expected == kUnknown) CHECK_EQ(use, result); |
@@ -211,6 +208,109 @@ class ControlReducerTester : HandleAndZoneScope { |
}; |
+struct Branch { |
+ Node* branch; |
+ Node* if_true; |
+ Node* if_false; |
+ |
+ Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) { |
+ if (control == NULL) control = R.start; |
+ branch = R.graph.NewNode(R.common.Branch(), cond, control); |
+ if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
+ if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
+ } |
+}; |
+ |
+ |
+// TODO(titzer): use the diamonds from src/compiler/diamond.h here. |
+struct Diamond { |
+ Node* branch; |
+ Node* if_true; |
+ Node* if_false; |
+ Node* merge; |
+ Node* phi; |
+ |
+ Diamond(ControlReducerTester& R, Node* cond) { |
+ branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
+ if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
+ if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
+ merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
+ phi = NULL; |
+ } |
+ |
+ Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) { |
+ branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
+ if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
+ if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
+ merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
+ phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge); |
+ } |
+ |
+ void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); } |
+ |
+ // Nest {this} into either the if_true or if_false branch of {that}. |
+ void nest(Diamond& that, bool if_true) { |
+ if (if_true) { |
+ branch->ReplaceInput(1, that.if_true); |
+ that.merge->ReplaceInput(0, merge); |
+ } else { |
+ branch->ReplaceInput(1, that.if_false); |
+ that.merge->ReplaceInput(1, merge); |
+ } |
+ } |
+}; |
+ |
+ |
+struct While { |
+ Node* branch; |
+ Node* if_true; |
+ Node* exit; |
+ Node* loop; |
+ |
+ While(ControlReducerTester& R, Node* cond) { |
+ loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
+ branch = R.graph.NewNode(R.common.Branch(), cond, loop); |
+ if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
+ exit = R.graph.NewNode(R.common.IfFalse(), branch); |
+ loop->ReplaceInput(1, if_true); |
+ } |
+ |
+ void chain(Node* control) { loop->ReplaceInput(0, control); } |
+}; |
+ |
+ |
+// Helper for checking that nodes are *not* reachable from end. |
+struct DeadChecker { |
+ Zone zone; |
+ AllNodes nodes; |
+ explicit DeadChecker(Graph* graph) : zone(), nodes(&zone, graph) {} |
+ |
+ void Check(Node* node) { CHECK(!nodes.IsLive(node)); } |
+ |
+ void Check(Diamond& d) { |
+ Check(d.branch); |
+ Check(d.if_true); |
+ Check(d.if_false); |
+ Check(d.merge); |
+ if (d.phi != NULL) Check(d.phi); |
+ } |
+ |
+ void CheckLive(Diamond& d, bool live_phi = true) { |
+ CheckInputs(d.merge, d.if_true, d.if_false); |
+ CheckInputs(d.if_true, d.branch); |
+ CheckInputs(d.if_false, d.branch); |
+ if (d.phi != NULL) { |
+ if (live_phi) { |
+ CHECK_EQ(3, d.phi->InputCount()); |
+ CHECK_EQ(d.merge, d.phi->InputAt(2)); |
+ } else { |
+ Check(d.phi); |
+ } |
+ } |
+ } |
+}; |
+ |
+ |
TEST(Trim1_live) { |
ControlReducerTester T; |
CHECK(IsUsedBy(T.start, T.p0)); |
@@ -897,7 +997,7 @@ TEST(CMergeReduce_exhaustive_4) { |
if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead); |
} |
- Node* result = ControlReducer::ReduceMerge(&R.jsgraph, &R.common, merge); |
+ Node* result = ControlReducer::ReduceMerge(&R.jsgraph, merge); |
int count = selector.count; |
if (count == 0) { |
@@ -993,77 +1093,6 @@ TEST(CMergeReduce_dead_chain2) { |
} |
-struct Branch { |
- Node* branch; |
- Node* if_true; |
- Node* if_false; |
- |
- Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) { |
- if (control == NULL) control = R.start; |
- branch = R.graph.NewNode(R.common.Branch(), cond, control); |
- if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
- if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
- } |
-}; |
- |
- |
-// TODO(titzer): use the diamonds from src/compiler/diamond.h here. |
-struct Diamond { |
- Node* branch; |
- Node* if_true; |
- Node* if_false; |
- Node* merge; |
- Node* phi; |
- |
- Diamond(ControlReducerTester& R, Node* cond) { |
- branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
- if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
- if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
- merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
- phi = NULL; |
- } |
- |
- Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) { |
- branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
- if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
- if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
- merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
- phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge); |
- } |
- |
- void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); } |
- |
- // Nest {this} into either the if_true or if_false branch of {that}. |
- void nest(Diamond& that, bool if_true) { |
- if (if_true) { |
- branch->ReplaceInput(1, that.if_true); |
- that.merge->ReplaceInput(0, merge); |
- } else { |
- branch->ReplaceInput(1, that.if_false); |
- that.merge->ReplaceInput(1, merge); |
- } |
- } |
-}; |
- |
- |
-struct While { |
- Node* branch; |
- Node* if_true; |
- Node* exit; |
- Node* loop; |
- |
- While(ControlReducerTester& R, Node* cond) { |
- loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
- branch = R.graph.NewNode(R.common.Branch(), cond, loop); |
- if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
- exit = R.graph.NewNode(R.common.IfFalse(), branch); |
- loop->ReplaceInput(1, if_true); |
- } |
- |
- void chain(Node* control) { loop->ReplaceInput(0, control); } |
-}; |
- |
- |
TEST(CBranchReduce_none1) { |
ControlReducerTester R; |
Diamond d(R, R.p0); |
@@ -1237,8 +1266,12 @@ TEST(CDeadLoop1) { |
loop->ReplaceInput(0, b.if_true); // loop is not connected to start. |
Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false); |
R.ReduceMergeIterative(R.start, merge); |
- CHECK(b.if_true->IsDead()); |
- CHECK(b.if_false->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(b.if_true); |
+ dead.Check(b.if_false); |
+ dead.Check(b.branch); |
+ dead.Check(loop); |
} |
@@ -1252,8 +1285,10 @@ TEST(CDeadLoop2) { |
d.merge->ReplaceInput(0, w.exit); |
R.ReduceMergeIterative(R.start, d.merge); |
- CHECK(d.if_true->IsDead()); |
- CHECK(d.if_false->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d); |
+ dead.Check(w.loop); |
} |
@@ -1271,10 +1306,12 @@ TEST(Return2) { |
Diamond d(R, R.one); |
Node* ret = R.Return(R.half, R.start, d.merge); |
R.ReduceGraph(); |
- CHECK(d.branch->IsDead()); |
- CHECK(d.if_true->IsDead()); |
- CHECK(d.if_false->IsDead()); |
- CHECK(d.merge->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d.branch); |
+ dead.Check(d.if_true); |
+ dead.Check(d.if_false); |
+ dead.Check(d.merge); |
CheckInputs(R.graph.end(), ret); |
CheckInputs(ret, R.half, R.start, R.start); |
@@ -1286,11 +1323,13 @@ TEST(Return_true1) { |
Diamond d(R, R.one, R.half, R.zero); |
Node* ret = R.Return(d.phi, R.start, d.merge); |
R.ReduceGraph(); |
- CHECK(d.branch->IsDead()); |
- CHECK(d.if_true->IsDead()); |
- CHECK(d.if_false->IsDead()); |
- CHECK(d.merge->IsDead()); |
- CHECK(d.phi->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d.branch); |
+ dead.Check(d.if_true); |
+ dead.Check(d.if_false); |
+ dead.Check(d.merge); |
+ dead.Check(d.phi); |
CheckInputs(R.graph.end(), ret); |
CheckInputs(ret, R.half, R.start, R.start); |
@@ -1302,41 +1341,19 @@ TEST(Return_false1) { |
Diamond d(R, R.zero, R.one, R.half); |
Node* ret = R.Return(d.phi, R.start, d.merge); |
R.ReduceGraph(); |
- CHECK(d.branch->IsDead()); |
- CHECK(d.if_true->IsDead()); |
- CHECK(d.if_false->IsDead()); |
- CHECK(d.merge->IsDead()); |
- CHECK(d.phi->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d.branch); |
+ dead.Check(d.if_true); |
+ dead.Check(d.if_false); |
+ dead.Check(d.merge); |
+ dead.Check(d.phi); |
CheckInputs(R.graph.end(), ret); |
CheckInputs(ret, R.half, R.start, R.start); |
} |
-void CheckDeadDiamond(Diamond& d) { |
- CHECK(d.branch->IsDead()); |
- CHECK(d.if_true->IsDead()); |
- CHECK(d.if_false->IsDead()); |
- CHECK(d.merge->IsDead()); |
- if (d.phi != NULL) CHECK(d.phi->IsDead()); |
-} |
- |
- |
-void CheckLiveDiamond(Diamond& d, bool live_phi = true) { |
- CheckInputs(d.merge, d.if_true, d.if_false); |
- CheckInputs(d.if_true, d.branch); |
- CheckInputs(d.if_false, d.branch); |
- if (d.phi != NULL) { |
- if (live_phi) { |
- CHECK_EQ(3, d.phi->InputCount()); |
- CHECK_EQ(d.merge, d.phi->InputAt(2)); |
- } else { |
- CHECK(d.phi->IsDead()); |
- } |
- } |
-} |
- |
- |
TEST(Return_effect1) { |
ControlReducerTester R; |
Diamond d(R, R.one); |
@@ -1345,8 +1362,10 @@ TEST(Return_effect1) { |
Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge); |
Node* ret = R.Return(R.p0, effect, d.merge); |
R.ReduceGraph(); |
- CheckDeadDiamond(d); |
- CHECK(effect->IsDead()); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d); |
+ dead.Check(effect); |
CheckInputs(R.graph.end(), ret); |
CheckInputs(ret, R.p0, e1, R.start); |
@@ -1355,9 +1374,9 @@ TEST(Return_effect1) { |
TEST(Return_nested_diamonds1) { |
ControlReducerTester R; |
- Diamond d1(R, R.p0, R.one, R.zero); |
- Diamond d2(R, R.p0); |
- Diamond d3(R, R.p0); |
+ Diamond d2(R, R.p0, R.one, R.zero); |
+ Diamond d3(R, R.p0, R.one, R.zero); |
+ Diamond d1(R, R.p0, d2.phi, d3.phi); |
d2.nest(d1, true); |
d3.nest(d1, false); |
@@ -1367,15 +1386,65 @@ TEST(Return_nested_diamonds1) { |
R.ReduceGraph(); // nothing should happen. |
CheckInputs(ret, d1.phi, R.start, d1.merge); |
+ CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge); |
+ CheckInputs(d1.merge, d2.merge, d3.merge); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.CheckLive(d2); |
+ dead.CheckLive(d3); |
+} |
+ |
+ |
+TEST(Return_nested_diamonds1_dead1) { |
+ ControlReducerTester R; |
+ Diamond d2(R, R.p0); // dead diamond |
+ Diamond d3(R, R.p0, R.one, R.zero); |
+ Diamond d1(R, R.p0, R.one, d3.phi); |
+ |
+ d2.nest(d1, true); |
+ d3.nest(d1, false); |
+ |
+ Node* ret = R.Return(d1.phi, R.start, d1.merge); |
+ |
+ R.ReduceGraph(); |
+ |
+ CheckInputs(ret, d1.phi, R.start, d1.merge); |
+ CheckInputs(d1.phi, R.one, d3.phi, d1.merge); |
+ CheckInputs(d1.merge, d1.if_true, d3.merge); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d2); // d2 was a dead diamond. |
+ dead.CheckLive(d3); |
+} |
+ |
+ |
+TEST(Return_nested_diamonds1_dead2) { |
+ ControlReducerTester R; |
+ Diamond d2(R, R.p0); // dead diamond |
+ Diamond d3(R, R.p0); // dead diamond |
+ Diamond d1(R, R.p0, R.one, R.zero); |
+ |
+ d2.nest(d1, true); |
+ d3.nest(d1, false); |
+ |
+ Node* ret = R.Return(d1.phi, R.start, d1.merge); |
+ |
+ R.ReduceGraph(); |
+ |
+ CheckInputs(ret, d1.phi, R.start, d1.merge); |
CheckInputs(d1.phi, R.one, R.zero, d1.merge); |
CheckInputs(d1.merge, d1.if_true, d1.if_false); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d2); |
+ dead.Check(d3); |
} |
TEST(Return_nested_diamonds_true1) { |
ControlReducerTester R; |
- Diamond d1(R, R.one, R.one, R.zero); |
- Diamond d2(R, R.p0); |
+ Diamond d2(R, R.p0, R.one, R.zero); |
+ Diamond d1(R, R.one, d2.phi, R.zero); |
Diamond d3(R, R.p0); |
d2.nest(d1, true); |
@@ -1385,15 +1454,21 @@ TEST(Return_nested_diamonds_true1) { |
R.ReduceGraph(); // d1 gets folded true. |
- CheckInputs(ret, R.one, R.start, R.start); |
+ CheckInputs(ret, d2.phi, R.start, d2.merge); |
+ CheckInputs(d2.branch, R.p0, R.start); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.CheckLive(d2); |
+ dead.Check(d3); |
} |
TEST(Return_nested_diamonds_false1) { |
ControlReducerTester R; |
- Diamond d1(R, R.zero, R.one, R.zero); |
+ Diamond d3(R, R.p0, R.one, R.zero); |
+ Diamond d1(R, R.zero, R.one, d3.phi); |
Diamond d2(R, R.p0); |
- Diamond d3(R, R.p0); |
d2.nest(d1, true); |
d3.nest(d1, false); |
@@ -1402,7 +1477,13 @@ TEST(Return_nested_diamonds_false1) { |
R.ReduceGraph(); // d1 gets folded false. |
- CheckInputs(ret, R.zero, R.start, R.start); |
+ CheckInputs(ret, d3.phi, R.start, d3.merge); |
+ CheckInputs(d3.branch, R.p0, R.start); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.Check(d2); |
+ dead.CheckLive(d3); |
} |
@@ -1420,9 +1501,11 @@ TEST(Return_nested_diamonds_true_true1) { |
R.ReduceGraph(); // d1 and d2 both get folded true. |
CheckInputs(ret, R.one, R.start, R.start); |
- CheckDeadDiamond(d1); |
- CheckDeadDiamond(d2); |
- CheckDeadDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.Check(d2); |
+ dead.Check(d3); |
} |
@@ -1440,9 +1523,11 @@ TEST(Return_nested_diamonds_true_false1) { |
R.ReduceGraph(); // d1 gets folded true and d2 gets folded false. |
CheckInputs(ret, R.one, R.start, R.start); |
- CheckDeadDiamond(d1); |
- CheckDeadDiamond(d2); |
- CheckDeadDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.Check(d2); |
+ dead.Check(d3); |
} |
@@ -1467,8 +1552,10 @@ TEST(Return_nested_diamonds2) { |
CheckInputs(ret, d1.phi, R.start, d1.merge); |
CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge); |
CheckInputs(d1.merge, d2.merge, d3.merge); |
- CheckLiveDiamond(d2); |
- CheckLiveDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.CheckLive(d2); |
+ dead.CheckLive(d3); |
} |
@@ -1492,9 +1579,11 @@ TEST(Return_nested_diamonds_true2) { |
CheckInputs(ret, d2.phi, R.start, d2.merge); |
CheckInputs(d2.branch, R.p0, R.start); |
- CheckDeadDiamond(d1); |
- CheckLiveDiamond(d2); |
- CheckDeadDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.CheckLive(d2); |
+ dead.Check(d3); |
} |
@@ -1517,9 +1606,11 @@ TEST(Return_nested_diamonds_true_true2) { |
R.ReduceGraph(); // d1 gets folded true. |
CheckInputs(ret, x2, R.start, R.start); |
- CheckDeadDiamond(d1); |
- CheckDeadDiamond(d2); |
- CheckDeadDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.Check(d2); |
+ dead.Check(d3); |
} |
@@ -1542,7 +1633,9 @@ TEST(Return_nested_diamonds_true_false2) { |
R.ReduceGraph(); // d1 gets folded true. |
CheckInputs(ret, y2, R.start, R.start); |
- CheckDeadDiamond(d1); |
- CheckDeadDiamond(d2); |
- CheckDeadDiamond(d3); |
+ |
+ DeadChecker dead(&R.graph); |
+ dead.Check(d1); |
+ dead.Check(d2); |
+ dead.Check(d3); |
} |