blob: 82ee93d5c2e8f128205439b3f226c705ba0723f7 [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 Bike6bd0272016-12-16 13:57:52 -0800177 // Returns true for narrowing linear induction.
178 bool IsNarrowingLinear(HInstruction* instruction) {
179 return HInductionVarAnalysis::IsNarrowingLinear(
180 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction));
181 }
182
Aart Bik30efb4e2015-07-30 12:14:31 -0700183 // Performs InductionVarAnalysis (after proper set up).
184 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000185 graph_->BuildDominatorTree();
Aart Bik30efb4e2015-07-30 12:14:31 -0700186 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
187 iva_->Run();
188 }
189
190 // General building fields.
191 ArenaPool pool_;
192 ArenaAllocator allocator_;
193 HGraph* graph_;
194 HInductionVarAnalysis* iva_;
195
196 // Fixed basic blocks and instructions.
197 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000198 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700199 HBasicBlock* exit_;
200 HInstruction* parameter_; // "this"
201 HInstruction* constant0_;
202 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800203 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800204 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700205 HInstruction* constant100_;
Aart Bikd0a022d2016-12-13 11:22:31 -0800206 HInstruction* constantm1_;
David Brazdil15693bf2015-12-16 10:30:45 +0000207 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700208
209 // Loop specifics.
210 HBasicBlock* loop_preheader_[10];
211 HBasicBlock* loop_header_[10];
212 HBasicBlock* loop_body_[10];
213 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000214 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700215};
216
217//
218// The actual InductionVarAnalysis tests.
219//
220
221TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
222 // Setup:
223 // for (int i_0 = 0; i_0 < 100; i_0++) {
224 // ..
225 // for (int i_9 = 0; i_9 < 100; i_9++) {
226 // }
227 // ..
228 // }
229 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000230 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700231
Aart Bik30efb4e2015-07-30 12:14:31 -0700232 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
233 for (int d = 0; d < 1; d++) {
234 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
235 (d == 0) ? nullptr
236 : loop_header_[d - 1]->GetLoopInformation());
237 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
238 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
239 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
240 loop_body_[d]->GetLoopInformation());
241 }
242 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
243}
244
Aart Bike609b7c2015-08-27 13:46:58 -0700245TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700246 // Setup:
247 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700248 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700249 // }
250 BuildLoopNest(1);
251 HInstruction* store = InsertArrayStore(basic_[0], 0);
252 PerformInductionVarAnalysis();
253
Aart Bik0d345cf2016-03-16 10:49:38 -0700254 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
255 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700256
Aart Bik78296912016-03-25 13:14:53 -0700257 // Offset matters!
258 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
259
Aart Bikd14c5952015-09-08 15:25:15 -0700260 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700261 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700262}
263
Aart Bike609b7c2015-08-27 13:46:58 -0700264TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700265 // Setup:
266 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800267 // t = 100 + i;
268 // t = 100 - i;
269 // t = 100 * i;
270 // t = i << 1;
271 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700272 // }
273 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700274 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000275 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700276 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000277 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700278 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000279 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700280 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000281 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700282 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000283 new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700284 PerformInductionVarAnalysis();
285
Aart Bik0d345cf2016-03-16 10:49:38 -0700286 EXPECT_STREQ("((1) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
287 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
288 EXPECT_STREQ("((100) * i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
289 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
290 EXPECT_STREQ("(( - (1)) * i + (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700291}
292
293TEST_F(InductionVarAnalysisTest, FindChainInduction) {
294 // Setup:
295 // k = 0;
296 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700297 // k = k + 100;
298 // a[k] = 0;
299 // k = k - 1;
300 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700301 // }
302 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800303 HPhi* k_header = InsertLoopPhi(0, 0);
304 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000305
Aart Bik7dc96932016-10-12 10:01:05 -0700306 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800307 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000308 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700309 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000310 new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
311 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800312 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700313 PerformInductionVarAnalysis();
314
Aart Bikc071a012016-12-01 10:22:31 -0800315 EXPECT_STREQ("(((100) - (1)) * i + (0)):PrimInt",
316 GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700317 EXPECT_STREQ("(((100) - (1)) * i + (100)):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700318 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700319 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700320 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700321}
322
323TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
324 // Setup:
325 // k = 0;
326 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700327 // if () k = k + 1;
328 // else k = k + 1;
329 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700330 // }
331 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000332 HPhi* k_header = InsertLoopPhi(0, 0);
333 k_header->AddInput(constant0_);
334
Aart Bik30efb4e2015-07-30 12:14:31 -0700335 HBasicBlock* ifTrue;
336 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000337 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
338
Aart Bik30efb4e2015-07-30 12:14:31 -0700339 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000340 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700341 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000342 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700343 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000344 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700345 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000346 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700347 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000348 HInstruction* store = InsertArrayStore(k_body, 0);
349 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700350 PerformInductionVarAnalysis();
351
Aart Bikc071a012016-12-01 10:22:31 -0800352 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700353 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700354
355 // Both increments get same induction.
356 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
357 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700358}
359
360TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
361 // Setup:
362 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700363 // if () k = i + 1;
364 // else k = i + 1;
365 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700366 // }
367 BuildLoopNest(1);
368 HBasicBlock* ifTrue;
369 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000370 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
371
Aart Bik30efb4e2015-07-30 12:14:31 -0700372 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000373 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700374 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000375 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700376 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000377 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700378 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000379 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700380 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000381 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700382 PerformInductionVarAnalysis();
383
Aart Bik0d345cf2016-03-16 10:49:38 -0700384 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800385
386 // Both increments get same induction.
387 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
388 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
389}
390
Aart Bikdf7822e2016-12-06 10:05:30 -0800391TEST_F(InductionVarAnalysisTest, AddLinear) {
392 // Setup:
393 // for (int i = 0; i < 100; i++) {
394 // t1 = i + i;
395 // t2 = 7 + i;
396 // t3 = t1 + t2;
397 // }
398 BuildLoopNest(1);
399
400 HInstruction* add1 = InsertInstruction(
401 new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], basic_[0]), 0);
402 HInstruction* add2 = InsertInstruction(
403 new (&allocator_) HAdd(Primitive::kPrimInt, constant7_, basic_[0]), 0);
404 HInstruction* add3 = InsertInstruction(
405 new (&allocator_) HAdd(Primitive::kPrimInt, add1, add2), 0);
406 PerformInductionVarAnalysis();
407
408 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(basic_[0], 0).c_str());
409 EXPECT_STREQ("(((1) + (1)) * i + (0)):PrimInt", GetInductionInfo(add1, 0).c_str());
410 EXPECT_STREQ("((1) * i + (7)):PrimInt", GetInductionInfo(add2, 0).c_str());
411 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):PrimInt", GetInductionInfo(add3, 0).c_str());
412}
413
414TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
415 // Setup:
416 // k = 1;
417 // for (int i = 0; i < 100; i++) {
418 // t = i * 2;
419 // t = 100 + t
420 // k = t + k; // polynomial
421 // }
422 BuildLoopNest(1);
423 HPhi* k_header = InsertLoopPhi(0, 0);
424 k_header->AddInput(constant1_);
425
426 HInstruction* mul = InsertInstruction(
427 new (&allocator_) HMul(Primitive::kPrimInt, basic_[0], constant2_), 0);
428 HInstruction* add = InsertInstruction(
429 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, mul), 0);
430 HInstruction* pol = InsertInstruction(
431 new (&allocator_) HAdd(Primitive::kPrimInt, add, k_header), 0);
432 k_header->AddInput(pol);
433 PerformInductionVarAnalysis();
434
435 // Note, only the phi in the cycle and the base linear induction are classified.
436 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):PrimInt) + (1)):PrimInt",
437 GetInductionInfo(k_header, 0).c_str());
438 EXPECT_STREQ("((2) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
439 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
440}
441
442TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
443 // Setup:
444 // k = 1;
445 // for (int i = 0; i < 100; i++) {
446 // t = k + 100;
447 // t = k - 1;
448 // t = - t
449 // t = k * 2;
450 // t = k << 2;
451 // k = k + i; // polynomial
452 // }
453 BuildLoopNest(1);
454 HPhi* k_header = InsertLoopPhi(0, 0);
455 k_header->AddInput(constant1_);
456
457 HInstruction* add = InsertInstruction(
458 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
459 HInstruction* sub = InsertInstruction(
460 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
461 HInstruction* neg = InsertInstruction(
462 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
463 HInstruction* mul = InsertInstruction(
464 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
465 HInstruction* shl = InsertInstruction(
466 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
467 HInstruction* pol = InsertInstruction(
468 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
469 k_header->AddInput(pol);
470 PerformInductionVarAnalysis();
471
472 // Note, only the phi in the cycle and derived are classified.
473 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (1)):PrimInt",
474 GetInductionInfo(k_header, 0).c_str());
475 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) + (100))):PrimInt",
476 GetInductionInfo(add, 0).c_str());
477 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
478 GetInductionInfo(sub, 0).c_str());
479 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
480 GetInductionInfo(neg, 0).c_str());
481 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):PrimInt) + (2)):PrimInt",
482 GetInductionInfo(mul, 0).c_str());
483 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):PrimInt) + (4)):PrimInt",
484 GetInductionInfo(shl, 0).c_str());
485 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
486}
487
488TEST_F(InductionVarAnalysisTest, AddPolynomial) {
489 // Setup:
490 // k = 7;
491 // for (int i = 0; i < 100; i++) {
492 // t = k + k;
493 // t = t + k;
494 // k = k + i
495 // }
496 BuildLoopNest(1);
497 HPhi* k_header = InsertLoopPhi(0, 0);
498 k_header->AddInput(constant7_);
499
500 HInstruction* add1 = InsertInstruction(
501 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, k_header), 0);
502 HInstruction* add2 = InsertInstruction(
503 new (&allocator_) HAdd(Primitive::kPrimInt, add1, k_header), 0);
504 HInstruction* add3 = InsertInstruction(
505 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
506 k_header->AddInput(add3);
507 PerformInductionVarAnalysis();
508
509 // Note, only the phi in the cycle and added-derived are classified.
510 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (7)):PrimInt",
511 GetInductionInfo(k_header, 0).c_str());
512 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):PrimInt) + ((7) + (7))):PrimInt",
513 GetInductionInfo(add1, 0).c_str());
514 EXPECT_STREQ(
515 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):PrimInt) + (((7) + (7)) + (7))):PrimInt",
516 GetInductionInfo(add2, 0).c_str());
517 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
518}
519
Aart Bikc071a012016-12-01 10:22:31 -0800520TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
521 // Setup:
522 // k = 1;
523 // for (int i = 0; i < 100; i++) {
524 // k = k * 100; // geometric (x 100)
525 // }
526 BuildLoopNest(1);
527 HPhi* k_header = InsertLoopPhi(0, 0);
528 k_header->AddInput(constant1_);
529
530 HInstruction* mul = InsertInstruction(
531 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
532 k_header->AddInput(mul);
533 PerformInductionVarAnalysis();
534
535 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
536 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
537}
538
539TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
540 // Setup:
541 // k = 1;
542 // for (int i = 0; i < 100; i++) {
543 // t = k + 1;
544 // k = k << 1; // geometric (x 2)
545 // t = k + 100;
546 // t = k - 1;
547 // t = - t;
548 // t = k * 2;
549 // t = k << 2;
550 // }
551 BuildLoopNest(1);
552 HPhi* k_header = InsertLoopPhi(0, 0);
553 k_header->AddInput(constant1_);
554
555 HInstruction* add1 = InsertInstruction(
556 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
557 HInstruction* shl1 = InsertInstruction(
558 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
559 HInstruction* add2 = InsertInstruction(
560 new (&allocator_) HAdd(Primitive::kPrimInt, shl1, constant100_), 0);
561 HInstruction* sub = InsertInstruction(
562 new (&allocator_) HSub(Primitive::kPrimInt, shl1, constant1_), 0);
563 HInstruction* neg = InsertInstruction(
564 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
565 HInstruction* mul = InsertInstruction(
566 new (&allocator_) HMul(Primitive::kPrimInt, shl1, constant2_), 0);
567 HInstruction* shl2 = InsertInstruction(
568 new (&allocator_) HShl(Primitive::kPrimInt, shl1, constant2_), 0);
569 k_header->AddInput(shl1);
570 PerformInductionVarAnalysis();
571
572 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
573 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):PrimInt", GetInductionInfo(add1, 0).c_str());
574 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl1, 0).c_str());
575 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):PrimInt", GetInductionInfo(add2, 0).c_str());
576 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
577 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):PrimInt",
578 GetInductionInfo(neg, 0).c_str());
579 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
580 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
581}
582
583TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
584 // Setup:
585 // k = 1;
586 // for (int i = 0; i < 100; i++) {
587 // t = k + 100;
588 // t = k - 1;
589 // t = - t
590 // t = k * 2;
591 // t = k << 2;
592 // k = k / 100; // geometric (/ 100)
593 // }
594 BuildLoopNest(1);
595 HPhi* k_header = InsertLoopPhi(0, 0);
596 k_header->AddInput(constant1_);
597
598 HInstruction* add = InsertInstruction(
599 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
600 HInstruction* sub = InsertInstruction(
601 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
602 HInstruction* neg = InsertInstruction(
603 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
604 HInstruction* mul = InsertInstruction(
605 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
606 HInstruction* shl = InsertInstruction(
607 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
608 HInstruction* div = InsertInstruction(
609 new (&allocator_) HDiv(Primitive::kPrimInt, k_header, constant100_, kNoDexPc), 0);
610 k_header->AddInput(div);
611 PerformInductionVarAnalysis();
612
613 // Note, only the phi in the cycle and direct additive derived are classified.
614 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
615 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
616 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
617 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
618 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
619 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
620 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
621}
622
Aart Bikd0a022d2016-12-13 11:22:31 -0800623TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
624 // Setup:
625 // k = 100;
626 // for (int i = 0; i < 100; i++) {
627 // k = k >> 1; // geometric (/ 2)
628 // }
629 BuildLoopNest(1);
630 HPhi* k_header = InsertLoopPhi(0, 0);
631 k_header->AddInput(constant100_);
632
633 HInstruction* shr = InsertInstruction(
634 new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
635 k_header->AddInput(shr);
636 PerformInductionVarAnalysis();
637
638 // Note, only the phi in the cycle is classified.
639 EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
640 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
641}
642
643TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
644 // Setup:
645 // k = -1;
646 // for (int i = 0; i < 100; i++) {
647 // k = k >> 1; // initial value is negative
648 // }
649 BuildLoopNest(1);
650 HPhi* k_header = InsertLoopPhi(0, 0);
651 k_header->AddInput(constantm1_);
652
653 HInstruction* shr = InsertInstruction(
654 new (&allocator_) HShr(Primitive::kPrimInt, k_header, constant1_), 0);
655 k_header->AddInput(shr);
656 PerformInductionVarAnalysis();
657
658 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
659 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
660}
661
Aart Bikdf7822e2016-12-06 10:05:30 -0800662TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800663 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800664 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800665 // for (int i = 0; i < 100; i++) {
666 // t = k + 100;
667 // t = k - 1;
668 // t = -t
669 // t = k * 2;
670 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800671 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800672 // }
673 BuildLoopNest(1);
674 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800675 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800676
677 HInstruction* add = InsertInstruction(
678 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
679 HInstruction* sub = InsertInstruction(
680 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
681 HInstruction* neg = InsertInstruction(
682 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
683 HInstruction* mul = InsertInstruction(
684 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
685 HInstruction* shl = InsertInstruction(
686 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
687 HInstruction* rem = InsertInstruction(
Aart Bikdf7822e2016-12-06 10:05:30 -0800688 new (&allocator_) HRem(Primitive::kPrimInt, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800689 k_header->AddInput(rem);
690 PerformInductionVarAnalysis();
691
Aart Bikdf7822e2016-12-06 10:05:30 -0800692 // Note, only the phi in the cycle and derived are classified.
693 EXPECT_STREQ("wrap((100), ((100) % (7))):PrimInt", GetInductionInfo(k_header, 0).c_str());
694 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):PrimInt", GetInductionInfo(add, 0).c_str());
695 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
696 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):PrimInt", GetInductionInfo(neg, 0).c_str());
697 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):PrimInt", GetInductionInfo(mul, 0).c_str());
698 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800699 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700700}
701
702TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
703 // Setup:
704 // k = 0;
705 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700706 // a[k] = 0;
707 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700708 // }
709 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800710 HPhi* k_header = InsertLoopPhi(0, 0);
711 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000712
Aart Bikc071a012016-12-01 10:22:31 -0800713 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700714 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000715 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800716 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700717 PerformInductionVarAnalysis();
718
Aart Bik0d345cf2016-03-16 10:49:38 -0700719 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800720 GetInductionInfo(k_header, 0).c_str());
721 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700722 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800723 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700724}
725
726TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
727 // Setup:
728 // k = 0;
729 // t = 100;
730 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700731 // a[k] = 0;
732 // k = t;
733 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700734 // }
735 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800736 HPhi* k_header = InsertLoopPhi(0, 0);
737 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000738 HPhi* t = InsertLoopPhi(1, 0);
739 t->AddInput(constant100_);
740
Aart Bikc071a012016-12-01 10:22:31 -0800741 HInstruction* store = InsertArrayStore(k_header, 0);
742 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700743 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000744 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
745 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700746 PerformInductionVarAnalysis();
747
Aart Bik0d345cf2016-03-16 10:49:38 -0700748 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):PrimInt):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700749 GetInductionInfo(store->InputAt(1), 0).c_str());
750}
751
752TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
753 // Setup:
754 // k = 0;
755 // for (int i = 0; i < 100; i++) {
756 // t = k + 100;
757 // t = k - 100;
758 // t = k * 100;
759 // t = k << 1;
760 // t = - k;
761 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800762 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700763 // }
764 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800765 HPhi* k_header = InsertLoopPhi(0, 0);
766 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000767
Aart Bik7dc96932016-10-12 10:01:05 -0700768 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800769 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700770 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800771 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700772 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800773 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
774 HInstruction* shl1 = InsertInstruction(
775 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
776 HInstruction* neg1 = InsertInstruction(
777 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
778 HInstruction* shl2 = InsertInstruction(
779 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
780 HInstruction* neg2 = InsertInstruction(
781 new (&allocator_) HNeg(Primitive::kPrimInt, shl2), 0);
782 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700783 PerformInductionVarAnalysis();
784
Aart Bik0d345cf2016-03-16 10:49:38 -0700785 EXPECT_STREQ("wrap((100), ((2) * i + (100)):PrimInt):PrimInt",
786 GetInductionInfo(add, 0).c_str());
787 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):PrimInt):PrimInt",
788 GetInductionInfo(sub, 0).c_str());
789 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):PrimInt):PrimInt",
790 GetInductionInfo(mul, 0).c_str());
791 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800792 GetInductionInfo(shl1, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700793 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800794 GetInductionInfo(neg1, 0).c_str());
795 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
796 EXPECT_STREQ("(( - (2)) * i + (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700797}
798
799TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
800 // Setup:
801 // k = 0;
802 // t = 100;
803 // for (int i = 0; i < 100; i++) {
804 // a[k] = 0;
805 // a[t] = 0;
806 // // Swap t <-> k.
807 // d = t;
808 // t = k;
809 // k = d;
810 // }
811 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800812 HPhi* k_header = InsertLoopPhi(0, 0);
813 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000814 HPhi* t = InsertLoopPhi(1, 0);
815 t->AddInput(constant100_);
816
Aart Bikc071a012016-12-01 10:22:31 -0800817 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000818 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800819 k_header->AddInput(t);
820 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700821 PerformInductionVarAnalysis();
822
Aart Bik0d345cf2016-03-16 10:49:38 -0700823 EXPECT_STREQ("periodic((0), (100)):PrimInt", GetInductionInfo(store1->InputAt(1), 0).c_str());
824 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700825}
826
827TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
828 // Setup:
829 // k = 0;
830 // for (int i = 0; i < 100; i++) {
831 // a[k] = 0;
832 // k = 1 - k;
833 // }
834 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800835 HPhi* k_header = InsertLoopPhi(0, 0);
836 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000837
Aart Bikc071a012016-12-01 10:22:31 -0800838 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700839 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800840 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
841 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700842 PerformInductionVarAnalysis();
843
Aart Bik0d345cf2016-03-16 10:49:38 -0700844 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
845 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700846}
847
Aart Bik7dc96932016-10-12 10:01:05 -0700848TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
849 // Setup:
850 // k = 0;
851 // for (int i = 0; i < 100; i++) {
852 // a[k] = 0;
853 // k = k ^ 1;
854 // }
855 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800856 HPhi* k_header = InsertLoopPhi(0, 0);
857 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700858
Aart Bikc071a012016-12-01 10:22:31 -0800859 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700860 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800861 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant1_), 0);
862 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700863 PerformInductionVarAnalysis();
864
865 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
866 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
867}
868
Aart Bik639cc8c2016-10-18 13:03:31 -0700869TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
870 // Setup:
871 // k = 1;
872 // for (int i = 0; i < 100; i++) {
873 // k = 1 ^ k;
874 // }
875 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800876 HPhi* k_header = InsertLoopPhi(0, 0);
877 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700878
879 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800880 new (&allocator_) HXor(Primitive::kPrimInt, constant1_, k_header), 0);
881 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700882 PerformInductionVarAnalysis();
883
Aart Bikc071a012016-12-01 10:22:31 -0800884 EXPECT_STREQ("periodic((1), ((1) ^ (1))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700885 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
886}
887
Aart Bik7dc96932016-10-12 10:01:05 -0700888TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
889 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700890 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700891 // for (int i = 0; i < 100; i++) {
892 // k = k ^ 100;
893 // }
894 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800895 HPhi* k_header = InsertLoopPhi(0, 0);
896 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700897
898 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800899 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant100_), 0);
900 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700901 PerformInductionVarAnalysis();
902
Aart Bikc071a012016-12-01 10:22:31 -0800903 EXPECT_STREQ("periodic((1), ((1) ^ (100))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700904 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
905}
906
907TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
908 // Setup:
909 // k = 0;
910 // for (int i = 0; i < 100; i++) {
911 // k = (k == 0);
912 // }
913 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800914 HPhi* k_header = InsertLoopPhi(0, 0);
915 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700916
Aart Bikc071a012016-12-01 10:22:31 -0800917 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(k_header, constant0_), 0);
918 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700919 PerformInductionVarAnalysis();
920
Aart Bikc071a012016-12-01 10:22:31 -0800921 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700922 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
923}
924
925TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
926 // Setup:
927 // k = 0;
928 // for (int i = 0; i < 100; i++) {
929 // k = (0 == k);
930 // }
931 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800932 HPhi* k_header = InsertLoopPhi(0, 0);
933 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700934
Aart Bikc071a012016-12-01 10:22:31 -0800935 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(constant0_, k_header), 0);
936 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700937 PerformInductionVarAnalysis();
938
Aart Bikc071a012016-12-01 10:22:31 -0800939 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700940 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
941}
942
943TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
944 // Setup:
945 // k = 0;
946 // for (int i = 0; i < 100; i++) {
947 // k = (k != 1);
948 // }
949 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800950 HPhi* k_header = InsertLoopPhi(0, 0);
951 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700952
Aart Bikc071a012016-12-01 10:22:31 -0800953 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(k_header, constant1_), 0);
954 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700955 PerformInductionVarAnalysis();
956
Aart Bikc071a012016-12-01 10:22:31 -0800957 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700958 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
959}
960
961TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
962 // Setup:
963 // k = 0;
964 // for (int i = 0; i < 100; i++) {
965 // k = (1 != k);
966 // }
967 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800968 HPhi* k_header = InsertLoopPhi(0, 0);
969 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700970
Aart Bikc071a012016-12-01 10:22:31 -0800971 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(constant1_, k_header), 0);
972 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700973 PerformInductionVarAnalysis();
974
Aart Bikc071a012016-12-01 10:22:31 -0800975 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700976 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700977}
978
Aart Bike609b7c2015-08-27 13:46:58 -0700979TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
980 // Setup:
981 // k = 0;
982 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800983 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700984 // k = 1 - k;
985 // t = k + 100;
986 // t = k - 100;
987 // t = k * 100;
988 // t = k << 1;
989 // t = - k;
990 // }
991 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000992 HPhi* k_header = InsertLoopPhi(0, 0);
993 k_header->AddInput(constant0_);
994
Aart Bikc071a012016-12-01 10:22:31 -0800995 HInstruction* neg1 = InsertInstruction(
996 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
997 HInstruction* idiom = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000998 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700999 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001000 new (&allocator_) HAdd(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001001 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001002 new (&allocator_) HSub(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001003 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001004 new (&allocator_) HMul(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001005 HInstruction* shl = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001006 new (&allocator_) HShl(Primitive::kPrimInt, idiom, constant1_), 0);
1007 HInstruction* neg2 = InsertInstruction(
1008 new (&allocator_) HNeg(Primitive::kPrimInt, idiom), 0);
1009 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -07001010 PerformInductionVarAnalysis();
1011
Aart Bikc071a012016-12-01 10:22:31 -08001012 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(k_header, 0).c_str());
1013 EXPECT_STREQ("periodic((0), ( - (1))):PrimInt", GetInductionInfo(neg1, 0).c_str());
1014 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(idiom, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001015 EXPECT_STREQ("periodic(((1) + (100)), (100)):PrimInt", GetInductionInfo(add, 0).c_str());
1016 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):PrimInt", GetInductionInfo(sub, 0).c_str());
1017 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
1018 EXPECT_STREQ("periodic((2), (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -08001019 EXPECT_STREQ("periodic(( - (1)), (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001020}
1021
1022TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
1023 // Setup:
1024 // k = 0;
1025 // for (int i_0 = 0; i_0 < 100; i_0++) {
1026 // ..
1027 // for (int i_9 = 0; i_9 < 100; i_9++) {
1028 // k = 1 + k;
1029 // a[k] = 0;
1030 // }
1031 // ..
1032 // }
1033 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +00001034
Aart Bikc071a012016-12-01 10:22:31 -08001035 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +00001036 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001037 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +00001038 }
1039
Aart Bik7dc96932016-10-12 10:01:05 -07001040 HInstruction* inc = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -08001041 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +00001042 HInstruction* store = InsertArrayStore(inc, 9);
1043
1044 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001045 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
1046 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001047 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001048 PerformInductionVarAnalysis();
1049
Aart Bike609b7c2015-08-27 13:46:58 -07001050 // Avoid exact phi number, since that depends on the SSA building phase.
1051 std::regex r("\\(\\(1\\) \\* i \\+ "
Aart Bik0d345cf2016-03-16 10:49:38 -07001052 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):PrimInt");
Aart Bik30efb4e2015-07-30 12:14:31 -07001053
1054 for (int d = 0; d < 10; d++) {
1055 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001056 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001057 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001058 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001059 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001060 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001061 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001062 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001063 }
1064}
1065
Aart Bik78296912016-03-25 13:14:53 -07001066TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1067 // Setup:
1068 // for (int i = 0; i < 100; i++) {
1069 // k = (byte) i;
1070 // a[k] = 0;
1071 // a[i] = 0;
1072 // }
1073 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001074 HInstruction* conv = InsertInstruction(
Aart Bike6bd0272016-12-16 13:57:52 -08001075 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], kNoDexPc), 0);
Aart Bik78296912016-03-25 13:14:53 -07001076 HInstruction* store1 = InsertArrayStore(conv, 0);
1077 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1078 PerformInductionVarAnalysis();
1079
Aart Bike6bd0272016-12-16 13:57:52 -08001080 // Regular int induction (i) is transferred over conversion into byte induction (k).
Aart Bik78296912016-03-25 13:14:53 -07001081 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
1082 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
1083 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
1084
Aart Bike6bd0272016-12-16 13:57:52 -08001085 // Narrowing detected.
1086 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1087 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));
1088
Aart Bik78296912016-03-25 13:14:53 -07001089 // Type matters!
1090 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1091
1092 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001093 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001094}
1095
Aart Bikcc42be02016-10-20 16:14:16 -07001096TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1097 // Setup:
1098 // for (int i = 0; i < 100; i++) {
1099 // k = (byte) i;
1100 // a[k] = 0;
1101 // k = k + 1
1102 // a[k] = 0;
1103 // }
1104 BuildLoopNest(1);
1105 HInstruction* conv = InsertInstruction(
Aart Bike6bd0272016-12-16 13:57:52 -08001106 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], kNoDexPc), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001107 HInstruction* store1 = InsertArrayStore(conv, 0);
1108 HInstruction* add = InsertInstruction(
1109 new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
1110 HInstruction* store2 = InsertArrayStore(add, 0);
1111
1112 PerformInductionVarAnalysis();
1113
Aart Bike6bd0272016-12-16 13:57:52 -08001114 // Byte induction (k) is detected, but it does not transfer over the addition,
1115 // since this may yield out-of-type values.
Aart Bikcc42be02016-10-20 16:14:16 -07001116 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001117 EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
1118
1119 // Narrowing detected.
1120 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1121 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1))); // works for null
1122}
1123
1124TEST_F(InductionVarAnalysisTest, ByteInduction) {
1125 // Setup:
1126 // k = -128;
1127 // for (int i = 0; i < 100; i++) {
1128 // k = k + 1;
1129 // k = (byte) k;
1130 // }
1131 BuildLoopNest(1);
1132 HPhi* k_header = InsertLoopPhi(0, 0);
1133 k_header->AddInput(graph_->GetIntConstant(-128));
1134
1135 HInstruction* add = InsertInstruction(
1136 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
1137 HInstruction* conv = InsertInstruction(
1138 new (&allocator_) HTypeConversion(Primitive::kPrimByte, add, kNoDexPc), 0);
1139 k_header->AddInput(conv);
1140 PerformInductionVarAnalysis();
1141
1142 // Byte induction (k) is detected, but it does not transfer over the addition,
1143 // since this may yield out-of-type values.
1144 EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(k_header, 0).c_str());
1145 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1146
1147 // Narrowing detected.
1148 EXPECT_TRUE(IsNarrowingLinear(k_header));
1149 EXPECT_FALSE(IsNarrowingLinear(add)); // works for null
1150}
1151
1152TEST_F(InductionVarAnalysisTest, NoByteInduction1) {
1153 // Setup:
1154 // k = -129; / does not fit!
1155 // for (int i = 0; i < 100; i++) {
1156 // k = k + 1;
1157 // k = (byte) k;
1158 // }
1159 BuildLoopNest(1);
1160 HPhi* k_header = InsertLoopPhi(0, 0);
1161 k_header->AddInput(graph_->GetIntConstant(-129));
1162
1163 HInstruction* add = InsertInstruction(
1164 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
1165 HInstruction* conv = InsertInstruction(
1166 new (&allocator_) HTypeConversion(Primitive::kPrimByte, add, kNoDexPc), 0);
1167 k_header->AddInput(conv);
1168 PerformInductionVarAnalysis();
1169
1170 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1171 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1172}
1173
1174TEST_F(InductionVarAnalysisTest, NoByteInduction2) {
1175 // Setup:
1176 // k = 0;
1177 // for (int i = 0; i < 100; i++) {
1178 // k = (byte) k; // conversion not done last!
1179 // k = k + 1;
1180 // }
1181 BuildLoopNest(1);
1182 HPhi* k_header = InsertLoopPhi(0, 0);
1183 k_header->AddInput(constant0_);
1184
1185 HInstruction* conv = InsertInstruction(
1186 new (&allocator_) HTypeConversion(Primitive::kPrimByte, k_header, kNoDexPc), 0);
1187 HInstruction* add = InsertInstruction(
1188 new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
1189 k_header->AddInput(add);
1190 PerformInductionVarAnalysis();
1191
1192 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1193 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
Aart Bikcc42be02016-10-20 16:14:16 -07001194}
1195
Aart Bik0d345cf2016-03-16 10:49:38 -07001196TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1197 // Setup:
1198 // for (byte i = -128; i < 127; i++) { // just fits!
1199 // }
1200 BuildLoopNest(1);
1201 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1202 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1203 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001204 HInstruction* conv =
1205 new (&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001206 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1207 basic_[0]->ReplaceInput(conv, 1);
1208 PerformInductionVarAnalysis();
1209
Aart Bike6bd0272016-12-16 13:57:52 -08001210 // Recorded at the phi, but not transferred to increment.
1211 EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(basic_[0], 0).c_str());
1212 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1213
1214 // Narrowing detected.
1215 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1216 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1217
Aart Bik0d345cf2016-03-16 10:49:38 -07001218 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001219 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001220}
1221
1222TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1223 // Setup:
1224 // for (byte i = -128; i < 128; i++) { // infinite loop!
1225 // }
1226 BuildLoopNest(1);
1227 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1228 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1229 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001230 HInstruction* conv =
1231 new (&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001232 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1233 basic_[0]->ReplaceInput(conv, 1);
1234 PerformInductionVarAnalysis();
1235
Aart Bike6bd0272016-12-16 13:57:52 -08001236 // Recorded at the phi, but not transferred to increment.
1237 EXPECT_STREQ("((1) * i + (-128)):PrimByte", GetInductionInfo(basic_[0], 0).c_str());
1238 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1239
1240 // Narrowing detected.
1241 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1242 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1243
Aart Bik0d345cf2016-03-16 10:49:38 -07001244 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001245 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001246}
1247
1248TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1249 // Setup:
1250 // for (short i = -32768; i < 32767; i++) { // just fits!
1251 // }
1252 BuildLoopNest(1);
1253 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1254 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1255 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001256 HInstruction* conv =
1257 new (&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001258 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1259 basic_[0]->ReplaceInput(conv, 1);
1260 PerformInductionVarAnalysis();
1261
Aart Bike6bd0272016-12-16 13:57:52 -08001262 // Recorded at the phi, but not transferred to increment.
1263 EXPECT_STREQ("((1) * i + (-32768)):PrimShort", GetInductionInfo(basic_[0], 0).c_str());
1264 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1265
1266 // Narrowing detected.
1267 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1268 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1269
Aart Bik0d345cf2016-03-16 10:49:38 -07001270 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001271 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001272}
1273
1274TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1275 // Setup:
1276 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1277 // }
1278 BuildLoopNest(1);
1279 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1280 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1281 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001282 HInstruction* conv =
1283 new (&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001284 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1285 basic_[0]->ReplaceInput(conv, 1);
1286 PerformInductionVarAnalysis();
1287
Aart Bike6bd0272016-12-16 13:57:52 -08001288 // Recorded at the phi, but not transferred to increment.
1289 EXPECT_STREQ("((1) * i + (-32768)):PrimShort", GetInductionInfo(basic_[0], 0).c_str());
1290 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1291
1292 // Narrowing detected.
1293 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1294 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1295
Aart Bik0d345cf2016-03-16 10:49:38 -07001296 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001297 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001298}
1299
1300TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1301 // Setup:
1302 // for (char i = 0; i < 65535; i++) { // just fits!
1303 // }
1304 BuildLoopNest(1);
1305 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1306 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001307 HInstruction* conv =
1308 new (&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001309 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1310 basic_[0]->ReplaceInput(conv, 1);
1311 PerformInductionVarAnalysis();
1312
Aart Bike6bd0272016-12-16 13:57:52 -08001313 // Recorded at the phi, but not transferred to increment.
1314 EXPECT_STREQ("((1) * i + (0)):PrimChar", GetInductionInfo(basic_[0], 0).c_str());
1315 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1316
1317 // Narrowing detected.
1318 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1319 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1320
Aart Bik0d345cf2016-03-16 10:49:38 -07001321 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001322 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001323}
1324
1325TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1326 // Setup:
1327 // for (char i = 0; i < 65536; i++) { // infinite loop!
1328 // }
1329 BuildLoopNest(1);
1330 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1331 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001332 HInstruction* conv =
1333 new (&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001334 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1335 basic_[0]->ReplaceInput(conv, 1);
1336 PerformInductionVarAnalysis();
1337
Aart Bike6bd0272016-12-16 13:57:52 -08001338 // Recorded at the phi, but not transferred to increment.
1339 EXPECT_STREQ("((1) * i + (0)):PrimChar", GetInductionInfo(basic_[0], 0).c_str());
1340 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1341
1342 // Narrowing detected.
1343 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1344 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1345
Aart Bik0d345cf2016-03-16 10:49:38 -07001346 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001347 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001348}
1349
Aart Bik30efb4e2015-07-30 12:14:31 -07001350} // namespace art