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. 4 5 #include "src/v8.h" 6 #include "test/cctest/cctest.h" 7 8 #include "src/compiler/common-operator.h" 9 #include "src/compiler/generic-node-inl.h" 10 #include "src/compiler/generic-node.h" 11 #include "src/compiler/graph.h" 12 #include "src/compiler/graph-visualizer.h" 13 #include "src/compiler/js-operator.h" 14 #include "src/compiler/machine-operator.h" 15 #include "src/compiler/node.h" 16 #include "src/compiler/operator.h" 17 #include "src/compiler/schedule.h" 18 #include "src/compiler/scheduler.h" 19 #include "src/compiler/verifier.h" 20 21 using namespace v8::internal; 22 using namespace v8::internal::compiler; 23 24 // TODO(titzer): pull RPO tests out to their own file. 25 struct TestLoop { 26 int count; 27 BasicBlock** nodes; 28 BasicBlock* header() { return nodes[0]; } 29 BasicBlock* last() { return nodes[count - 1]; } 30 ~TestLoop() { delete[] nodes; } 31 }; 32 33 34 static TestLoop* CreateLoop(Schedule* schedule, int count) { 35 TestLoop* loop = new TestLoop(); 36 loop->count = count; 37 loop->nodes = new BasicBlock* [count]; 38 for (int i = 0; i < count; i++) { 39 loop->nodes[i] = schedule->NewBasicBlock(); 40 if (i > 0) schedule->AddSuccessor(loop->nodes[i - 1], loop->nodes[i]); 41 } 42 schedule->AddSuccessor(loop->nodes[count - 1], loop->nodes[0]); 43 return loop; 44 } 45 46 47 static void CheckRPONumbers(BasicBlockVector* order, int expected, 48 bool loops_allowed) { 49 CHECK_EQ(expected, static_cast<int>(order->size())); 50 for (int i = 0; i < static_cast<int>(order->size()); i++) { 51 CHECK(order->at(i)->rpo_number_ == i); 52 if (!loops_allowed) CHECK_LT(order->at(i)->loop_end_, 0); 53 } 54 } 55 56 57 static void CheckLoopContains(BasicBlock** blocks, int body_size) { 58 BasicBlock* header = blocks[0]; 59 CHECK_GT(header->loop_end_, 0); 60 CHECK_EQ(body_size, (header->loop_end_ - header->rpo_number_)); 61 for (int i = 0; i < body_size; i++) { 62 int num = blocks[i]->rpo_number_; 63 CHECK(num >= header->rpo_number_ && num < header->loop_end_); 64 CHECK(header->LoopContains(blocks[i])); 65 CHECK(header->IsLoopHeader() || blocks[i]->loop_header_ == header); 66 } 67 } 68 69 70 static int GetScheduledNodeCount(Schedule* schedule) { 71 int node_count = 0; 72 for (BasicBlockVectorIter i = schedule->rpo_order()->begin(); 73 i != schedule->rpo_order()->end(); ++i) { 74 BasicBlock* block = *i; 75 for (BasicBlock::const_iterator j = block->begin(); j != block->end(); 76 ++j) { 77 ++node_count; 78 } 79 BasicBlock::Control control = block->control_; 80 if (control != BasicBlock::kNone) { 81 ++node_count; 82 } 83 } 84 return node_count; 85 } 86 87 88 static Schedule* ComputeAndVerifySchedule(int expected, Graph* graph) { 89 if (FLAG_trace_turbo) { 90 OFStream os(stdout); 91 os << AsDOT(*graph); 92 } 93 94 Schedule* schedule = Scheduler::ComputeSchedule(graph); 95 96 if (FLAG_trace_turbo_scheduler) { 97 OFStream os(stdout); 98 os << *schedule << endl; 99 } 100 ScheduleVerifier::Run(schedule); 101 CHECK_EQ(expected, GetScheduledNodeCount(schedule)); 102 return schedule; 103 } 104 105 106 TEST(RPODegenerate1) { 107 HandleAndZoneScope scope; 108 Schedule schedule(scope.main_zone()); 109 110 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 111 CheckRPONumbers(order, 1, false); 112 CHECK_EQ(schedule.start(), order->at(0)); 113 } 114 115 116 TEST(RPODegenerate2) { 117 HandleAndZoneScope scope; 118 Schedule schedule(scope.main_zone()); 119 120 schedule.AddGoto(schedule.start(), schedule.end()); 121 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 122 CheckRPONumbers(order, 2, false); 123 CHECK_EQ(schedule.start(), order->at(0)); 124 CHECK_EQ(schedule.end(), order->at(1)); 125 } 126 127 128 TEST(RPOLine) { 129 HandleAndZoneScope scope; 130 131 for (int i = 0; i < 10; i++) { 132 Schedule schedule(scope.main_zone()); 133 134 BasicBlock* last = schedule.start(); 135 for (int j = 0; j < i; j++) { 136 BasicBlock* block = schedule.NewBasicBlock(); 137 schedule.AddGoto(last, block); 138 last = block; 139 } 140 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 141 CheckRPONumbers(order, 1 + i, false); 142 143 Schedule::BasicBlocks blocks(schedule.all_blocks()); 144 for (Schedule::BasicBlocks::iterator iter = blocks.begin(); 145 iter != blocks.end(); ++iter) { 146 BasicBlock* block = *iter; 147 if (block->rpo_number_ >= 0 && block->SuccessorCount() == 1) { 148 CHECK(block->rpo_number_ + 1 == block->SuccessorAt(0)->rpo_number_); 149 } 150 } 151 } 152 } 153 154 155 TEST(RPOSelfLoop) { 156 HandleAndZoneScope scope; 157 Schedule schedule(scope.main_zone()); 158 schedule.AddSuccessor(schedule.start(), schedule.start()); 159 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 160 CheckRPONumbers(order, 1, true); 161 BasicBlock* loop[] = {schedule.start()}; 162 CheckLoopContains(loop, 1); 163 } 164 165 166 TEST(RPOEntryLoop) { 167 HandleAndZoneScope scope; 168 Schedule schedule(scope.main_zone()); 169 schedule.AddSuccessor(schedule.start(), schedule.end()); 170 schedule.AddSuccessor(schedule.end(), schedule.start()); 171 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 172 CheckRPONumbers(order, 2, true); 173 BasicBlock* loop[] = {schedule.start(), schedule.end()}; 174 CheckLoopContains(loop, 2); 175 } 176 177 178 TEST(RPOEndLoop) { 179 HandleAndZoneScope scope; 180 Schedule schedule(scope.main_zone()); 181 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); 182 schedule.AddSuccessor(schedule.start(), loop1->header()); 183 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 184 CheckRPONumbers(order, 3, true); 185 CheckLoopContains(loop1->nodes, loop1->count); 186 } 187 188 189 TEST(RPOEndLoopNested) { 190 HandleAndZoneScope scope; 191 Schedule schedule(scope.main_zone()); 192 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); 193 schedule.AddSuccessor(schedule.start(), loop1->header()); 194 schedule.AddSuccessor(loop1->last(), schedule.start()); 195 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 196 CheckRPONumbers(order, 3, true); 197 CheckLoopContains(loop1->nodes, loop1->count); 198 } 199 200 201 TEST(RPODiamond) { 202 HandleAndZoneScope scope; 203 Schedule schedule(scope.main_zone()); 204 205 BasicBlock* A = schedule.start(); 206 BasicBlock* B = schedule.NewBasicBlock(); 207 BasicBlock* C = schedule.NewBasicBlock(); 208 BasicBlock* D = schedule.end(); 209 210 schedule.AddSuccessor(A, B); 211 schedule.AddSuccessor(A, C); 212 schedule.AddSuccessor(B, D); 213 schedule.AddSuccessor(C, D); 214 215 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 216 CheckRPONumbers(order, 4, false); 217 218 CHECK_EQ(0, A->rpo_number_); 219 CHECK((B->rpo_number_ == 1 && C->rpo_number_ == 2) || 220 (B->rpo_number_ == 2 && C->rpo_number_ == 1)); 221 CHECK_EQ(3, D->rpo_number_); 222 } 223 224 225 TEST(RPOLoop1) { 226 HandleAndZoneScope scope; 227 Schedule schedule(scope.main_zone()); 228 229 BasicBlock* A = schedule.start(); 230 BasicBlock* B = schedule.NewBasicBlock(); 231 BasicBlock* C = schedule.NewBasicBlock(); 232 BasicBlock* D = schedule.end(); 233 234 schedule.AddSuccessor(A, B); 235 schedule.AddSuccessor(B, C); 236 schedule.AddSuccessor(C, B); 237 schedule.AddSuccessor(C, D); 238 239 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 240 CheckRPONumbers(order, 4, true); 241 BasicBlock* loop[] = {B, C}; 242 CheckLoopContains(loop, 2); 243 } 244 245 246 TEST(RPOLoop2) { 247 HandleAndZoneScope scope; 248 Schedule schedule(scope.main_zone()); 249 250 BasicBlock* A = schedule.start(); 251 BasicBlock* B = schedule.NewBasicBlock(); 252 BasicBlock* C = schedule.NewBasicBlock(); 253 BasicBlock* D = schedule.end(); 254 255 schedule.AddSuccessor(A, B); 256 schedule.AddSuccessor(B, C); 257 schedule.AddSuccessor(C, B); 258 schedule.AddSuccessor(B, D); 259 260 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 261 CheckRPONumbers(order, 4, true); 262 BasicBlock* loop[] = {B, C}; 263 CheckLoopContains(loop, 2); 264 } 265 266 267 TEST(RPOLoopN) { 268 HandleAndZoneScope scope; 269 270 for (int i = 0; i < 11; i++) { 271 Schedule schedule(scope.main_zone()); 272 BasicBlock* A = schedule.start(); 273 BasicBlock* B = schedule.NewBasicBlock(); 274 BasicBlock* C = schedule.NewBasicBlock(); 275 BasicBlock* D = schedule.NewBasicBlock(); 276 BasicBlock* E = schedule.NewBasicBlock(); 277 BasicBlock* F = schedule.NewBasicBlock(); 278 BasicBlock* G = schedule.end(); 279 280 schedule.AddSuccessor(A, B); 281 schedule.AddSuccessor(B, C); 282 schedule.AddSuccessor(C, D); 283 schedule.AddSuccessor(D, E); 284 schedule.AddSuccessor(E, F); 285 schedule.AddSuccessor(F, B); 286 schedule.AddSuccessor(B, G); 287 288 // Throw in extra backedges from time to time. 289 if (i == 1) schedule.AddSuccessor(B, B); 290 if (i == 2) schedule.AddSuccessor(C, B); 291 if (i == 3) schedule.AddSuccessor(D, B); 292 if (i == 4) schedule.AddSuccessor(E, B); 293 if (i == 5) schedule.AddSuccessor(F, B); 294 295 // Throw in extra loop exits from time to time. 296 if (i == 6) schedule.AddSuccessor(B, G); 297 if (i == 7) schedule.AddSuccessor(C, G); 298 if (i == 8) schedule.AddSuccessor(D, G); 299 if (i == 9) schedule.AddSuccessor(E, G); 300 if (i == 10) schedule.AddSuccessor(F, G); 301 302 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 303 CheckRPONumbers(order, 7, true); 304 BasicBlock* loop[] = {B, C, D, E, F}; 305 CheckLoopContains(loop, 5); 306 } 307 } 308 309 310 TEST(RPOLoopNest1) { 311 HandleAndZoneScope scope; 312 Schedule schedule(scope.main_zone()); 313 314 BasicBlock* A = schedule.start(); 315 BasicBlock* B = schedule.NewBasicBlock(); 316 BasicBlock* C = schedule.NewBasicBlock(); 317 BasicBlock* D = schedule.NewBasicBlock(); 318 BasicBlock* E = schedule.NewBasicBlock(); 319 BasicBlock* F = schedule.end(); 320 321 schedule.AddSuccessor(A, B); 322 schedule.AddSuccessor(B, C); 323 schedule.AddSuccessor(C, D); 324 schedule.AddSuccessor(D, C); 325 schedule.AddSuccessor(D, E); 326 schedule.AddSuccessor(E, B); 327 schedule.AddSuccessor(E, F); 328 329 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 330 CheckRPONumbers(order, 6, true); 331 BasicBlock* loop1[] = {B, C, D, E}; 332 CheckLoopContains(loop1, 4); 333 334 BasicBlock* loop2[] = {C, D}; 335 CheckLoopContains(loop2, 2); 336 } 337 338 339 TEST(RPOLoopNest2) { 340 HandleAndZoneScope scope; 341 Schedule schedule(scope.main_zone()); 342 343 BasicBlock* A = schedule.start(); 344 BasicBlock* B = schedule.NewBasicBlock(); 345 BasicBlock* C = schedule.NewBasicBlock(); 346 BasicBlock* D = schedule.NewBasicBlock(); 347 BasicBlock* E = schedule.NewBasicBlock(); 348 BasicBlock* F = schedule.NewBasicBlock(); 349 BasicBlock* G = schedule.NewBasicBlock(); 350 BasicBlock* H = schedule.end(); 351 352 schedule.AddSuccessor(A, B); 353 schedule.AddSuccessor(B, C); 354 schedule.AddSuccessor(C, D); 355 schedule.AddSuccessor(D, E); 356 schedule.AddSuccessor(E, F); 357 schedule.AddSuccessor(F, G); 358 schedule.AddSuccessor(G, H); 359 360 schedule.AddSuccessor(E, D); 361 schedule.AddSuccessor(F, C); 362 schedule.AddSuccessor(G, B); 363 364 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 365 CheckRPONumbers(order, 8, true); 366 BasicBlock* loop1[] = {B, C, D, E, F, G}; 367 CheckLoopContains(loop1, 6); 368 369 BasicBlock* loop2[] = {C, D, E, F}; 370 CheckLoopContains(loop2, 4); 371 372 BasicBlock* loop3[] = {D, E}; 373 CheckLoopContains(loop3, 2); 374 } 375 376 377 TEST(RPOLoopFollow1) { 378 HandleAndZoneScope scope; 379 Schedule schedule(scope.main_zone()); 380 381 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); 382 SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); 383 384 BasicBlock* A = schedule.start(); 385 BasicBlock* E = schedule.end(); 386 387 schedule.AddSuccessor(A, loop1->header()); 388 schedule.AddSuccessor(loop1->header(), loop2->header()); 389 schedule.AddSuccessor(loop2->last(), E); 390 391 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 392 393 CheckLoopContains(loop1->nodes, loop1->count); 394 395 CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); 396 CheckLoopContains(loop1->nodes, loop1->count); 397 CheckLoopContains(loop2->nodes, loop2->count); 398 } 399 400 401 TEST(RPOLoopFollow2) { 402 HandleAndZoneScope scope; 403 Schedule schedule(scope.main_zone()); 404 405 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); 406 SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); 407 408 BasicBlock* A = schedule.start(); 409 BasicBlock* S = schedule.NewBasicBlock(); 410 BasicBlock* E = schedule.end(); 411 412 schedule.AddSuccessor(A, loop1->header()); 413 schedule.AddSuccessor(loop1->header(), S); 414 schedule.AddSuccessor(S, loop2->header()); 415 schedule.AddSuccessor(loop2->last(), E); 416 417 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 418 419 CheckLoopContains(loop1->nodes, loop1->count); 420 421 CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); 422 CheckLoopContains(loop1->nodes, loop1->count); 423 CheckLoopContains(loop2->nodes, loop2->count); 424 } 425 426 427 TEST(RPOLoopFollowN) { 428 HandleAndZoneScope scope; 429 430 for (int size = 1; size < 5; size++) { 431 for (int exit = 0; exit < size; exit++) { 432 Schedule schedule(scope.main_zone()); 433 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); 434 SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); 435 BasicBlock* A = schedule.start(); 436 BasicBlock* E = schedule.end(); 437 438 schedule.AddSuccessor(A, loop1->header()); 439 schedule.AddSuccessor(loop1->nodes[exit], loop2->header()); 440 schedule.AddSuccessor(loop2->nodes[exit], E); 441 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 442 CheckLoopContains(loop1->nodes, loop1->count); 443 444 CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); 445 CheckLoopContains(loop1->nodes, loop1->count); 446 CheckLoopContains(loop2->nodes, loop2->count); 447 } 448 } 449 } 450 451 452 TEST(RPONestedLoopFollow1) { 453 HandleAndZoneScope scope; 454 Schedule schedule(scope.main_zone()); 455 456 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); 457 SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); 458 459 BasicBlock* A = schedule.start(); 460 BasicBlock* B = schedule.NewBasicBlock(); 461 BasicBlock* C = schedule.NewBasicBlock(); 462 BasicBlock* E = schedule.end(); 463 464 schedule.AddSuccessor(A, B); 465 schedule.AddSuccessor(B, loop1->header()); 466 schedule.AddSuccessor(loop1->header(), loop2->header()); 467 schedule.AddSuccessor(loop2->last(), C); 468 schedule.AddSuccessor(C, E); 469 schedule.AddSuccessor(C, B); 470 471 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 472 473 CheckLoopContains(loop1->nodes, loop1->count); 474 475 CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); 476 CheckLoopContains(loop1->nodes, loop1->count); 477 CheckLoopContains(loop2->nodes, loop2->count); 478 479 BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C}; 480 CheckLoopContains(loop3, 4); 481 } 482 483 484 TEST(RPOLoopBackedges1) { 485 HandleAndZoneScope scope; 486 487 int size = 8; 488 for (int i = 0; i < size; i++) { 489 for (int j = 0; j < size; j++) { 490 Schedule schedule(scope.main_zone()); 491 BasicBlock* A = schedule.start(); 492 BasicBlock* E = schedule.end(); 493 494 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); 495 schedule.AddSuccessor(A, loop1->header()); 496 schedule.AddSuccessor(loop1->last(), E); 497 498 schedule.AddSuccessor(loop1->nodes[i], loop1->header()); 499 schedule.AddSuccessor(loop1->nodes[j], E); 500 501 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 502 CheckRPONumbers(order, schedule.BasicBlockCount(), true); 503 CheckLoopContains(loop1->nodes, loop1->count); 504 } 505 } 506 } 507 508 509 TEST(RPOLoopOutedges1) { 510 HandleAndZoneScope scope; 511 512 int size = 8; 513 for (int i = 0; i < size; i++) { 514 for (int j = 0; j < size; j++) { 515 Schedule schedule(scope.main_zone()); 516 BasicBlock* A = schedule.start(); 517 BasicBlock* D = schedule.NewBasicBlock(); 518 BasicBlock* E = schedule.end(); 519 520 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); 521 schedule.AddSuccessor(A, loop1->header()); 522 schedule.AddSuccessor(loop1->last(), E); 523 524 schedule.AddSuccessor(loop1->nodes[i], loop1->header()); 525 schedule.AddSuccessor(loop1->nodes[j], D); 526 schedule.AddSuccessor(D, E); 527 528 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 529 CheckRPONumbers(order, schedule.BasicBlockCount(), true); 530 CheckLoopContains(loop1->nodes, loop1->count); 531 } 532 } 533 } 534 535 536 TEST(RPOLoopOutedges2) { 537 HandleAndZoneScope scope; 538 539 int size = 8; 540 for (int i = 0; i < size; i++) { 541 Schedule schedule(scope.main_zone()); 542 BasicBlock* A = schedule.start(); 543 BasicBlock* E = schedule.end(); 544 545 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); 546 schedule.AddSuccessor(A, loop1->header()); 547 schedule.AddSuccessor(loop1->last(), E); 548 549 for (int j = 0; j < size; j++) { 550 BasicBlock* O = schedule.NewBasicBlock(); 551 schedule.AddSuccessor(loop1->nodes[j], O); 552 schedule.AddSuccessor(O, E); 553 } 554 555 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 556 CheckRPONumbers(order, schedule.BasicBlockCount(), true); 557 CheckLoopContains(loop1->nodes, loop1->count); 558 } 559 } 560 561 562 TEST(RPOLoopOutloops1) { 563 HandleAndZoneScope scope; 564 565 int size = 8; 566 for (int i = 0; i < size; i++) { 567 Schedule schedule(scope.main_zone()); 568 BasicBlock* A = schedule.start(); 569 BasicBlock* E = schedule.end(); 570 SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); 571 schedule.AddSuccessor(A, loop1->header()); 572 schedule.AddSuccessor(loop1->last(), E); 573 574 TestLoop** loopN = new TestLoop* [size]; 575 for (int j = 0; j < size; j++) { 576 loopN[j] = CreateLoop(&schedule, 2); 577 schedule.AddSuccessor(loop1->nodes[j], loopN[j]->header()); 578 schedule.AddSuccessor(loopN[j]->last(), E); 579 } 580 581 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 582 CheckRPONumbers(order, schedule.BasicBlockCount(), true); 583 CheckLoopContains(loop1->nodes, loop1->count); 584 585 for (int j = 0; j < size; j++) { 586 CheckLoopContains(loopN[j]->nodes, loopN[j]->count); 587 delete loopN[j]; 588 } 589 delete[] loopN; 590 } 591 } 592 593 594 TEST(RPOLoopMultibackedge) { 595 HandleAndZoneScope scope; 596 Schedule schedule(scope.main_zone()); 597 598 BasicBlock* A = schedule.start(); 599 BasicBlock* B = schedule.NewBasicBlock(); 600 BasicBlock* C = schedule.NewBasicBlock(); 601 BasicBlock* D = schedule.end(); 602 BasicBlock* E = schedule.NewBasicBlock(); 603 604 schedule.AddSuccessor(A, B); 605 schedule.AddSuccessor(B, C); 606 schedule.AddSuccessor(B, D); 607 schedule.AddSuccessor(B, E); 608 schedule.AddSuccessor(C, B); 609 schedule.AddSuccessor(D, B); 610 schedule.AddSuccessor(E, B); 611 612 BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); 613 CheckRPONumbers(order, 5, true); 614 615 BasicBlock* loop1[] = {B, C, D, E}; 616 CheckLoopContains(loop1, 4); 617 } 618 619 620 TEST(BuildScheduleEmpty) { 621 HandleAndZoneScope scope; 622 Graph graph(scope.main_zone()); 623 CommonOperatorBuilder builder(scope.main_zone()); 624 graph.SetStart(graph.NewNode(builder.Start(0))); 625 graph.SetEnd(graph.NewNode(builder.End(), graph.start())); 626 627 USE(Scheduler::ComputeSchedule(&graph)); 628 } 629 630 631 TEST(BuildScheduleOneParameter) { 632 HandleAndZoneScope scope; 633 Graph graph(scope.main_zone()); 634 CommonOperatorBuilder builder(scope.main_zone()); 635 graph.SetStart(graph.NewNode(builder.Start(0))); 636 637 Node* p1 = graph.NewNode(builder.Parameter(0), graph.start()); 638 Node* ret = graph.NewNode(builder.Return(), p1, graph.start(), graph.start()); 639 640 graph.SetEnd(graph.NewNode(builder.End(), ret)); 641 642 USE(Scheduler::ComputeSchedule(&graph)); 643 } 644 645 646 TEST(BuildScheduleIfSplit) { 647 HandleAndZoneScope scope; 648 Graph graph(scope.main_zone()); 649 CommonOperatorBuilder builder(scope.main_zone()); 650 JSOperatorBuilder js_builder(scope.main_zone()); 651 graph.SetStart(graph.NewNode(builder.Start(3))); 652 653 Node* p1 = graph.NewNode(builder.Parameter(0), graph.start()); 654 Node* p2 = graph.NewNode(builder.Parameter(1), graph.start()); 655 Node* p3 = graph.NewNode(builder.Parameter(2), graph.start()); 656 Node* p4 = graph.NewNode(builder.Parameter(3), graph.start()); 657 Node* p5 = graph.NewNode(builder.Parameter(4), graph.start()); 658 Node* cmp = graph.NewNode(js_builder.LessThanOrEqual(), p1, p2, p3, 659 graph.start(), graph.start()); 660 Node* branch = graph.NewNode(builder.Branch(), cmp, graph.start()); 661 Node* true_branch = graph.NewNode(builder.IfTrue(), branch); 662 Node* false_branch = graph.NewNode(builder.IfFalse(), branch); 663 664 Node* ret1 = graph.NewNode(builder.Return(), p4, graph.start(), true_branch); 665 Node* ret2 = graph.NewNode(builder.Return(), p5, graph.start(), false_branch); 666 Node* merge = graph.NewNode(builder.Merge(2), ret1, ret2); 667 graph.SetEnd(graph.NewNode(builder.End(), merge)); 668 669 ComputeAndVerifySchedule(13, &graph); 670 } 671 672 673 TEST(BuildScheduleIfSplitWithEffects) { 674 HandleAndZoneScope scope; 675 Isolate* isolate = scope.main_isolate(); 676 Graph graph(scope.main_zone()); 677 CommonOperatorBuilder common_builder(scope.main_zone()); 678 JSOperatorBuilder js_builder(scope.main_zone()); 679 const Operator* op; 680 681 Handle<Object> object = 682 Handle<Object>(isolate->heap()->undefined_value(), isolate); 683 Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); 684 685 // Manually transcripted code for: 686 // function turbo_fan_test(a, b, c, y) { 687 // if (a < b) { 688 // return a + b - c * c - a + y; 689 // } else { 690 // return c * c - a; 691 // } 692 // } 693 op = common_builder.Start(0); 694 Node* n0 = graph.NewNode(op); 695 USE(n0); 696 Node* nil = graph.NewNode(common_builder.Dead()); 697 op = common_builder.End(); 698 Node* n23 = graph.NewNode(op, nil); 699 USE(n23); 700 op = common_builder.Merge(2); 701 Node* n22 = graph.NewNode(op, nil, nil); 702 USE(n22); 703 op = common_builder.Return(); 704 Node* n16 = graph.NewNode(op, nil, nil, nil); 705 USE(n16); 706 op = js_builder.Add(); 707 Node* n15 = graph.NewNode(op, nil, nil, nil, nil, nil); 708 USE(n15); 709 op = js_builder.Subtract(); 710 Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); 711 USE(n14); 712 op = js_builder.Subtract(); 713 Node* n13 = graph.NewNode(op, nil, nil, nil, nil, nil); 714 USE(n13); 715 op = js_builder.Add(); 716 Node* n11 = graph.NewNode(op, nil, nil, nil, nil, nil); 717 USE(n11); 718 op = common_builder.Parameter(0); 719 Node* n2 = graph.NewNode(op, n0); 720 USE(n2); 721 n11->ReplaceInput(0, n2); 722 op = common_builder.Parameter(0); 723 Node* n3 = graph.NewNode(op, n0); 724 USE(n3); 725 n11->ReplaceInput(1, n3); 726 op = common_builder.HeapConstant(unique_constant); 727 Node* n7 = graph.NewNode(op); 728 USE(n7); 729 n11->ReplaceInput(2, n7); 730 op = js_builder.LessThan(); 731 Node* n8 = graph.NewNode(op, nil, nil, nil, nil, nil); 732 USE(n8); 733 n8->ReplaceInput(0, n2); 734 n8->ReplaceInput(1, n3); 735 n8->ReplaceInput(2, n7); 736 n8->ReplaceInput(3, n0); 737 n8->ReplaceInput(4, n0); 738 n11->ReplaceInput(3, n8); 739 op = common_builder.IfTrue(); 740 Node* n10 = graph.NewNode(op, nil); 741 USE(n10); 742 op = common_builder.Branch(); 743 Node* n9 = graph.NewNode(op, nil, nil); 744 USE(n9); 745 n9->ReplaceInput(0, n8); 746 n9->ReplaceInput(1, n0); 747 n10->ReplaceInput(0, n9); 748 n11->ReplaceInput(4, n10); 749 n13->ReplaceInput(0, n11); 750 op = js_builder.Multiply(); 751 Node* n12 = graph.NewNode(op, nil, nil, nil, nil, nil); 752 USE(n12); 753 op = common_builder.Parameter(0); 754 Node* n4 = graph.NewNode(op, n0); 755 USE(n4); 756 n12->ReplaceInput(0, n4); 757 n12->ReplaceInput(1, n4); 758 n12->ReplaceInput(2, n7); 759 n12->ReplaceInput(3, n11); 760 n12->ReplaceInput(4, n10); 761 n13->ReplaceInput(1, n12); 762 n13->ReplaceInput(2, n7); 763 n13->ReplaceInput(3, n12); 764 n13->ReplaceInput(4, n10); 765 n14->ReplaceInput(0, n13); 766 n14->ReplaceInput(1, n2); 767 n14->ReplaceInput(2, n7); 768 n14->ReplaceInput(3, n13); 769 n14->ReplaceInput(4, n10); 770 n15->ReplaceInput(0, n14); 771 op = common_builder.Parameter(0); 772 Node* n5 = graph.NewNode(op, n0); 773 USE(n5); 774 n15->ReplaceInput(1, n5); 775 n15->ReplaceInput(2, n7); 776 n15->ReplaceInput(3, n14); 777 n15->ReplaceInput(4, n10); 778 n16->ReplaceInput(0, n15); 779 n16->ReplaceInput(1, n15); 780 n16->ReplaceInput(2, n10); 781 n22->ReplaceInput(0, n16); 782 op = common_builder.Return(); 783 Node* n21 = graph.NewNode(op, nil, nil, nil); 784 USE(n21); 785 op = js_builder.Subtract(); 786 Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); 787 USE(n20); 788 op = js_builder.Multiply(); 789 Node* n19 = graph.NewNode(op, nil, nil, nil, nil, nil); 790 USE(n19); 791 n19->ReplaceInput(0, n4); 792 n19->ReplaceInput(1, n4); 793 n19->ReplaceInput(2, n7); 794 n19->ReplaceInput(3, n8); 795 op = common_builder.IfFalse(); 796 Node* n18 = graph.NewNode(op, nil); 797 USE(n18); 798 n18->ReplaceInput(0, n9); 799 n19->ReplaceInput(4, n18); 800 n20->ReplaceInput(0, n19); 801 n20->ReplaceInput(1, n2); 802 n20->ReplaceInput(2, n7); 803 n20->ReplaceInput(3, n19); 804 n20->ReplaceInput(4, n18); 805 n21->ReplaceInput(0, n20); 806 n21->ReplaceInput(1, n20); 807 n21->ReplaceInput(2, n18); 808 n22->ReplaceInput(1, n21); 809 n23->ReplaceInput(0, n22); 810 811 graph.SetStart(n0); 812 graph.SetEnd(n23); 813 814 ComputeAndVerifySchedule(20, &graph); 815 } 816 817 818 TEST(BuildScheduleSimpleLoop) { 819 HandleAndZoneScope scope; 820 Isolate* isolate = scope.main_isolate(); 821 Graph graph(scope.main_zone()); 822 CommonOperatorBuilder common_builder(scope.main_zone()); 823 JSOperatorBuilder js_builder(scope.main_zone()); 824 const Operator* op; 825 826 Handle<Object> object = 827 Handle<Object>(isolate->heap()->undefined_value(), isolate); 828 Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); 829 830 // Manually transcripted code for: 831 // function turbo_fan_test(a, b) { 832 // while (a < b) { 833 // a++; 834 // } 835 // return a; 836 // } 837 op = common_builder.Start(0); 838 Node* n0 = graph.NewNode(op); 839 USE(n0); 840 Node* nil = graph.NewNode(common_builder.Dead()); 841 op = common_builder.End(); 842 Node* n20 = graph.NewNode(op, nil); 843 USE(n20); 844 op = common_builder.Return(); 845 Node* n19 = graph.NewNode(op, nil, nil, nil); 846 USE(n19); 847 op = common_builder.Phi(kMachAnyTagged, 2); 848 Node* n8 = graph.NewNode(op, nil, nil, nil); 849 USE(n8); 850 op = common_builder.Parameter(0); 851 Node* n2 = graph.NewNode(op, n0); 852 USE(n2); 853 n8->ReplaceInput(0, n2); 854 op = js_builder.Add(); 855 Node* n18 = graph.NewNode(op, nil, nil, nil, nil, nil); 856 USE(n18); 857 op = js_builder.ToNumber(); 858 Node* n16 = graph.NewNode(op, nil, nil, nil, nil); 859 USE(n16); 860 n16->ReplaceInput(0, n8); 861 op = common_builder.HeapConstant(unique_constant); 862 Node* n5 = graph.NewNode(op); 863 USE(n5); 864 n16->ReplaceInput(1, n5); 865 op = js_builder.LessThan(); 866 Node* n12 = graph.NewNode(op, nil, nil, nil, nil, nil); 867 USE(n12); 868 n12->ReplaceInput(0, n8); 869 op = common_builder.Phi(kMachAnyTagged, 2); 870 Node* n9 = graph.NewNode(op, nil, nil, nil); 871 USE(n9); 872 op = common_builder.Parameter(0); 873 Node* n3 = graph.NewNode(op, n0); 874 USE(n3); 875 n9->ReplaceInput(0, n3); 876 n9->ReplaceInput(1, n9); 877 op = common_builder.Loop(2); 878 Node* n6 = graph.NewNode(op, nil, nil); 879 USE(n6); 880 n6->ReplaceInput(0, n0); 881 op = common_builder.IfTrue(); 882 Node* n14 = graph.NewNode(op, nil); 883 USE(n14); 884 op = common_builder.Branch(); 885 Node* n13 = graph.NewNode(op, nil, nil); 886 USE(n13); 887 n13->ReplaceInput(0, n12); 888 n13->ReplaceInput(1, n6); 889 n14->ReplaceInput(0, n13); 890 n6->ReplaceInput(1, n14); 891 n9->ReplaceInput(2, n6); 892 n12->ReplaceInput(1, n9); 893 n12->ReplaceInput(2, n5); 894 op = common_builder.Phi(kMachAnyTagged, 2); 895 Node* n10 = graph.NewNode(op, nil, nil, nil); 896 USE(n10); 897 n10->ReplaceInput(0, n0); 898 n10->ReplaceInput(1, n18); 899 n10->ReplaceInput(2, n6); 900 n12->ReplaceInput(3, n10); 901 n12->ReplaceInput(4, n6); 902 n16->ReplaceInput(2, n12); 903 n16->ReplaceInput(3, n14); 904 n18->ReplaceInput(0, n16); 905 op = common_builder.NumberConstant(0); 906 Node* n17 = graph.NewNode(op); 907 USE(n17); 908 n18->ReplaceInput(1, n17); 909 n18->ReplaceInput(2, n5); 910 n18->ReplaceInput(3, n16); 911 n18->ReplaceInput(4, n14); 912 n8->ReplaceInput(1, n18); 913 n8->ReplaceInput(2, n6); 914 n19->ReplaceInput(0, n8); 915 n19->ReplaceInput(1, n12); 916 op = common_builder.IfFalse(); 917 Node* n15 = graph.NewNode(op, nil); 918 USE(n15); 919 n15->ReplaceInput(0, n13); 920 n19->ReplaceInput(2, n15); 921 n20->ReplaceInput(0, n19); 922 923 graph.SetStart(n0); 924 graph.SetEnd(n20); 925 926 ComputeAndVerifySchedule(19, &graph); 927 } 928 929 930 TEST(BuildScheduleComplexLoops) { 931 HandleAndZoneScope scope; 932 Isolate* isolate = scope.main_isolate(); 933 Graph graph(scope.main_zone()); 934 CommonOperatorBuilder common_builder(scope.main_zone()); 935 JSOperatorBuilder js_builder(scope.main_zone()); 936 const Operator* op; 937 938 Handle<Object> object = 939 Handle<Object>(isolate->heap()->undefined_value(), isolate); 940 Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); 941 942 // Manually transcripted code for: 943 // function turbo_fan_test(a, b, c) { 944 // while (a < b) { 945 // a++; 946 // while (c < b) { 947 // c++; 948 // } 949 // } 950 // while (a < b) { 951 // a += 2; 952 // } 953 // return a; 954 // } 955 op = common_builder.Start(0); 956 Node* n0 = graph.NewNode(op); 957 USE(n0); 958 Node* nil = graph.NewNode(common_builder.Dead()); 959 op = common_builder.End(); 960 Node* n46 = graph.NewNode(op, nil); 961 USE(n46); 962 op = common_builder.Return(); 963 Node* n45 = graph.NewNode(op, nil, nil, nil); 964 USE(n45); 965 op = common_builder.Phi(kMachAnyTagged, 2); 966 Node* n35 = graph.NewNode(op, nil, nil, nil); 967 USE(n35); 968 op = common_builder.Phi(kMachAnyTagged, 2); 969 Node* n9 = graph.NewNode(op, nil, nil, nil); 970 USE(n9); 971 op = common_builder.Parameter(0); 972 Node* n2 = graph.NewNode(op, n0); 973 USE(n2); 974 n9->ReplaceInput(0, n2); 975 op = common_builder.Phi(kMachAnyTagged, 2); 976 Node* n23 = graph.NewNode(op, nil, nil, nil); 977 USE(n23); 978 op = js_builder.Add(); 979 Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); 980 USE(n20); 981 op = js_builder.ToNumber(); 982 Node* n18 = graph.NewNode(op, nil, nil, nil, nil); 983 USE(n18); 984 n18->ReplaceInput(0, n9); 985 op = common_builder.HeapConstant(unique_constant); 986 Node* n6 = graph.NewNode(op); 987 USE(n6); 988 n18->ReplaceInput(1, n6); 989 op = js_builder.LessThan(); 990 Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); 991 USE(n14); 992 n14->ReplaceInput(0, n9); 993 op = common_builder.Phi(kMachAnyTagged, 2); 994 Node* n10 = graph.NewNode(op, nil, nil, nil); 995 USE(n10); 996 op = common_builder.Parameter(0); 997 Node* n3 = graph.NewNode(op, n0); 998 USE(n3); 999 n10->ReplaceInput(0, n3); 1000 op = common_builder.Phi(kMachAnyTagged, 2); 1001 Node* n24 = graph.NewNode(op, nil, nil, nil); 1002 USE(n24); 1003 n24->ReplaceInput(0, n10); 1004 n24->ReplaceInput(1, n24); 1005 op = common_builder.Loop(2); 1006 Node* n21 = graph.NewNode(op, nil, nil); 1007 USE(n21); 1008 op = common_builder.IfTrue(); 1009 Node* n16 = graph.NewNode(op, nil); 1010 USE(n16); 1011 op = common_builder.Branch(); 1012 Node* n15 = graph.NewNode(op, nil, nil); 1013 USE(n15); 1014 n15->ReplaceInput(0, n14); 1015 op = common_builder.Loop(2); 1016 Node* n7 = graph.NewNode(op, nil, nil); 1017 USE(n7); 1018 n7->ReplaceInput(0, n0); 1019 op = common_builder.IfFalse(); 1020 Node* n30 = graph.NewNode(op, nil); 1021 USE(n30); 1022 op = common_builder.Branch(); 1023 Node* n28 = graph.NewNode(op, nil, nil); 1024 USE(n28); 1025 op = js_builder.LessThan(); 1026 Node* n27 = graph.NewNode(op, nil, nil, nil, nil, nil); 1027 USE(n27); 1028 op = common_builder.Phi(kMachAnyTagged, 2); 1029 Node* n25 = graph.NewNode(op, nil, nil, nil); 1030 USE(n25); 1031 op = common_builder.Phi(kMachAnyTagged, 2); 1032 Node* n11 = graph.NewNode(op, nil, nil, nil); 1033 USE(n11); 1034 op = common_builder.Parameter(0); 1035 Node* n4 = graph.NewNode(op, n0); 1036 USE(n4); 1037 n11->ReplaceInput(0, n4); 1038 n11->ReplaceInput(1, n25); 1039 n11->ReplaceInput(2, n7); 1040 n25->ReplaceInput(0, n11); 1041 op = js_builder.Add(); 1042 Node* n32 = graph.NewNode(op, nil, nil, nil, nil, nil); 1043 USE(n32); 1044 op = js_builder.ToNumber(); 1045 Node* n31 = graph.NewNode(op, nil, nil, nil, nil); 1046 USE(n31); 1047 n31->ReplaceInput(0, n25); 1048 n31->ReplaceInput(1, n6); 1049 n31->ReplaceInput(2, n27); 1050 op = common_builder.IfTrue(); 1051 Node* n29 = graph.NewNode(op, nil); 1052 USE(n29); 1053 n29->ReplaceInput(0, n28); 1054 n31->ReplaceInput(3, n29); 1055 n32->ReplaceInput(0, n31); 1056 op = common_builder.NumberConstant(0); 1057 Node* n19 = graph.NewNode(op); 1058 USE(n19); 1059 n32->ReplaceInput(1, n19); 1060 n32->ReplaceInput(2, n6); 1061 n32->ReplaceInput(3, n31); 1062 n32->ReplaceInput(4, n29); 1063 n25->ReplaceInput(1, n32); 1064 n25->ReplaceInput(2, n21); 1065 n27->ReplaceInput(0, n25); 1066 n27->ReplaceInput(1, n24); 1067 n27->ReplaceInput(2, n6); 1068 op = common_builder.Phi(kMachAnyTagged, 2); 1069 Node* n26 = graph.NewNode(op, nil, nil, nil); 1070 USE(n26); 1071 n26->ReplaceInput(0, n20); 1072 n26->ReplaceInput(1, n32); 1073 n26->ReplaceInput(2, n21); 1074 n27->ReplaceInput(3, n26); 1075 n27->ReplaceInput(4, n21); 1076 n28->ReplaceInput(0, n27); 1077 n28->ReplaceInput(1, n21); 1078 n30->ReplaceInput(0, n28); 1079 n7->ReplaceInput(1, n30); 1080 n15->ReplaceInput(1, n7); 1081 n16->ReplaceInput(0, n15); 1082 n21->ReplaceInput(0, n16); 1083 n21->ReplaceInput(1, n29); 1084 n24->ReplaceInput(2, n21); 1085 n10->ReplaceInput(1, n24); 1086 n10->ReplaceInput(2, n7); 1087 n14->ReplaceInput(1, n10); 1088 n14->ReplaceInput(2, n6); 1089 op = common_builder.Phi(kMachAnyTagged, 2); 1090 Node* n12 = graph.NewNode(op, nil, nil, nil); 1091 USE(n12); 1092 n12->ReplaceInput(0, n0); 1093 n12->ReplaceInput(1, n27); 1094 n12->ReplaceInput(2, n7); 1095 n14->ReplaceInput(3, n12); 1096 n14->ReplaceInput(4, n7); 1097 n18->ReplaceInput(2, n14); 1098 n18->ReplaceInput(3, n16); 1099 n20->ReplaceInput(0, n18); 1100 n20->ReplaceInput(1, n19); 1101 n20->ReplaceInput(2, n6); 1102 n20->ReplaceInput(3, n18); 1103 n20->ReplaceInput(4, n16); 1104 n23->ReplaceInput(0, n20); 1105 n23->ReplaceInput(1, n23); 1106 n23->ReplaceInput(2, n21); 1107 n9->ReplaceInput(1, n23); 1108 n9->ReplaceInput(2, n7); 1109 n35->ReplaceInput(0, n9); 1110 op = js_builder.Add(); 1111 Node* n44 = graph.NewNode(op, nil, nil, nil, nil, nil); 1112 USE(n44); 1113 n44->ReplaceInput(0, n35); 1114 op = common_builder.NumberConstant(0); 1115 Node* n43 = graph.NewNode(op); 1116 USE(n43); 1117 n44->ReplaceInput(1, n43); 1118 n44->ReplaceInput(2, n6); 1119 op = js_builder.LessThan(); 1120 Node* n39 = graph.NewNode(op, nil, nil, nil, nil, nil); 1121 USE(n39); 1122 n39->ReplaceInput(0, n35); 1123 op = common_builder.Phi(kMachAnyTagged, 2); 1124 Node* n36 = graph.NewNode(op, nil, nil, nil); 1125 USE(n36); 1126 n36->ReplaceInput(0, n10); 1127 n36->ReplaceInput(1, n36); 1128 op = common_builder.Loop(2); 1129 Node* n33 = graph.NewNode(op, nil, nil); 1130 USE(n33); 1131 op = common_builder.IfFalse(); 1132 Node* n17 = graph.NewNode(op, nil); 1133 USE(n17); 1134 n17->ReplaceInput(0, n15); 1135 n33->ReplaceInput(0, n17); 1136 op = common_builder.IfTrue(); 1137 Node* n41 = graph.NewNode(op, nil); 1138 USE(n41); 1139 op = common_builder.Branch(); 1140 Node* n40 = graph.NewNode(op, nil, nil); 1141 USE(n40); 1142 n40->ReplaceInput(0, n39); 1143 n40->ReplaceInput(1, n33); 1144 n41->ReplaceInput(0, n40); 1145 n33->ReplaceInput(1, n41); 1146 n36->ReplaceInput(2, n33); 1147 n39->ReplaceInput(1, n36); 1148 n39->ReplaceInput(2, n6); 1149 op = common_builder.Phi(kMachAnyTagged, 2); 1150 Node* n38 = graph.NewNode(op, nil, nil, nil); 1151 USE(n38); 1152 n38->ReplaceInput(0, n14); 1153 n38->ReplaceInput(1, n44); 1154 n38->ReplaceInput(2, n33); 1155 n39->ReplaceInput(3, n38); 1156 n39->ReplaceInput(4, n33); 1157 n44->ReplaceInput(3, n39); 1158 n44->ReplaceInput(4, n41); 1159 n35->ReplaceInput(1, n44); 1160 n35->ReplaceInput(2, n33); 1161 n45->ReplaceInput(0, n35); 1162 n45->ReplaceInput(1, n39); 1163 op = common_builder.IfFalse(); 1164 Node* n42 = graph.NewNode(op, nil); 1165 USE(n42); 1166 n42->ReplaceInput(0, n40); 1167 n45->ReplaceInput(2, n42); 1168 n46->ReplaceInput(0, n45); 1169 1170 graph.SetStart(n0); 1171 graph.SetEnd(n46); 1172 1173 ComputeAndVerifySchedule(46, &graph); 1174 } 1175 1176 1177 TEST(BuildScheduleBreakAndContinue) { 1178 HandleAndZoneScope scope; 1179 Isolate* isolate = scope.main_isolate(); 1180 Graph graph(scope.main_zone()); 1181 CommonOperatorBuilder common_builder(scope.main_zone()); 1182 JSOperatorBuilder js_builder(scope.main_zone()); 1183 const Operator* op; 1184 1185 Handle<Object> object = 1186 Handle<Object>(isolate->heap()->undefined_value(), isolate); 1187 Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); 1188 1189 // Manually transcripted code for: 1190 // function turbo_fan_test(a, b, c) { 1191 // var d = 0; 1192 // while (a < b) { 1193 // a++; 1194 // while (c < b) { 1195 // c++; 1196 // if (d == 0) break; 1197 // a++; 1198 // } 1199 // if (a == 1) continue; 1200 // d++; 1201 // } 1202 // return a + d; 1203 // } 1204 op = common_builder.Start(0); 1205 Node* n0 = graph.NewNode(op); 1206 USE(n0); 1207 Node* nil = graph.NewNode(common_builder.Dead()); 1208 op = common_builder.End(); 1209 Node* n58 = graph.NewNode(op, nil); 1210 USE(n58); 1211 op = common_builder.Return(); 1212 Node* n57 = graph.NewNode(op, nil, nil, nil); 1213 USE(n57); 1214 op = js_builder.Add(); 1215 Node* n56 = graph.NewNode(op, nil, nil, nil, nil, nil); 1216 USE(n56); 1217 op = common_builder.Phi(kMachAnyTagged, 2); 1218 Node* n10 = graph.NewNode(op, nil, nil, nil); 1219 USE(n10); 1220 op = common_builder.Parameter(0); 1221 Node* n2 = graph.NewNode(op, n0); 1222 USE(n2); 1223 n10->ReplaceInput(0, n2); 1224 op = common_builder.Phi(kMachAnyTagged, 2); 1225 Node* n25 = graph.NewNode(op, nil, nil, nil); 1226 USE(n25); 1227 op = js_builder.Add(); 1228 Node* n22 = graph.NewNode(op, nil, nil, nil, nil, nil); 1229 USE(n22); 1230 op = js_builder.ToNumber(); 1231 Node* n20 = graph.NewNode(op, nil, nil, nil, nil); 1232 USE(n20); 1233 n20->ReplaceInput(0, n10); 1234 op = common_builder.HeapConstant(unique_constant); 1235 Node* n6 = graph.NewNode(op); 1236 USE(n6); 1237 n20->ReplaceInput(1, n6); 1238 op = js_builder.LessThan(); 1239 Node* n16 = graph.NewNode(op, nil, nil, nil, nil, nil); 1240 USE(n16); 1241 n16->ReplaceInput(0, n10); 1242 op = common_builder.Phi(kMachAnyTagged, 2); 1243 Node* n11 = graph.NewNode(op, nil, nil, nil); 1244 USE(n11); 1245 op = common_builder.Parameter(0); 1246 Node* n3 = graph.NewNode(op, n0); 1247 USE(n3); 1248 n11->ReplaceInput(0, n3); 1249 op = common_builder.Phi(kMachAnyTagged, 2); 1250 Node* n26 = graph.NewNode(op, nil, nil, nil); 1251 USE(n26); 1252 n26->ReplaceInput(0, n11); 1253 n26->ReplaceInput(1, n26); 1254 op = common_builder.Loop(2); 1255 Node* n23 = graph.NewNode(op, nil, nil); 1256 USE(n23); 1257 op = common_builder.IfTrue(); 1258 Node* n18 = graph.NewNode(op, nil); 1259 USE(n18); 1260 op = common_builder.Branch(); 1261 Node* n17 = graph.NewNode(op, nil, nil); 1262 USE(n17); 1263 n17->ReplaceInput(0, n16); 1264 op = common_builder.Loop(2); 1265 Node* n8 = graph.NewNode(op, nil, nil); 1266 USE(n8); 1267 n8->ReplaceInput(0, n0); 1268 op = common_builder.Merge(2); 1269 Node* n53 = graph.NewNode(op, nil, nil); 1270 USE(n53); 1271 op = common_builder.IfTrue(); 1272 Node* n49 = graph.NewNode(op, nil); 1273 USE(n49); 1274 op = common_builder.Branch(); 1275 Node* n48 = graph.NewNode(op, nil, nil); 1276 USE(n48); 1277 op = js_builder.Equal(); 1278 Node* n47 = graph.NewNode(op, nil, nil, nil, nil, nil); 1279 USE(n47); 1280 n47->ReplaceInput(0, n25); 1281 op = common_builder.NumberConstant(0); 1282 Node* n46 = graph.NewNode(op); 1283 USE(n46); 1284 n47->ReplaceInput(1, n46); 1285 n47->ReplaceInput(2, n6); 1286 op = common_builder.Phi(kMachAnyTagged, 2); 1287 Node* n42 = graph.NewNode(op, nil, nil, nil); 1288 USE(n42); 1289 op = js_builder.LessThan(); 1290 Node* n30 = graph.NewNode(op, nil, nil, nil, nil, nil); 1291 USE(n30); 1292 op = common_builder.Phi(kMachAnyTagged, 2); 1293 Node* n27 = graph.NewNode(op, nil, nil, nil); 1294 USE(n27); 1295 op = common_builder.Phi(kMachAnyTagged, 2); 1296 Node* n12 = graph.NewNode(op, nil, nil, nil); 1297 USE(n12); 1298 op = common_builder.Parameter(0); 1299 Node* n4 = graph.NewNode(op, n0); 1300 USE(n4); 1301 n12->ReplaceInput(0, n4); 1302 op = common_builder.Phi(kMachAnyTagged, 2); 1303 Node* n41 = graph.NewNode(op, nil, nil, nil); 1304 USE(n41); 1305 n41->ReplaceInput(0, n27); 1306 op = js_builder.Add(); 1307 Node* n35 = graph.NewNode(op, nil, nil, nil, nil, nil); 1308 USE(n35); 1309 op = js_builder.ToNumber(); 1310 Node* n34 = graph.NewNode(op, nil, nil, nil, nil); 1311 USE(n34); 1312 n34->ReplaceInput(0, n27); 1313 n34->ReplaceInput(1, n6); 1314 n34->ReplaceInput(2, n30); 1315 op = common_builder.IfTrue(); 1316 Node* n32 = graph.NewNode(op, nil); 1317 USE(n32); 1318 op = common_builder.Branch(); 1319 Node* n31 = graph.NewNode(op, nil, nil); 1320 USE(n31); 1321 n31->ReplaceInput(0, n30); 1322 n31->ReplaceInput(1, n23); 1323 n32->ReplaceInput(0, n31); 1324 n34->ReplaceInput(3, n32); 1325 n35->ReplaceInput(0, n34); 1326 op = common_builder.NumberConstant(0); 1327 Node* n21 = graph.NewNode(op); 1328 USE(n21); 1329 n35->ReplaceInput(1, n21); 1330 n35->ReplaceInput(2, n6); 1331 n35->ReplaceInput(3, n34); 1332 n35->ReplaceInput(4, n32); 1333 n41->ReplaceInput(1, n35); 1334 op = common_builder.Merge(2); 1335 Node* n40 = graph.NewNode(op, nil, nil); 1336 USE(n40); 1337 op = common_builder.IfFalse(); 1338 Node* n33 = graph.NewNode(op, nil); 1339 USE(n33); 1340 n33->ReplaceInput(0, n31); 1341 n40->ReplaceInput(0, n33); 1342 op = common_builder.IfTrue(); 1343 Node* n39 = graph.NewNode(op, nil); 1344 USE(n39); 1345 op = common_builder.Branch(); 1346 Node* n38 = graph.NewNode(op, nil, nil); 1347 USE(n38); 1348 op = js_builder.Equal(); 1349 Node* n37 = graph.NewNode(op, nil, nil, nil, nil, nil); 1350 USE(n37); 1351 op = common_builder.Phi(kMachAnyTagged, 2); 1352 Node* n28 = graph.NewNode(op, nil, nil, nil); 1353 USE(n28); 1354 op = common_builder.Phi(kMachAnyTagged, 2); 1355 Node* n13 = graph.NewNode(op, nil, nil, nil); 1356 USE(n13); 1357 op = common_builder.NumberConstant(0); 1358 Node* n7 = graph.NewNode(op); 1359 USE(n7); 1360 n13->ReplaceInput(0, n7); 1361 op = common_builder.Phi(kMachAnyTagged, 2); 1362 Node* n54 = graph.NewNode(op, nil, nil, nil); 1363 USE(n54); 1364 n54->ReplaceInput(0, n28); 1365 op = js_builder.Add(); 1366 Node* n52 = graph.NewNode(op, nil, nil, nil, nil, nil); 1367 USE(n52); 1368 op = js_builder.ToNumber(); 1369 Node* n51 = graph.NewNode(op, nil, nil, nil, nil); 1370 USE(n51); 1371 n51->ReplaceInput(0, n28); 1372 n51->ReplaceInput(1, n6); 1373 n51->ReplaceInput(2, n47); 1374 op = common_builder.IfFalse(); 1375 Node* n50 = graph.NewNode(op, nil); 1376 USE(n50); 1377 n50->ReplaceInput(0, n48); 1378 n51->ReplaceInput(3, n50); 1379 n52->ReplaceInput(0, n51); 1380 n52->ReplaceInput(1, n21); 1381 n52->ReplaceInput(2, n6); 1382 n52->ReplaceInput(3, n51); 1383 n52->ReplaceInput(4, n50); 1384 n54->ReplaceInput(1, n52); 1385 n54->ReplaceInput(2, n53); 1386 n13->ReplaceInput(1, n54); 1387 n13->ReplaceInput(2, n8); 1388 n28->ReplaceInput(0, n13); 1389 n28->ReplaceInput(1, n28); 1390 n28->ReplaceInput(2, n23); 1391 n37->ReplaceInput(0, n28); 1392 op = common_builder.NumberConstant(0); 1393 Node* n36 = graph.NewNode(op); 1394 USE(n36); 1395 n37->ReplaceInput(1, n36); 1396 n37->ReplaceInput(2, n6); 1397 n37->ReplaceInput(3, n35); 1398 n37->ReplaceInput(4, n32); 1399 n38->ReplaceInput(0, n37); 1400 n38->ReplaceInput(1, n32); 1401 n39->ReplaceInput(0, n38); 1402 n40->ReplaceInput(1, n39); 1403 n41->ReplaceInput(2, n40); 1404 n12->ReplaceInput(1, n41); 1405 n12->ReplaceInput(2, n8); 1406 n27->ReplaceInput(0, n12); 1407 n27->ReplaceInput(1, n35); 1408 n27->ReplaceInput(2, n23); 1409 n30->ReplaceInput(0, n27); 1410 n30->ReplaceInput(1, n26); 1411 n30->ReplaceInput(2, n6); 1412 op = common_builder.Phi(kMachAnyTagged, 2); 1413 Node* n29 = graph.NewNode(op, nil, nil, nil); 1414 USE(n29); 1415 n29->ReplaceInput(0, n22); 1416 op = js_builder.Add(); 1417 Node* n45 = graph.NewNode(op, nil, nil, nil, nil, nil); 1418 USE(n45); 1419 op = js_builder.ToNumber(); 1420 Node* n44 = graph.NewNode(op, nil, nil, nil, nil); 1421 USE(n44); 1422 n44->ReplaceInput(0, n25); 1423 n44->ReplaceInput(1, n6); 1424 n44->ReplaceInput(2, n37); 1425 op = common_builder.IfFalse(); 1426 Node* n43 = graph.NewNode(op, nil); 1427 USE(n43); 1428 n43->ReplaceInput(0, n38); 1429 n44->ReplaceInput(3, n43); 1430 n45->ReplaceInput(0, n44); 1431 n45->ReplaceInput(1, n21); 1432 n45->ReplaceInput(2, n6); 1433 n45->ReplaceInput(3, n44); 1434 n45->ReplaceInput(4, n43); 1435 n29->ReplaceInput(1, n45); 1436 n29->ReplaceInput(2, n23); 1437 n30->ReplaceInput(3, n29); 1438 n30->ReplaceInput(4, n23); 1439 n42->ReplaceInput(0, n30); 1440 n42->ReplaceInput(1, n37); 1441 n42->ReplaceInput(2, n40); 1442 n47->ReplaceInput(3, n42); 1443 n47->ReplaceInput(4, n40); 1444 n48->ReplaceInput(0, n47); 1445 n48->ReplaceInput(1, n40); 1446 n49->ReplaceInput(0, n48); 1447 n53->ReplaceInput(0, n49); 1448 n53->ReplaceInput(1, n50); 1449 n8->ReplaceInput(1, n53); 1450 n17->ReplaceInput(1, n8); 1451 n18->ReplaceInput(0, n17); 1452 n23->ReplaceInput(0, n18); 1453 n23->ReplaceInput(1, n43); 1454 n26->ReplaceInput(2, n23); 1455 n11->ReplaceInput(1, n26); 1456 n11->ReplaceInput(2, n8); 1457 n16->ReplaceInput(1, n11); 1458 n16->ReplaceInput(2, n6); 1459 op = common_builder.Phi(kMachAnyTagged, 2); 1460 Node* n14 = graph.NewNode(op, nil, nil, nil); 1461 USE(n14); 1462 n14->ReplaceInput(0, n0); 1463 op = common_builder.Phi(kMachAnyTagged, 2); 1464 Node* n55 = graph.NewNode(op, nil, nil, nil); 1465 USE(n55); 1466 n55->ReplaceInput(0, n47); 1467 n55->ReplaceInput(1, n52); 1468 n55->ReplaceInput(2, n53); 1469 n14->ReplaceInput(1, n55); 1470 n14->ReplaceInput(2, n8); 1471 n16->ReplaceInput(3, n14); 1472 n16->ReplaceInput(4, n8); 1473 n20->ReplaceInput(2, n16); 1474 n20->ReplaceInput(3, n18); 1475 n22->ReplaceInput(0, n20); 1476 n22->ReplaceInput(1, n21); 1477 n22->ReplaceInput(2, n6); 1478 n22->ReplaceInput(3, n20); 1479 n22->ReplaceInput(4, n18); 1480 n25->ReplaceInput(0, n22); 1481 n25->ReplaceInput(1, n45); 1482 n25->ReplaceInput(2, n23); 1483 n10->ReplaceInput(1, n25); 1484 n10->ReplaceInput(2, n8); 1485 n56->ReplaceInput(0, n10); 1486 n56->ReplaceInput(1, n13); 1487 n56->ReplaceInput(2, n6); 1488 n56->ReplaceInput(3, n16); 1489 op = common_builder.IfFalse(); 1490 Node* n19 = graph.NewNode(op, nil); 1491 USE(n19); 1492 n19->ReplaceInput(0, n17); 1493 n56->ReplaceInput(4, n19); 1494 n57->ReplaceInput(0, n56); 1495 n57->ReplaceInput(1, n56); 1496 n57->ReplaceInput(2, n19); 1497 n58->ReplaceInput(0, n57); 1498 1499 graph.SetStart(n0); 1500 graph.SetEnd(n58); 1501 1502 ComputeAndVerifySchedule(62, &graph); 1503 } 1504 1505 1506 TEST(BuildScheduleSimpleLoopWithCodeMotion) { 1507 HandleAndZoneScope scope; 1508 Isolate* isolate = scope.main_isolate(); 1509 Graph graph(scope.main_zone()); 1510 CommonOperatorBuilder common_builder(scope.main_zone()); 1511 JSOperatorBuilder js_builder(scope.main_zone()); 1512 MachineOperatorBuilder machine_builder; 1513 const Operator* op; 1514 1515 Handle<Object> object = 1516 Handle<Object>(isolate->heap()->undefined_value(), isolate); 1517 Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); 1518 1519 // Manually transcripted code for: 1520 // function turbo_fan_test(a, b, c) { 1521 // while (a < b) { 1522 // a += b + c; 1523 // } 1524 // return a; 1525 // } 1526 op = common_builder.Start(0); 1527 Node* n0 = graph.NewNode(op); 1528 USE(n0); 1529 Node* nil = graph.NewNode(common_builder.Dead()); 1530 op = common_builder.End(); 1531 Node* n22 = graph.NewNode(op, nil); 1532 USE(n22); 1533 op = common_builder.Return(); 1534 Node* n21 = graph.NewNode(op, nil, nil, nil); 1535 USE(n21); 1536 op = common_builder.Phi(kMachAnyTagged, 2); 1537 Node* n9 = graph.NewNode(op, nil, nil, nil); 1538 USE(n9); 1539 op = common_builder.Parameter(0); 1540 Node* n2 = graph.NewNode(op, n0); 1541 USE(n2); 1542 n9->ReplaceInput(0, n2); 1543 op = js_builder.Add(); 1544 Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); 1545 USE(n20); 1546 n20->ReplaceInput(0, n9); 1547 op = machine_builder.Int32Add(); 1548 Node* n19 = graph.NewNode(op, nil, nil); 1549 USE(n19); 1550 op = common_builder.Phi(kMachAnyTagged, 2); 1551 Node* n10 = graph.NewNode(op, nil, nil, nil); 1552 USE(n10); 1553 op = common_builder.Parameter(0); 1554 Node* n3 = graph.NewNode(op, n0); 1555 USE(n3); 1556 n10->ReplaceInput(0, n3); 1557 n10->ReplaceInput(1, n10); 1558 op = common_builder.Loop(2); 1559 Node* n7 = graph.NewNode(op, nil, nil); 1560 USE(n7); 1561 n7->ReplaceInput(0, n0); 1562 op = common_builder.IfTrue(); 1563 Node* n17 = graph.NewNode(op, nil); 1564 USE(n17); 1565 op = common_builder.Branch(); 1566 Node* n16 = graph.NewNode(op, nil, nil); 1567 USE(n16); 1568 op = js_builder.ToBoolean(); 1569 Node* n15 = graph.NewNode(op, nil, nil, nil, nil); 1570 USE(n15); 1571 op = js_builder.LessThan(); 1572 Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); 1573 USE(n14); 1574 n14->ReplaceInput(0, n9); 1575 n14->ReplaceInput(1, n10); 1576 op = common_builder.HeapConstant(unique_constant); 1577 Node* n6 = graph.NewNode(op); 1578 USE(n6); 1579 n14->ReplaceInput(2, n6); 1580 op = common_builder.Phi(kMachAnyTagged, 2); 1581 Node* n12 = graph.NewNode(op, nil, nil, nil); 1582 USE(n12); 1583 n12->ReplaceInput(0, n0); 1584 n12->ReplaceInput(1, n20); 1585 n12->ReplaceInput(2, n7); 1586 n14->ReplaceInput(3, n12); 1587 n14->ReplaceInput(4, n7); 1588 n15->ReplaceInput(0, n14); 1589 n15->ReplaceInput(1, n6); 1590 n15->ReplaceInput(2, n14); 1591 n15->ReplaceInput(3, n7); 1592 n16->ReplaceInput(0, n15); 1593 n16->ReplaceInput(1, n7); 1594 n17->ReplaceInput(0, n16); 1595 n7->ReplaceInput(1, n17); 1596 n10->ReplaceInput(2, n7); 1597 n19->ReplaceInput(0, n2); 1598 op = common_builder.Phi(kMachAnyTagged, 2); 1599 Node* n11 = graph.NewNode(op, nil, nil, nil); 1600 USE(n11); 1601 op = common_builder.Parameter(0); 1602 Node* n4 = graph.NewNode(op, n0); 1603 USE(n4); 1604 n11->ReplaceInput(0, n4); 1605 n11->ReplaceInput(1, n11); 1606 n11->ReplaceInput(2, n7); 1607 n19->ReplaceInput(1, n3); 1608 n20->ReplaceInput(1, n19); 1609 n20->ReplaceInput(2, n6); 1610 n20->ReplaceInput(3, n19); 1611 n20->ReplaceInput(4, n17); 1612 n9->ReplaceInput(1, n20); 1613 n9->ReplaceInput(2, n7); 1614 n21->ReplaceInput(0, n9); 1615 n21->ReplaceInput(1, n15); 1616 op = common_builder.IfFalse(); 1617 Node* n18 = graph.NewNode(op, nil); 1618 USE(n18); 1619 n18->ReplaceInput(0, n16); 1620 n21->ReplaceInput(2, n18); 1621 n22->ReplaceInput(0, n21); 1622 1623 graph.SetStart(n0); 1624 graph.SetEnd(n22); 1625 1626 Schedule* schedule = ComputeAndVerifySchedule(19, &graph); 1627 // Make sure the integer-only add gets hoisted to a different block that the 1628 // JSAdd. 1629 CHECK(schedule->block(n19) != schedule->block(n20)); 1630 } 1631 1632 1633 #if V8_TURBOFAN_TARGET 1634 1635 static Node* CreateDiamond(Graph* graph, CommonOperatorBuilder* common, 1636 Node* cond) { 1637 Node* tv = graph->NewNode(common->Int32Constant(6)); 1638 Node* fv = graph->NewNode(common->Int32Constant(7)); 1639 Node* br = graph->NewNode(common->Branch(), cond, graph->start()); 1640 Node* t = graph->NewNode(common->IfTrue(), br); 1641 Node* f = graph->NewNode(common->IfFalse(), br); 1642 Node* m = graph->NewNode(common->Merge(2), t, f); 1643 Node* phi = graph->NewNode(common->Phi(kMachAnyTagged, 2), tv, fv, m); 1644 return phi; 1645 } 1646 1647 1648 TEST(FloatingDiamond1) { 1649 HandleAndZoneScope scope; 1650 Graph graph(scope.main_zone()); 1651 CommonOperatorBuilder common(scope.main_zone()); 1652 1653 Node* start = graph.NewNode(common.Start(1)); 1654 graph.SetStart(start); 1655 1656 Node* p0 = graph.NewNode(common.Parameter(0), start); 1657 Node* d1 = CreateDiamond(&graph, &common, p0); 1658 Node* ret = graph.NewNode(common.Return(), d1, start, start); 1659 Node* end = graph.NewNode(common.End(), ret, start); 1660 1661 graph.SetEnd(end); 1662 1663 ComputeAndVerifySchedule(13, &graph); 1664 } 1665 1666 1667 TEST(FloatingDiamond2) { 1668 HandleAndZoneScope scope; 1669 Graph graph(scope.main_zone()); 1670 CommonOperatorBuilder common(scope.main_zone()); 1671 MachineOperatorBuilder machine; 1672 1673 Node* start = graph.NewNode(common.Start(2)); 1674 graph.SetStart(start); 1675 1676 Node* p0 = graph.NewNode(common.Parameter(0), start); 1677 Node* p1 = graph.NewNode(common.Parameter(1), start); 1678 Node* d1 = CreateDiamond(&graph, &common, p0); 1679 Node* d2 = CreateDiamond(&graph, &common, p1); 1680 Node* add = graph.NewNode(machine.Int32Add(), d1, d2); 1681 Node* ret = graph.NewNode(common.Return(), add, start, start); 1682 Node* end = graph.NewNode(common.End(), ret, start); 1683 1684 graph.SetEnd(end); 1685 1686 ComputeAndVerifySchedule(24, &graph); 1687 } 1688 1689 1690 TEST(FloatingDiamond3) { 1691 HandleAndZoneScope scope; 1692 Graph graph(scope.main_zone()); 1693 CommonOperatorBuilder common(scope.main_zone()); 1694 MachineOperatorBuilder machine; 1695 1696 Node* start = graph.NewNode(common.Start(2)); 1697 graph.SetStart(start); 1698 1699 Node* p0 = graph.NewNode(common.Parameter(0), start); 1700 Node* p1 = graph.NewNode(common.Parameter(1), start); 1701 Node* d1 = CreateDiamond(&graph, &common, p0); 1702 Node* d2 = CreateDiamond(&graph, &common, p1); 1703 Node* add = graph.NewNode(machine.Int32Add(), d1, d2); 1704 Node* d3 = CreateDiamond(&graph, &common, add); 1705 Node* ret = graph.NewNode(common.Return(), d3, start, start); 1706 Node* end = graph.NewNode(common.End(), ret, start); 1707 1708 graph.SetEnd(end); 1709 1710 ComputeAndVerifySchedule(33, &graph); 1711 } 1712 1713 #endif 1714