Home | History | Annotate | Download | only in optimizing
      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 "base/arena_allocator.h"
     18 #include "bounds_check_elimination.h"
     19 #include "builder.h"
     20 #include "gvn.h"
     21 #include "induction_var_analysis.h"
     22 #include "instruction_simplifier.h"
     23 #include "nodes.h"
     24 #include "optimizing_unit_test.h"
     25 #include "side_effects_analysis.h"
     26 
     27 #include "gtest/gtest.h"
     28 
     29 namespace art {
     30 
     31 /**
     32  * Fixture class for the BoundsCheckElimination tests.
     33  */
     34 class BoundsCheckEliminationTest : public testing::Test {
     35  public:
     36   BoundsCheckEliminationTest()  : pool_(), allocator_(&pool_) {
     37     graph_ = CreateGraph(&allocator_);
     38     graph_->SetHasBoundsChecks(true);
     39   }
     40 
     41   ~BoundsCheckEliminationTest() { }
     42 
     43   void RunBCE() {
     44     graph_->BuildDominatorTree();
     45 
     46     InstructionSimplifier(graph_, /* codegen */ nullptr, /* driver */ nullptr).Run();
     47 
     48     SideEffectsAnalysis side_effects(graph_);
     49     side_effects.Run();
     50 
     51     GVNOptimization(graph_, side_effects).Run();
     52 
     53     HInductionVarAnalysis induction(graph_);
     54     induction.Run();
     55 
     56     BoundsCheckElimination(graph_, side_effects, &induction).Run();
     57   }
     58 
     59   ArenaPool pool_;
     60   ArenaAllocator allocator_;
     61   HGraph* graph_;
     62 };
     63 
     64 
     65 // if (i < 0) { array[i] = 1; // Can't eliminate. }
     66 // else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
     67 // else { array[i] = 1; // Can eliminate. }
     68 TEST_F(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
     69   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
     70   graph_->AddBlock(entry);
     71   graph_->SetEntryBlock(entry);
     72   HInstruction* parameter1 = new (&allocator_)
     73       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
     74   HInstruction* parameter2 = new (&allocator_)
     75       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
     76   entry->AddInstruction(parameter1);
     77   entry->AddInstruction(parameter2);
     78 
     79   HInstruction* constant_1 = graph_->GetIntConstant(1);
     80   HInstruction* constant_0 = graph_->GetIntConstant(0);
     81 
     82   HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
     83   graph_->AddBlock(block1);
     84   HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(parameter2, constant_0);
     85   HIf* if_inst = new (&allocator_) HIf(cmp);
     86   block1->AddInstruction(cmp);
     87   block1->AddInstruction(if_inst);
     88   entry->AddSuccessor(block1);
     89 
     90   HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
     91   graph_->AddBlock(block2);
     92   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
     93   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
     94   HBoundsCheck* bounds_check2 = new (&allocator_)
     95       HBoundsCheck(parameter2, array_length, 0);
     96   HArraySet* array_set = new (&allocator_) HArraySet(
     97     null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
     98   block2->AddInstruction(null_check);
     99   block2->AddInstruction(array_length);
    100   block2->AddInstruction(bounds_check2);
    101   block2->AddInstruction(array_set);
    102 
    103   HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
    104   graph_->AddBlock(block3);
    105   null_check = new (&allocator_) HNullCheck(parameter1, 0);
    106   array_length = new (&allocator_) HArrayLength(null_check, 0);
    107   cmp = new (&allocator_) HLessThan(parameter2, array_length);
    108   if_inst = new (&allocator_) HIf(cmp);
    109   block3->AddInstruction(null_check);
    110   block3->AddInstruction(array_length);
    111   block3->AddInstruction(cmp);
    112   block3->AddInstruction(if_inst);
    113 
    114   HBasicBlock* block4 = new (&allocator_) HBasicBlock(graph_);
    115   graph_->AddBlock(block4);
    116   null_check = new (&allocator_) HNullCheck(parameter1, 0);
    117   array_length = new (&allocator_) HArrayLength(null_check, 0);
    118   HBoundsCheck* bounds_check4 = new (&allocator_)
    119       HBoundsCheck(parameter2, array_length, 0);
    120   array_set = new (&allocator_) HArraySet(
    121     null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
    122   block4->AddInstruction(null_check);
    123   block4->AddInstruction(array_length);
    124   block4->AddInstruction(bounds_check4);
    125   block4->AddInstruction(array_set);
    126 
    127   HBasicBlock* block5 = new (&allocator_) HBasicBlock(graph_);
    128   graph_->AddBlock(block5);
    129   null_check = new (&allocator_) HNullCheck(parameter1, 0);
    130   array_length = new (&allocator_) HArrayLength(null_check, 0);
    131   HBoundsCheck* bounds_check5 = new (&allocator_)
    132       HBoundsCheck(parameter2, array_length, 0);
    133   array_set = new (&allocator_) HArraySet(
    134     null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
    135   block5->AddInstruction(null_check);
    136   block5->AddInstruction(array_length);
    137   block5->AddInstruction(bounds_check5);
    138   block5->AddInstruction(array_set);
    139 
    140   HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
    141   graph_->AddBlock(exit);
    142   block2->AddSuccessor(exit);
    143   block4->AddSuccessor(exit);
    144   block5->AddSuccessor(exit);
    145   exit->AddInstruction(new (&allocator_) HExit());
    146 
    147   block1->AddSuccessor(block3);  // True successor
    148   block1->AddSuccessor(block2);  // False successor
    149 
    150   block3->AddSuccessor(block5);  // True successor
    151   block3->AddSuccessor(block4);  // False successor
    152 
    153   RunBCE();
    154 
    155   ASSERT_FALSE(IsRemoved(bounds_check2));
    156   ASSERT_FALSE(IsRemoved(bounds_check4));
    157   ASSERT_TRUE(IsRemoved(bounds_check5));
    158 }
    159 
    160 // if (i > 0) {
    161 //   // Positive number plus MAX_INT will overflow and be negative.
    162 //   int j = i + Integer.MAX_VALUE;
    163 //   if (j < array.length) array[j] = 1;  // Can't eliminate.
    164 // }
    165 TEST_F(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
    166   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
    167   graph_->AddBlock(entry);
    168   graph_->SetEntryBlock(entry);
    169   HInstruction* parameter1 = new (&allocator_)
    170       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
    171   HInstruction* parameter2 = new (&allocator_)
    172       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
    173   entry->AddInstruction(parameter1);
    174   entry->AddInstruction(parameter2);
    175 
    176   HInstruction* constant_1 = graph_->GetIntConstant(1);
    177   HInstruction* constant_0 = graph_->GetIntConstant(0);
    178   HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
    179 
    180   HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
    181   graph_->AddBlock(block1);
    182   HInstruction* cmp = new (&allocator_) HLessThanOrEqual(parameter2, constant_0);
    183   HIf* if_inst = new (&allocator_) HIf(cmp);
    184   block1->AddInstruction(cmp);
    185   block1->AddInstruction(if_inst);
    186   entry->AddSuccessor(block1);
    187 
    188   HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
    189   graph_->AddBlock(block2);
    190   HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
    191   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
    192   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
    193   HInstruction* cmp2 = new (&allocator_) HGreaterThanOrEqual(add, array_length);
    194   if_inst = new (&allocator_) HIf(cmp2);
    195   block2->AddInstruction(add);
    196   block2->AddInstruction(null_check);
    197   block2->AddInstruction(array_length);
    198   block2->AddInstruction(cmp2);
    199   block2->AddInstruction(if_inst);
    200 
    201   HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
    202   graph_->AddBlock(block3);
    203   HBoundsCheck* bounds_check = new (&allocator_)
    204       HBoundsCheck(add, array_length, 0);
    205   HArraySet* array_set = new (&allocator_) HArraySet(
    206     null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
    207   block3->AddInstruction(bounds_check);
    208   block3->AddInstruction(array_set);
    209 
    210   HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
    211   graph_->AddBlock(exit);
    212   exit->AddInstruction(new (&allocator_) HExit());
    213   block1->AddSuccessor(exit);    // true successor
    214   block1->AddSuccessor(block2);  // false successor
    215   block2->AddSuccessor(exit);    // true successor
    216   block2->AddSuccessor(block3);  // false successor
    217   block3->AddSuccessor(exit);
    218 
    219   RunBCE();
    220 
    221   ASSERT_FALSE(IsRemoved(bounds_check));
    222 }
    223 
    224 // if (i < array.length) {
    225 //   int j = i - Integer.MAX_VALUE;
    226 //   j = j - Integer.MAX_VALUE;  // j is (i+2) after subtracting MAX_INT twice
    227 //   if (j > 0) array[j] = 1;    // Can't eliminate.
    228 // }
    229 TEST_F(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
    230   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
    231   graph_->AddBlock(entry);
    232   graph_->SetEntryBlock(entry);
    233   HInstruction* parameter1 = new (&allocator_)
    234       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
    235   HInstruction* parameter2 = new (&allocator_)
    236       HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
    237   entry->AddInstruction(parameter1);
    238   entry->AddInstruction(parameter2);
    239 
    240   HInstruction* constant_1 = graph_->GetIntConstant(1);
    241   HInstruction* constant_0 = graph_->GetIntConstant(0);
    242   HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
    243 
    244   HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
    245   graph_->AddBlock(block1);
    246   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
    247   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
    248   HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(parameter2, array_length);
    249   HIf* if_inst = new (&allocator_) HIf(cmp);
    250   block1->AddInstruction(null_check);
    251   block1->AddInstruction(array_length);
    252   block1->AddInstruction(cmp);
    253   block1->AddInstruction(if_inst);
    254   entry->AddSuccessor(block1);
    255 
    256   HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
    257   graph_->AddBlock(block2);
    258   HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
    259   HInstruction* sub2 = new (&allocator_) HSub(Primitive::kPrimInt, sub1, constant_max_int);
    260   HInstruction* cmp2 = new (&allocator_) HLessThanOrEqual(sub2, constant_0);
    261   if_inst = new (&allocator_) HIf(cmp2);
    262   block2->AddInstruction(sub1);
    263   block2->AddInstruction(sub2);
    264   block2->AddInstruction(cmp2);
    265   block2->AddInstruction(if_inst);
    266 
    267   HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
    268   graph_->AddBlock(block3);
    269   HBoundsCheck* bounds_check = new (&allocator_)
    270       HBoundsCheck(sub2, array_length, 0);
    271   HArraySet* array_set = new (&allocator_) HArraySet(
    272     null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
    273   block3->AddInstruction(bounds_check);
    274   block3->AddInstruction(array_set);
    275 
    276   HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
    277   graph_->AddBlock(exit);
    278   exit->AddInstruction(new (&allocator_) HExit());
    279   block1->AddSuccessor(exit);    // true successor
    280   block1->AddSuccessor(block2);  // false successor
    281   block2->AddSuccessor(exit);    // true successor
    282   block2->AddSuccessor(block3);  // false successor
    283   block3->AddSuccessor(exit);
    284 
    285   RunBCE();
    286 
    287   ASSERT_FALSE(IsRemoved(bounds_check));
    288 }
    289 
    290 // array[6] = 1; // Can't eliminate.
    291 // array[5] = 1; // Can eliminate.
    292 // array[4] = 1; // Can eliminate.
    293 TEST_F(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
    294   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
    295   graph_->AddBlock(entry);
    296   graph_->SetEntryBlock(entry);
    297   HInstruction* parameter = new (&allocator_) HParameterValue(
    298       graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
    299   entry->AddInstruction(parameter);
    300 
    301   HInstruction* constant_5 = graph_->GetIntConstant(5);
    302   HInstruction* constant_4 = graph_->GetIntConstant(4);
    303   HInstruction* constant_6 = graph_->GetIntConstant(6);
    304   HInstruction* constant_1 = graph_->GetIntConstant(1);
    305 
    306   HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
    307   graph_->AddBlock(block);
    308   entry->AddSuccessor(block);
    309 
    310   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter, 0);
    311   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
    312   HBoundsCheck* bounds_check6 = new (&allocator_)
    313       HBoundsCheck(constant_6, array_length, 0);
    314   HInstruction* array_set = new (&allocator_) HArraySet(
    315     null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
    316   block->AddInstruction(null_check);
    317   block->AddInstruction(array_length);
    318   block->AddInstruction(bounds_check6);
    319   block->AddInstruction(array_set);
    320 
    321   null_check = new (&allocator_) HNullCheck(parameter, 0);
    322   array_length = new (&allocator_) HArrayLength(null_check, 0);
    323   HBoundsCheck* bounds_check5 = new (&allocator_)
    324       HBoundsCheck(constant_5, array_length, 0);
    325   array_set = new (&allocator_) HArraySet(
    326     null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
    327   block->AddInstruction(null_check);
    328   block->AddInstruction(array_length);
    329   block->AddInstruction(bounds_check5);
    330   block->AddInstruction(array_set);
    331 
    332   null_check = new (&allocator_) HNullCheck(parameter, 0);
    333   array_length = new (&allocator_) HArrayLength(null_check, 0);
    334   HBoundsCheck* bounds_check4 = new (&allocator_)
    335       HBoundsCheck(constant_4, array_length, 0);
    336   array_set = new (&allocator_) HArraySet(
    337     null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
    338   block->AddInstruction(null_check);
    339   block->AddInstruction(array_length);
    340   block->AddInstruction(bounds_check4);
    341   block->AddInstruction(array_set);
    342 
    343   block->AddInstruction(new (&allocator_) HGoto());
    344 
    345   HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
    346   graph_->AddBlock(exit);
    347   block->AddSuccessor(exit);
    348   exit->AddInstruction(new (&allocator_) HExit());
    349 
    350   RunBCE();
    351 
    352   ASSERT_FALSE(IsRemoved(bounds_check6));
    353   ASSERT_TRUE(IsRemoved(bounds_check5));
    354   ASSERT_TRUE(IsRemoved(bounds_check4));
    355 }
    356 
    357 // for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
    358 static HInstruction* BuildSSAGraph1(HGraph* graph,
    359                                     ArenaAllocator* allocator,
    360                                     int initial,
    361                                     int increment,
    362                                     IfCondition cond = kCondGE) {
    363   HBasicBlock* entry = new (allocator) HBasicBlock(graph);
    364   graph->AddBlock(entry);
    365   graph->SetEntryBlock(entry);
    366   HInstruction* parameter = new (allocator) HParameterValue(
    367       graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
    368   entry->AddInstruction(parameter);
    369 
    370   HInstruction* constant_initial = graph->GetIntConstant(initial);
    371   HInstruction* constant_increment = graph->GetIntConstant(increment);
    372   HInstruction* constant_10 = graph->GetIntConstant(10);
    373 
    374   HBasicBlock* block = new (allocator) HBasicBlock(graph);
    375   graph->AddBlock(block);
    376   entry->AddSuccessor(block);
    377   block->AddInstruction(new (allocator) HGoto());
    378 
    379   HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
    380   HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
    381   HBasicBlock* exit = new (allocator) HBasicBlock(graph);
    382 
    383   graph->AddBlock(loop_header);
    384   graph->AddBlock(loop_body);
    385   graph->AddBlock(exit);
    386   block->AddSuccessor(loop_header);
    387   loop_header->AddSuccessor(exit);       // true successor
    388   loop_header->AddSuccessor(loop_body);  // false successor
    389   loop_body->AddSuccessor(loop_header);
    390 
    391   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
    392   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
    393   HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
    394   HInstruction* cmp = nullptr;
    395   if (cond == kCondGE) {
    396     cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
    397   } else {
    398     DCHECK(cond == kCondGT);
    399     cmp = new (allocator) HGreaterThan(phi, array_length);
    400   }
    401   HInstruction* if_inst = new (allocator) HIf(cmp);
    402   loop_header->AddPhi(phi);
    403   loop_header->AddInstruction(null_check);
    404   loop_header->AddInstruction(array_length);
    405   loop_header->AddInstruction(cmp);
    406   loop_header->AddInstruction(if_inst);
    407   phi->AddInput(constant_initial);
    408 
    409   null_check = new (allocator) HNullCheck(parameter, 0);
    410   array_length = new (allocator) HArrayLength(null_check, 0);
    411   HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
    412   HInstruction* array_set = new (allocator) HArraySet(
    413       null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
    414 
    415   HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
    416   loop_body->AddInstruction(null_check);
    417   loop_body->AddInstruction(array_length);
    418   loop_body->AddInstruction(bounds_check);
    419   loop_body->AddInstruction(array_set);
    420   loop_body->AddInstruction(add);
    421   loop_body->AddInstruction(new (allocator) HGoto());
    422   phi->AddInput(add);
    423 
    424   exit->AddInstruction(new (allocator) HExit());
    425 
    426   return bounds_check;
    427 }
    428 
    429 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1a) {
    430   // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
    431   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 1);
    432   RunBCE();
    433   ASSERT_TRUE(IsRemoved(bounds_check));
    434 }
    435 
    436 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1b) {
    437   // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
    438   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 1, 1);
    439   RunBCE();
    440   ASSERT_TRUE(IsRemoved(bounds_check));
    441 }
    442 
    443 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1c) {
    444   // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
    445   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, -1, 1);
    446   RunBCE();
    447   ASSERT_FALSE(IsRemoved(bounds_check));
    448 }
    449 
    450 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1d) {
    451   // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
    452   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 1, kCondGT);
    453   RunBCE();
    454   ASSERT_FALSE(IsRemoved(bounds_check));
    455 }
    456 
    457 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1e) {
    458   // for (int i=0; i<array.length; i += 2) {
    459   //   array[i] = 10; // Can't eliminate due to overflow concern. }
    460   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 2);
    461   RunBCE();
    462   ASSERT_FALSE(IsRemoved(bounds_check));
    463 }
    464 
    465 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1f) {
    466   // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
    467   HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 1, 2);
    468   RunBCE();
    469   ASSERT_TRUE(IsRemoved(bounds_check));
    470 }
    471 
    472 // for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
    473 static HInstruction* BuildSSAGraph2(HGraph *graph,
    474                                     ArenaAllocator* allocator,
    475                                     int initial,
    476                                     int increment = -1,
    477                                     IfCondition cond = kCondLE) {
    478   HBasicBlock* entry = new (allocator) HBasicBlock(graph);
    479   graph->AddBlock(entry);
    480   graph->SetEntryBlock(entry);
    481   HInstruction* parameter = new (allocator) HParameterValue(
    482       graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
    483   entry->AddInstruction(parameter);
    484 
    485   HInstruction* constant_initial = graph->GetIntConstant(initial);
    486   HInstruction* constant_increment = graph->GetIntConstant(increment);
    487   HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
    488   HInstruction* constant_10 = graph->GetIntConstant(10);
    489 
    490   HBasicBlock* block = new (allocator) HBasicBlock(graph);
    491   graph->AddBlock(block);
    492   entry->AddSuccessor(block);
    493   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
    494   HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
    495   block->AddInstruction(null_check);
    496   block->AddInstruction(array_length);
    497   block->AddInstruction(new (allocator) HGoto());
    498 
    499   HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
    500   HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
    501   HBasicBlock* exit = new (allocator) HBasicBlock(graph);
    502 
    503   graph->AddBlock(loop_header);
    504   graph->AddBlock(loop_body);
    505   graph->AddBlock(exit);
    506   block->AddSuccessor(loop_header);
    507   loop_header->AddSuccessor(exit);       // true successor
    508   loop_header->AddSuccessor(loop_body);  // false successor
    509   loop_body->AddSuccessor(loop_header);
    510 
    511   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
    512   HInstruction* cmp = nullptr;
    513   if (cond == kCondLE) {
    514     cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
    515   } else {
    516     DCHECK(cond == kCondLT);
    517     cmp = new (allocator) HLessThan(phi, constant_initial);
    518   }
    519   HInstruction* if_inst = new (allocator) HIf(cmp);
    520   loop_header->AddPhi(phi);
    521   loop_header->AddInstruction(cmp);
    522   loop_header->AddInstruction(if_inst);
    523   phi->AddInput(array_length);
    524 
    525   HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
    526   null_check = new (allocator) HNullCheck(parameter, 0);
    527   array_length = new (allocator) HArrayLength(null_check, 0);
    528   HInstruction* bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
    529   HInstruction* array_set = new (allocator) HArraySet(
    530       null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
    531   HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
    532   loop_body->AddInstruction(add);
    533   loop_body->AddInstruction(null_check);
    534   loop_body->AddInstruction(array_length);
    535   loop_body->AddInstruction(bounds_check);
    536   loop_body->AddInstruction(array_set);
    537   loop_body->AddInstruction(add_phi);
    538   loop_body->AddInstruction(new (allocator) HGoto());
    539   phi->AddInput(add);
    540 
    541   exit->AddInstruction(new (allocator) HExit());
    542 
    543   return bounds_check;
    544 }
    545 
    546 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2a) {
    547   // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
    548   HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0);
    549   RunBCE();
    550   ASSERT_TRUE(IsRemoved(bounds_check));
    551 }
    552 
    553 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2b) {
    554   // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
    555   HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 1);
    556   RunBCE();
    557   ASSERT_TRUE(IsRemoved(bounds_check));
    558 }
    559 
    560 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2c) {
    561   // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
    562   HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, -1);
    563   RunBCE();
    564   ASSERT_FALSE(IsRemoved(bounds_check));
    565 }
    566 
    567 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2d) {
    568   // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
    569   HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0, -1, kCondLT);
    570   RunBCE();
    571   ASSERT_FALSE(IsRemoved(bounds_check));
    572 }
    573 
    574 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2e) {
    575   // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
    576   HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0, -2);
    577   RunBCE();
    578   ASSERT_TRUE(IsRemoved(bounds_check));
    579 }
    580 
    581 // int[] array = new int[10];
    582 // for (int i=0; i<10; i+=increment) { array[i] = 10; }
    583 static HInstruction* BuildSSAGraph3(HGraph* graph,
    584                                     ArenaAllocator* allocator,
    585                                     int initial,
    586                                     int increment,
    587                                     IfCondition cond) {
    588   HBasicBlock* entry = new (allocator) HBasicBlock(graph);
    589   graph->AddBlock(entry);
    590   graph->SetEntryBlock(entry);
    591 
    592   HInstruction* constant_10 = graph->GetIntConstant(10);
    593   HInstruction* constant_initial = graph->GetIntConstant(initial);
    594   HInstruction* constant_increment = graph->GetIntConstant(increment);
    595 
    596   HBasicBlock* block = new (allocator) HBasicBlock(graph);
    597   graph->AddBlock(block);
    598   entry->AddSuccessor(block);
    599   // We pass a bogus constant for the class to avoid mocking one.
    600   HInstruction* new_array = new (allocator) HNewArray(
    601       constant_10,
    602       constant_10,
    603       0);
    604   block->AddInstruction(new_array);
    605   block->AddInstruction(new (allocator) HGoto());
    606 
    607   HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
    608   HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
    609   HBasicBlock* exit = new (allocator) HBasicBlock(graph);
    610 
    611   graph->AddBlock(loop_header);
    612   graph->AddBlock(loop_body);
    613   graph->AddBlock(exit);
    614   block->AddSuccessor(loop_header);
    615   loop_header->AddSuccessor(exit);       // true successor
    616   loop_header->AddSuccessor(loop_body);  // false successor
    617   loop_body->AddSuccessor(loop_header);
    618 
    619   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
    620   HInstruction* cmp = nullptr;
    621   if (cond == kCondGE) {
    622     cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
    623   } else {
    624     DCHECK(cond == kCondGT);
    625     cmp = new (allocator) HGreaterThan(phi, constant_10);
    626   }
    627   HInstruction* if_inst = new (allocator) HIf(cmp);
    628   loop_header->AddPhi(phi);
    629   loop_header->AddInstruction(cmp);
    630   loop_header->AddInstruction(if_inst);
    631   phi->AddInput(constant_initial);
    632 
    633   HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
    634   HArrayLength* array_length = new (allocator) HArrayLength(null_check, 0);
    635   HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
    636   HInstruction* array_set = new (allocator) HArraySet(
    637       null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
    638   HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
    639   loop_body->AddInstruction(null_check);
    640   loop_body->AddInstruction(array_length);
    641   loop_body->AddInstruction(bounds_check);
    642   loop_body->AddInstruction(array_set);
    643   loop_body->AddInstruction(add);
    644   loop_body->AddInstruction(new (allocator) HGoto());
    645   phi->AddInput(add);
    646 
    647   exit->AddInstruction(new (allocator) HExit());
    648 
    649   return bounds_check;
    650 }
    651 
    652 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3a) {
    653   // int[] array = new int[10];
    654   // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
    655   HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 0, 1, kCondGE);
    656   RunBCE();
    657   ASSERT_TRUE(IsRemoved(bounds_check));
    658 }
    659 
    660 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3b) {
    661   // int[] array = new int[10];
    662   // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
    663   HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 1, 1, kCondGE);
    664   RunBCE();
    665   ASSERT_TRUE(IsRemoved(bounds_check));
    666 }
    667 
    668 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3c) {
    669   // int[] array = new int[10];
    670   // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
    671   HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 0, 1, kCondGT);
    672   RunBCE();
    673   ASSERT_FALSE(IsRemoved(bounds_check));
    674 }
    675 
    676 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3d) {
    677   // int[] array = new int[10];
    678   // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
    679   HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 1, 8, kCondGE);
    680   RunBCE();
    681   ASSERT_TRUE(IsRemoved(bounds_check));
    682 }
    683 
    684 // for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
    685 static HInstruction* BuildSSAGraph4(HGraph* graph,
    686                                     ArenaAllocator* allocator,
    687                                     int initial,
    688                                     IfCondition cond = kCondGE) {
    689   HBasicBlock* entry = new (allocator) HBasicBlock(graph);
    690   graph->AddBlock(entry);
    691   graph->SetEntryBlock(entry);
    692   HInstruction* parameter = new (allocator) HParameterValue(
    693       graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
    694   entry->AddInstruction(parameter);
    695 
    696   HInstruction* constant_initial = graph->GetIntConstant(initial);
    697   HInstruction* constant_1 = graph->GetIntConstant(1);
    698   HInstruction* constant_10 = graph->GetIntConstant(10);
    699   HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
    700 
    701   HBasicBlock* block = new (allocator) HBasicBlock(graph);
    702   graph->AddBlock(block);
    703   entry->AddSuccessor(block);
    704   block->AddInstruction(new (allocator) HGoto());
    705 
    706   HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
    707   HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
    708   HBasicBlock* exit = new (allocator) HBasicBlock(graph);
    709 
    710   graph->AddBlock(loop_header);
    711   graph->AddBlock(loop_body);
    712   graph->AddBlock(exit);
    713   block->AddSuccessor(loop_header);
    714   loop_header->AddSuccessor(exit);       // true successor
    715   loop_header->AddSuccessor(loop_body);  // false successor
    716   loop_body->AddSuccessor(loop_header);
    717 
    718   HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
    719   HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
    720   HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
    721   HInstruction* cmp = nullptr;
    722   if (cond == kCondGE) {
    723     cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
    724   } else if (cond == kCondGT) {
    725     cmp = new (allocator) HGreaterThan(phi, array_length);
    726   }
    727   HInstruction* if_inst = new (allocator) HIf(cmp);
    728   loop_header->AddPhi(phi);
    729   loop_header->AddInstruction(null_check);
    730   loop_header->AddInstruction(array_length);
    731   loop_header->AddInstruction(cmp);
    732   loop_header->AddInstruction(if_inst);
    733   phi->AddInput(constant_initial);
    734 
    735   null_check = new (allocator) HNullCheck(parameter, 0);
    736   array_length = new (allocator) HArrayLength(null_check, 0);
    737   HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
    738   HInstruction* add_minus_1 = new (allocator)
    739       HAdd(Primitive::kPrimInt, sub, constant_minus_1);
    740   HInstruction* bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
    741   HInstruction* array_set = new (allocator) HArraySet(
    742       null_check, bounds_check, constant_10, Primitive::kPrimInt, 0);
    743   HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
    744   loop_body->AddInstruction(null_check);
    745   loop_body->AddInstruction(array_length);
    746   loop_body->AddInstruction(sub);
    747   loop_body->AddInstruction(add_minus_1);
    748   loop_body->AddInstruction(bounds_check);
    749   loop_body->AddInstruction(array_set);
    750   loop_body->AddInstruction(add);
    751   loop_body->AddInstruction(new (allocator) HGoto());
    752   phi->AddInput(add);
    753 
    754   exit->AddInstruction(new (allocator) HExit());
    755 
    756   return bounds_check;
    757 }
    758 
    759 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4a) {
    760   // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
    761   HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 0);
    762   RunBCE();
    763   ASSERT_TRUE(IsRemoved(bounds_check));
    764 }
    765 
    766 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4b) {
    767   // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
    768   HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 1);
    769   RunBCE();
    770   ASSERT_TRUE(IsRemoved(bounds_check));
    771 }
    772 
    773 TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4c) {
    774   // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
    775   HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 0, kCondGT);
    776   RunBCE();
    777   ASSERT_FALSE(IsRemoved(bounds_check));
    778 }
    779 
    780 // Bubble sort:
    781 // (Every array access bounds-check can be eliminated.)
    782 // for (int i=0; i<array.length-1; i++) {
    783 //  for (int j=0; j<array.length-i-1; j++) {
    784 //     if (array[j] > array[j+1]) {
    785 //       int temp = array[j+1];
    786 //       array[j+1] = array[j];
    787 //       array[j] = temp;
    788 //     }
    789 //  }
    790 // }
    791 TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
    792   HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
    793   graph_->AddBlock(entry);
    794   graph_->SetEntryBlock(entry);
    795   HInstruction* parameter = new (&allocator_) HParameterValue(
    796       graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
    797   entry->AddInstruction(parameter);
    798 
    799   HInstruction* constant_0 = graph_->GetIntConstant(0);
    800   HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
    801   HInstruction* constant_1 = graph_->GetIntConstant(1);
    802 
    803   HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
    804   graph_->AddBlock(block);
    805   entry->AddSuccessor(block);
    806   block->AddInstruction(new (&allocator_) HGoto());
    807 
    808   HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
    809   graph_->AddBlock(exit);
    810   exit->AddInstruction(new (&allocator_) HExit());
    811 
    812   HBasicBlock* outer_header = new (&allocator_) HBasicBlock(graph_);
    813   graph_->AddBlock(outer_header);
    814   HPhi* phi_i = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
    815   HNullCheck* null_check = new (&allocator_) HNullCheck(parameter, 0);
    816   HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
    817   HAdd* add = new (&allocator_) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
    818   HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi_i, add);
    819   HIf* if_inst = new (&allocator_) HIf(cmp);
    820   outer_header->AddPhi(phi_i);
    821   outer_header->AddInstruction(null_check);
    822   outer_header->AddInstruction(array_length);
    823   outer_header->AddInstruction(add);
    824   outer_header->AddInstruction(cmp);
    825   outer_header->AddInstruction(if_inst);
    826   phi_i->AddInput(constant_0);
    827 
    828   HBasicBlock* inner_header = new (&allocator_) HBasicBlock(graph_);
    829   graph_->AddBlock(inner_header);
    830   HPhi* phi_j = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
    831   null_check = new (&allocator_) HNullCheck(parameter, 0);
    832   array_length = new (&allocator_) HArrayLength(null_check, 0);
    833   HSub* sub = new (&allocator_) HSub(Primitive::kPrimInt, array_length, phi_i);
    834   add = new (&allocator_) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
    835   cmp = new (&allocator_) HGreaterThanOrEqual(phi_j, add);
    836   if_inst = new (&allocator_) HIf(cmp);
    837   inner_header->AddPhi(phi_j);
    838   inner_header->AddInstruction(null_check);
    839   inner_header->AddInstruction(array_length);
    840   inner_header->AddInstruction(sub);
    841   inner_header->AddInstruction(add);
    842   inner_header->AddInstruction(cmp);
    843   inner_header->AddInstruction(if_inst);
    844   phi_j->AddInput(constant_0);
    845 
    846   HBasicBlock* inner_body_compare = new (&allocator_) HBasicBlock(graph_);
    847   graph_->AddBlock(inner_body_compare);
    848   null_check = new (&allocator_) HNullCheck(parameter, 0);
    849   array_length = new (&allocator_) HArrayLength(null_check, 0);
    850   HBoundsCheck* bounds_check1 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
    851   HArrayGet* array_get_j = new (&allocator_)
    852       HArrayGet(null_check, bounds_check1, Primitive::kPrimInt, 0);
    853   inner_body_compare->AddInstruction(null_check);
    854   inner_body_compare->AddInstruction(array_length);
    855   inner_body_compare->AddInstruction(bounds_check1);
    856   inner_body_compare->AddInstruction(array_get_j);
    857   HInstruction* j_plus_1 = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
    858   null_check = new (&allocator_) HNullCheck(parameter, 0);
    859   array_length = new (&allocator_) HArrayLength(null_check, 0);
    860   HBoundsCheck* bounds_check2 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
    861   HArrayGet* array_get_j_plus_1 = new (&allocator_)
    862       HArrayGet(null_check, bounds_check2, Primitive::kPrimInt, 0);
    863   cmp = new (&allocator_) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
    864   if_inst = new (&allocator_) HIf(cmp);
    865   inner_body_compare->AddInstruction(j_plus_1);
    866   inner_body_compare->AddInstruction(null_check);
    867   inner_body_compare->AddInstruction(array_length);
    868   inner_body_compare->AddInstruction(bounds_check2);
    869   inner_body_compare->AddInstruction(array_get_j_plus_1);
    870   inner_body_compare->AddInstruction(cmp);
    871   inner_body_compare->AddInstruction(if_inst);
    872 
    873   HBasicBlock* inner_body_swap = new (&allocator_) HBasicBlock(graph_);
    874   graph_->AddBlock(inner_body_swap);
    875   j_plus_1 = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
    876   // temp = array[j+1]
    877   null_check = new (&allocator_) HNullCheck(parameter, 0);
    878   array_length = new (&allocator_) HArrayLength(null_check, 0);
    879   HInstruction* bounds_check3 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
    880   array_get_j_plus_1 = new (&allocator_)
    881       HArrayGet(null_check, bounds_check3, Primitive::kPrimInt, 0);
    882   inner_body_swap->AddInstruction(j_plus_1);
    883   inner_body_swap->AddInstruction(null_check);
    884   inner_body_swap->AddInstruction(array_length);
    885   inner_body_swap->AddInstruction(bounds_check3);
    886   inner_body_swap->AddInstruction(array_get_j_plus_1);
    887   // array[j+1] = array[j]
    888   null_check = new (&allocator_) HNullCheck(parameter, 0);
    889   array_length = new (&allocator_) HArrayLength(null_check, 0);
    890   HInstruction* bounds_check4 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
    891   array_get_j = new (&allocator_)
    892       HArrayGet(null_check, bounds_check4, Primitive::kPrimInt, 0);
    893   inner_body_swap->AddInstruction(null_check);
    894   inner_body_swap->AddInstruction(array_length);
    895   inner_body_swap->AddInstruction(bounds_check4);
    896   inner_body_swap->AddInstruction(array_get_j);
    897   null_check = new (&allocator_) HNullCheck(parameter, 0);
    898   array_length = new (&allocator_) HArrayLength(null_check, 0);
    899   HInstruction* bounds_check5 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
    900   HArraySet* array_set_j_plus_1 = new (&allocator_)
    901       HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
    902   inner_body_swap->AddInstruction(null_check);
    903   inner_body_swap->AddInstruction(array_length);
    904   inner_body_swap->AddInstruction(bounds_check5);
    905   inner_body_swap->AddInstruction(array_set_j_plus_1);
    906   // array[j] = temp
    907   null_check = new (&allocator_) HNullCheck(parameter, 0);
    908   array_length = new (&allocator_) HArrayLength(null_check, 0);
    909   HInstruction* bounds_check6 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
    910   HArraySet* array_set_j = new (&allocator_)
    911       HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
    912   inner_body_swap->AddInstruction(null_check);
    913   inner_body_swap->AddInstruction(array_length);
    914   inner_body_swap->AddInstruction(bounds_check6);
    915   inner_body_swap->AddInstruction(array_set_j);
    916   inner_body_swap->AddInstruction(new (&allocator_) HGoto());
    917 
    918   HBasicBlock* inner_body_add = new (&allocator_) HBasicBlock(graph_);
    919   graph_->AddBlock(inner_body_add);
    920   add = new (&allocator_) HAdd(Primitive::kPrimInt, phi_j, constant_1);
    921   inner_body_add->AddInstruction(add);
    922   inner_body_add->AddInstruction(new (&allocator_) HGoto());
    923   phi_j->AddInput(add);
    924 
    925   HBasicBlock* outer_body_add = new (&allocator_) HBasicBlock(graph_);
    926   graph_->AddBlock(outer_body_add);
    927   add = new (&allocator_) HAdd(Primitive::kPrimInt, phi_i, constant_1);
    928   outer_body_add->AddInstruction(add);
    929   outer_body_add->AddInstruction(new (&allocator_) HGoto());
    930   phi_i->AddInput(add);
    931 
    932   block->AddSuccessor(outer_header);
    933   outer_header->AddSuccessor(exit);
    934   outer_header->AddSuccessor(inner_header);
    935   inner_header->AddSuccessor(outer_body_add);
    936   inner_header->AddSuccessor(inner_body_compare);
    937   inner_body_compare->AddSuccessor(inner_body_add);
    938   inner_body_compare->AddSuccessor(inner_body_swap);
    939   inner_body_swap->AddSuccessor(inner_body_add);
    940   inner_body_add->AddSuccessor(inner_header);
    941   outer_body_add->AddSuccessor(outer_header);
    942 
    943   RunBCE();  // gvn removes same bounds check already
    944 
    945   ASSERT_TRUE(IsRemoved(bounds_check1));
    946   ASSERT_TRUE(IsRemoved(bounds_check2));
    947   ASSERT_TRUE(IsRemoved(bounds_check3));
    948   ASSERT_TRUE(IsRemoved(bounds_check4));
    949   ASSERT_TRUE(IsRemoved(bounds_check5));
    950   ASSERT_TRUE(IsRemoved(bounds_check6));
    951 }
    952 
    953 }  // namespace art
    954