Home | History | Annotate | Download | only in compiler
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/schedule.h"
      6 #include "src/compiler/scheduler.h"
      7 #include "test/unittests/compiler/compiler-test-utils.h"
      8 #include "test/unittests/test-utils.h"
      9 #include "testing/gmock/include/gmock/gmock.h"
     10 
     11 using testing::AnyOf;
     12 
     13 namespace v8 {
     14 namespace internal {
     15 namespace compiler {
     16 
     17 class SchedulerRPOTest : public TestWithZone {
     18  public:
     19   SchedulerRPOTest() {}
     20 
     21   void CheckRPONumbers(BasicBlockVector* order, size_t expected,
     22                        bool loops_allowed) {
     23     CHECK(expected == order->size());
     24     for (int i = 0; i < static_cast<int>(order->size()); i++) {
     25       CHECK(order->at(i)->rpo_number() == i);
     26       if (!loops_allowed) {
     27         CHECK(!order->at(i)->loop_end());
     28         CHECK(!order->at(i)->loop_header());
     29       }
     30     }
     31   }
     32 
     33   void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) {
     34     BasicBlock* header = blocks[0];
     35     BasicBlock* end = header->loop_end();
     36     CHECK(end);
     37     CHECK_GT(end->rpo_number(), 0);
     38     CHECK_EQ(body_size, end->rpo_number() - header->rpo_number());
     39     for (int i = 0; i < body_size; i++) {
     40       CHECK_GE(blocks[i]->rpo_number(), header->rpo_number());
     41       CHECK_LT(blocks[i]->rpo_number(), end->rpo_number());
     42       CHECK(header->LoopContains(blocks[i]));
     43       CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header);
     44     }
     45     if (header->rpo_number() > 0) {
     46       CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header);
     47     }
     48     if (end->rpo_number() < static_cast<int>(order->size())) {
     49       CHECK_NE(order->at(end->rpo_number())->loop_header(), header);
     50     }
     51   }
     52 
     53   struct TestLoop {
     54     int count;
     55     BasicBlock** nodes;
     56     BasicBlock* header() { return nodes[0]; }
     57     BasicBlock* last() { return nodes[count - 1]; }
     58     ~TestLoop() { delete[] nodes; }
     59   };
     60 
     61   TestLoop* CreateLoop(Schedule* schedule, int count) {
     62     TestLoop* loop = new TestLoop();
     63     loop->count = count;
     64     loop->nodes = new BasicBlock*[count];
     65     for (int i = 0; i < count; i++) {
     66       loop->nodes[i] = schedule->NewBasicBlock();
     67       if (i > 0) {
     68         schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]);
     69       }
     70     }
     71     schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]);
     72     return loop;
     73   }
     74 };
     75 
     76 TEST_F(SchedulerRPOTest, Degenerate1) {
     77   Schedule schedule(zone());
     78   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
     79   CheckRPONumbers(order, 1, false);
     80   EXPECT_EQ(schedule.start(), order->at(0));
     81 }
     82 
     83 TEST_F(SchedulerRPOTest, Degenerate2) {
     84   Schedule schedule(zone());
     85 
     86   schedule.AddGoto(schedule.start(), schedule.end());
     87   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
     88   CheckRPONumbers(order, 2, false);
     89   EXPECT_EQ(schedule.start(), order->at(0));
     90   EXPECT_EQ(schedule.end(), order->at(1));
     91 }
     92 
     93 TEST_F(SchedulerRPOTest, Line) {
     94   for (int i = 0; i < 10; i++) {
     95     Schedule schedule(zone());
     96 
     97     BasicBlock* last = schedule.start();
     98     for (int j = 0; j < i; j++) {
     99       BasicBlock* block = schedule.NewBasicBlock();
    100       block->set_deferred(i & 1);
    101       schedule.AddGoto(last, block);
    102       last = block;
    103     }
    104     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    105     CheckRPONumbers(order, 1 + i, false);
    106 
    107     for (size_t i = 0; i < schedule.BasicBlockCount(); i++) {
    108       BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i));
    109       if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) {
    110         EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number());
    111       }
    112     }
    113   }
    114 }
    115 
    116 TEST_F(SchedulerRPOTest, SelfLoop) {
    117   Schedule schedule(zone());
    118   schedule.AddSuccessorForTesting(schedule.start(), schedule.start());
    119   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    120   CheckRPONumbers(order, 1, true);
    121   BasicBlock* loop[] = {schedule.start()};
    122   CheckLoop(order, loop, 1);
    123 }
    124 
    125 TEST_F(SchedulerRPOTest, EntryLoop) {
    126   Schedule schedule(zone());
    127   BasicBlock* body = schedule.NewBasicBlock();
    128   schedule.AddSuccessorForTesting(schedule.start(), body);
    129   schedule.AddSuccessorForTesting(body, schedule.start());
    130   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    131   CheckRPONumbers(order, 2, true);
    132   BasicBlock* loop[] = {schedule.start(), body};
    133   CheckLoop(order, loop, 2);
    134 }
    135 
    136 TEST_F(SchedulerRPOTest, EndLoop) {
    137   Schedule schedule(zone());
    138   base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
    139   schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
    140   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    141   CheckRPONumbers(order, 3, true);
    142   CheckLoop(order, loop1->nodes, loop1->count);
    143 }
    144 
    145 TEST_F(SchedulerRPOTest, EndLoopNested) {
    146   Schedule schedule(zone());
    147   base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
    148   schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
    149   schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
    150   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    151   CheckRPONumbers(order, 3, true);
    152   CheckLoop(order, loop1->nodes, loop1->count);
    153 }
    154 
    155 TEST_F(SchedulerRPOTest, Diamond) {
    156   Schedule schedule(zone());
    157 
    158   BasicBlock* A = schedule.start();
    159   BasicBlock* B = schedule.NewBasicBlock();
    160   BasicBlock* C = schedule.NewBasicBlock();
    161   BasicBlock* D = schedule.end();
    162 
    163   schedule.AddSuccessorForTesting(A, B);
    164   schedule.AddSuccessorForTesting(A, C);
    165   schedule.AddSuccessorForTesting(B, D);
    166   schedule.AddSuccessorForTesting(C, D);
    167 
    168   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    169   CheckRPONumbers(order, 4, false);
    170 
    171   EXPECT_EQ(0, A->rpo_number());
    172   EXPECT_THAT(B->rpo_number(), AnyOf(1, 2));
    173   EXPECT_THAT(C->rpo_number(), AnyOf(1, 2));
    174   EXPECT_EQ(3, D->rpo_number());
    175 }
    176 
    177 TEST_F(SchedulerRPOTest, Loop1) {
    178   Schedule schedule(zone());
    179 
    180   BasicBlock* A = schedule.start();
    181   BasicBlock* B = schedule.NewBasicBlock();
    182   BasicBlock* C = schedule.NewBasicBlock();
    183   BasicBlock* D = schedule.end();
    184 
    185   schedule.AddSuccessorForTesting(A, B);
    186   schedule.AddSuccessorForTesting(B, C);
    187   schedule.AddSuccessorForTesting(C, B);
    188   schedule.AddSuccessorForTesting(C, D);
    189 
    190   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    191   CheckRPONumbers(order, 4, true);
    192   BasicBlock* loop[] = {B, C};
    193   CheckLoop(order, loop, 2);
    194 }
    195 
    196 TEST_F(SchedulerRPOTest, Loop2) {
    197   Schedule schedule(zone());
    198 
    199   BasicBlock* A = schedule.start();
    200   BasicBlock* B = schedule.NewBasicBlock();
    201   BasicBlock* C = schedule.NewBasicBlock();
    202   BasicBlock* D = schedule.end();
    203 
    204   schedule.AddSuccessorForTesting(A, B);
    205   schedule.AddSuccessorForTesting(B, C);
    206   schedule.AddSuccessorForTesting(C, B);
    207   schedule.AddSuccessorForTesting(B, D);
    208 
    209   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    210   CheckRPONumbers(order, 4, true);
    211   BasicBlock* loop[] = {B, C};
    212   CheckLoop(order, loop, 2);
    213 }
    214 
    215 TEST_F(SchedulerRPOTest, LoopN) {
    216   for (int i = 0; i < 11; i++) {
    217     Schedule schedule(zone());
    218     BasicBlock* A = schedule.start();
    219     BasicBlock* B = schedule.NewBasicBlock();
    220     BasicBlock* C = schedule.NewBasicBlock();
    221     BasicBlock* D = schedule.NewBasicBlock();
    222     BasicBlock* E = schedule.NewBasicBlock();
    223     BasicBlock* F = schedule.NewBasicBlock();
    224     BasicBlock* G = schedule.end();
    225 
    226     schedule.AddSuccessorForTesting(A, B);
    227     schedule.AddSuccessorForTesting(B, C);
    228     schedule.AddSuccessorForTesting(C, D);
    229     schedule.AddSuccessorForTesting(D, E);
    230     schedule.AddSuccessorForTesting(E, F);
    231     schedule.AddSuccessorForTesting(F, B);
    232     schedule.AddSuccessorForTesting(B, G);
    233 
    234     // Throw in extra backedges from time to time.
    235     if (i == 1) schedule.AddSuccessorForTesting(B, B);
    236     if (i == 2) schedule.AddSuccessorForTesting(C, B);
    237     if (i == 3) schedule.AddSuccessorForTesting(D, B);
    238     if (i == 4) schedule.AddSuccessorForTesting(E, B);
    239     if (i == 5) schedule.AddSuccessorForTesting(F, B);
    240 
    241     // Throw in extra loop exits from time to time.
    242     if (i == 6) schedule.AddSuccessorForTesting(B, G);
    243     if (i == 7) schedule.AddSuccessorForTesting(C, G);
    244     if (i == 8) schedule.AddSuccessorForTesting(D, G);
    245     if (i == 9) schedule.AddSuccessorForTesting(E, G);
    246     if (i == 10) schedule.AddSuccessorForTesting(F, G);
    247 
    248     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    249     CheckRPONumbers(order, 7, true);
    250     BasicBlock* loop[] = {B, C, D, E, F};
    251     CheckLoop(order, loop, 5);
    252   }
    253 }
    254 
    255 TEST_F(SchedulerRPOTest, LoopNest1) {
    256   Schedule schedule(zone());
    257 
    258   BasicBlock* A = schedule.start();
    259   BasicBlock* B = schedule.NewBasicBlock();
    260   BasicBlock* C = schedule.NewBasicBlock();
    261   BasicBlock* D = schedule.NewBasicBlock();
    262   BasicBlock* E = schedule.NewBasicBlock();
    263   BasicBlock* F = schedule.end();
    264 
    265   schedule.AddSuccessorForTesting(A, B);
    266   schedule.AddSuccessorForTesting(B, C);
    267   schedule.AddSuccessorForTesting(C, D);
    268   schedule.AddSuccessorForTesting(D, C);
    269   schedule.AddSuccessorForTesting(D, E);
    270   schedule.AddSuccessorForTesting(E, B);
    271   schedule.AddSuccessorForTesting(E, F);
    272 
    273   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    274   CheckRPONumbers(order, 6, true);
    275   BasicBlock* loop1[] = {B, C, D, E};
    276   CheckLoop(order, loop1, 4);
    277 
    278   BasicBlock* loop2[] = {C, D};
    279   CheckLoop(order, loop2, 2);
    280 }
    281 
    282 TEST_F(SchedulerRPOTest, LoopNest2) {
    283   Schedule schedule(zone());
    284 
    285   BasicBlock* A = schedule.start();
    286   BasicBlock* B = schedule.NewBasicBlock();
    287   BasicBlock* C = schedule.NewBasicBlock();
    288   BasicBlock* D = schedule.NewBasicBlock();
    289   BasicBlock* E = schedule.NewBasicBlock();
    290   BasicBlock* F = schedule.NewBasicBlock();
    291   BasicBlock* G = schedule.NewBasicBlock();
    292   BasicBlock* H = schedule.end();
    293 
    294   schedule.AddSuccessorForTesting(A, B);
    295   schedule.AddSuccessorForTesting(B, C);
    296   schedule.AddSuccessorForTesting(C, D);
    297   schedule.AddSuccessorForTesting(D, E);
    298   schedule.AddSuccessorForTesting(E, F);
    299   schedule.AddSuccessorForTesting(F, G);
    300   schedule.AddSuccessorForTesting(G, H);
    301 
    302   schedule.AddSuccessorForTesting(E, D);
    303   schedule.AddSuccessorForTesting(F, C);
    304   schedule.AddSuccessorForTesting(G, B);
    305 
    306   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    307   CheckRPONumbers(order, 8, true);
    308   BasicBlock* loop1[] = {B, C, D, E, F, G};
    309   CheckLoop(order, loop1, 6);
    310 
    311   BasicBlock* loop2[] = {C, D, E, F};
    312   CheckLoop(order, loop2, 4);
    313 
    314   BasicBlock* loop3[] = {D, E};
    315   CheckLoop(order, loop3, 2);
    316 }
    317 
    318 TEST_F(SchedulerRPOTest, LoopFollow1) {
    319   Schedule schedule(zone());
    320 
    321   base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
    322   base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
    323 
    324   BasicBlock* A = schedule.start();
    325   BasicBlock* E = schedule.end();
    326 
    327   schedule.AddSuccessorForTesting(A, loop1->header());
    328   schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
    329   schedule.AddSuccessorForTesting(loop2->last(), E);
    330 
    331   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    332 
    333   EXPECT_EQ(schedule.BasicBlockCount(), order->size());
    334   CheckLoop(order, loop1->nodes, loop1->count);
    335   CheckLoop(order, loop2->nodes, loop2->count);
    336 }
    337 
    338 TEST_F(SchedulerRPOTest, LoopFollow2) {
    339   Schedule schedule(zone());
    340 
    341   base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
    342   base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
    343 
    344   BasicBlock* A = schedule.start();
    345   BasicBlock* S = schedule.NewBasicBlock();
    346   BasicBlock* E = schedule.end();
    347 
    348   schedule.AddSuccessorForTesting(A, loop1->header());
    349   schedule.AddSuccessorForTesting(loop1->header(), S);
    350   schedule.AddSuccessorForTesting(S, loop2->header());
    351   schedule.AddSuccessorForTesting(loop2->last(), E);
    352 
    353   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    354 
    355   EXPECT_EQ(schedule.BasicBlockCount(), order->size());
    356   CheckLoop(order, loop1->nodes, loop1->count);
    357   CheckLoop(order, loop2->nodes, loop2->count);
    358 }
    359 
    360 TEST_F(SchedulerRPOTest, LoopFollowN) {
    361   for (int size = 1; size < 5; size++) {
    362     for (int exit = 0; exit < size; exit++) {
    363       Schedule schedule(zone());
    364       base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
    365       base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size));
    366       BasicBlock* A = schedule.start();
    367       BasicBlock* E = schedule.end();
    368 
    369       schedule.AddSuccessorForTesting(A, loop1->header());
    370       schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header());
    371       schedule.AddSuccessorForTesting(loop2->nodes[exit], E);
    372       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    373 
    374       EXPECT_EQ(schedule.BasicBlockCount(), order->size());
    375       CheckLoop(order, loop1->nodes, loop1->count);
    376       CheckLoop(order, loop2->nodes, loop2->count);
    377     }
    378   }
    379 }
    380 
    381 TEST_F(SchedulerRPOTest, NestedLoopFollow1) {
    382   Schedule schedule(zone());
    383 
    384   base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1));
    385   base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1));
    386 
    387   BasicBlock* A = schedule.start();
    388   BasicBlock* B = schedule.NewBasicBlock();
    389   BasicBlock* C = schedule.NewBasicBlock();
    390   BasicBlock* E = schedule.end();
    391 
    392   schedule.AddSuccessorForTesting(A, B);
    393   schedule.AddSuccessorForTesting(B, loop1->header());
    394   schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
    395   schedule.AddSuccessorForTesting(loop2->last(), C);
    396   schedule.AddSuccessorForTesting(C, E);
    397   schedule.AddSuccessorForTesting(C, B);
    398 
    399   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    400 
    401   EXPECT_EQ(schedule.BasicBlockCount(), order->size());
    402   CheckLoop(order, loop1->nodes, loop1->count);
    403   CheckLoop(order, loop2->nodes, loop2->count);
    404 
    405   BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C};
    406   CheckLoop(order, loop3, 4);
    407 }
    408 
    409 TEST_F(SchedulerRPOTest, LoopBackedges1) {
    410   int size = 8;
    411   for (int i = 0; i < size; i++) {
    412     for (int j = 0; j < size; j++) {
    413       Schedule schedule(zone());
    414       BasicBlock* A = schedule.start();
    415       BasicBlock* E = schedule.end();
    416 
    417       base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
    418       schedule.AddSuccessorForTesting(A, loop1->header());
    419       schedule.AddSuccessorForTesting(loop1->last(), E);
    420 
    421       schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
    422       schedule.AddSuccessorForTesting(loop1->nodes[j], E);
    423 
    424       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    425       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
    426       CheckLoop(order, loop1->nodes, loop1->count);
    427     }
    428   }
    429 }
    430 
    431 TEST_F(SchedulerRPOTest, LoopOutedges1) {
    432   int size = 8;
    433   for (int i = 0; i < size; i++) {
    434     for (int j = 0; j < size; j++) {
    435       Schedule schedule(zone());
    436       BasicBlock* A = schedule.start();
    437       BasicBlock* D = schedule.NewBasicBlock();
    438       BasicBlock* E = schedule.end();
    439 
    440       base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
    441       schedule.AddSuccessorForTesting(A, loop1->header());
    442       schedule.AddSuccessorForTesting(loop1->last(), E);
    443 
    444       schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
    445       schedule.AddSuccessorForTesting(loop1->nodes[j], D);
    446       schedule.AddSuccessorForTesting(D, E);
    447 
    448       BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    449       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
    450       CheckLoop(order, loop1->nodes, loop1->count);
    451     }
    452   }
    453 }
    454 
    455 TEST_F(SchedulerRPOTest, LoopOutedges2) {
    456   int size = 8;
    457   for (int i = 0; i < size; i++) {
    458     Schedule schedule(zone());
    459     BasicBlock* A = schedule.start();
    460     BasicBlock* E = schedule.end();
    461 
    462     base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
    463     schedule.AddSuccessorForTesting(A, loop1->header());
    464     schedule.AddSuccessorForTesting(loop1->last(), E);
    465 
    466     for (int j = 0; j < size; j++) {
    467       BasicBlock* O = schedule.NewBasicBlock();
    468       schedule.AddSuccessorForTesting(loop1->nodes[j], O);
    469       schedule.AddSuccessorForTesting(O, E);
    470     }
    471 
    472     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    473     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
    474     CheckLoop(order, loop1->nodes, loop1->count);
    475   }
    476 }
    477 
    478 TEST_F(SchedulerRPOTest, LoopOutloops1) {
    479   int size = 8;
    480   for (int i = 0; i < size; i++) {
    481     Schedule schedule(zone());
    482     BasicBlock* A = schedule.start();
    483     BasicBlock* E = schedule.end();
    484     base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
    485     schedule.AddSuccessorForTesting(A, loop1->header());
    486     schedule.AddSuccessorForTesting(loop1->last(), E);
    487 
    488     TestLoop** loopN = new TestLoop*[size];
    489     for (int j = 0; j < size; j++) {
    490       loopN[j] = CreateLoop(&schedule, 2);
    491       schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header());
    492       schedule.AddSuccessorForTesting(loopN[j]->last(), E);
    493     }
    494 
    495     BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    496     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
    497     CheckLoop(order, loop1->nodes, loop1->count);
    498 
    499     for (int j = 0; j < size; j++) {
    500       CheckLoop(order, loopN[j]->nodes, loopN[j]->count);
    501       delete loopN[j];
    502     }
    503     delete[] loopN;
    504   }
    505 }
    506 
    507 TEST_F(SchedulerRPOTest, LoopMultibackedge) {
    508   Schedule schedule(zone());
    509 
    510   BasicBlock* A = schedule.start();
    511   BasicBlock* B = schedule.NewBasicBlock();
    512   BasicBlock* C = schedule.NewBasicBlock();
    513   BasicBlock* D = schedule.NewBasicBlock();
    514   BasicBlock* E = schedule.NewBasicBlock();
    515 
    516   schedule.AddSuccessorForTesting(A, B);
    517   schedule.AddSuccessorForTesting(B, C);
    518   schedule.AddSuccessorForTesting(B, D);
    519   schedule.AddSuccessorForTesting(B, E);
    520   schedule.AddSuccessorForTesting(C, B);
    521   schedule.AddSuccessorForTesting(D, B);
    522   schedule.AddSuccessorForTesting(E, B);
    523 
    524   BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule);
    525   CheckRPONumbers(order, 5, true);
    526 
    527   BasicBlock* loop1[] = {B, C, D, E};
    528   CheckLoop(order, loop1, 4);
    529 }
    530 
    531 }  // namespace compiler
    532 }  // namespace internal
    533 }  // namespace v8
    534