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