Index: test/cctest/compiler/test-osr.cc |
diff --git a/test/cctest/compiler/test-osr.cc b/test/cctest/compiler/test-osr.cc |
index 83e0fd0516221ad0bb6976c71d28f8df1a795b5d..d2171188f844e79984625c1d8dac9bfb3f24f709 100644 |
--- a/test/cctest/compiler/test-osr.cc |
+++ b/test/cctest/compiler/test-osr.cc |
@@ -36,6 +36,8 @@ static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL, |
static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure, |
"Int32LessThan", 2, 0, 0, 1, 0, 0); |
+static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, |
+ 0, 1, 0, 0); |
static const int kMaxOsrValues = 10; |
@@ -489,3 +491,105 @@ TEST(Deconstruct_osr_nested2) { |
CheckInputs(new_outer_phi, new_entry_phi, new_inner_phi, |
T.jsgraph.ZeroConstant(), new_outer_loop); |
} |
+ |
+ |
+Node* MakeCounter(JSGraph* jsgraph, Node* start, Node* loop) { |
+ int count = loop->InputCount(); |
+ NodeVector tmp_inputs(jsgraph->graph()->zone()); |
+ for (int i = 0; i < count; i++) { |
+ tmp_inputs.push_back(start); |
+ } |
+ tmp_inputs.push_back(loop); |
+ |
+ Node* phi = jsgraph->graph()->NewNode( |
+ jsgraph->common()->Phi(kMachInt32, count), count + 1, &tmp_inputs[0]); |
+ Node* inc = jsgraph->graph()->NewNode(&kIntAdd, phi, jsgraph->OneConstant()); |
+ |
+ for (int i = 1; i < count; i++) { |
+ phi->ReplaceInput(i, inc); |
+ } |
+ return phi; |
+} |
+ |
+ |
+TEST(Deconstruct_osr_nested3) { |
+ OsrDeconstructorTester T(1); |
+ |
+ // outermost loop. |
+ While loop0(T, T.p0, false, 1); |
+ Node* loop0_cntr = MakeCounter(&T.jsgraph, T.p0, loop0.loop); |
+ loop0.branch->ReplaceInput(0, loop0_cntr); |
+ |
+ // middle loop. |
+ Node* loop1 = T.graph.NewNode(T.common.Loop(2), loop0.if_true, T.self); |
+ loop1->ReplaceInput(0, loop0.if_true); |
+ Node* loop1_phi = |
+ T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), loop0_cntr, loop0_cntr); |
+ |
+ // innermost (OSR) loop. |
+ While loop2(T, T.p0, true, 1); |
+ loop2.loop->ReplaceInput(0, loop1); |
+ |
+ Node* loop2_cntr = MakeCounter(&T.jsgraph, loop1_phi, loop2.loop); |
+ loop2_cntr->ReplaceInput(1, T.osr_values[0]); |
+ Node* osr_phi = loop2_cntr; |
+ Node* loop2_inc = loop2_cntr->InputAt(2); |
+ loop2.branch->ReplaceInput(0, loop2_cntr); |
+ |
+ loop1_phi->ReplaceInput(1, loop2_cntr); |
+ loop0_cntr->ReplaceInput(1, loop2_cntr); |
+ |
+ // Branch to either the outer or middle loop. |
+ Node* branch = T.graph.NewNode(T.common.Branch(), loop2_cntr, loop2.exit); |
+ Node* if_true = T.graph.NewNode(T.common.IfTrue(), branch); |
+ Node* if_false = T.graph.NewNode(T.common.IfFalse(), branch); |
+ |
+ loop0.loop->ReplaceInput(1, if_true); |
+ loop1->ReplaceInput(1, if_false); |
+ |
+ Node* ret = |
+ T.graph.NewNode(T.common.Return(), loop0_cntr, T.start, loop0.exit); |
+ Node* end = T.graph.NewNode(T.common.End(), ret); |
+ T.graph.SetEnd(end); |
+ |
+ T.DeconstructOsr(); |
+ |
+ // Check structure of deconstructed graph. |
+ // Check loop2 (OSR loop) is directly connected to start. |
+ CheckInputs(loop2.loop, T.start, loop2.if_true); |
+ CheckInputs(osr_phi, T.osr_values[0], loop2_inc, loop2.loop); |
+ CheckInputs(loop2.branch, osr_phi, loop2.loop); |
+ CheckInputs(loop2.if_true, loop2.branch); |
+ CheckInputs(loop2.exit, loop2.branch); |
+ CheckInputs(branch, osr_phi, loop2.exit); |
+ CheckInputs(if_true, branch); |
+ CheckInputs(if_false, branch); |
+ |
+ // Check structure of new_loop1. |
+ Node* new_loop1_loop = FindSuccessor(if_false, IrOpcode::kLoop); |
+ // TODO(titzer): check the internal copy of loop2. |
+ USE(new_loop1_loop); |
+ |
+ // Check structure of new_loop0. |
+ Node* new_loop0_loop_entry = FindSuccessor(if_true, IrOpcode::kMerge); |
+ Node* new_loop0_loop = FindSuccessor(new_loop0_loop_entry, IrOpcode::kLoop); |
+ // TODO(titzer): check the internal copies of loop1 and loop2. |
+ |
+ Node* new_loop0_branch = FindSuccessor(new_loop0_loop, IrOpcode::kBranch); |
+ Node* new_loop0_if_true = FindSuccessor(new_loop0_branch, IrOpcode::kIfTrue); |
+ Node* new_loop0_exit = FindSuccessor(new_loop0_branch, IrOpcode::kIfFalse); |
+ |
+ USE(new_loop0_if_true); |
+ |
+ Node* new_ret = T.graph.end()->InputAt(0); |
+ CHECK_EQ(IrOpcode::kReturn, new_ret->opcode()); |
+ |
+ Node* new_loop0_phi = new_ret->InputAt(0); |
+ CHECK_EQ(IrOpcode::kPhi, new_loop0_phi->opcode()); |
+ CHECK_EQ(new_loop0_loop, NodeProperties::GetControlInput(new_loop0_phi)); |
+ CHECK_EQ(new_loop0_phi, FindSuccessor(new_loop0_loop, IrOpcode::kPhi)); |
+ |
+ // Check that the return returns the phi from the OSR loop and control |
+ // depends on the copy of the outer loop0. |
+ CheckInputs(new_ret, new_loop0_phi, T.graph.start(), new_loop0_exit); |
+} |