blob: f52a1aad5a9c20a6d18f4e3a4ae4fe6bdad0128c [file] [log] [blame]
Aart Bik30efb4e2015-07-30 12:14:31 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <regex>
18
19#include "base/arena_allocator.h"
20#include "builder.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070021#include "induction_var_analysis.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24
25namespace art {
26
27/**
28 * Fixture class for the InductionVarAnalysis tests.
29 */
David Brazdil4833f5a2015-12-16 10:37:39 +000030class InductionVarAnalysisTest : public CommonCompilerTest {
Aart Bik30efb4e2015-07-30 12:14:31 -070031 public:
32 InductionVarAnalysisTest() : pool_(), allocator_(&pool_) {
33 graph_ = CreateGraph(&allocator_);
34 }
35
36 ~InductionVarAnalysisTest() { }
37
38 // Builds single for-loop at depth d.
39 void BuildForLoop(int d, int n) {
40 ASSERT_LT(d, n);
41 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
42 graph_->AddBlock(loop_preheader_[d]);
43 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
44 graph_->AddBlock(loop_header_[d]);
45 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
46 if (d < (n - 1)) {
47 BuildForLoop(d + 1, n);
48 }
49 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
50 graph_->AddBlock(loop_body_[d]);
51 loop_body_[d]->AddSuccessor(loop_header_[d]);
52 if (d < (n - 1)) {
53 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
54 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
55 } else {
56 loop_header_[d]->AddSuccessor(loop_body_[d]);
57 }
58 }
59
60 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
61 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
62 // populate the loop with instructions to set up interesting scenarios.
63 void BuildLoopNest(int n) {
64 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070065 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070066
67 // Build basic blocks with entry, nested loop, exit.
68 entry_ = new (&allocator_) HBasicBlock(graph_);
69 graph_->AddBlock(entry_);
70 BuildForLoop(0, n);
David Brazdildb51efb2015-11-06 01:36:20 +000071 return_ = new (&allocator_) HBasicBlock(graph_);
72 graph_->AddBlock(return_);
Aart Bik30efb4e2015-07-30 12:14:31 -070073 exit_ = new (&allocator_) HBasicBlock(graph_);
74 graph_->AddBlock(exit_);
75 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000076 loop_header_[0]->AddSuccessor(return_);
77 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070078 graph_->SetEntryBlock(entry_);
79 graph_->SetExitBlock(exit_);
80
81 // Provide entry and exit instructions.
Calin Juravlee6e3bea2015-10-14 13:53:10 +000082 parameter_ = new (&allocator_) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -080083 graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070084 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070085 constant0_ = graph_->GetIntConstant(0);
86 constant1_ = graph_->GetIntConstant(1);
Aart Bikc071a012016-12-01 10:22:31 -080087 constant2_ = graph_->GetIntConstant(2);
Aart Bikdf7822e2016-12-06 10:05:30 -080088 constant7_ = graph_->GetIntConstant(7);
Aart Bike609b7c2015-08-27 13:46:58 -070089 constant100_ = graph_->GetIntConstant(100);
Aart Bikd0a022d2016-12-13 11:22:31 -080090 constantm1_ = graph_->GetIntConstant(-1);
David Brazdil15693bf2015-12-16 10:30:45 +000091 float_constant0_ = graph_->GetFloatConstant(0.0f);
David Brazdildb51efb2015-11-06 01:36:20 +000092 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bike609b7c2015-08-27 13:46:58 -070093 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070094
95 // Provide loop instructions.
96 for (int d = 0; d < n; d++) {
David Brazdilbadd8262016-02-02 16:28:56 +000097 basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, Primitive::kPrimInt);
David Brazdil4833f5a2015-12-16 10:37:39 +000098 loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +000099 loop_header_[d]->AddPhi(basic_[d]);
100 HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700101 loop_header_[d]->AddInstruction(compare);
102 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
David Brazdilbadd8262016-02-02 16:28:56 +0000103 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700104 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700105 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000106
107 basic_[d]->AddInput(constant0_);
108 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700109 }
110 }
111
112 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700113 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700114 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
115 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
116 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
117 graph_->AddBlock(cond);
118 graph_->AddBlock(ifTrue);
119 graph_->AddBlock(ifFalse);
120 // Conditional split.
121 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
122 cond->AddSuccessor(ifTrue);
123 cond->AddSuccessor(ifFalse);
124 ifTrue->AddSuccessor(loop_body_[d]);
125 ifFalse->AddSuccessor(loop_body_[d]);
126 cond->AddInstruction(new (&allocator_) HIf(parameter_));
127 *ifT = ifTrue;
128 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000129
130 HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, Primitive::kPrimInt);
131 loop_body_[d]->AddPhi(select_phi);
132 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700133 }
134
135 // Inserts instruction right before increment at depth d.
136 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
137 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
138 return instruction;
139 }
140
David Brazdilbadd8262016-02-02 16:28:56 +0000141 // Inserts a phi to loop header at depth d and returns it.
142 HPhi* InsertLoopPhi(int vreg, int d) {
143 HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, Primitive::kPrimInt);
144 loop_header_[d]->AddPhi(phi);
145 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700146 }
147
David Brazdilbadd8262016-02-02 16:28:56 +0000148 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700149 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000150 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000151 // ArraySet is given a float value in order to avoid SsaBuilder typing
152 // it from the array's non-existent reference type info.
Aart Bik30efb4e2015-07-30 12:14:31 -0700153 return InsertInstruction(new (&allocator_) HArraySet(
David Brazdilbadd8262016-02-02 16:28:56 +0000154 parameter_, subscript, float_constant0_, Primitive::kPrimFloat, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700155 }
156
Aart Bike609b7c2015-08-27 13:46:58 -0700157 // Returns induction information of instruction in loop at depth d.
158 std::string GetInductionInfo(HInstruction* instruction, int d) {
159 return HInductionVarAnalysis::InductionToString(
160 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700161 }
162
Aart Bik009cace2016-09-16 10:15:19 -0700163 // Returns induction information of the trip-count of loop at depth d.
164 std::string GetTripCount(int d) {
165 HInstruction* control = loop_header_[d]->GetLastInstruction();
166 DCHECK(control->IsIf());
167 return GetInductionInfo(control, d);
168 }
169
Aart Bik78296912016-03-25 13:14:53 -0700170 // Returns true if instructions have identical induction.
171 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
172 return HInductionVarAnalysis::InductionEqual(
173 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
174 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
175 }
176
Aart Bik30efb4e2015-07-30 12:14:31 -0700177 // Performs InductionVarAnalysis (after proper set up).
178 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000179 graph_->BuildDominatorTree();
Aart Bik30efb4e2015-07-30 12:14:31 -0700180 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
181 iva_->Run();
182 }
183
184 // General building fields.
185 ArenaPool pool_;
186 ArenaAllocator allocator_;
187 HGraph* graph_;
188 HInductionVarAnalysis* iva_;
189
190 // Fixed basic blocks and instructions.
191 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000192 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700193 HBasicBlock* exit_;
194 HInstruction* parameter_; // "this"
195 HInstruction* constant0_;
196 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800197 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800198 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700199 HInstruction* constant100_;
Aart Bikd0a022d2016-12-13 11:22:31 -0800200 HInstruction* constantm1_;
David Brazdil15693bf2015-12-16 10:30:45 +0000201 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700202
203 // Loop specifics.
204 HBasicBlock* loop_preheader_[10];
205 HBasicBlock* loop_header_[10];
206 HBasicBlock* loop_body_[10];
207 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000208 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700209};
210
211//
212// The actual InductionVarAnalysis tests.
213//
214
215TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
216 // Setup:
217 // for (int i_0 = 0; i_0 < 100; i_0++) {
218 // ..
219 // for (int i_9 = 0; i_9 < 100; i_9++) {
220 // }
221 // ..
222 // }
223 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000224 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700225
Aart Bik30efb4e2015-07-30 12:14:31 -0700226 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
227 for (int d = 0; d < 1; d++) {
228 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
229 (d == 0) ? nullptr
230 : loop_header_[d - 1]->GetLoopInformation());
231 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
232 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
233 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
234 loop_body_[d]->GetLoopInformation());
235 }
236 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
237}
238
Aart Bike609b7c2015-08-27 13:46:58 -0700239TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700240 // Setup:
241 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700242 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700243 // }
244 BuildLoopNest(1);
245 HInstruction* store = InsertArrayStore(basic_[0], 0);
246 PerformInductionVarAnalysis();
247
Aart Bik0d345cf2016-03-16 10:49:38 -0700248 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
249 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700250
Aart Bik78296912016-03-25 13:14:53 -0700251 // Offset matters!
252 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
253
Aart Bikd14c5952015-09-08 15:25:15 -0700254 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700255 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700256}
257
Aart Bike609b7c2015-08-27 13:46:58 -0700258TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700259 // Setup:
260 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800261 // t = 100 + i;
262 // t = 100 - i;
263 // t = 100 * i;
264 // t = i << 1;
265 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700266 // }
267 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700268 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000269 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700270 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000271 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700272 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000273 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700274 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000275 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700276 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000277 new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700278 PerformInductionVarAnalysis();
279
Aart Bik0d345cf2016-03-16 10:49:38 -0700280 EXPECT_STREQ("((1) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
281 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
282 EXPECT_STREQ("((100) * i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
283 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
284 EXPECT_STREQ("(( - (1)) * i + (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700285}
286
287TEST_F(InductionVarAnalysisTest, FindChainInduction) {
288 // Setup:
289 // k = 0;
290 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700291 // k = k + 100;
292 // a[k] = 0;
293 // k = k - 1;
294 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700295 // }
296 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800297 HPhi* k_header = InsertLoopPhi(0, 0);
298 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000299
Aart Bik7dc96932016-10-12 10:01:05 -0700300 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800301 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000302 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700303 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000304 new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
305 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800306 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700307 PerformInductionVarAnalysis();
308
Aart Bikc071a012016-12-01 10:22:31 -0800309 EXPECT_STREQ("(((100) - (1)) * i + (0)):PrimInt",
310 GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700311 EXPECT_STREQ("(((100) - (1)) * i + (100)):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700312 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700313 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700314 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700315}
316
317TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
318 // Setup:
319 // k = 0;
320 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700321 // if () k = k + 1;
322 // else k = k + 1;
323 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700324 // }
325 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000326 HPhi* k_header = InsertLoopPhi(0, 0);
327 k_header->AddInput(constant0_);
328
Aart Bik30efb4e2015-07-30 12:14:31 -0700329 HBasicBlock* ifTrue;
330 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000331 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
332
Aart Bik30efb4e2015-07-30 12:14:31 -0700333 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000334 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700335 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000336 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700337 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000338 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700339 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000340 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700341 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000342 HInstruction* store = InsertArrayStore(k_body, 0);
343 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700344 PerformInductionVarAnalysis();
345
Aart Bikc071a012016-12-01 10:22:31 -0800346 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700347 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700348
349 // Both increments get same induction.
350 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
351 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700352}
353
354TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
355 // Setup:
356 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700357 // if () k = i + 1;
358 // else k = i + 1;
359 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700360 // }
361 BuildLoopNest(1);
362 HBasicBlock* ifTrue;
363 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000364 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
365
Aart Bik30efb4e2015-07-30 12:14:31 -0700366 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000367 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700368 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000369 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700370 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000371 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700372 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000373 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700374 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000375 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700376 PerformInductionVarAnalysis();
377
Aart Bik0d345cf2016-03-16 10:49:38 -0700378 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800379
380 // Both increments get same induction.
381 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
382 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
383}
384
Aart Bikdf7822e2016-12-06 10:05:30 -0800385TEST_F(InductionVarAnalysisTest, AddLinear) {
386 // Setup:
387 // for (int i = 0; i < 100; i++) {
388 // t1 = i + i;
389 // t2 = 7 + i;
390 // t3 = t1 + t2;
391 // }
392 BuildLoopNest(1);
393
394 HInstruction* add1 = InsertInstruction(
395 new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], basic_[0]), 0);
396 HInstruction* add2 = InsertInstruction(
397 new (&allocator_) HAdd(Primitive::kPrimInt, constant7_, basic_[0]), 0);
398 HInstruction* add3 = InsertInstruction(
399 new (&allocator_) HAdd(Primitive::kPrimInt, add1, add2), 0);
400 PerformInductionVarAnalysis();
401
402 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(basic_[0], 0).c_str());
403 EXPECT_STREQ("(((1) + (1)) * i + (0)):PrimInt", GetInductionInfo(add1, 0).c_str());
404 EXPECT_STREQ("((1) * i + (7)):PrimInt", GetInductionInfo(add2, 0).c_str());
405 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):PrimInt", GetInductionInfo(add3, 0).c_str());
406}
407
408TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
409 // Setup:
410 // k = 1;
411 // for (int i = 0; i < 100; i++) {
412 // t = i * 2;
413 // t = 100 + t
414 // k = t + k; // polynomial
415 // }
416 BuildLoopNest(1);
417 HPhi* k_header = InsertLoopPhi(0, 0);
418 k_header->AddInput(constant1_);
419
420 HInstruction* mul = InsertInstruction(
421 new (&allocator_) HMul(Primitive::kPrimInt, basic_[0], constant2_), 0);
422 HInstruction* add = InsertInstruction(
423 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, mul), 0);
424 HInstruction* pol = InsertInstruction(
425 new (&allocator_) HAdd(Primitive::kPrimInt, add, k_header), 0);
426 k_header->AddInput(pol);
427 PerformInductionVarAnalysis();
428
429 // Note, only the phi in the cycle and the base linear induction are classified.
430 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):PrimInt) + (1)):PrimInt",
431 GetInductionInfo(k_header, 0).c_str());
432 EXPECT_STREQ("((2) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
433 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
434}
435
436TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
437 // Setup:
438 // k = 1;
439 // for (int i = 0; i < 100; i++) {
440 // t = k + 100;
441 // t = k - 1;
442 // t = - t
443 // t = k * 2;
444 // t = k << 2;
445 // k = k + i; // polynomial
446 // }
447 BuildLoopNest(1);
448 HPhi* k_header = InsertLoopPhi(0, 0);
449 k_header->AddInput(constant1_);
450
451 HInstruction* add = InsertInstruction(
452 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
453 HInstruction* sub = InsertInstruction(
454 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
455 HInstruction* neg = InsertInstruction(
456 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
457 HInstruction* mul = InsertInstruction(
458 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
459 HInstruction* shl = InsertInstruction(
460 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
461 HInstruction* pol = InsertInstruction(
462 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
463 k_header->AddInput(pol);
464 PerformInductionVarAnalysis();
465
466 // Note, only the phi in the cycle and derived are classified.
467 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (1)):PrimInt",
468 GetInductionInfo(k_header, 0).c_str());
469 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) + (100))):PrimInt",
470 GetInductionInfo(add, 0).c_str());
471 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
472 GetInductionInfo(sub, 0).c_str());
473 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
474 GetInductionInfo(neg, 0).c_str());
475 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):PrimInt) + (2)):PrimInt",
476 GetInductionInfo(mul, 0).c_str());
477 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):PrimInt) + (4)):PrimInt",
478 GetInductionInfo(shl, 0).c_str());
479 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
480}
481
482TEST_F(InductionVarAnalysisTest, AddPolynomial) {
483 // Setup:
484 // k = 7;
485 // for (int i = 0; i < 100; i++) {
486 // t = k + k;
487 // t = t + k;
488 // k = k + i
489 // }
490 BuildLoopNest(1);
491 HPhi* k_header = InsertLoopPhi(0, 0);
492 k_header->AddInput(constant7_);
493
494 HInstruction* add1 = InsertInstruction(
495 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, k_header), 0);
496 HInstruction* add2 = InsertInstruction(
497 new (&allocator_) HAdd(Primitive::kPrimInt, add1, k_header), 0);
498 HInstruction* add3 = InsertInstruction(
499 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
500 k_header->AddInput(add3);
501 PerformInductionVarAnalysis();
502
503 // Note, only the phi in the cycle and added-derived are classified.
504 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (7)):PrimInt",
505 GetInductionInfo(k_header, 0).c_str());
506 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):PrimInt) + ((7) + (7))):PrimInt",
507 GetInductionInfo(add1, 0).c_str());
508 EXPECT_STREQ(
509 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):PrimInt) + (((7) + (7)) + (7))):PrimInt",
510 GetInductionInfo(add2, 0).c_str());
511 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
512}
513
Aart Bikc071a012016-12-01 10:22:31 -0800514TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
515 // Setup:
516 // k = 1;
517 // for (int i = 0; i < 100; i++) {
518 // k = k * 100; // geometric (x 100)
519 // }
520 BuildLoopNest(1);
521 HPhi* k_header = InsertLoopPhi(0, 0);
522 k_header->AddInput(constant1_);
523
524 HInstruction* mul = InsertInstruction(
525 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
526 k_header->AddInput(mul);
527 PerformInductionVarAnalysis();
528
529 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
530 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
531}
532
533TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
534 // Setup:
535 // k = 1;
536 // for (int i = 0; i < 100; i++) {
537 // t = k + 1;
538 // k = k << 1; // geometric (x 2)
539 // t = k + 100;
540 // t = k - 1;
541 // t = - t;
542 // t = k * 2;
543 // t = k << 2;
544 // }
545 BuildLoopNest(1);
546 HPhi* k_header = InsertLoopPhi(0, 0);
547 k_header->AddInput(constant1_);
548
549 HInstruction* add1 = InsertInstruction(
550 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
551 HInstruction* shl1 = InsertInstruction(
552 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
553 HInstruction* add2 = InsertInstruction(
554 new (&allocator_) HAdd(Primitive::kPrimInt, shl1, constant100_), 0);
555 HInstruction* sub = InsertInstruction(
556 new (&allocator_) HSub(Primitive::kPrimInt, shl1, constant1_), 0);
557 HInstruction* neg = InsertInstruction(
558 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
559 HInstruction* mul = InsertInstruction(
560 new (&allocator_) HMul(Primitive::kPrimInt, shl1, constant2_), 0);
561 HInstruction* shl2 = InsertInstruction(
562 new (&allocator_) HShl(Primitive::kPrimInt, shl1, constant2_), 0);
563 k_header->AddInput(shl1);
564 PerformInductionVarAnalysis();
565
566 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
567 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):PrimInt", GetInductionInfo(add1, 0).c_str());
568 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl1, 0).c_str());
569 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):PrimInt", GetInductionInfo(add2, 0).c_str());
570 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
571 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):PrimInt",
572 GetInductionInfo(neg, 0).c_str());
573 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
574 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
575}
576
577TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
578 // Setup:
579 // k = 1;
580 // for (int i = 0; i < 100; i++) {
581 // t = k + 100;
582 // t = k - 1;
583 // t = - t
584 // t = k * 2;
585 // t = k << 2;
586 // k = k / 100; // geometric (/ 100)
587 // }
588 BuildLoopNest(1);
589 HPhi* k_header = InsertLoopPhi(0, 0);
590 k_header->AddInput(constant1_);
591
592 HInstruction* add = InsertInstruction(
593 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
594 HInstruction* sub = InsertInstruction(
595 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
596 HInstruction* neg = InsertInstruction(
597 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
598 HInstruction* mul = InsertInstruction(
599 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
600 HInstruction* shl = InsertInstruction(
601 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
602 HInstruction* div = InsertInstruction(
603 new (&allocator_) HDiv(Primitive::kPrimInt, k_header, constant100_, kNoDexPc), 0);
604 k_header->AddInput(div);
605 PerformInductionVarAnalysis();
606
607 // Note, only the phi in the cycle and direct additive derived are classified.
608 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
609 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
610 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
611 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
612 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
613 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
614 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
615}
616
Aart Bikd0a022d2016-12-13 11:22:31 -0800617TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
618 // Setup:
619 // k = 100;
620 // for (int i = 0; i < 100; i++) {
621 // k = k >> 1; // geometric (/ 2)
622 // }
623 BuildLoopNest(1);
624 HPhi* k_header = InsertLoopPhi(0, 0);
625 k_header->AddInput(constant100_);
626
627 HInstruction* shr = InsertInstruction(
628 new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
629 k_header->AddInput(shr);
630 PerformInductionVarAnalysis();
631
632 // Note, only the phi in the cycle is classified.
633 EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
634 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
635}
636
637TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
638 // Setup:
639 // k = -1;
640 // for (int i = 0; i < 100; i++) {
641 // k = k >> 1; // initial value is negative
642 // }
643 BuildLoopNest(1);
644 HPhi* k_header = InsertLoopPhi(0, 0);
645 k_header->AddInput(constantm1_);
646
647 HInstruction* shr = InsertInstruction(
648 new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
649 k_header->AddInput(shr);
650 PerformInductionVarAnalysis();
651
652 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
653 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
654}
655
Aart Bikdf7822e2016-12-06 10:05:30 -0800656TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800657 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800658 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800659 // for (int i = 0; i < 100; i++) {
660 // t = k + 100;
661 // t = k - 1;
662 // t = -t
663 // t = k * 2;
664 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800665 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800666 // }
667 BuildLoopNest(1);
668 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800669 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800670
671 HInstruction* add = InsertInstruction(
672 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
673 HInstruction* sub = InsertInstruction(
674 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
675 HInstruction* neg = InsertInstruction(
676 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
677 HInstruction* mul = InsertInstruction(
678 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
679 HInstruction* shl = InsertInstruction(
680 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
681 HInstruction* rem = InsertInstruction(
Aart Bikdf7822e2016-12-06 10:05:30 -0800682 new (&allocator_) HRem(Primitive::kPrimInt, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800683 k_header->AddInput(rem);
684 PerformInductionVarAnalysis();
685
Aart Bikdf7822e2016-12-06 10:05:30 -0800686 // Note, only the phi in the cycle and derived are classified.
687 EXPECT_STREQ("wrap((100), ((100) % (7))):PrimInt", GetInductionInfo(k_header, 0).c_str());
688 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):PrimInt", GetInductionInfo(add, 0).c_str());
689 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
690 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):PrimInt", GetInductionInfo(neg, 0).c_str());
691 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):PrimInt", GetInductionInfo(mul, 0).c_str());
692 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800693 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700694}
695
696TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
697 // Setup:
698 // k = 0;
699 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700700 // a[k] = 0;
701 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700702 // }
703 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800704 HPhi* k_header = InsertLoopPhi(0, 0);
705 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000706
Aart Bikc071a012016-12-01 10:22:31 -0800707 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700708 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000709 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800710 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700711 PerformInductionVarAnalysis();
712
Aart Bik0d345cf2016-03-16 10:49:38 -0700713 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800714 GetInductionInfo(k_header, 0).c_str());
715 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700716 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800717 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700718}
719
720TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
721 // Setup:
722 // k = 0;
723 // t = 100;
724 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700725 // a[k] = 0;
726 // k = t;
727 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700728 // }
729 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800730 HPhi* k_header = InsertLoopPhi(0, 0);
731 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000732 HPhi* t = InsertLoopPhi(1, 0);
733 t->AddInput(constant100_);
734
Aart Bikc071a012016-12-01 10:22:31 -0800735 HInstruction* store = InsertArrayStore(k_header, 0);
736 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700737 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000738 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
739 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700740 PerformInductionVarAnalysis();
741
Aart Bik0d345cf2016-03-16 10:49:38 -0700742 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):PrimInt):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700743 GetInductionInfo(store->InputAt(1), 0).c_str());
744}
745
746TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
747 // Setup:
748 // k = 0;
749 // for (int i = 0; i < 100; i++) {
750 // t = k + 100;
751 // t = k - 100;
752 // t = k * 100;
753 // t = k << 1;
754 // t = - k;
755 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800756 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700757 // }
758 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800759 HPhi* k_header = InsertLoopPhi(0, 0);
760 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000761
Aart Bik7dc96932016-10-12 10:01:05 -0700762 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800763 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700764 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800765 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700766 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800767 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
768 HInstruction* shl1 = InsertInstruction(
769 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
770 HInstruction* neg1 = InsertInstruction(
771 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
772 HInstruction* shl2 = InsertInstruction(
773 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
774 HInstruction* neg2 = InsertInstruction(
775 new (&allocator_) HNeg(Primitive::kPrimInt, shl2), 0);
776 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700777 PerformInductionVarAnalysis();
778
Aart Bik0d345cf2016-03-16 10:49:38 -0700779 EXPECT_STREQ("wrap((100), ((2) * i + (100)):PrimInt):PrimInt",
780 GetInductionInfo(add, 0).c_str());
781 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):PrimInt):PrimInt",
782 GetInductionInfo(sub, 0).c_str());
783 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):PrimInt):PrimInt",
784 GetInductionInfo(mul, 0).c_str());
785 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800786 GetInductionInfo(shl1, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700787 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800788 GetInductionInfo(neg1, 0).c_str());
789 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
790 EXPECT_STREQ("(( - (2)) * i + (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700791}
792
793TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
794 // Setup:
795 // k = 0;
796 // t = 100;
797 // for (int i = 0; i < 100; i++) {
798 // a[k] = 0;
799 // a[t] = 0;
800 // // Swap t <-> k.
801 // d = t;
802 // t = k;
803 // k = d;
804 // }
805 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800806 HPhi* k_header = InsertLoopPhi(0, 0);
807 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000808 HPhi* t = InsertLoopPhi(1, 0);
809 t->AddInput(constant100_);
810
Aart Bikc071a012016-12-01 10:22:31 -0800811 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000812 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800813 k_header->AddInput(t);
814 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700815 PerformInductionVarAnalysis();
816
Aart Bik0d345cf2016-03-16 10:49:38 -0700817 EXPECT_STREQ("periodic((0), (100)):PrimInt", GetInductionInfo(store1->InputAt(1), 0).c_str());
818 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700819}
820
821TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
822 // Setup:
823 // k = 0;
824 // for (int i = 0; i < 100; i++) {
825 // a[k] = 0;
826 // k = 1 - k;
827 // }
828 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800829 HPhi* k_header = InsertLoopPhi(0, 0);
830 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000831
Aart Bikc071a012016-12-01 10:22:31 -0800832 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700833 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800834 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
835 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700836 PerformInductionVarAnalysis();
837
Aart Bik0d345cf2016-03-16 10:49:38 -0700838 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
839 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700840}
841
Aart Bik7dc96932016-10-12 10:01:05 -0700842TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
843 // Setup:
844 // k = 0;
845 // for (int i = 0; i < 100; i++) {
846 // a[k] = 0;
847 // k = k ^ 1;
848 // }
849 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800850 HPhi* k_header = InsertLoopPhi(0, 0);
851 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700852
Aart Bikc071a012016-12-01 10:22:31 -0800853 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700854 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800855 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant1_), 0);
856 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700857 PerformInductionVarAnalysis();
858
859 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
860 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
861}
862
Aart Bik639cc8c2016-10-18 13:03:31 -0700863TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
864 // Setup:
865 // k = 1;
866 // for (int i = 0; i < 100; i++) {
867 // k = 1 ^ k;
868 // }
869 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800870 HPhi* k_header = InsertLoopPhi(0, 0);
871 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700872
873 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800874 new (&allocator_) HXor(Primitive::kPrimInt, constant1_, k_header), 0);
875 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700876 PerformInductionVarAnalysis();
877
Aart Bikc071a012016-12-01 10:22:31 -0800878 EXPECT_STREQ("periodic((1), ((1) ^ (1))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700879 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
880}
881
Aart Bik7dc96932016-10-12 10:01:05 -0700882TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
883 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700884 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700885 // for (int i = 0; i < 100; i++) {
886 // k = k ^ 100;
887 // }
888 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800889 HPhi* k_header = InsertLoopPhi(0, 0);
890 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700891
892 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800893 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant100_), 0);
894 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700895 PerformInductionVarAnalysis();
896
Aart Bikc071a012016-12-01 10:22:31 -0800897 EXPECT_STREQ("periodic((1), ((1) ^ (100))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700898 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
899}
900
901TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
902 // Setup:
903 // k = 0;
904 // for (int i = 0; i < 100; i++) {
905 // k = (k == 0);
906 // }
907 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800908 HPhi* k_header = InsertLoopPhi(0, 0);
909 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700910
Aart Bikc071a012016-12-01 10:22:31 -0800911 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(k_header, constant0_), 0);
912 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700913 PerformInductionVarAnalysis();
914
Aart Bikc071a012016-12-01 10:22:31 -0800915 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700916 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
917}
918
919TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
920 // Setup:
921 // k = 0;
922 // for (int i = 0; i < 100; i++) {
923 // k = (0 == k);
924 // }
925 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800926 HPhi* k_header = InsertLoopPhi(0, 0);
927 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700928
Aart Bikc071a012016-12-01 10:22:31 -0800929 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(constant0_, k_header), 0);
930 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700931 PerformInductionVarAnalysis();
932
Aart Bikc071a012016-12-01 10:22:31 -0800933 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700934 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
935}
936
937TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
938 // Setup:
939 // k = 0;
940 // for (int i = 0; i < 100; i++) {
941 // k = (k != 1);
942 // }
943 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800944 HPhi* k_header = InsertLoopPhi(0, 0);
945 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700946
Aart Bikc071a012016-12-01 10:22:31 -0800947 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(k_header, constant1_), 0);
948 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700949 PerformInductionVarAnalysis();
950
Aart Bikc071a012016-12-01 10:22:31 -0800951 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700952 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
953}
954
955TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
956 // Setup:
957 // k = 0;
958 // for (int i = 0; i < 100; i++) {
959 // k = (1 != k);
960 // }
961 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800962 HPhi* k_header = InsertLoopPhi(0, 0);
963 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700964
Aart Bikc071a012016-12-01 10:22:31 -0800965 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(constant1_, k_header), 0);
966 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700967 PerformInductionVarAnalysis();
968
Aart Bikc071a012016-12-01 10:22:31 -0800969 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700970 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700971}
972
Aart Bike609b7c2015-08-27 13:46:58 -0700973TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
974 // Setup:
975 // k = 0;
976 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800977 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700978 // k = 1 - k;
979 // t = k + 100;
980 // t = k - 100;
981 // t = k * 100;
982 // t = k << 1;
983 // t = - k;
984 // }
985 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000986 HPhi* k_header = InsertLoopPhi(0, 0);
987 k_header->AddInput(constant0_);
988
Aart Bikc071a012016-12-01 10:22:31 -0800989 HInstruction* neg1 = InsertInstruction(
990 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
991 HInstruction* idiom = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000992 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700993 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800994 new (&allocator_) HAdd(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700995 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800996 new (&allocator_) HSub(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700997 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800998 new (&allocator_) HMul(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700999 HInstruction* shl = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001000 new (&allocator_) HShl(Primitive::kPrimInt, idiom, constant1_), 0);
1001 HInstruction* neg2 = InsertInstruction(
1002 new (&allocator_) HNeg(Primitive::kPrimInt, idiom), 0);
1003 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -07001004 PerformInductionVarAnalysis();
1005
Aart Bikc071a012016-12-01 10:22:31 -08001006 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(k_header, 0).c_str());
1007 EXPECT_STREQ("periodic((0), ( - (1))):PrimInt", GetInductionInfo(neg1, 0).c_str());
1008 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(idiom, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001009 EXPECT_STREQ("periodic(((1) + (100)), (100)):PrimInt", GetInductionInfo(add, 0).c_str());
1010 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):PrimInt", GetInductionInfo(sub, 0).c_str());
1011 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
1012 EXPECT_STREQ("periodic((2), (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -08001013 EXPECT_STREQ("periodic(( - (1)), (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001014}
1015
1016TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
1017 // Setup:
1018 // k = 0;
1019 // for (int i_0 = 0; i_0 < 100; i_0++) {
1020 // ..
1021 // for (int i_9 = 0; i_9 < 100; i_9++) {
1022 // k = 1 + k;
1023 // a[k] = 0;
1024 // }
1025 // ..
1026 // }
1027 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +00001028
Aart Bikc071a012016-12-01 10:22:31 -08001029 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +00001030 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001031 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +00001032 }
1033
Aart Bik7dc96932016-10-12 10:01:05 -07001034 HInstruction* inc = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001035 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +00001036 HInstruction* store = InsertArrayStore(inc, 9);
1037
1038 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001039 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
1040 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001041 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001042 PerformInductionVarAnalysis();
1043
Aart Bike609b7c2015-08-27 13:46:58 -07001044 // Avoid exact phi number, since that depends on the SSA building phase.
1045 std::regex r("\\(\\(1\\) \\* i \\+ "
Aart Bik0d345cf2016-03-16 10:49:38 -07001046 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):PrimInt");
Aart Bik30efb4e2015-07-30 12:14:31 -07001047
1048 for (int d = 0; d < 10; d++) {
1049 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001050 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001051 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001052 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001053 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001054 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001055 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001056 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001057 }
1058}
1059
Aart Bik78296912016-03-25 13:14:53 -07001060TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1061 // Setup:
1062 // for (int i = 0; i < 100; i++) {
1063 // k = (byte) i;
1064 // a[k] = 0;
1065 // a[i] = 0;
1066 // }
1067 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001068 HInstruction* conv = InsertInstruction(
Aart Bik78296912016-03-25 13:14:53 -07001069 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
1070 HInstruction* store1 = InsertArrayStore(conv, 0);
1071 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1072 PerformInductionVarAnalysis();
1073
1074 // Regular int induction (i) is "transferred" over conversion into byte induction (k).
1075 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
1076 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
1077 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
1078
1079 // Type matters!
1080 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1081
1082 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001083 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001084}
1085
Aart Bikcc42be02016-10-20 16:14:16 -07001086TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1087 // Setup:
1088 // for (int i = 0; i < 100; i++) {
1089 // k = (byte) i;
1090 // a[k] = 0;
1091 // k = k + 1
1092 // a[k] = 0;
1093 // }
1094 BuildLoopNest(1);
1095 HInstruction* conv = InsertInstruction(
1096 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
1097 HInstruction* store1 = InsertArrayStore(conv, 0);
1098 HInstruction* add = InsertInstruction(
1099 new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
1100 HInstruction* store2 = InsertArrayStore(add, 0);
1101
1102 PerformInductionVarAnalysis();
1103
1104 // Byte induction (k) is "transferred" over conversion into addition (k + 1).
1105 // This means only values within byte range can be trusted (even though
1106 // addition can jump out of the range of course).
1107 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
1108 EXPECT_STREQ("((1) * i + (1)):PrimByte", GetInductionInfo(store2->InputAt(1), 0).c_str());
1109}
1110
Aart Bik0d345cf2016-03-16 10:49:38 -07001111TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1112 // Setup:
1113 // for (byte i = -128; i < 127; i++) { // just fits!
1114 // }
1115 BuildLoopNest(1);
1116 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1117 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1118 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
1119 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
1120 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1121 basic_[0]->ReplaceInput(conv, 1);
1122 PerformInductionVarAnalysis();
1123
1124 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
1125 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001126 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001127}
1128
1129TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1130 // Setup:
1131 // for (byte i = -128; i < 128; i++) { // infinite loop!
1132 // }
1133 BuildLoopNest(1);
1134 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1135 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1136 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
1137 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
1138 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1139 basic_[0]->ReplaceInput(conv, 1);
1140 PerformInductionVarAnalysis();
1141
1142 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
1143 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001144 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001145}
1146
1147TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1148 // Setup:
1149 // for (short i = -32768; i < 32767; i++) { // just fits!
1150 // }
1151 BuildLoopNest(1);
1152 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1153 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1154 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
1155 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
1156 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1157 basic_[0]->ReplaceInput(conv, 1);
1158 PerformInductionVarAnalysis();
1159
1160 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
1161 GetInductionInfo(increment_[0], 0).c_str());
1162 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001163 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001164}
1165
1166TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1167 // Setup:
1168 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1169 // }
1170 BuildLoopNest(1);
1171 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1172 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1173 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
1174 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
1175 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1176 basic_[0]->ReplaceInput(conv, 1);
1177 PerformInductionVarAnalysis();
1178
1179 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
1180 GetInductionInfo(increment_[0], 0).c_str());
1181 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001182 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001183}
1184
1185TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1186 // Setup:
1187 // for (char i = 0; i < 65535; i++) { // just fits!
1188 // }
1189 BuildLoopNest(1);
1190 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1191 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
1192 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
1193 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1194 basic_[0]->ReplaceInput(conv, 1);
1195 PerformInductionVarAnalysis();
1196
1197 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
1198 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001199 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001200}
1201
1202TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1203 // Setup:
1204 // for (char i = 0; i < 65536; i++) { // infinite loop!
1205 // }
1206 BuildLoopNest(1);
1207 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1208 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
1209 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
1210 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1211 basic_[0]->ReplaceInput(conv, 1);
1212 PerformInductionVarAnalysis();
1213
1214 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
1215 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001216 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001217}
1218
Aart Bik30efb4e2015-07-30 12:14:31 -07001219} // namespace art