Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "compiler_ir.h"
     18 #include "dataflow_iterator-inl.h"
     19 #include "mir_graph.h"
     20 #include "gtest/gtest.h"
     21 
     22 namespace art {
     23 
     24 class TopologicalSortOrderTest : public testing::Test {
     25  protected:
     26   struct BBDef {
     27     static constexpr size_t kMaxSuccessors = 4;
     28     static constexpr size_t kMaxPredecessors = 4;
     29 
     30     BBType type;
     31     size_t num_successors;
     32     BasicBlockId successors[kMaxPredecessors];
     33     size_t num_predecessors;
     34     BasicBlockId predecessors[kMaxPredecessors];
     35   };
     36 
     37 #define DEF_SUCC0() \
     38     0u, { }
     39 #define DEF_SUCC1(s1) \
     40     1u, { s1 }
     41 #define DEF_SUCC2(s1, s2) \
     42     2u, { s1, s2 }
     43 #define DEF_SUCC3(s1, s2, s3) \
     44     3u, { s1, s2, s3 }
     45 #define DEF_SUCC4(s1, s2, s3, s4) \
     46     4u, { s1, s2, s3, s4 }
     47 #define DEF_PRED0() \
     48     0u, { }
     49 #define DEF_PRED1(p1) \
     50     1u, { p1 }
     51 #define DEF_PRED2(p1, p2) \
     52     2u, { p1, p2 }
     53 #define DEF_PRED3(p1, p2, p3) \
     54     3u, { p1, p2, p3 }
     55 #define DEF_PRED4(p1, p2, p3, p4) \
     56     4u, { p1, p2, p3, p4 }
     57 #define DEF_BB(type, succ, pred) \
     58     { type, succ, pred }
     59 
     60   void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
     61     cu_.mir_graph->block_id_map_.clear();
     62     cu_.mir_graph->block_list_.clear();
     63     ASSERT_LT(3u, count);  // null, entry, exit and at least one bytecode block.
     64     ASSERT_EQ(kNullBlock, defs[0].type);
     65     ASSERT_EQ(kEntryBlock, defs[1].type);
     66     ASSERT_EQ(kExitBlock, defs[2].type);
     67     for (size_t i = 0u; i != count; ++i) {
     68       const BBDef* def = &defs[i];
     69       BasicBlock* bb = cu_.mir_graph->CreateNewBB(def->type);
     70       if (def->num_successors <= 2) {
     71         bb->successor_block_list_type = kNotUsed;
     72         bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
     73         bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
     74       } else {
     75         bb->successor_block_list_type = kPackedSwitch;
     76         bb->fall_through = 0u;
     77         bb->taken = 0u;
     78         bb->successor_blocks.reserve(def->num_successors);
     79         for (size_t j = 0u; j != def->num_successors; ++j) {
     80           SuccessorBlockInfo* successor_block_info =
     81               static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
     82                                                                kArenaAllocSuccessor));
     83           successor_block_info->block = j;
     84           successor_block_info->key = 0u;  // Not used by class init check elimination.
     85           bb->successor_blocks.push_back(successor_block_info);
     86         }
     87       }
     88       bb->predecessors.assign(def->predecessors, def->predecessors + def->num_predecessors);
     89       if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
     90         bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
     91             cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
     92       }
     93     }
     94     ASSERT_EQ(count, cu_.mir_graph->block_list_.size());
     95     cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_[1];
     96     ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
     97     cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_[2];
     98     ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
     99 
    100     DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>(cu_.arena.Alloc(sizeof(DexFile::CodeItem),
    101                                                                                    kArenaAllocMisc));
    102     cu_.mir_graph->current_code_item_ = code_item;
    103   }
    104 
    105   template <size_t count>
    106   void PrepareBasicBlocks(const BBDef (&defs)[count]) {
    107     DoPrepareBasicBlocks(defs, count);
    108   }
    109 
    110   void ComputeTopologicalSortOrder() {
    111     cu_.mir_graph->SSATransformationStart();
    112     cu_.mir_graph->ComputeDFSOrders();
    113     cu_.mir_graph->ComputeDominators();
    114     cu_.mir_graph->ComputeTopologicalSortOrder();
    115     cu_.mir_graph->SSATransformationEnd();
    116     ASSERT_FALSE(cu_.mir_graph->topological_order_.empty());
    117     ASSERT_FALSE(cu_.mir_graph->topological_order_loop_ends_.empty());
    118     ASSERT_FALSE(cu_.mir_graph->topological_order_indexes_.empty());
    119     ASSERT_EQ(cu_.mir_graph->GetNumBlocks(), cu_.mir_graph->topological_order_indexes_.size());
    120     for (size_t i = 0, size = cu_.mir_graph->GetTopologicalSortOrder().size(); i != size; ++i) {
    121       ASSERT_LT(cu_.mir_graph->topological_order_[i], cu_.mir_graph->GetNumBlocks());
    122       BasicBlockId id = cu_.mir_graph->topological_order_[i];
    123       EXPECT_EQ(i, cu_.mir_graph->topological_order_indexes_[id]);
    124     }
    125   }
    126 
    127   void DoCheckOrder(const BasicBlockId* ids, size_t count) {
    128     ASSERT_EQ(count, cu_.mir_graph->GetTopologicalSortOrder().size());
    129     for (size_t i = 0; i != count; ++i) {
    130       EXPECT_EQ(ids[i], cu_.mir_graph->GetTopologicalSortOrder()[i]) << i;
    131     }
    132   }
    133 
    134   template <size_t count>
    135   void CheckOrder(const BasicBlockId (&ids)[count]) {
    136     DoCheckOrder(ids, count);
    137   }
    138 
    139   void DoCheckLoopEnds(const uint16_t* ends, size_t count) {
    140     for (size_t i = 0; i != count; ++i) {
    141       ASSERT_LT(i, cu_.mir_graph->GetTopologicalSortOrderLoopEnds().size());
    142       EXPECT_EQ(ends[i], cu_.mir_graph->GetTopologicalSortOrderLoopEnds()[i]) << i;
    143     }
    144   }
    145 
    146   template <size_t count>
    147   void CheckLoopEnds(const uint16_t (&ends)[count]) {
    148     DoCheckLoopEnds(ends, count);
    149   }
    150 
    151   TopologicalSortOrderTest()
    152       : pool_(),
    153         cu_(&pool_, kRuntimeISA, nullptr, nullptr) {
    154     cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
    155   }
    156 
    157   ArenaPool pool_;
    158   CompilationUnit cu_;
    159 };
    160 
    161 TEST_F(TopologicalSortOrderTest, DoWhile) {
    162   const BBDef bbs[] = {
    163       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    164       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    165       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
    166       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
    167       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)),  // "taken" loops to self.
    168       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
    169   };
    170   const BasicBlockId expected_order[] = {
    171       1, 3, 4, 5, 2
    172   };
    173   const uint16_t loop_ends[] = {
    174       0, 0, 3, 0, 0
    175   };
    176 
    177   PrepareBasicBlocks(bbs);
    178   ComputeTopologicalSortOrder();
    179   CheckOrder(expected_order);
    180   CheckLoopEnds(loop_ends);
    181 }
    182 
    183 TEST_F(TopologicalSortOrderTest, While) {
    184   const BBDef bbs[] = {
    185       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    186       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    187       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
    188       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED2(1, 4)),
    189       DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(3)),     // Loops to 3.
    190       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    191   };
    192   const BasicBlockId expected_order[] = {
    193       1, 3, 4, 5, 2
    194   };
    195   const uint16_t loop_ends[] = {
    196       0, 3, 0, 0, 0
    197   };
    198 
    199   PrepareBasicBlocks(bbs);
    200   ComputeTopologicalSortOrder();
    201   CheckOrder(expected_order);
    202   CheckLoopEnds(loop_ends);
    203 }
    204 
    205 TEST_F(TopologicalSortOrderTest, WhileWithTwoBackEdges) {
    206   const BBDef bbs[] = {
    207       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    208       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    209       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
    210       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED3(1, 4, 5)),
    211       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED1(3)),     // Loops to 3.
    212       DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)),        // Loops to 3.
    213       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    214   };
    215   const BasicBlockId expected_order[] = {
    216       1, 3, 4, 5, 6, 2
    217   };
    218   const uint16_t loop_ends[] = {
    219       0, 4, 0, 0, 0, 0
    220   };
    221 
    222   PrepareBasicBlocks(bbs);
    223   ComputeTopologicalSortOrder();
    224   CheckOrder(expected_order);
    225   CheckLoopEnds(loop_ends);
    226 }
    227 
    228 TEST_F(TopologicalSortOrderTest, NestedLoop) {
    229   const BBDef bbs[] = {
    230       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    231       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    232       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
    233       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED2(1, 6)),
    234       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED2(3, 5)),
    235       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to 4.
    236       DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)),            // Loops to 3.
    237       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    238   };
    239   const BasicBlockId expected_order[] = {
    240       1, 3, 4, 5, 6, 7, 2
    241   };
    242   const uint16_t loop_ends[] = {
    243       0, 5, 4, 0, 0, 0, 0
    244   };
    245 
    246   PrepareBasicBlocks(bbs);
    247   ComputeTopologicalSortOrder();
    248   CheckOrder(expected_order);
    249   CheckLoopEnds(loop_ends);
    250 }
    251 
    252 TEST_F(TopologicalSortOrderTest, NestedLoopHeadLoops) {
    253   const BBDef bbs[] = {
    254       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    255       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    256       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
    257       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 4)),
    258       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED2(3, 5)),      // Nested head, loops to 3.
    259       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to 4.
    260       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    261   };
    262   const BasicBlockId expected_order[] = {
    263       1, 3, 4, 5, 6, 2
    264   };
    265   const uint16_t loop_ends[] = {
    266       0, 4, 4, 0, 0, 0
    267   };
    268 
    269   PrepareBasicBlocks(bbs);
    270   ComputeTopologicalSortOrder();
    271   CheckOrder(expected_order);
    272   CheckLoopEnds(loop_ends);
    273 }
    274 
    275 TEST_F(TopologicalSortOrderTest, NestedLoopSameBackBranchBlock) {
    276   const BBDef bbs[] = {
    277       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    278       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    279       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
    280       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 5)),
    281       DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 5)),
    282       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 3), DEF_PRED1(4)),         // Loops to 4 and 3.
    283       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    284   };
    285   const BasicBlockId expected_order[] = {
    286       1, 3, 4, 5, 6, 2
    287   };
    288   const uint16_t loop_ends[] = {
    289       0, 4, 4, 0, 0, 0
    290   };
    291 
    292   PrepareBasicBlocks(bbs);
    293   ComputeTopologicalSortOrder();
    294   CheckOrder(expected_order);
    295   CheckLoopEnds(loop_ends);
    296 }
    297 
    298 TEST_F(TopologicalSortOrderTest, TwoReorderedInnerLoops) {
    299   // This is a simplified version of real code graph where the branch from 8 to 5 must prevent
    300   // the block 5 from being considered a loop head before processing the loop 7-8.
    301   const BBDef bbs[] = {
    302       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    303       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    304       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(9)),
    305       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 9), DEF_PRED2(1, 5)),
    306       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 7), DEF_PRED1(3)),         // Branch over loop in 5.
    307       DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 3), DEF_PRED3(4, 6, 8)),   // Loops to 4; inner loop.
    308       DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)),            // Loops to 5.
    309       DEF_BB(kDalvikByteCode, DEF_SUCC1(8), DEF_PRED2(4, 8)),         // Loop head.
    310       DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 5), DEF_PRED1(7)),         // Loops to 7; branches to 5.
    311       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
    312   };
    313   const BasicBlockId expected_order[] = {
    314       1, 3, 4, 7, 8, 5, 6, 9, 2
    315   };
    316   const uint16_t loop_ends[] = {
    317       0, 7, 0, 5, 0, 7, 0, 0, 0
    318   };
    319 
    320   PrepareBasicBlocks(bbs);
    321   ComputeTopologicalSortOrder();
    322   CheckOrder(expected_order);
    323   CheckLoopEnds(loop_ends);
    324 }
    325 
    326 TEST_F(TopologicalSortOrderTest, NestedLoopWithBackEdgeAfterOuterLoopBackEdge) {
    327   // This is a simplified version of real code graph. The back-edge from 7 to the inner
    328   // loop head 4 comes after the back-edge from 6 to the outer loop head 3. To make this
    329   // appear a bit more complex, there's also a back-edge from 5 to 4.
    330   const BBDef bbs[] = {
    331       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    332       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    333       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
    334       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED2(1, 6)),         // Outer loop head.
    335       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED3(3, 5, 7)),   // Inner loop head.
    336       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to inner loop head 4.
    337       DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 3), DEF_PRED1(4)),         // Loops to outer loop head 3.
    338       DEF_BB(kDalvikByteCode, DEF_SUCC2(2, 4), DEF_PRED1(6)),         // Loops to inner loop head 4.
    339   };
    340   const BasicBlockId expected_order[] = {
    341       // NOTE: The 5 goes before 6 only because 5 is a "fall-through" from 4 while 6 is "taken".
    342       1, 3, 4, 5, 6, 7, 2
    343   };
    344   const uint16_t loop_ends[] = {
    345       0, 6, 6, 0, 0, 0, 0
    346   };
    347 
    348   PrepareBasicBlocks(bbs);
    349   ComputeTopologicalSortOrder();
    350   CheckOrder(expected_order);
    351   CheckLoopEnds(loop_ends);
    352 }
    353 
    354 TEST_F(TopologicalSortOrderTest, LoopWithTwoEntryPoints) {
    355   const BBDef bbs[] = {
    356       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    357       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    358       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
    359       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
    360       DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 6)),  // Fall-back block is chosen as
    361       DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED2(3, 4)),  // the earlier from these two.
    362       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED1(5)),
    363       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(6)),
    364   };
    365   const BasicBlockId expected_order[] = {
    366       1, 3, 4, 5, 6, 7, 2
    367   };
    368   const uint16_t loop_ends[] = {
    369       0, 0, 5, 0, 0, 0, 0
    370   };
    371 
    372   PrepareBasicBlocks(bbs);
    373   ComputeTopologicalSortOrder();
    374   CheckOrder(expected_order);
    375   CheckLoopEnds(loop_ends);
    376 }
    377 
    378 TEST_F(TopologicalSortOrderTest, UnnaturalLoops) {
    379   const BBDef bbs[] = {
    380       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
    381       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
    382       DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(10)),
    383       DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
    384       DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(11, 3)),  // Unnatural loop head (top-level).
    385       DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED2(3, 4)),
    386       DEF_BB(kDalvikByteCode, DEF_SUCC2(9, 7), DEF_PRED1(5)),
    387       DEF_BB(kDalvikByteCode, DEF_SUCC1(8), DEF_PRED1(6)),
    388       DEF_BB(kDalvikByteCode, DEF_SUCC1(9), DEF_PRED2(10, 7)),  // Unnatural loop head (nested).
    389       DEF_BB(kDalvikByteCode, DEF_SUCC1(10), DEF_PRED2(6, 8)),
    390       DEF_BB(kDalvikByteCode, DEF_SUCC2(8, 11), DEF_PRED1(9)),
    391       DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 2), DEF_PRED1(10)),
    392   };
    393   const BasicBlockId expected_order[] = {
    394       1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 2
    395   };
    396   const uint16_t loop_ends[] = {
    397       0, 0, 10, 0, 0, 0, 9, 0, 0, 0, 0,
    398   };
    399 
    400   PrepareBasicBlocks(bbs);
    401   ComputeTopologicalSortOrder();
    402   CheckOrder(expected_order);
    403   CheckLoopEnds(loop_ends);
    404 
    405   const std::pair<BasicBlockId, bool> expected_and_change[] = {
    406       { 1, false },
    407       { 3, false },
    408       { 4, true },    // Initial run of the outer loop.
    409       { 5, true },
    410       { 6, true },
    411       { 7, true },
    412       { 8, true },    // Initial run of the inner loop.
    413       { 9, true },
    414       { 10, true },
    415       { 8, true },    // Recalculation of the inner loop - changed.
    416       { 9, true },
    417       { 10, true },
    418       { 8, false },   // Recalculation of the inner loop - unchanged.
    419       { 11, true },
    420       { 4, true },    // Recalculation of the outer loop - changed.
    421       { 5, true },
    422       { 6, true },
    423       { 7, false },   // No change: skip inner loop head because inputs are unchanged.
    424       { 9, true },
    425       { 10, true },
    426       { 8, true },    // Recalculation of the inner loop - changed.
    427       { 9, true },
    428       { 10, true },
    429       { 8, false },   // Recalculation of the inner loop - unchanged.
    430       { 11, true },
    431       { 4, false },   // Recalculation of the outer loop - unchanged.
    432       { 2, false },
    433   };
    434   size_t pos = 0;
    435   LoopRepeatingTopologicalSortIterator iter(cu_.mir_graph.get());
    436   bool change = false;
    437   for (BasicBlock* bb = iter.Next(change); bb != nullptr; bb = iter.Next(change)) {
    438     ASSERT_NE(arraysize(expected_and_change), pos);
    439     ASSERT_EQ(expected_and_change[pos].first, bb->id) << pos;
    440     change = expected_and_change[pos].second;
    441     ++pos;
    442   }
    443   ASSERT_EQ(arraysize(expected_and_change), pos);
    444 }
    445 
    446 }  // namespace art
    447