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