Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2015 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 <regex>
     18 
     19 #include "base/arena_allocator.h"
     20 #include "builder.h"
     21 #include "induction_var_analysis.h"
     22 #include "nodes.h"
     23 #include "optimizing_unit_test.h"
     24 
     25 namespace art {
     26 
     27 /**
     28  * Fixture class for the InductionVarAnalysis tests.
     29  */
     30 class InductionVarAnalysisTest : public OptimizingUnitTest {
     31  public:
     32   InductionVarAnalysisTest()
     33       : iva_(nullptr),
     34         entry_(nullptr),
     35         return_(nullptr),
     36         exit_(nullptr),
     37         parameter_(nullptr),
     38         constant0_(nullptr),
     39         constant1_(nullptr),
     40         constant2_(nullptr),
     41         constant7_(nullptr),
     42         constant100_(nullptr),
     43         constantm1_(nullptr),
     44         float_constant0_(nullptr) {
     45     graph_ = CreateGraph();
     46   }
     47 
     48   ~InductionVarAnalysisTest() { }
     49 
     50   // Builds single for-loop at depth d.
     51   void BuildForLoop(int d, int n) {
     52     ASSERT_LT(d, n);
     53     loop_preheader_[d] = new (GetAllocator()) HBasicBlock(graph_);
     54     graph_->AddBlock(loop_preheader_[d]);
     55     loop_header_[d] = new (GetAllocator()) HBasicBlock(graph_);
     56     graph_->AddBlock(loop_header_[d]);
     57     loop_preheader_[d]->AddSuccessor(loop_header_[d]);
     58     if (d < (n - 1)) {
     59       BuildForLoop(d + 1, n);
     60     }
     61     loop_body_[d] = new (GetAllocator()) HBasicBlock(graph_);
     62     graph_->AddBlock(loop_body_[d]);
     63     loop_body_[d]->AddSuccessor(loop_header_[d]);
     64     if (d < (n - 1)) {
     65       loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
     66       loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
     67     } else {
     68       loop_header_[d]->AddSuccessor(loop_body_[d]);
     69     }
     70   }
     71 
     72   // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
     73   // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
     74   // populate the loop with instructions to set up interesting scenarios.
     75   void BuildLoopNest(int n) {
     76     ASSERT_LE(n, 10);
     77     graph_->SetNumberOfVRegs(n + 3);
     78 
     79     // Build basic blocks with entry, nested loop, exit.
     80     entry_ = new (GetAllocator()) HBasicBlock(graph_);
     81     graph_->AddBlock(entry_);
     82     BuildForLoop(0, n);
     83     return_ = new (GetAllocator()) HBasicBlock(graph_);
     84     graph_->AddBlock(return_);
     85     exit_ = new (GetAllocator()) HBasicBlock(graph_);
     86     graph_->AddBlock(exit_);
     87     entry_->AddSuccessor(loop_preheader_[0]);
     88     loop_header_[0]->AddSuccessor(return_);
     89     return_->AddSuccessor(exit_);
     90     graph_->SetEntryBlock(entry_);
     91     graph_->SetExitBlock(exit_);
     92 
     93     // Provide entry and exit instructions.
     94     parameter_ = new (GetAllocator()) HParameterValue(
     95         graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true);
     96     entry_->AddInstruction(parameter_);
     97     constant0_ = graph_->GetIntConstant(0);
     98     constant1_ = graph_->GetIntConstant(1);
     99     constant2_ = graph_->GetIntConstant(2);
    100     constant7_ = graph_->GetIntConstant(7);
    101     constant100_ = graph_->GetIntConstant(100);
    102     constantm1_ = graph_->GetIntConstant(-1);
    103     float_constant0_ = graph_->GetFloatConstant(0.0f);
    104     return_->AddInstruction(new (GetAllocator()) HReturnVoid());
    105     exit_->AddInstruction(new (GetAllocator()) HExit());
    106 
    107     // Provide loop instructions.
    108     for (int d = 0; d < n; d++) {
    109       basic_[d] = new (GetAllocator()) HPhi(GetAllocator(), d, 0, DataType::Type::kInt32);
    110       loop_preheader_[d]->AddInstruction(new (GetAllocator()) HGoto());
    111       loop_header_[d]->AddPhi(basic_[d]);
    112       HInstruction* compare = new (GetAllocator()) HLessThan(basic_[d], constant100_);
    113       loop_header_[d]->AddInstruction(compare);
    114       loop_header_[d]->AddInstruction(new (GetAllocator()) HIf(compare));
    115       increment_[d] = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[d], constant1_);
    116       loop_body_[d]->AddInstruction(increment_[d]);
    117       loop_body_[d]->AddInstruction(new (GetAllocator()) HGoto());
    118 
    119       basic_[d]->AddInput(constant0_);
    120       basic_[d]->AddInput(increment_[d]);
    121     }
    122   }
    123 
    124   // Builds if-statement at depth d.
    125   HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
    126     HBasicBlock* cond = new (GetAllocator()) HBasicBlock(graph_);
    127     HBasicBlock* ifTrue = new (GetAllocator()) HBasicBlock(graph_);
    128     HBasicBlock* ifFalse = new (GetAllocator()) HBasicBlock(graph_);
    129     graph_->AddBlock(cond);
    130     graph_->AddBlock(ifTrue);
    131     graph_->AddBlock(ifFalse);
    132     // Conditional split.
    133     loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
    134     cond->AddSuccessor(ifTrue);
    135     cond->AddSuccessor(ifFalse);
    136     ifTrue->AddSuccessor(loop_body_[d]);
    137     ifFalse->AddSuccessor(loop_body_[d]);
    138     cond->AddInstruction(new (GetAllocator()) HIf(parameter_));
    139     *ifT = ifTrue;
    140     *ifF = ifFalse;
    141 
    142     HPhi* select_phi = new (GetAllocator()) HPhi(GetAllocator(), -1, 0, DataType::Type::kInt32);
    143     loop_body_[d]->AddPhi(select_phi);
    144     return select_phi;
    145   }
    146 
    147   // Inserts instruction right before increment at depth d.
    148   HInstruction* InsertInstruction(HInstruction* instruction, int d) {
    149     loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
    150     return instruction;
    151   }
    152 
    153   // Inserts a phi to loop header at depth d and returns it.
    154   HPhi* InsertLoopPhi(int vreg, int d) {
    155     HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), vreg, 0, DataType::Type::kInt32);
    156     loop_header_[d]->AddPhi(phi);
    157     return phi;
    158   }
    159 
    160   // Inserts an array store with given `subscript` at depth d to
    161   // enable tests to inspect the computed induction at that point easily.
    162   HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
    163     // ArraySet is given a float value in order to avoid SsaBuilder typing
    164     // it from the array's non-existent reference type info.
    165     return InsertInstruction(new (GetAllocator()) HArraySet(
    166         parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d);
    167   }
    168 
    169   // Returns induction information of instruction in loop at depth d.
    170   std::string GetInductionInfo(HInstruction* instruction, int d) {
    171     return HInductionVarAnalysis::InductionToString(
    172         iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
    173   }
    174 
    175   // Returns induction information of the trip-count of loop at depth d.
    176   std::string GetTripCount(int d) {
    177     HInstruction* control = loop_header_[d]->GetLastInstruction();
    178     DCHECK(control->IsIf());
    179     return GetInductionInfo(control, d);
    180   }
    181 
    182   // Returns true if instructions have identical induction.
    183   bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
    184     return HInductionVarAnalysis::InductionEqual(
    185       iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
    186       iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
    187   }
    188 
    189   // Returns true for narrowing linear induction.
    190   bool IsNarrowingLinear(HInstruction* instruction) {
    191     return HInductionVarAnalysis::IsNarrowingLinear(
    192         iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction));
    193   }
    194 
    195   // Performs InductionVarAnalysis (after proper set up).
    196   void PerformInductionVarAnalysis() {
    197     graph_->BuildDominatorTree();
    198     iva_ = new (GetAllocator()) HInductionVarAnalysis(graph_);
    199     iva_->Run();
    200   }
    201 
    202   // General building fields.
    203   HGraph* graph_;
    204   HInductionVarAnalysis* iva_;
    205 
    206   // Fixed basic blocks and instructions.
    207   HBasicBlock* entry_;
    208   HBasicBlock* return_;
    209   HBasicBlock* exit_;
    210   HInstruction* parameter_;  // "this"
    211   HInstruction* constant0_;
    212   HInstruction* constant1_;
    213   HInstruction* constant2_;
    214   HInstruction* constant7_;
    215   HInstruction* constant100_;
    216   HInstruction* constantm1_;
    217   HInstruction* float_constant0_;
    218 
    219   // Loop specifics.
    220   HBasicBlock* loop_preheader_[10];
    221   HBasicBlock* loop_header_[10];
    222   HBasicBlock* loop_body_[10];
    223   HInstruction* increment_[10];
    224   HPhi* basic_[10];  // "vreg_d", the "i_d"
    225 };
    226 
    227 //
    228 // The actual InductionVarAnalysis tests.
    229 //
    230 
    231 TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
    232   // Setup:
    233   // for (int i_0 = 0; i_0 < 100; i_0++) {
    234   //   ..
    235   //     for (int i_9 = 0; i_9 < 100; i_9++) {
    236   //     }
    237   //   ..
    238   // }
    239   BuildLoopNest(10);
    240   graph_->BuildDominatorTree();
    241 
    242   ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
    243   for (int d = 0; d < 1; d++) {
    244     ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
    245               (d == 0) ? nullptr
    246                        : loop_header_[d - 1]->GetLoopInformation());
    247     ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
    248     ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
    249     ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
    250               loop_body_[d]->GetLoopInformation());
    251   }
    252   ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
    253 }
    254 
    255 TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
    256   // Setup:
    257   // for (int i = 0; i < 100; i++) {
    258   //   a[i] = 0;
    259   // }
    260   BuildLoopNest(1);
    261   HInstruction* store = InsertArrayStore(basic_[0], 0);
    262   PerformInductionVarAnalysis();
    263 
    264   EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
    265   EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
    266 
    267   // Offset matters!
    268   EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
    269 
    270   // Trip-count.
    271   EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
    272 }
    273 
    274 TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
    275   // Setup:
    276   // for (int i = 0; i < 100; i++) {
    277   //   t = 100 + i;
    278   //   t = 100 - i;
    279   //   t = 100 * i;
    280   //   t = i << 1;
    281   //   t = - i;
    282   // }
    283   BuildLoopNest(1);
    284   HInstruction* add = InsertInstruction(
    285       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0);
    286   HInstruction* sub = InsertInstruction(
    287       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
    288   HInstruction* mul = InsertInstruction(
    289       new (GetAllocator()) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0);
    290   HInstruction* shl = InsertInstruction(
    291       new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
    292   HInstruction* neg = InsertInstruction(
    293       new (GetAllocator()) HNeg(DataType::Type::kInt32, basic_[0]), 0);
    294   PerformInductionVarAnalysis();
    295 
    296   EXPECT_STREQ("((1) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
    297   EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
    298   EXPECT_STREQ("((100) * i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
    299   EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl, 0).c_str());
    300   EXPECT_STREQ("(( - (1)) * i + (0)):Int32", GetInductionInfo(neg, 0).c_str());
    301 }
    302 
    303 TEST_F(InductionVarAnalysisTest, FindChainInduction) {
    304   // Setup:
    305   // k = 0;
    306   // for (int i = 0; i < 100; i++) {
    307   //   k = k + 100;
    308   //   a[k] = 0;
    309   //   k = k - 1;
    310   //   a[k] = 0;
    311   // }
    312   BuildLoopNest(1);
    313   HPhi* k_header = InsertLoopPhi(0, 0);
    314   k_header->AddInput(constant0_);
    315 
    316   HInstruction* add = InsertInstruction(
    317       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
    318   HInstruction* store1 = InsertArrayStore(add, 0);
    319   HInstruction* sub = InsertInstruction(
    320       new (GetAllocator()) HSub(DataType::Type::kInt32, add, constant1_), 0);
    321   HInstruction* store2 = InsertArrayStore(sub, 0);
    322   k_header->AddInput(sub);
    323   PerformInductionVarAnalysis();
    324 
    325   EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32",
    326                GetInductionInfo(k_header, 0).c_str());
    327   EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32",
    328                GetInductionInfo(store1->InputAt(1), 0).c_str());
    329   EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32",
    330                GetInductionInfo(store2->InputAt(1), 0).c_str());
    331 }
    332 
    333 TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
    334   // Setup:
    335   // k = 0;
    336   // for (int i = 0; i < 100; i++) {
    337   //   if () k = k + 1;
    338   //   else  k = k + 1;
    339   //   a[k] = 0;
    340   // }
    341   BuildLoopNest(1);
    342   HPhi* k_header = InsertLoopPhi(0, 0);
    343   k_header->AddInput(constant0_);
    344 
    345   HBasicBlock* ifTrue;
    346   HBasicBlock* ifFalse;
    347   HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
    348 
    349   // True-branch.
    350   HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
    351   ifTrue->AddInstruction(inc1);
    352   k_body->AddInput(inc1);
    353   // False-branch.
    354   HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
    355   ifFalse->AddInstruction(inc2);
    356   k_body->AddInput(inc2);
    357   // Merge over a phi.
    358   HInstruction* store = InsertArrayStore(k_body, 0);
    359   k_header->AddInput(k_body);
    360   PerformInductionVarAnalysis();
    361 
    362   EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
    363   EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
    364 
    365   // Both increments get same induction.
    366   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
    367   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
    368 }
    369 
    370 TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
    371   // Setup:
    372   // for (int i = 0; i < 100; i++) {
    373   //   if () k = i + 1;
    374   //   else  k = i + 1;
    375   //   a[k] = 0;
    376   // }
    377   BuildLoopNest(1);
    378   HBasicBlock* ifTrue;
    379   HBasicBlock* ifFalse;
    380   HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
    381 
    382   // True-branch.
    383   HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
    384   ifTrue->AddInstruction(inc1);
    385   k->AddInput(inc1);
    386   // False-branch.
    387   HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
    388   ifFalse->AddInstruction(inc2);
    389   k->AddInput(inc2);
    390   // Merge over a phi.
    391   HInstruction* store = InsertArrayStore(k, 0);
    392   PerformInductionVarAnalysis();
    393 
    394   EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
    395 
    396   // Both increments get same induction.
    397   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
    398   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
    399 }
    400 
    401 TEST_F(InductionVarAnalysisTest, AddLinear) {
    402   // Setup:
    403   // for (int i = 0; i < 100; i++) {
    404   //   t1 = i + i;
    405   //   t2 = 7 + i;
    406   //   t3 = t1 + t2;
    407   // }
    408   BuildLoopNest(1);
    409 
    410   HInstruction* add1 = InsertInstruction(
    411       new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0);
    412   HInstruction* add2 = InsertInstruction(
    413       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0);
    414   HInstruction* add3 = InsertInstruction(
    415       new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, add2), 0);
    416   PerformInductionVarAnalysis();
    417 
    418   EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(basic_[0], 0).c_str());
    419   EXPECT_STREQ("(((1) + (1)) * i + (0)):Int32", GetInductionInfo(add1, 0).c_str());
    420   EXPECT_STREQ("((1) * i + (7)):Int32", GetInductionInfo(add2, 0).c_str());
    421   EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):Int32", GetInductionInfo(add3, 0).c_str());
    422 }
    423 
    424 TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
    425   // Setup:
    426   // k = 1;
    427   // for (int i = 0; i < 100; i++) {
    428   //   t = i * 2;
    429   //   t = 100 + t
    430   //   k = t + k;  // polynomial
    431   // }
    432   BuildLoopNest(1);
    433   HPhi* k_header = InsertLoopPhi(0, 0);
    434   k_header->AddInput(constant1_);
    435 
    436   HInstruction* mul = InsertInstruction(
    437       new (GetAllocator()) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0);
    438   HInstruction* add = InsertInstruction(
    439       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, mul), 0);
    440   HInstruction* pol = InsertInstruction(
    441       new (GetAllocator()) HAdd(DataType::Type::kInt32, add, k_header), 0);
    442   k_header->AddInput(pol);
    443   PerformInductionVarAnalysis();
    444 
    445   // Note, only the phi in the cycle and the base linear induction are classified.
    446   EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32",
    447                GetInductionInfo(k_header, 0).c_str());
    448   EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
    449   EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
    450 }
    451 
    452 TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
    453   // Setup:
    454   // k = 1;
    455   // for (int i = 0; i < 100; i++) {
    456   //   t = k + 100;
    457   //   t = k - 1;
    458   //   t = - t
    459   //   t = k * 2;
    460   //   t = k << 2;
    461   //   k = k + i;  // polynomial
    462   // }
    463   BuildLoopNest(1);
    464   HPhi* k_header = InsertLoopPhi(0, 0);
    465   k_header->AddInput(constant1_);
    466 
    467   HInstruction* add = InsertInstruction(
    468       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
    469   HInstruction* sub = InsertInstruction(
    470       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
    471   HInstruction* neg = InsertInstruction(
    472       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
    473   HInstruction* mul = InsertInstruction(
    474       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
    475   HInstruction* shl = InsertInstruction(
    476       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
    477   HInstruction* pol = InsertInstruction(
    478       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
    479   k_header->AddInput(pol);
    480   PerformInductionVarAnalysis();
    481 
    482   // Note, only the phi in the cycle and derived are classified.
    483   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32",
    484                GetInductionInfo(k_header, 0).c_str());
    485   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32",
    486                GetInductionInfo(add, 0).c_str());
    487   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32",
    488                GetInductionInfo(sub, 0).c_str());
    489   EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32",
    490                GetInductionInfo(neg, 0).c_str());
    491   EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32",
    492                GetInductionInfo(mul, 0).c_str());
    493   EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32",
    494                GetInductionInfo(shl, 0).c_str());
    495   EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
    496 }
    497 
    498 TEST_F(InductionVarAnalysisTest, AddPolynomial) {
    499   // Setup:
    500   // k = 7;
    501   // for (int i = 0; i < 100; i++) {
    502   //   t = k + k;
    503   //   t = t + k;
    504   //   k = k + i
    505   // }
    506   BuildLoopNest(1);
    507   HPhi* k_header = InsertLoopPhi(0, 0);
    508   k_header->AddInput(constant7_);
    509 
    510   HInstruction* add1 = InsertInstruction(
    511       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, k_header), 0);
    512   HInstruction* add2 = InsertInstruction(
    513       new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, k_header), 0);
    514   HInstruction* add3 = InsertInstruction(
    515       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
    516   k_header->AddInput(add3);
    517   PerformInductionVarAnalysis();
    518 
    519   // Note, only the phi in the cycle and added-derived are classified.
    520   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32",
    521                GetInductionInfo(k_header, 0).c_str());
    522   EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32",
    523                GetInductionInfo(add1, 0).c_str());
    524   EXPECT_STREQ(
    525       "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32",
    526       GetInductionInfo(add2, 0).c_str());
    527   EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
    528 }
    529 
    530 TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
    531   // Setup:
    532   // k = 1;
    533   // for (int i = 0; i < 100; i++) {
    534   //   k = k * 100;  // geometric (x 100)
    535   // }
    536   BuildLoopNest(1);
    537   HPhi* k_header = InsertLoopPhi(0, 0);
    538   k_header->AddInput(constant1_);
    539 
    540   HInstruction* mul = InsertInstruction(
    541       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
    542   k_header->AddInput(mul);
    543   PerformInductionVarAnalysis();
    544 
    545   EXPECT_STREQ("geo((1) * 100 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
    546   EXPECT_STREQ("geo((100) * 100 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
    547 }
    548 
    549 TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
    550   // Setup:
    551   // k = 1;
    552   // for (int i = 0; i < 100; i++) {
    553   //   t = k + 1;
    554   //   k = k << 1;  // geometric (x 2)
    555   //   t = k + 100;
    556   //   t = k - 1;
    557   //   t = - t;
    558   //   t = k * 2;
    559   //   t = k << 2;
    560   // }
    561   BuildLoopNest(1);
    562   HPhi* k_header = InsertLoopPhi(0, 0);
    563   k_header->AddInput(constant1_);
    564 
    565   HInstruction* add1 = InsertInstruction(
    566       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
    567   HInstruction* shl1 = InsertInstruction(
    568       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
    569   HInstruction* add2 = InsertInstruction(
    570       new (GetAllocator()) HAdd(DataType::Type::kInt32, shl1, constant100_), 0);
    571   HInstruction* sub = InsertInstruction(
    572       new (GetAllocator()) HSub(DataType::Type::kInt32, shl1, constant1_), 0);
    573   HInstruction* neg = InsertInstruction(
    574       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
    575   HInstruction* mul = InsertInstruction(
    576       new (GetAllocator()) HMul(DataType::Type::kInt32, shl1, constant2_), 0);
    577   HInstruction* shl2 = InsertInstruction(
    578       new (GetAllocator()) HShl(DataType::Type::kInt32, shl1, constant2_), 0);
    579   k_header->AddInput(shl1);
    580   PerformInductionVarAnalysis();
    581 
    582   EXPECT_STREQ("geo((1) * 2 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
    583   EXPECT_STREQ("geo((1) * 2 ^ i + (1)):Int32", GetInductionInfo(add1, 0).c_str());
    584   EXPECT_STREQ("geo((2) * 2 ^ i + (0)):Int32", GetInductionInfo(shl1, 0).c_str());
    585   EXPECT_STREQ("geo((2) * 2 ^ i + (100)):Int32", GetInductionInfo(add2, 0).c_str());
    586   EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
    587   EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):Int32",
    588                GetInductionInfo(neg, 0).c_str());
    589   EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
    590   EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
    591 }
    592 
    593 TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
    594   // Setup:
    595   // k = 1;
    596   // for (int i = 0; i < 100; i++) {
    597   //   t = k + 100;
    598   //   t = k - 1;
    599   //   t = - t
    600   //   t = k * 2;
    601   //   t = k << 2;
    602   //   k = k / 100;  // geometric (/ 100)
    603   // }
    604   BuildLoopNest(1);
    605   HPhi* k_header = InsertLoopPhi(0, 0);
    606   k_header->AddInput(constant1_);
    607 
    608   HInstruction* add = InsertInstruction(
    609       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
    610   HInstruction* sub = InsertInstruction(
    611       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
    612   HInstruction* neg = InsertInstruction(
    613       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
    614   HInstruction* mul = InsertInstruction(
    615       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
    616   HInstruction* shl = InsertInstruction(
    617       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
    618   HInstruction* div = InsertInstruction(
    619       new (GetAllocator()) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0);
    620   k_header->AddInput(div);
    621   PerformInductionVarAnalysis();
    622 
    623   // Note, only the phi in the cycle and direct additive derived are classified.
    624   EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
    625   EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):Int32", GetInductionInfo(add, 0).c_str());
    626   EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
    627   EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
    628   EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
    629   EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
    630   EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
    631 }
    632 
    633 TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
    634   // Setup:
    635   // k = 100;
    636   // for (int i = 0; i < 100; i++) {
    637   //   k = k >> 1;  // geometric (/ 2)
    638   // }
    639   BuildLoopNest(1);
    640   HPhi* k_header = InsertLoopPhi(0, 0);
    641   k_header->AddInput(constant100_);
    642 
    643   HInstruction* shr = InsertInstruction(
    644       new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
    645   k_header->AddInput(shr);
    646   PerformInductionVarAnalysis();
    647 
    648   // Note, only the phi in the cycle is classified.
    649   EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
    650   EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
    651 }
    652 
    653 TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
    654   // Setup:
    655   // k = -1;
    656   // for (int i = 0; i < 100; i++) {
    657   //   k = k >> 1;  // initial value is negative
    658   // }
    659   BuildLoopNest(1);
    660   HPhi* k_header = InsertLoopPhi(0, 0);
    661   k_header->AddInput(constantm1_);
    662 
    663   HInstruction* shr = InsertInstruction(
    664       new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
    665   k_header->AddInput(shr);
    666   PerformInductionVarAnalysis();
    667 
    668   EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
    669   EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
    670 }
    671 
    672 TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
    673   // Setup:
    674   // k = 100;
    675   // for (int i = 0; i < 100; i++) {
    676   //   t = k + 100;
    677   //   t = k - 1;
    678   //   t = -t
    679   //   t = k * 2;
    680   //   t = k << 2;
    681   //   k = k % 7;
    682   // }
    683   BuildLoopNest(1);
    684   HPhi* k_header = InsertLoopPhi(0, 0);
    685   k_header->AddInput(constant100_);
    686 
    687   HInstruction* add = InsertInstruction(
    688       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
    689   HInstruction* sub = InsertInstruction(
    690       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
    691   HInstruction* neg = InsertInstruction(
    692       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
    693   HInstruction* mul = InsertInstruction(
    694       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
    695   HInstruction* shl = InsertInstruction(
    696       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
    697   HInstruction* rem = InsertInstruction(
    698       new (GetAllocator()) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0);
    699   k_header->AddInput(rem);
    700   PerformInductionVarAnalysis();
    701 
    702   // Note, only the phi in the cycle and derived are classified.
    703   EXPECT_STREQ("wrap((100), ((100) % (7))):Int32", GetInductionInfo(k_header, 0).c_str());
    704   EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):Int32",
    705                GetInductionInfo(add, 0).c_str());
    706   EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):Int32",
    707                GetInductionInfo(sub, 0).c_str());
    708   EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):Int32",
    709                GetInductionInfo(neg, 0).c_str());
    710   EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):Int32",
    711                GetInductionInfo(mul, 0).c_str());
    712   EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):Int32",
    713                GetInductionInfo(shl, 0).c_str());
    714   EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
    715 }
    716 
    717 TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
    718   // Setup:
    719   // k = 0;
    720   // for (int i = 0; i < 100; i++) {
    721   //   a[k] = 0;
    722   //   k = 100 - i;
    723   // }
    724   BuildLoopNest(1);
    725   HPhi* k_header = InsertLoopPhi(0, 0);
    726   k_header->AddInput(constant0_);
    727 
    728   HInstruction* store = InsertArrayStore(k_header, 0);
    729   HInstruction* sub = InsertInstruction(
    730       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
    731   k_header->AddInput(sub);
    732   PerformInductionVarAnalysis();
    733 
    734   EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
    735                GetInductionInfo(k_header, 0).c_str());
    736   EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
    737                GetInductionInfo(store->InputAt(1), 0).c_str());
    738   EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
    739 }
    740 
    741 TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
    742   // Setup:
    743   // k = 0;
    744   // t = 100;
    745   // for (int i = 0; i < 100; i++) {
    746   //   a[k] = 0;
    747   //   k = t;
    748   //   t = 100 - i;
    749   // }
    750   BuildLoopNest(1);
    751   HPhi* k_header = InsertLoopPhi(0, 0);
    752   k_header->AddInput(constant0_);
    753   HPhi* t = InsertLoopPhi(1, 0);
    754   t->AddInput(constant100_);
    755 
    756   HInstruction* store = InsertArrayStore(k_header, 0);
    757   k_header->AddInput(t);
    758   HInstruction* sub = InsertInstruction(
    759       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0);
    760   t->AddInput(sub);
    761   PerformInductionVarAnalysis();
    762 
    763   EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32",
    764                GetInductionInfo(store->InputAt(1), 0).c_str());
    765 }
    766 
    767 TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
    768   // Setup:
    769   // k = 0;
    770   // for (int i = 0; i < 100; i++) {
    771   //   t = k + 100;
    772   //   t = k - 100;
    773   //   t = k * 100;
    774   //   t = k << 1;
    775   //   t = - k;
    776   //   k = i << 1;
    777   //   t = - k;
    778   // }
    779   BuildLoopNest(1);
    780   HPhi* k_header = InsertLoopPhi(0, 0);
    781   k_header->AddInput(constant0_);
    782 
    783   HInstruction* add = InsertInstruction(
    784       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
    785   HInstruction* sub = InsertInstruction(
    786       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant100_), 0);
    787   HInstruction* mul = InsertInstruction(
    788       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
    789   HInstruction* shl1 = InsertInstruction(
    790       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
    791   HInstruction* neg1 = InsertInstruction(
    792       new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
    793   HInstruction* shl2 = InsertInstruction(
    794       new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
    795   HInstruction* neg2 = InsertInstruction(
    796       new (GetAllocator()) HNeg(DataType::Type::kInt32, shl2), 0);
    797   k_header->AddInput(shl2);
    798   PerformInductionVarAnalysis();
    799 
    800   EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32",
    801                GetInductionInfo(add, 0).c_str());
    802   EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32",
    803                GetInductionInfo(sub, 0).c_str());
    804   EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32",
    805                GetInductionInfo(mul, 0).c_str());
    806   EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32",
    807                GetInductionInfo(shl1, 0).c_str());
    808   EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32",
    809                GetInductionInfo(neg1, 0).c_str());
    810   EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
    811   EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str());
    812 }
    813 
    814 TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
    815   // Setup:
    816   // k = 0;
    817   // t = 100;
    818   // for (int i = 0; i < 100; i++) {
    819   //   a[k] = 0;
    820   //   a[t] = 0;
    821   //   // Swap t <-> k.
    822   //   d = t;
    823   //   t = k;
    824   //   k = d;
    825   // }
    826   BuildLoopNest(1);
    827   HPhi* k_header = InsertLoopPhi(0, 0);
    828   k_header->AddInput(constant0_);
    829   HPhi* t = InsertLoopPhi(1, 0);
    830   t->AddInput(constant100_);
    831 
    832   HInstruction* store1 = InsertArrayStore(k_header, 0);
    833   HInstruction* store2 = InsertArrayStore(t, 0);
    834   k_header->AddInput(t);
    835   t->AddInput(k_header);
    836   PerformInductionVarAnalysis();
    837 
    838   EXPECT_STREQ("periodic((0), (100)):Int32", GetInductionInfo(store1->InputAt(1), 0).c_str());
    839   EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
    840 }
    841 
    842 TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
    843   // Setup:
    844   // k = 0;
    845   // for (int i = 0; i < 100; i++) {
    846   //   a[k] = 0;
    847   //   k = 1 - k;
    848   // }
    849   BuildLoopNest(1);
    850   HPhi* k_header = InsertLoopPhi(0, 0);
    851   k_header->AddInput(constant0_);
    852 
    853   HInstruction* store = InsertArrayStore(k_header, 0);
    854   HInstruction* sub = InsertInstruction(
    855       new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
    856   k_header->AddInput(sub);
    857   PerformInductionVarAnalysis();
    858 
    859   EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
    860   EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(sub, 0).c_str());
    861 }
    862 
    863 TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
    864   // Setup:
    865   // k = 0;
    866   // for (int i = 0; i < 100; i++) {
    867   //   a[k] = 0;
    868   //   k = k ^ 1;
    869   // }
    870   BuildLoopNest(1);
    871   HPhi* k_header = InsertLoopPhi(0, 0);
    872   k_header->AddInput(constant0_);
    873 
    874   HInstruction* store = InsertArrayStore(k_header, 0);
    875   HInstruction* x = InsertInstruction(
    876       new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant1_), 0);
    877   k_header->AddInput(x);
    878   PerformInductionVarAnalysis();
    879 
    880   EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
    881   EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(x, 0).c_str());
    882 }
    883 
    884 TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
    885   // Setup:
    886   // k = 1;
    887   // for (int i = 0; i < 100; i++) {
    888   //   k = 1 ^ k;
    889   // }
    890   BuildLoopNest(1);
    891   HPhi* k_header = InsertLoopPhi(0, 0);
    892   k_header->AddInput(constant1_);
    893 
    894   HInstruction* x = InsertInstruction(
    895       new (GetAllocator()) HXor(DataType::Type::kInt32, constant1_, k_header), 0);
    896   k_header->AddInput(x);
    897   PerformInductionVarAnalysis();
    898 
    899   EXPECT_STREQ("periodic((1), ((1) ^ (1))):Int32", GetInductionInfo(k_header, 0).c_str());
    900   EXPECT_STREQ("periodic(((1) ^ (1)), (1)):Int32", GetInductionInfo(x, 0).c_str());
    901 }
    902 
    903 TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
    904   // Setup:
    905   // k = 1;
    906   // for (int i = 0; i < 100; i++) {
    907   //   k = k ^ 100;
    908   // }
    909   BuildLoopNest(1);
    910   HPhi* k_header = InsertLoopPhi(0, 0);
    911   k_header->AddInput(constant1_);
    912 
    913   HInstruction* x = InsertInstruction(
    914       new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant100_), 0);
    915   k_header->AddInput(x);
    916   PerformInductionVarAnalysis();
    917 
    918   EXPECT_STREQ("periodic((1), ((1) ^ (100))):Int32", GetInductionInfo(k_header, 0).c_str());
    919   EXPECT_STREQ("periodic(((1) ^ (100)), (1)):Int32", GetInductionInfo(x, 0).c_str());
    920 }
    921 
    922 TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
    923   // Setup:
    924   // k = 0;
    925   // for (int i = 0; i < 100; i++) {
    926   //   k = (k == 0);
    927   // }
    928   BuildLoopNest(1);
    929   HPhi* k_header = InsertLoopPhi(0, 0);
    930   k_header->AddInput(constant0_);
    931 
    932   HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(k_header, constant0_), 0);
    933   k_header->AddInput(x);
    934   PerformInductionVarAnalysis();
    935 
    936   EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
    937   EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
    938 }
    939 
    940 TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
    941   // Setup:
    942   // k = 0;
    943   // for (int i = 0; i < 100; i++) {
    944   //   k = (0 == k);
    945   // }
    946   BuildLoopNest(1);
    947   HPhi* k_header = InsertLoopPhi(0, 0);
    948   k_header->AddInput(constant0_);
    949 
    950   HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(constant0_, k_header), 0);
    951   k_header->AddInput(x);
    952   PerformInductionVarAnalysis();
    953 
    954   EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
    955   EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
    956 }
    957 
    958 TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
    959   // Setup:
    960   // k = 0;
    961   // for (int i = 0; i < 100; i++) {
    962   //   k = (k != 1);
    963   // }
    964   BuildLoopNest(1);
    965   HPhi* k_header = InsertLoopPhi(0, 0);
    966   k_header->AddInput(constant0_);
    967 
    968   HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(k_header, constant1_), 0);
    969   k_header->AddInput(x);
    970   PerformInductionVarAnalysis();
    971 
    972   EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
    973   EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
    974 }
    975 
    976 TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
    977   // Setup:
    978   // k = 0;
    979   // for (int i = 0; i < 100; i++) {
    980   //   k = (1 != k);
    981   // }
    982   BuildLoopNest(1);
    983   HPhi* k_header = InsertLoopPhi(0, 0);
    984   k_header->AddInput(constant0_);
    985 
    986   HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(constant1_, k_header), 0);
    987   k_header->AddInput(x);
    988   PerformInductionVarAnalysis();
    989 
    990   EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
    991   EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
    992 }
    993 
    994 TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
    995   // Setup:
    996   // k = 0;
    997   // for (int i = 0; i < 100; i++) {
    998   //   t = - k;
    999   //   k = 1 - k;
   1000   //   t = k + 100;
   1001   //   t = k - 100;
   1002   //   t = k * 100;
   1003   //   t = k << 1;
   1004   //   t = - k;
   1005   // }
   1006   BuildLoopNest(1);
   1007   HPhi* k_header = InsertLoopPhi(0, 0);
   1008   k_header->AddInput(constant0_);
   1009 
   1010   HInstruction* neg1 = InsertInstruction(
   1011       new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
   1012   HInstruction* idiom = InsertInstruction(
   1013       new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
   1014   HInstruction* add = InsertInstruction(
   1015       new (GetAllocator()) HAdd(DataType::Type::kInt32, idiom, constant100_), 0);
   1016   HInstruction* sub = InsertInstruction(
   1017       new (GetAllocator()) HSub(DataType::Type::kInt32, idiom, constant100_), 0);
   1018   HInstruction* mul = InsertInstruction(
   1019       new (GetAllocator()) HMul(DataType::Type::kInt32, idiom, constant100_), 0);
   1020   HInstruction* shl = InsertInstruction(
   1021       new (GetAllocator()) HShl(DataType::Type::kInt32, idiom, constant1_), 0);
   1022   HInstruction* neg2 = InsertInstruction(
   1023       new (GetAllocator()) HNeg(DataType::Type::kInt32, idiom), 0);
   1024   k_header->AddInput(idiom);
   1025   PerformInductionVarAnalysis();
   1026 
   1027   EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(k_header, 0).c_str());
   1028   EXPECT_STREQ("periodic((0), ( - (1))):Int32", GetInductionInfo(neg1, 0).c_str());
   1029   EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(idiom, 0).c_str());
   1030   EXPECT_STREQ("periodic(((1) + (100)), (100)):Int32", GetInductionInfo(add, 0).c_str());
   1031   EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):Int32", GetInductionInfo(sub, 0).c_str());
   1032   EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(mul, 0).c_str());
   1033   EXPECT_STREQ("periodic((2), (0)):Int32", GetInductionInfo(shl, 0).c_str());
   1034   EXPECT_STREQ("periodic(( - (1)), (0)):Int32", GetInductionInfo(neg2, 0).c_str());
   1035 }
   1036 
   1037 TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
   1038   // Setup:
   1039   // k = 0;
   1040   // for (int i_0 = 0; i_0 < 100; i_0++) {
   1041   //   ..
   1042   //     for (int i_9 = 0; i_9 < 100; i_9++) {
   1043   //       k = 1 + k;
   1044   //       a[k] = 0;
   1045   //     }
   1046   //   ..
   1047   // }
   1048   BuildLoopNest(10);
   1049 
   1050   HPhi* k_header[10];
   1051   for (int d = 0; d < 10; d++) {
   1052     k_header[d] = InsertLoopPhi(0, d);
   1053   }
   1054 
   1055   HInstruction* inc = InsertInstruction(
   1056       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9);
   1057   HInstruction* store = InsertArrayStore(inc, 9);
   1058 
   1059   for (int d = 0; d < 10; d++) {
   1060     k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
   1061     k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
   1062   }
   1063   PerformInductionVarAnalysis();
   1064 
   1065   // Avoid exact phi number, since that depends on the SSA building phase.
   1066   std::regex r("\\(\\(1\\) \\* i \\+ "
   1067                "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32");
   1068 
   1069   for (int d = 0; d < 10; d++) {
   1070     if (d == 9) {
   1071       EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
   1072     } else {
   1073       EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
   1074     }
   1075     EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str());
   1076     // Trip-count.
   1077     EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
   1078   }
   1079 }
   1080 
   1081 TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
   1082   // Setup:
   1083   // for (int i = 0; i < 100; i++) {
   1084   //   k = (byte) i;
   1085   //   a[k] = 0;
   1086   //   a[i] = 0;
   1087   // }
   1088   BuildLoopNest(1);
   1089   HInstruction* conv = InsertInstruction(
   1090       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
   1091   HInstruction* store1 = InsertArrayStore(conv, 0);
   1092   HInstruction* store2 = InsertArrayStore(basic_[0], 0);
   1093   PerformInductionVarAnalysis();
   1094 
   1095   // Regular int induction (i) is transferred over conversion into byte induction (k).
   1096   EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
   1097   EXPECT_STREQ("((1) * i + (0)):Int32",  GetInductionInfo(store2->InputAt(1), 0).c_str());
   1098   EXPECT_STREQ("((1) * i + (1)):Int32",  GetInductionInfo(increment_[0], 0).c_str());
   1099 
   1100   // Narrowing detected.
   1101   EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
   1102   EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));
   1103 
   1104   // Type matters!
   1105   EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
   1106 
   1107   // Trip-count.
   1108   EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
   1109 }
   1110 
   1111 TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
   1112   // Setup:
   1113   // for (int i = 0; i < 100; i++) {
   1114   //   k = (byte) i;
   1115   //   a[k] = 0;
   1116   //   k = k + 1
   1117   //   a[k] = 0;
   1118   // }
   1119   BuildLoopNest(1);
   1120   HInstruction* conv = InsertInstruction(
   1121       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
   1122   HInstruction* store1 = InsertArrayStore(conv, 0);
   1123   HInstruction* add = InsertInstruction(
   1124       new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
   1125   HInstruction* store2 = InsertArrayStore(add, 0);
   1126 
   1127   PerformInductionVarAnalysis();
   1128 
   1129   // Byte induction (k) is detected, but it does not transfer over the addition,
   1130   // since this may yield out-of-type values.
   1131   EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
   1132   EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
   1133 
   1134   // Narrowing detected.
   1135   EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
   1136   EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));  // works for null
   1137 }
   1138 
   1139 TEST_F(InductionVarAnalysisTest, ByteInduction) {
   1140   // Setup:
   1141   // k = -128;
   1142   // for (int i = 0; i < 100; i++) {
   1143   //   k = k + 1;
   1144   //   k = (byte) k;
   1145   // }
   1146   BuildLoopNest(1);
   1147   HPhi* k_header = InsertLoopPhi(0, 0);
   1148   k_header->AddInput(graph_->GetIntConstant(-128));
   1149 
   1150   HInstruction* add = InsertInstruction(
   1151       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
   1152   HInstruction* conv = InsertInstruction(
   1153       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
   1154   k_header->AddInput(conv);
   1155   PerformInductionVarAnalysis();
   1156 
   1157   // Byte induction (k) is detected, but it does not transfer over the addition,
   1158   // since this may yield out-of-type values.
   1159   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str());
   1160   EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
   1161 
   1162   // Narrowing detected.
   1163   EXPECT_TRUE(IsNarrowingLinear(k_header));
   1164   EXPECT_FALSE(IsNarrowingLinear(add));  // works for null
   1165 }
   1166 
   1167 TEST_F(InductionVarAnalysisTest, NoByteInduction1) {
   1168   // Setup:
   1169   // k = -129;  / does not fit!
   1170   // for (int i = 0; i < 100; i++) {
   1171   //   k = k + 1;
   1172   //   k = (byte) k;
   1173   // }
   1174   BuildLoopNest(1);
   1175   HPhi* k_header = InsertLoopPhi(0, 0);
   1176   k_header->AddInput(graph_->GetIntConstant(-129));
   1177 
   1178   HInstruction* add = InsertInstruction(
   1179       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
   1180   HInstruction* conv = InsertInstruction(
   1181       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
   1182   k_header->AddInput(conv);
   1183   PerformInductionVarAnalysis();
   1184 
   1185   EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
   1186   EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
   1187 }
   1188 
   1189 TEST_F(InductionVarAnalysisTest, NoByteInduction2) {
   1190   // Setup:
   1191   // k = 0;
   1192   // for (int i = 0; i < 100; i++) {
   1193   //   k = (byte) k;   // conversion not done last!
   1194   //   k = k + 1;
   1195   // }
   1196   BuildLoopNest(1);
   1197   HPhi* k_header = InsertLoopPhi(0, 0);
   1198   k_header->AddInput(constant0_);
   1199 
   1200   HInstruction* conv = InsertInstruction(
   1201       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0);
   1202   HInstruction* add = InsertInstruction(
   1203       new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
   1204   k_header->AddInput(add);
   1205   PerformInductionVarAnalysis();
   1206 
   1207   EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
   1208   EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
   1209 }
   1210 
   1211 TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
   1212   // Setup:
   1213   // for (byte i = -128; i < 127; i++) {  // just fits!
   1214   // }
   1215   BuildLoopNest(1);
   1216   basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
   1217   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1218   ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
   1219   HInstruction* conv =
   1220       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
   1221   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1222   basic_[0]->ReplaceInput(conv, 1);
   1223   PerformInductionVarAnalysis();
   1224 
   1225   // Recorded at the phi, but not transferred to increment.
   1226   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
   1227   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1228 
   1229   // Narrowing detected.
   1230   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1231   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1232 
   1233   // Trip-count.
   1234   EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
   1235 }
   1236 
   1237 TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
   1238   // Setup:
   1239   // for (byte i = -128; i < 128; i++) {  // infinite loop!
   1240   // }
   1241   BuildLoopNest(1);
   1242   basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
   1243   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1244   ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
   1245   HInstruction* conv =
   1246       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
   1247   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1248   basic_[0]->ReplaceInput(conv, 1);
   1249   PerformInductionVarAnalysis();
   1250 
   1251   // Recorded at the phi, but not transferred to increment.
   1252   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
   1253   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1254 
   1255   // Narrowing detected.
   1256   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1257   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1258 
   1259   // Trip-count undefined.
   1260   EXPECT_STREQ("", GetTripCount(0).c_str());
   1261 }
   1262 
   1263 TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
   1264   // Setup:
   1265   // for (short i = -32768; i < 32767; i++) {  // just fits!
   1266   // }
   1267   BuildLoopNest(1);
   1268   basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
   1269   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1270   ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
   1271   HInstruction* conv =
   1272       new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
   1273   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1274   basic_[0]->ReplaceInput(conv, 1);
   1275   PerformInductionVarAnalysis();
   1276 
   1277   // Recorded at the phi, but not transferred to increment.
   1278   EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
   1279   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1280 
   1281   // Narrowing detected.
   1282   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1283   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1284 
   1285   // Trip-count.
   1286   EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
   1287 }
   1288 
   1289 TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
   1290   // Setup:
   1291   // for (short i = -32768; i < 32768; i++) {  // infinite loop!
   1292   // }
   1293   BuildLoopNest(1);
   1294   basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
   1295   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1296   ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
   1297   HInstruction* conv =
   1298       new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
   1299   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1300   basic_[0]->ReplaceInput(conv, 1);
   1301   PerformInductionVarAnalysis();
   1302 
   1303   // Recorded at the phi, but not transferred to increment.
   1304   EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
   1305   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1306 
   1307   // Narrowing detected.
   1308   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1309   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1310 
   1311   // Trip-count undefined.
   1312   EXPECT_STREQ("", GetTripCount(0).c_str());
   1313 }
   1314 
   1315 TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
   1316   // Setup:
   1317   // for (char i = 0; i < 65535; i++) {  // just fits!
   1318   // }
   1319   BuildLoopNest(1);
   1320   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1321   ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
   1322   HInstruction* conv =
   1323       new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
   1324   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1325   basic_[0]->ReplaceInput(conv, 1);
   1326   PerformInductionVarAnalysis();
   1327 
   1328   // Recorded at the phi, but not transferred to increment.
   1329   EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
   1330   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1331 
   1332   // Narrowing detected.
   1333   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1334   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1335 
   1336   // Trip-count.
   1337   EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
   1338 }
   1339 
   1340 TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
   1341   // Setup:
   1342   // for (char i = 0; i < 65536; i++) {  // infinite loop!
   1343   // }
   1344   BuildLoopNest(1);
   1345   HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
   1346   ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
   1347   HInstruction* conv =
   1348       new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
   1349   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
   1350   basic_[0]->ReplaceInput(conv, 1);
   1351   PerformInductionVarAnalysis();
   1352 
   1353   // Recorded at the phi, but not transferred to increment.
   1354   EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
   1355   EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
   1356 
   1357   // Narrowing detected.
   1358   EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
   1359   EXPECT_FALSE(IsNarrowingLinear(increment_[0]));  // works for null
   1360 
   1361   // Trip-count undefined.
   1362   EXPECT_STREQ("", GetTripCount(0).c_str());
   1363 }
   1364 
   1365 }  // namespace art
   1366