OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/codegen.h" | 5 #include "src/codegen.h" |
6 #include "src/compiler/common-operator.h" | 6 #include "src/compiler/common-operator.h" |
7 #include "src/compiler/diamond.h" | 7 #include "src/compiler/diamond.h" |
8 #include "src/compiler/graph.h" | 8 #include "src/compiler/graph.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/js-operator.h" | 10 #include "src/compiler/js-operator.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 class OsrDeconstructorTester : public HandleAndZoneScope { | 42 class OsrDeconstructorTester : public HandleAndZoneScope { |
43 public: | 43 public: |
44 explicit OsrDeconstructorTester(int num_values) | 44 explicit OsrDeconstructorTester(int num_values) |
45 : isolate(main_isolate()), | 45 : isolate(main_isolate()), |
46 common(main_zone()), | 46 common(main_zone()), |
47 graph(main_zone()), | 47 graph(main_zone()), |
48 jsgraph(main_isolate(), &graph, &common, NULL, NULL), | 48 jsgraph(main_isolate(), &graph, &common, NULL, NULL), |
49 start(graph.NewNode(common.Start(1))), | 49 start(graph.NewNode(common.Start(1))), |
50 p0(graph.NewNode(common.Parameter(0), start)), | 50 p0(graph.NewNode(common.Parameter(0), start)), |
51 end(graph.NewNode(common.End(), start)), | 51 end(graph.NewNode(common.End(), start)), |
52 osr_normal_entry(graph.NewNode(common.OsrNormalEntry(), start)), | 52 osr_normal_entry(graph.NewNode(common.OsrNormalEntry(), start, start)), |
53 osr_loop_entry(graph.NewNode(common.OsrLoopEntry(), start)), | 53 osr_loop_entry(graph.NewNode(common.OsrLoopEntry(), start, start)), |
54 self(graph.NewNode(common.Int32Constant(0xaabbccdd))) { | 54 self(graph.NewNode(common.Int32Constant(0xaabbccdd))) { |
55 CHECK(num_values <= kMaxOsrValues); | 55 CHECK(num_values <= kMaxOsrValues); |
56 graph.SetStart(start); | 56 graph.SetStart(start); |
57 for (int i = 0; i < num_values; i++) { | 57 for (int i = 0; i < num_values; i++) { |
58 osr_values[i] = graph.NewNode(common.OsrValue(i), osr_loop_entry); | 58 osr_values[i] = graph.NewNode(common.OsrValue(i), osr_loop_entry); |
59 } | 59 } |
60 } | 60 } |
61 | 61 |
62 Isolate* isolate; | 62 Isolate* isolate; |
63 CommonOperatorBuilder common; | 63 CommonOperatorBuilder common; |
(...skipping 19 matching lines...) Expand all Loading... |
83 Node* inputs[6]; | 83 Node* inputs[6]; |
84 inputs[0] = incoming; | 84 inputs[0] = incoming; |
85 inputs[1] = osr_values[osr_value]; | 85 inputs[1] = osr_values[osr_value]; |
86 if (count > 2) inputs[2] = back1; | 86 if (count > 2) inputs[2] = back1; |
87 if (count > 3) inputs[3] = back2; | 87 if (count > 3) inputs[3] = back2; |
88 if (count > 4) inputs[4] = back3; | 88 if (count > 4) inputs[4] = back3; |
89 inputs[count] = loop; | 89 inputs[count] = loop; |
90 return graph.NewNode(common.Phi(kMachAnyTagged, count), count + 1, inputs); | 90 return graph.NewNode(common.Phi(kMachAnyTagged, count), count + 1, inputs); |
91 } | 91 } |
92 | 92 |
93 Node* NewOsrLoop(int num_backedges, Node* entry = NULL) { | 93 Node* NewLoop(bool is_osr, int num_backedges, Node* entry = NULL) { |
94 CHECK_LT(num_backedges, 4); | 94 CHECK_LT(num_backedges, 4); |
95 CHECK_GE(num_backedges, 0); | 95 CHECK_GE(num_backedges, 0); |
96 int count = 2 + num_backedges; | 96 int count = 1 + num_backedges; |
97 if (entry == NULL) entry = osr_normal_entry; | 97 if (entry == NULL) entry = osr_normal_entry; |
98 Node* inputs[5] = {entry, osr_loop_entry, self, self, self}; | 98 Node* inputs[5] = {entry, self, self, self, self}; |
| 99 if (is_osr) { |
| 100 count = 2 + num_backedges; |
| 101 inputs[1] = osr_loop_entry; |
| 102 } |
99 | 103 |
100 Node* loop = graph.NewNode(common.Loop(count), count, inputs); | 104 Node* loop = graph.NewNode(common.Loop(count), count, inputs); |
101 for (int i = 0; i < num_backedges; i++) { | 105 for (int i = 0; i < loop->InputCount(); i++) { |
102 loop->ReplaceInput(2 + i, loop); | 106 if (loop->InputAt(i) == self) loop->ReplaceInput(i, loop); |
103 } | 107 } |
104 | 108 |
105 return loop; | 109 return loop; |
106 } | 110 } |
| 111 |
| 112 Node* NewOsrLoop(int num_backedges, Node* entry = NULL) { |
| 113 return NewLoop(true, num_backedges, entry); |
| 114 } |
107 }; | 115 }; |
108 | 116 |
109 | 117 |
110 TEST(Deconstruct_osr0) { | 118 TEST(Deconstruct_osr0) { |
111 OsrDeconstructorTester T(0); | 119 OsrDeconstructorTester T(0); |
112 | 120 |
113 Node* loop = T.NewOsrLoop(1); | 121 Node* loop = T.NewOsrLoop(1); |
114 | 122 |
115 T.graph.SetEnd(loop); | 123 T.graph.SetEnd(loop); |
116 | 124 |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 CheckInputs(branch2, T.p0, if_true1); | 273 CheckInputs(branch2, T.p0, if_true1); |
266 CheckInputs(if_true1, branch1); | 274 CheckInputs(if_true1, branch1); |
267 CheckInputs(if_false1, branch1); | 275 CheckInputs(if_false1, branch1); |
268 CheckInputs(if_true2, branch2); | 276 CheckInputs(if_true2, branch2); |
269 CheckInputs(if_false2, branch2); | 277 CheckInputs(if_false2, branch2); |
270 | 278 |
271 CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), | 279 CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), |
272 T.jsgraph.ZeroConstant(), loop); | 280 T.jsgraph.ZeroConstant(), loop); |
273 CheckInputs(ret, osr_phi, T.start, if_false2); | 281 CheckInputs(ret, osr_phi, T.start, if_false2); |
274 } | 282 } |
| 283 |
| 284 |
| 285 struct While { |
| 286 OsrDeconstructorTester& t; |
| 287 Node* branch; |
| 288 Node* if_true; |
| 289 Node* exit; |
| 290 Node* loop; |
| 291 |
| 292 While(OsrDeconstructorTester& R, Node* cond, bool is_osr, int backedges = 1) |
| 293 : t(R) { |
| 294 loop = t.NewLoop(is_osr, backedges); |
| 295 branch = t.graph.NewNode(t.common.Branch(), cond, loop); |
| 296 if_true = t.graph.NewNode(t.common.IfTrue(), branch); |
| 297 exit = t.graph.NewNode(t.common.IfFalse(), branch); |
| 298 loop->ReplaceInput(loop->InputCount() - 1, if_true); |
| 299 } |
| 300 |
| 301 void Nest(While& that) { |
| 302 that.loop->ReplaceInput(that.loop->InputCount() - 1, exit); |
| 303 this->loop->ReplaceInput(0, that.if_true); |
| 304 } |
| 305 |
| 306 Node* Phi(Node* i1, Node* i2, Node* i3) { |
| 307 if (loop->InputCount() == 2) { |
| 308 return t.graph.NewNode(t.common.Phi(kMachAnyTagged, 2), i1, i2, loop); |
| 309 } else { |
| 310 return t.graph.NewNode(t.common.Phi(kMachAnyTagged, 3), i1, i2, i3, loop); |
| 311 } |
| 312 } |
| 313 }; |
| 314 |
| 315 |
| 316 static Node* FindSuccessor(Node* node, IrOpcode::Value opcode) { |
| 317 for (Node* use : node->uses()) { |
| 318 if (use->opcode() == opcode) return use; |
| 319 } |
| 320 UNREACHABLE(); // should have been found. |
| 321 return nullptr; |
| 322 } |
| 323 |
| 324 |
| 325 TEST(Deconstruct_osr_nested1) { |
| 326 OsrDeconstructorTester T(1); |
| 327 |
| 328 While outer(T, T.p0, false); |
| 329 While inner(T, T.p0, true); |
| 330 inner.Nest(outer); |
| 331 |
| 332 Node* outer_phi = outer.Phi(T.p0, T.p0, nullptr); |
| 333 outer.branch->ReplaceInput(0, outer_phi); |
| 334 |
| 335 Node* osr_phi = inner.Phi(T.jsgraph.OneConstant(), T.osr_values[0], |
| 336 T.jsgraph.ZeroConstant()); |
| 337 inner.branch->ReplaceInput(0, osr_phi); |
| 338 outer_phi->ReplaceInput(1, osr_phi); |
| 339 |
| 340 Node* ret = |
| 341 T.graph.NewNode(T.common.Return(), outer_phi, T.start, outer.exit); |
| 342 Node* end = T.graph.NewNode(T.common.End(), ret); |
| 343 T.graph.SetEnd(end); |
| 344 |
| 345 OsrHelper helper(0, 0); |
| 346 helper.Deconstruct(&T.jsgraph, &T.common, T.main_zone()); |
| 347 |
| 348 // Check structure of deconstructed graph. |
| 349 // Check inner OSR loop is directly connected to start. |
| 350 CheckInputs(inner.loop, T.start, inner.if_true); |
| 351 CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), inner.loop); |
| 352 |
| 353 // Check control transfer to copy of outer loop. |
| 354 Node* new_outer_loop = FindSuccessor(inner.exit, IrOpcode::kLoop); |
| 355 Node* new_outer_phi = FindSuccessor(new_outer_loop, IrOpcode::kPhi); |
| 356 CHECK_NE(new_outer_loop, outer.loop); |
| 357 CHECK_NE(new_outer_phi, outer_phi); |
| 358 |
| 359 CheckInputs(new_outer_loop, inner.exit, new_outer_loop->InputAt(1)); |
| 360 |
| 361 // Check structure of outer loop. |
| 362 Node* new_outer_branch = FindSuccessor(new_outer_loop, IrOpcode::kBranch); |
| 363 CHECK_NE(new_outer_branch, outer.branch); |
| 364 CheckInputs(new_outer_branch, new_outer_phi, new_outer_loop); |
| 365 Node* new_outer_exit = FindSuccessor(new_outer_branch, IrOpcode::kIfFalse); |
| 366 Node* new_outer_if_true = FindSuccessor(new_outer_branch, IrOpcode::kIfTrue); |
| 367 |
| 368 // Check structure of return. |
| 369 end = T.graph.end(); |
| 370 Node* new_ret = end->InputAt(0); |
| 371 CHECK_EQ(IrOpcode::kReturn, new_ret->opcode()); |
| 372 CheckInputs(new_ret, new_outer_phi, T.start, new_outer_exit); |
| 373 |
| 374 // Check structure of inner loop. |
| 375 Node* new_inner_loop = FindSuccessor(new_outer_if_true, IrOpcode::kLoop); |
| 376 Node* new_inner_phi = FindSuccessor(new_inner_loop, IrOpcode::kPhi); |
| 377 |
| 378 CheckInputs(new_inner_phi, T.jsgraph.OneConstant(), T.jsgraph.ZeroConstant(), |
| 379 new_inner_loop); |
| 380 CheckInputs(new_outer_phi, osr_phi, new_inner_phi, new_outer_loop); |
| 381 } |
| 382 |
| 383 |
| 384 TEST(Deconstruct_osr_nested2) { |
| 385 OsrDeconstructorTester T(1); |
| 386 |
| 387 // Test multiple backedge outer loop. |
| 388 While outer(T, T.p0, false, 2); |
| 389 While inner(T, T.p0, true); |
| 390 inner.Nest(outer); |
| 391 |
| 392 Node* outer_phi = outer.Phi(T.p0, T.p0, T.p0); |
| 393 outer.branch->ReplaceInput(0, outer_phi); |
| 394 |
| 395 Node* osr_phi = inner.Phi(T.jsgraph.OneConstant(), T.osr_values[0], |
| 396 T.jsgraph.ZeroConstant()); |
| 397 inner.branch->ReplaceInput(0, osr_phi); |
| 398 outer_phi->ReplaceInput(1, osr_phi); |
| 399 outer_phi->ReplaceInput(2, T.jsgraph.ZeroConstant()); |
| 400 |
| 401 Node* x_branch = T.graph.NewNode(T.common.Branch(), osr_phi, inner.exit); |
| 402 Node* x_true = T.graph.NewNode(T.common.IfTrue(), x_branch); |
| 403 Node* x_false = T.graph.NewNode(T.common.IfFalse(), x_branch); |
| 404 |
| 405 outer.loop->ReplaceInput(1, x_true); |
| 406 outer.loop->ReplaceInput(2, x_false); |
| 407 |
| 408 Node* ret = |
| 409 T.graph.NewNode(T.common.Return(), outer_phi, T.start, outer.exit); |
| 410 Node* end = T.graph.NewNode(T.common.End(), ret); |
| 411 T.graph.SetEnd(end); |
| 412 |
| 413 OsrHelper helper(0, 0); |
| 414 helper.Deconstruct(&T.jsgraph, &T.common, T.main_zone()); |
| 415 |
| 416 // Check structure of deconstructed graph. |
| 417 // Check inner OSR loop is directly connected to start. |
| 418 CheckInputs(inner.loop, T.start, inner.if_true); |
| 419 CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), inner.loop); |
| 420 |
| 421 // Check control transfer to copy of outer loop. |
| 422 Node* new_merge = FindSuccessor(x_true, IrOpcode::kMerge); |
| 423 CHECK_EQ(new_merge, FindSuccessor(x_false, IrOpcode::kMerge)); |
| 424 CheckInputs(new_merge, x_true, x_false); |
| 425 |
| 426 Node* new_outer_loop = FindSuccessor(new_merge, IrOpcode::kLoop); |
| 427 Node* new_outer_phi = FindSuccessor(new_outer_loop, IrOpcode::kPhi); |
| 428 CHECK_NE(new_outer_loop, outer.loop); |
| 429 CHECK_NE(new_outer_phi, outer_phi); |
| 430 |
| 431 Node* new_entry_phi = FindSuccessor(new_merge, IrOpcode::kPhi); |
| 432 CheckInputs(new_entry_phi, osr_phi, T.jsgraph.ZeroConstant(), new_merge); |
| 433 |
| 434 CHECK_EQ(new_merge, new_outer_loop->InputAt(0)); |
| 435 |
| 436 // Check structure of outer loop. |
| 437 Node* new_outer_branch = FindSuccessor(new_outer_loop, IrOpcode::kBranch); |
| 438 CHECK_NE(new_outer_branch, outer.branch); |
| 439 CheckInputs(new_outer_branch, new_outer_phi, new_outer_loop); |
| 440 Node* new_outer_exit = FindSuccessor(new_outer_branch, IrOpcode::kIfFalse); |
| 441 Node* new_outer_if_true = FindSuccessor(new_outer_branch, IrOpcode::kIfTrue); |
| 442 |
| 443 // Check structure of return. |
| 444 end = T.graph.end(); |
| 445 Node* new_ret = end->InputAt(0); |
| 446 CHECK_EQ(IrOpcode::kReturn, new_ret->opcode()); |
| 447 CheckInputs(new_ret, new_outer_phi, T.start, new_outer_exit); |
| 448 |
| 449 // Check structure of inner loop. |
| 450 Node* new_inner_loop = FindSuccessor(new_outer_if_true, IrOpcode::kLoop); |
| 451 Node* new_inner_phi = FindSuccessor(new_inner_loop, IrOpcode::kPhi); |
| 452 |
| 453 CheckInputs(new_inner_phi, T.jsgraph.OneConstant(), T.jsgraph.ZeroConstant(), |
| 454 new_inner_loop); |
| 455 CheckInputs(new_outer_phi, new_entry_phi, new_inner_phi, |
| 456 T.jsgraph.ZeroConstant(), new_outer_loop); |
| 457 } |
OLD | NEW |