| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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 |  | 
| Igor Murashkin | 5573c37 | 2017-11-16 13:34:30 -0800 | [diff] [blame] | 17 | #include <regex> | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 18 |  | 
 | 19 | #include "base/arena_allocator.h" | 
 | 20 | #include "builder.h" | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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 |  */ | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 30 | class InductionVarAnalysisTest : public OptimizingUnitTest { | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 31 |  public: | 
| Andreas Gampe | d9911ee | 2017-03-27 13:27:24 -0700 | [diff] [blame] | 32 |   InductionVarAnalysisTest() | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 33 |       : iva_(nullptr), | 
| Andreas Gampe | d9911ee | 2017-03-27 13:27:24 -0700 | [diff] [blame] | 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) { | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 45 |     graph_ = CreateGraph(); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 53 |     loop_preheader_[d] = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 54 |     graph_->AddBlock(loop_preheader_[d]); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 55 |     loop_header_[d] = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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 |     } | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 61 |     loop_body_[d] = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 77 |     graph_->SetNumberOfVRegs(n + 3); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 78 |  | 
 | 79 |     // Build basic blocks with entry, nested loop, exit. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 80 |     entry_ = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 81 |     graph_->AddBlock(entry_); | 
 | 82 |     BuildForLoop(0, n); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 83 |     return_ = new (GetAllocator()) HBasicBlock(graph_); | 
| David Brazdil | db51efb | 2015-11-06 01:36:20 +0000 | [diff] [blame] | 84 |     graph_->AddBlock(return_); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 85 |     exit_ = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 86 |     graph_->AddBlock(exit_); | 
 | 87 |     entry_->AddSuccessor(loop_preheader_[0]); | 
| David Brazdil | db51efb | 2015-11-06 01:36:20 +0000 | [diff] [blame] | 88 |     loop_header_[0]->AddSuccessor(return_); | 
 | 89 |     return_->AddSuccessor(exit_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 90 |     graph_->SetEntryBlock(entry_); | 
 | 91 |     graph_->SetExitBlock(exit_); | 
 | 92 |  | 
 | 93 |     // Provide entry and exit instructions. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 94 |     parameter_ = new (GetAllocator()) HParameterValue( | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 95 |         graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 96 |     entry_->AddInstruction(parameter_); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 97 |     constant0_ = graph_->GetIntConstant(0); | 
 | 98 |     constant1_ = graph_->GetIntConstant(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 99 |     constant2_ = graph_->GetIntConstant(2); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 100 |     constant7_ = graph_->GetIntConstant(7); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 101 |     constant100_ = graph_->GetIntConstant(100); | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 102 |     constantm1_ = graph_->GetIntConstant(-1); | 
| David Brazdil | 15693bf | 2015-12-16 10:30:45 +0000 | [diff] [blame] | 103 |     float_constant0_ = graph_->GetFloatConstant(0.0f); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 104 |     return_->AddInstruction(new (GetAllocator()) HReturnVoid()); | 
 | 105 |     exit_->AddInstruction(new (GetAllocator()) HExit()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 106 |  | 
 | 107 |     // Provide loop instructions. | 
 | 108 |     for (int d = 0; d < n; d++) { | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 109 |       basic_[d] = new (GetAllocator()) HPhi(GetAllocator(), d, 0, DataType::Type::kInt32); | 
 | 110 |       loop_preheader_[d]->AddInstruction(new (GetAllocator()) HGoto()); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 111 |       loop_header_[d]->AddPhi(basic_[d]); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 112 |       HInstruction* compare = new (GetAllocator()) HLessThan(basic_[d], constant100_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 113 |       loop_header_[d]->AddInstruction(compare); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 114 |       loop_header_[d]->AddInstruction(new (GetAllocator()) HIf(compare)); | 
 | 115 |       increment_[d] = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[d], constant1_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 116 |       loop_body_[d]->AddInstruction(increment_[d]); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 117 |       loop_body_[d]->AddInstruction(new (GetAllocator()) HGoto()); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 118 |  | 
 | 119 |       basic_[d]->AddInput(constant0_); | 
 | 120 |       basic_[d]->AddInput(increment_[d]); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 121 |     } | 
 | 122 |   } | 
 | 123 |  | 
 | 124 |   // Builds if-statement at depth d. | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 125 |   HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) { | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 126 |     HBasicBlock* cond = new (GetAllocator()) HBasicBlock(graph_); | 
 | 127 |     HBasicBlock* ifTrue = new (GetAllocator()) HBasicBlock(graph_); | 
 | 128 |     HBasicBlock* ifFalse = new (GetAllocator()) HBasicBlock(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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]); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 138 |     cond->AddInstruction(new (GetAllocator()) HIf(parameter_)); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 139 |     *ifT = ifTrue; | 
 | 140 |     *ifF = ifFalse; | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 141 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 142 |     HPhi* select_phi = new (GetAllocator()) HPhi(GetAllocator(), -1, 0, DataType::Type::kInt32); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 143 |     loop_body_[d]->AddPhi(select_phi); | 
 | 144 |     return select_phi; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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 |  | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 153 |   // Inserts a phi to loop header at depth d and returns it. | 
 | 154 |   HPhi* InsertLoopPhi(int vreg, int d) { | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 155 |     HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), vreg, 0, DataType::Type::kInt32); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 156 |     loop_header_[d]->AddPhi(phi); | 
 | 157 |     return phi; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 158 |   } | 
 | 159 |  | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 160 |   // Inserts an array store with given `subscript` at depth d to | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 161 |   // enable tests to inspect the computed induction at that point easily. | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 162 |   HInstruction* InsertArrayStore(HInstruction* subscript, int d) { | 
| David Brazdil | 15693bf | 2015-12-16 10:30:45 +0000 | [diff] [blame] | 163 |     // ArraySet is given a float value in order to avoid SsaBuilder typing | 
 | 164 |     // it from the array's non-existent reference type info. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 165 |     return InsertInstruction(new (GetAllocator()) HArraySet( | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 166 |         parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 167 |   } | 
 | 168 |  | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 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)); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 173 |   } | 
 | 174 |  | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 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 |  | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 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 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 195 |   // Performs InductionVarAnalysis (after proper set up). | 
 | 196 |   void PerformInductionVarAnalysis() { | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 197 |     graph_->BuildDominatorTree(); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 198 |     iva_ = new (GetAllocator()) HInductionVarAnalysis(graph_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 199 |     iva_->Run(); | 
 | 200 |   } | 
 | 201 |  | 
 | 202 |   // General building fields. | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 203 |   HGraph* graph_; | 
 | 204 |   HInductionVarAnalysis* iva_; | 
 | 205 |  | 
 | 206 |   // Fixed basic blocks and instructions. | 
 | 207 |   HBasicBlock* entry_; | 
| David Brazdil | db51efb | 2015-11-06 01:36:20 +0000 | [diff] [blame] | 208 |   HBasicBlock* return_; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 209 |   HBasicBlock* exit_; | 
 | 210 |   HInstruction* parameter_;  // "this" | 
 | 211 |   HInstruction* constant0_; | 
 | 212 |   HInstruction* constant1_; | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 213 |   HInstruction* constant2_; | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 214 |   HInstruction* constant7_; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 215 |   HInstruction* constant100_; | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 216 |   HInstruction* constantm1_; | 
| David Brazdil | 15693bf | 2015-12-16 10:30:45 +0000 | [diff] [blame] | 217 |   HInstruction* float_constant0_; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 218 |  | 
 | 219 |   // Loop specifics. | 
 | 220 |   HBasicBlock* loop_preheader_[10]; | 
 | 221 |   HBasicBlock* loop_header_[10]; | 
 | 222 |   HBasicBlock* loop_body_[10]; | 
 | 223 |   HInstruction* increment_[10]; | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 224 |   HPhi* basic_[10];  // "vreg_d", the "i_d" | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 240 |   graph_->BuildDominatorTree(); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 241 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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 |  | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 255 | TEST_F(InductionVarAnalysisTest, FindBasicInduction) { | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 256 |   // Setup: | 
 | 257 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 258 |   //   a[i] = 0; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 259 |   // } | 
 | 260 |   BuildLoopNest(1); | 
 | 261 |   HInstruction* store = InsertArrayStore(basic_[0], 0); | 
 | 262 |   PerformInductionVarAnalysis(); | 
 | 263 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | d14c595 | 2015-09-08 15:25:15 -0700 | [diff] [blame] | 266 |  | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 267 |   // Offset matters! | 
 | 268 |   EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0])); | 
 | 269 |  | 
| Aart Bik | d14c595 | 2015-09-08 15:25:15 -0700 | [diff] [blame] | 270 |   // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 271 |   EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 272 | } | 
 | 273 |  | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 274 | TEST_F(InductionVarAnalysisTest, FindDerivedInduction) { | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 275 |   // Setup: | 
 | 276 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 277 |   //   t = 100 + i; | 
 | 278 |   //   t = 100 - i; | 
 | 279 |   //   t = 100 * i; | 
 | 280 |   //   t = i << 1; | 
 | 281 |   //   t = - i; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 282 |   // } | 
 | 283 |   BuildLoopNest(1); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 284 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 285 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 286 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 287 |       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 288 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 289 |       new (GetAllocator()) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 290 |   HInstruction* shl = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 291 |       new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 292 |   HInstruction* neg = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 293 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, basic_[0]), 0); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 294 |   PerformInductionVarAnalysis(); | 
 | 295 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 301 | } | 
 | 302 |  | 
 | 303 | TEST_F(InductionVarAnalysisTest, FindChainInduction) { | 
 | 304 |   // Setup: | 
 | 305 |   // k = 0; | 
 | 306 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 307 |   //   k = k + 100; | 
 | 308 |   //   a[k] = 0; | 
 | 309 |   //   k = k - 1; | 
 | 310 |   //   a[k] = 0; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 311 |   // } | 
 | 312 |   BuildLoopNest(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 313 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 314 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 315 |  | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 316 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 317 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 318 |   HInstruction* store1 = InsertArrayStore(add, 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 319 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 320 |       new (GetAllocator()) HSub(DataType::Type::kInt32, add, constant1_), 0); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 321 |   HInstruction* store2 = InsertArrayStore(sub, 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 322 |   k_header->AddInput(sub); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 323 |   PerformInductionVarAnalysis(); | 
 | 324 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 325 |   EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32", | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 326 |                GetInductionInfo(k_header, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 327 |   EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32", | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 328 |                GetInductionInfo(store1->InputAt(1), 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 329 |   EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32", | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 330 |                GetInductionInfo(store2->InputAt(1), 0).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 331 | } | 
 | 332 |  | 
 | 333 | TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) { | 
 | 334 |   // Setup: | 
 | 335 |   // k = 0; | 
 | 336 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 337 |   //   if () k = k + 1; | 
 | 338 |   //   else  k = k + 1; | 
 | 339 |   //   a[k] = 0; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 340 |   // } | 
 | 341 |   BuildLoopNest(1); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 342 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 343 |   k_header->AddInput(constant0_); | 
 | 344 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 345 |   HBasicBlock* ifTrue; | 
 | 346 |   HBasicBlock* ifFalse; | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 347 |   HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse); | 
 | 348 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 349 |   // True-branch. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 350 |   HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 351 |   ifTrue->AddInstruction(inc1); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 352 |   k_body->AddInput(inc1); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 353 |   // False-branch. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 354 |   HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 355 |   ifFalse->AddInstruction(inc2); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 356 |   k_body->AddInput(inc2); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 357 |   // Merge over a phi. | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 358 |   HInstruction* store = InsertArrayStore(k_body, 0); | 
 | 359 |   k_header->AddInput(k_body); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 360 |   PerformInductionVarAnalysis(); | 
 | 361 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 364 |  | 
 | 365 |   // Both increments get same induction. | 
 | 366 |   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1)); | 
 | 367 |   EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2)); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 368 | } | 
 | 369 |  | 
 | 370 | TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) { | 
 | 371 |   // Setup: | 
 | 372 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 373 |   //   if () k = i + 1; | 
 | 374 |   //   else  k = i + 1; | 
 | 375 |   //   a[k] = 0; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 376 |   // } | 
 | 377 |   BuildLoopNest(1); | 
 | 378 |   HBasicBlock* ifTrue; | 
 | 379 |   HBasicBlock* ifFalse; | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 380 |   HPhi* k = BuildIf(0, &ifTrue, &ifFalse); | 
 | 381 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 382 |   // True-branch. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 383 |   HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 384 |   ifTrue->AddInstruction(inc1); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 385 |   k->AddInput(inc1); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 386 |   // False-branch. | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 387 |   HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 388 |   ifFalse->AddInstruction(inc2); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 389 |   k->AddInput(inc2); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 390 |   // Merge over a phi. | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 391 |   HInstruction* store = InsertArrayStore(k, 0); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 392 |   PerformInductionVarAnalysis(); | 
 | 393 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 394 |   EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str()); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 411 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 412 |   HInstruction* add2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 413 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 414 |   HInstruction* add3 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 415 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, add2), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 416 |   PerformInductionVarAnalysis(); | 
 | 417 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 437 |       new (GetAllocator()) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 438 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 439 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, mul), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 440 |   HInstruction* pol = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 441 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, add, k_header), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 442 |   k_header->AddInput(pol); | 
 | 443 |   PerformInductionVarAnalysis(); | 
 | 444 |  | 
 | 445 |   // Note, only the phi in the cycle and the base linear induction are classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 446 |   EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 447 |                GetInductionInfo(k_header, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 448 |   EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str()); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 468 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 469 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 470 |       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 471 |   HInstruction* neg = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 472 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 473 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 474 |       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 475 |   HInstruction* shl = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 476 |       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 477 |   HInstruction* pol = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 478 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 479 |   k_header->AddInput(pol); | 
 | 480 |   PerformInductionVarAnalysis(); | 
 | 481 |  | 
 | 482 |   // Note, only the phi in the cycle and derived are classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 483 |   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 484 |                GetInductionInfo(k_header, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 485 |   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 486 |                GetInductionInfo(add, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 487 |   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 488 |                GetInductionInfo(sub, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 489 |   EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 490 |                GetInductionInfo(neg, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 491 |   EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 492 |                GetInductionInfo(mul, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 493 |   EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 511 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, k_header), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 512 |   HInstruction* add2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 513 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, k_header), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 514 |   HInstruction* add3 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 515 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 516 |   k_header->AddInput(add3); | 
 | 517 |   PerformInductionVarAnalysis(); | 
 | 518 |  | 
 | 519 |   // Note, only the phi in the cycle and added-derived are classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 520 |   EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 521 |                GetInductionInfo(k_header, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 522 |   EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 523 |                GetInductionInfo(add1, 0).c_str()); | 
 | 524 |   EXPECT_STREQ( | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 525 |       "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32", | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 526 |       GetInductionInfo(add2, 0).c_str()); | 
 | 527 |   EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str()); | 
 | 528 | } | 
 | 529 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 541 |       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 542 |   k_header->AddInput(mul); | 
 | 543 |   PerformInductionVarAnalysis(); | 
 | 544 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 566 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 567 |   HInstruction* shl1 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 568 |       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 569 |   HInstruction* add2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 570 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, shl1, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 571 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 572 |       new (GetAllocator()) HSub(DataType::Type::kInt32, shl1, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 573 |   HInstruction* neg = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 574 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 575 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 576 |       new (GetAllocator()) HMul(DataType::Type::kInt32, shl1, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 577 |   HInstruction* shl2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 578 |       new (GetAllocator()) HShl(DataType::Type::kInt32, shl1, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 579 |   k_header->AddInput(shl1); | 
 | 580 |   PerformInductionVarAnalysis(); | 
 | 581 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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", | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 588 |                GetInductionInfo(neg, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 609 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 610 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 611 |       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 612 |   HInstruction* neg = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 613 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 614 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 615 |       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 616 |   HInstruction* shl = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 617 |       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 618 |   HInstruction* div = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 619 |       new (GetAllocator()) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 620 |   k_header->AddInput(div); | 
 | 621 |   PerformInductionVarAnalysis(); | 
 | 622 |  | 
 | 623 |   // Note, only the phi in the cycle and direct additive derived are classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 644 |       new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 645 |   k_header->AddInput(shr); | 
 | 646 |   PerformInductionVarAnalysis(); | 
 | 647 |  | 
 | 648 |   // Note, only the phi in the cycle is classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 649 |   EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str()); | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 664 |       new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | d0a022d | 2016-12-13 11:22:31 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 672 | TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) { | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 673 |   // Setup: | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 674 |   // k = 100; | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 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; | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 681 |   //   k = k % 7; | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 682 |   // } | 
 | 683 |   BuildLoopNest(1); | 
 | 684 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 685 |   k_header->AddInput(constant100_); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 686 |  | 
 | 687 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 688 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 689 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 690 |       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 691 |   HInstruction* neg = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 692 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 693 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 694 |       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 695 |   HInstruction* shl = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 696 |       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 697 |   HInstruction* rem = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 698 |       new (GetAllocator()) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 699 |   k_header->AddInput(rem); | 
 | 700 |   PerformInductionVarAnalysis(); | 
 | 701 |  | 
| Aart Bik | df7822e | 2016-12-06 10:05:30 -0800 | [diff] [blame] | 702 |   // Note, only the phi in the cycle and derived are classified. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 714 |   EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 715 | } | 
 | 716 |  | 
 | 717 | TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) { | 
 | 718 |   // Setup: | 
 | 719 |   // k = 0; | 
 | 720 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 721 |   //   a[k] = 0; | 
 | 722 |   //   k = 100 - i; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 723 |   // } | 
 | 724 |   BuildLoopNest(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 725 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 726 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 727 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 728 |   HInstruction* store = InsertArrayStore(k_header, 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 729 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 730 |       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 731 |   k_header->AddInput(sub); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 732 |   PerformInductionVarAnalysis(); | 
 | 733 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 734 |   EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32", | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 735 |                GetInductionInfo(k_header, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 736 |   EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32", | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 737 |                GetInductionInfo(store->InputAt(1), 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 738 |   EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 739 | } | 
 | 740 |  | 
 | 741 | TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) { | 
 | 742 |   // Setup: | 
 | 743 |   // k = 0; | 
 | 744 |   // t = 100; | 
 | 745 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 746 |   //   a[k] = 0; | 
 | 747 |   //   k = t; | 
 | 748 |   //   t = 100 - i; | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 749 |   // } | 
 | 750 |   BuildLoopNest(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 751 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 752 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 753 |   HPhi* t = InsertLoopPhi(1, 0); | 
 | 754 |   t->AddInput(constant100_); | 
 | 755 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 756 |   HInstruction* store = InsertArrayStore(k_header, 0); | 
 | 757 |   k_header->AddInput(t); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 758 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 759 |       new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 760 |   t->AddInput(sub); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 761 |   PerformInductionVarAnalysis(); | 
 | 762 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 763 |   EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32", | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 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; | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 777 |   //   t = - k; | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 778 |   // } | 
 | 779 |   BuildLoopNest(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 780 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 781 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 782 |  | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 783 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 784 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 785 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 786 |       new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 787 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 788 |       new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 789 |   HInstruction* shl1 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 790 |       new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 791 |   HInstruction* neg1 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 792 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 793 |   HInstruction* shl2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 794 |       new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 795 |   HInstruction* neg2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 796 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, shl2), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 797 |   k_header->AddInput(shl2); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 798 |   PerformInductionVarAnalysis(); | 
 | 799 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 800 |   EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32", | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 801 |                GetInductionInfo(add, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 802 |   EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32", | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 803 |                GetInductionInfo(sub, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 804 |   EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32", | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 805 |                GetInductionInfo(mul, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 806 |   EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32", | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 807 |                GetInductionInfo(shl1, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 808 |   EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32", | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 809 |                GetInductionInfo(neg1, 0).c_str()); | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 810 |   EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str()); | 
 | 811 |   EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str()); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 827 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 828 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 829 |   HPhi* t = InsertLoopPhi(1, 0); | 
 | 830 |   t->AddInput(constant100_); | 
 | 831 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 832 |   HInstruction* store1 = InsertArrayStore(k_header, 0); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 833 |   HInstruction* store2 = InsertArrayStore(t, 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 834 |   k_header->AddInput(t); | 
 | 835 |   t->AddInput(k_header); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 836 |   PerformInductionVarAnalysis(); | 
 | 837 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 850 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 851 |   k_header->AddInput(constant0_); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 852 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 853 |   HInstruction* store = InsertArrayStore(k_header, 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 854 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 855 |       new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 856 |   k_header->AddInput(sub); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 857 |   PerformInductionVarAnalysis(); | 
 | 858 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 861 | } | 
 | 862 |  | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 871 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 872 |   k_header->AddInput(constant0_); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 873 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 874 |   HInstruction* store = InsertArrayStore(k_header, 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 875 |   HInstruction* x = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 876 |       new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 877 |   k_header->AddInput(x); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 878 |   PerformInductionVarAnalysis(); | 
 | 879 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 882 | } | 
 | 883 |  | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 891 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 892 |   k_header->AddInput(constant1_); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 893 |  | 
 | 894 |   HInstruction* x = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 895 |       new (GetAllocator()) HXor(DataType::Type::kInt32, constant1_, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 896 |   k_header->AddInput(x); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 897 |   PerformInductionVarAnalysis(); | 
 | 898 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 901 | } | 
 | 902 |  | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 903 | TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) { | 
 | 904 |   // Setup: | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 905 |   // k = 1; | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 906 |   // for (int i = 0; i < 100; i++) { | 
 | 907 |   //   k = k ^ 100; | 
 | 908 |   // } | 
 | 909 |   BuildLoopNest(1); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 910 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 911 |   k_header->AddInput(constant1_); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 912 |  | 
 | 913 |   HInstruction* x = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 914 |       new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant100_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 915 |   k_header->AddInput(x); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 916 |   PerformInductionVarAnalysis(); | 
 | 917 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 929 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 930 |   k_header->AddInput(constant0_); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 931 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 932 |   HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(k_header, constant0_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 933 |   k_header->AddInput(x); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 934 |   PerformInductionVarAnalysis(); | 
 | 935 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 947 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 948 |   k_header->AddInput(constant0_); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 949 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 950 |   HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(constant0_, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 951 |   k_header->AddInput(x); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 952 |   PerformInductionVarAnalysis(); | 
 | 953 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 965 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 966 |   k_header->AddInput(constant0_); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 967 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 968 |   HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(k_header, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 969 |   k_header->AddInput(x); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 970 |   PerformInductionVarAnalysis(); | 
 | 971 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 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); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 983 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 984 |   k_header->AddInput(constant0_); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 985 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 986 |   HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(constant1_, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 987 |   k_header->AddInput(x); | 
| Aart Bik | 639cc8c | 2016-10-18 13:03:31 -0700 | [diff] [blame] | 988 |   PerformInductionVarAnalysis(); | 
 | 989 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 992 | } | 
 | 993 |  | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 994 | TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) { | 
 | 995 |   // Setup: | 
 | 996 |   // k = 0; | 
 | 997 |   // for (int i = 0; i < 100; i++) { | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 998 |   //   t = - k; | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 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); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1007 |   HPhi* k_header = InsertLoopPhi(0, 0); | 
 | 1008 |   k_header->AddInput(constant0_); | 
 | 1009 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1010 |   HInstruction* neg1 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1011 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1012 |   HInstruction* idiom = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1013 |       new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1014 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1015 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, idiom, constant100_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1016 |   HInstruction* sub = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1017 |       new (GetAllocator()) HSub(DataType::Type::kInt32, idiom, constant100_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1018 |   HInstruction* mul = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1019 |       new (GetAllocator()) HMul(DataType::Type::kInt32, idiom, constant100_), 0); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1020 |   HInstruction* shl = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1021 |       new (GetAllocator()) HShl(DataType::Type::kInt32, idiom, constant1_), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1022 |   HInstruction* neg2 = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1023 |       new (GetAllocator()) HNeg(DataType::Type::kInt32, idiom), 0); | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1024 |   k_header->AddInput(idiom); | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 1025 |   PerformInductionVarAnalysis(); | 
 | 1026 |  | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 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); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1049 |  | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1050 |   HPhi* k_header[10]; | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1051 |   for (int d = 0; d < 10; d++) { | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1052 |     k_header[d] = InsertLoopPhi(0, d); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1053 |   } | 
 | 1054 |  | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1055 |   HInstruction* inc = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1056 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1057 |   HInstruction* store = InsertArrayStore(inc, 9); | 
 | 1058 |  | 
 | 1059 |   for (int d = 0; d < 10; d++) { | 
| Aart Bik | c071a01 | 2016-12-01 10:22:31 -0800 | [diff] [blame] | 1060 |     k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_); | 
 | 1061 |     k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc); | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 1062 |   } | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1063 |   PerformInductionVarAnalysis(); | 
 | 1064 |  | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 1065 |   // Avoid exact phi number, since that depends on the SSA building phase. | 
 | 1066 |   std::regex r("\\(\\(1\\) \\* i \\+ " | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1067 |                "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32"); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1068 |  | 
 | 1069 |   for (int d = 0; d < 10; d++) { | 
 | 1070 |     if (d == 9) { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 1071 |       EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r)); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1072 |     } else { | 
| Aart Bik | e609b7c | 2015-08-27 13:46:58 -0700 | [diff] [blame] | 1073 |       EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1074 |     } | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1075 |     EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str()); | 
| Aart Bik | d14c595 | 2015-09-08 15:25:15 -0700 | [diff] [blame] | 1076 |     // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1077 |     EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str()); | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1078 |   } | 
 | 1079 | } | 
 | 1080 |  | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 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); | 
| Aart Bik | 7dc9693 | 2016-10-12 10:01:05 -0700 | [diff] [blame] | 1089 |   HInstruction* conv = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1090 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0); | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 1091 |   HInstruction* store1 = InsertArrayStore(conv, 0); | 
 | 1092 |   HInstruction* store2 = InsertArrayStore(basic_[0], 0); | 
 | 1093 |   PerformInductionVarAnalysis(); | 
 | 1094 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1095 |   // Regular int induction (i) is transferred over conversion into byte induction (k). | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 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()); | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 1099 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1100 |   // Narrowing detected. | 
 | 1101 |   EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1))); | 
 | 1102 |   EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1))); | 
 | 1103 |  | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 1104 |   // Type matters! | 
 | 1105 |   EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1))); | 
 | 1106 |  | 
 | 1107 |   // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1108 |   EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str()); | 
| Aart Bik | 7829691 | 2016-03-25 13:14:53 -0700 | [diff] [blame] | 1109 | } | 
 | 1110 |  | 
| Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1121 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0); | 
| Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 1122 |   HInstruction* store1 = InsertArrayStore(conv, 0); | 
 | 1123 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1124 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0); | 
| Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 1125 |   HInstruction* store2 = InsertArrayStore(add, 0); | 
 | 1126 |  | 
 | 1127 |   PerformInductionVarAnalysis(); | 
 | 1128 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1129 |   // Byte induction (k) is detected, but it does not transfer over the addition, | 
 | 1130 |   // since this may yield out-of-type values. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1131 |   EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1151 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1152 |   HInstruction* conv = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1153 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1159 |   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1179 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1180 |   HInstruction* conv = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1181 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1201 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1202 |   HInstruction* add = InsertInstruction( | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1203 |       new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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()); | 
| Aart Bik | cc42be0 | 2016-10-20 16:14:16 -0700 | [diff] [blame] | 1209 | } | 
 | 1210 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1219 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1220 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1221 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1222 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1223 |   PerformInductionVarAnalysis(); | 
 | 1224 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1225 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1226 |   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1233 |   // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1234 |   EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1245 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1246 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1247 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1248 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1249 |   PerformInductionVarAnalysis(); | 
 | 1250 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1251 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1252 |   EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1259 |   // Trip-count undefined. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1260 |   EXPECT_STREQ("", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1271 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1272 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1273 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1274 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1275 |   PerformInductionVarAnalysis(); | 
 | 1276 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1277 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1278 |   EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1285 |   // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1286 |   EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1297 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1298 |       new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1299 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1300 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1301 |   PerformInductionVarAnalysis(); | 
 | 1302 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1303 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1304 |   EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1311 |   // Trip-count undefined. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1312 |   EXPECT_STREQ("", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1322 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1323 |       new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1324 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1325 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1326 |   PerformInductionVarAnalysis(); | 
 | 1327 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1328 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1329 |   EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1336 |   // Trip-count. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1337 |   EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 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); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1347 |   HInstruction* conv = | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 1348 |       new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1349 |   loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext()); | 
 | 1350 |   basic_[0]->ReplaceInput(conv, 1); | 
 | 1351 |   PerformInductionVarAnalysis(); | 
 | 1352 |  | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 1353 |   // Recorded at the phi, but not transferred to increment. | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 1354 |   EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str()); | 
| Aart Bik | e6bd027 | 2016-12-16 13:57:52 -0800 | [diff] [blame] | 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 |  | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1361 |   // Trip-count undefined. | 
| Aart Bik | 009cace | 2016-09-16 10:15:19 -0700 | [diff] [blame] | 1362 |   EXPECT_STREQ("", GetTripCount(0).c_str()); | 
| Aart Bik | 0d345cf | 2016-03-16 10:49:38 -0700 | [diff] [blame] | 1363 | } | 
 | 1364 |  | 
| Aart Bik | 30efb4e | 2015-07-30 12:14:31 -0700 | [diff] [blame] | 1365 | }  // namespace art |