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