blob: 19af2fb5db94eb425ed5bcc6ece65bc2bda1acda [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"
21#include "gtest/gtest.h"
22#include "induction_var_analysis.h"
Aart Bikf475bee2015-09-16 12:50:25 -070023#include "induction_var_range.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070024#include "nodes.h"
25#include "optimizing_unit_test.h"
26
27namespace art {
28
29/**
30 * Fixture class for the InductionVarAnalysis tests.
31 */
32class InductionVarAnalysisTest : public testing::Test {
33 public:
34 InductionVarAnalysisTest() : pool_(), allocator_(&pool_) {
35 graph_ = CreateGraph(&allocator_);
36 }
37
38 ~InductionVarAnalysisTest() { }
39
40 // Builds single for-loop at depth d.
41 void BuildForLoop(int d, int n) {
42 ASSERT_LT(d, n);
43 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
44 graph_->AddBlock(loop_preheader_[d]);
45 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
46 graph_->AddBlock(loop_header_[d]);
47 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
48 if (d < (n - 1)) {
49 BuildForLoop(d + 1, n);
50 }
51 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
52 graph_->AddBlock(loop_body_[d]);
53 loop_body_[d]->AddSuccessor(loop_header_[d]);
54 if (d < (n - 1)) {
55 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
56 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
57 } else {
58 loop_header_[d]->AddSuccessor(loop_body_[d]);
59 }
60 }
61
62 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
63 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
64 // populate the loop with instructions to set up interesting scenarios.
65 void BuildLoopNest(int n) {
66 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070067 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070068
69 // Build basic blocks with entry, nested loop, exit.
70 entry_ = new (&allocator_) HBasicBlock(graph_);
71 graph_->AddBlock(entry_);
72 BuildForLoop(0, n);
73 exit_ = new (&allocator_) HBasicBlock(graph_);
74 graph_->AddBlock(exit_);
75 entry_->AddSuccessor(loop_preheader_[0]);
76 loop_header_[0]->AddSuccessor(exit_);
77 graph_->SetEntryBlock(entry_);
78 graph_->SetExitBlock(exit_);
79
80 // Provide entry and exit instructions.
Calin Juravle2c1ffc32015-10-12 15:01:58 +010081 parameter_ = new (&allocator_) HParameterValue(
82 graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070083 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070084 constant0_ = graph_->GetIntConstant(0);
85 constant1_ = graph_->GetIntConstant(1);
86 constant100_ = graph_->GetIntConstant(100);
Aart Bik30efb4e2015-07-30 12:14:31 -070087 induc_ = new (&allocator_) HLocal(n);
88 entry_->AddInstruction(induc_);
89 entry_->AddInstruction(new (&allocator_) HStoreLocal(induc_, constant0_));
90 tmp_ = new (&allocator_) HLocal(n + 1);
91 entry_->AddInstruction(tmp_);
92 entry_->AddInstruction(new (&allocator_) HStoreLocal(tmp_, constant100_));
Aart Bike609b7c2015-08-27 13:46:58 -070093 dum_ = new (&allocator_) HLocal(n + 2);
94 entry_->AddInstruction(dum_);
95 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070096
97 // Provide loop instructions.
98 for (int d = 0; d < n; d++) {
99 basic_[d] = new (&allocator_) HLocal(d);
100 entry_->AddInstruction(basic_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700101 loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
102 HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700103 loop_header_[d]->AddInstruction(load);
Aart Bikd14c5952015-09-08 15:25:15 -0700104 HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700105 loop_header_[d]->AddInstruction(compare);
106 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
107 load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
108 loop_body_[d]->AddInstruction(load);
Aart Bike609b7c2015-08-27 13:46:58 -0700109 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700110 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700111 loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
Aart Bik30efb4e2015-07-30 12:14:31 -0700112 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
113 }
114 }
115
116 // Builds if-statement at depth d.
117 void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
118 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
119 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
120 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
121 graph_->AddBlock(cond);
122 graph_->AddBlock(ifTrue);
123 graph_->AddBlock(ifFalse);
124 // Conditional split.
125 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
126 cond->AddSuccessor(ifTrue);
127 cond->AddSuccessor(ifFalse);
128 ifTrue->AddSuccessor(loop_body_[d]);
129 ifFalse->AddSuccessor(loop_body_[d]);
130 cond->AddInstruction(new (&allocator_) HIf(parameter_));
131 *ifT = ifTrue;
132 *ifF = ifFalse;
133 }
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
141 // Inserts local load at depth d.
142 HInstruction* InsertLocalLoad(HLocal* local, int d) {
Aart Bike609b7c2015-08-27 13:46:58 -0700143 return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700144 }
145
146 // Inserts local store at depth d.
147 HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
148 return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
149 }
150
151 // Inserts an array store with given local as subscript at depth d to
152 // enable tests to inspect the computed induction at that point easily.
153 HInstruction* InsertArrayStore(HLocal* subscript, int d) {
154 HInstruction* load = InsertInstruction(
155 new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
156 return InsertInstruction(new (&allocator_) HArraySet(
157 parameter_, load, constant0_, Primitive::kPrimInt, 0), d);
158 }
159
Aart Bike609b7c2015-08-27 13:46:58 -0700160 // Returns induction information of instruction in loop at depth d.
161 std::string GetInductionInfo(HInstruction* instruction, int d) {
162 return HInductionVarAnalysis::InductionToString(
163 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700164 }
165
166 // Performs InductionVarAnalysis (after proper set up).
167 void PerformInductionVarAnalysis() {
168 ASSERT_TRUE(graph_->TryBuildingSsa());
169 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
170 iva_->Run();
171 }
172
173 // General building fields.
174 ArenaPool pool_;
175 ArenaAllocator allocator_;
176 HGraph* graph_;
177 HInductionVarAnalysis* iva_;
178
179 // Fixed basic blocks and instructions.
180 HBasicBlock* entry_;
181 HBasicBlock* exit_;
182 HInstruction* parameter_; // "this"
183 HInstruction* constant0_;
184 HInstruction* constant1_;
185 HInstruction* constant100_;
186 HLocal* induc_; // "vreg_n", the "k"
187 HLocal* tmp_; // "vreg_n+1"
Aart Bike609b7c2015-08-27 13:46:58 -0700188 HLocal* dum_; // "vreg_n+2"
Aart Bik30efb4e2015-07-30 12:14:31 -0700189
190 // Loop specifics.
191 HBasicBlock* loop_preheader_[10];
192 HBasicBlock* loop_header_[10];
193 HBasicBlock* loop_body_[10];
194 HInstruction* increment_[10];
195 HLocal* basic_[10]; // "vreg_d", the "i_d"
196};
197
198//
199// The actual InductionVarAnalysis tests.
200//
201
202TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
203 // Setup:
204 // for (int i_0 = 0; i_0 < 100; i_0++) {
205 // ..
206 // for (int i_9 = 0; i_9 < 100; i_9++) {
207 // }
208 // ..
209 // }
210 BuildLoopNest(10);
211 ASSERT_TRUE(graph_->TryBuildingSsa());
212 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
213 for (int d = 0; d < 1; d++) {
214 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
215 (d == 0) ? nullptr
216 : loop_header_[d - 1]->GetLoopInformation());
217 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
218 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
219 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
220 loop_body_[d]->GetLoopInformation());
221 }
222 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
223}
224
Aart Bike609b7c2015-08-27 13:46:58 -0700225TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700226 // Setup:
227 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700228 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700229 // }
230 BuildLoopNest(1);
231 HInstruction* store = InsertArrayStore(basic_[0], 0);
232 PerformInductionVarAnalysis();
233
Aart Bike609b7c2015-08-27 13:46:58 -0700234 EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700235 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700236
237 // Trip-count.
Aart Bik9401f532015-09-28 16:25:56 -0700238 EXPECT_STREQ("(TC-loop:(100))",
239 GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700240}
241
Aart Bike609b7c2015-08-27 13:46:58 -0700242TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700243 // Setup:
244 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700245 // k = 100 + i;
246 // k = 100 - i;
247 // k = 100 * i;
248 // k = i << 1;
249 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700250 // }
251 BuildLoopNest(1);
252 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700253 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700255 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700256 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700257 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700259 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700261 HInstruction *shl = InsertInstruction(
262 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
263 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700264 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700265 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700266 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700267 PerformInductionVarAnalysis();
268
Aart Bik471a2032015-09-04 18:22:11 -0700269 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
270 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
271 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
272 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
273 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700274}
275
276TEST_F(InductionVarAnalysisTest, FindChainInduction) {
277 // Setup:
278 // k = 0;
279 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700280 // k = k + 100;
281 // a[k] = 0;
282 // k = k - 1;
283 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700284 // }
285 BuildLoopNest(1);
286 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700287 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700288 InsertLocalStore(induc_, add, 0);
289 HInstruction* store1 = InsertArrayStore(induc_, 0);
290 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700291 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700292 InsertLocalStore(induc_, sub, 0);
293 HInstruction* store2 = InsertArrayStore(induc_, 0);
294 PerformInductionVarAnalysis();
295
Aart Bik471a2032015-09-04 18:22:11 -0700296 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700297 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700298 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700299 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700300}
301
302TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
303 // Setup:
304 // k = 0;
305 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700306 // if () k = k + 1;
307 // else k = k + 1;
308 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700309 // }
310 BuildLoopNest(1);
311 HBasicBlock* ifTrue;
312 HBasicBlock* ifFalse;
313 BuildIf(0, &ifTrue, &ifFalse);
314 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700315 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700316 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700317 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700318 ifTrue->AddInstruction(inc1);
319 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
320 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700321 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700322 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700323 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700324 ifFalse->AddInstruction(inc2);
325 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
326 // Merge over a phi.
327 HInstruction* store = InsertArrayStore(induc_, 0);
328 PerformInductionVarAnalysis();
329
Aart Bik471a2032015-09-04 18:22:11 -0700330 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700331}
332
333TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
334 // Setup:
335 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700336 // if () k = i + 1;
337 // else k = i + 1;
338 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700339 // }
340 BuildLoopNest(1);
341 HBasicBlock* ifTrue;
342 HBasicBlock* ifFalse;
343 BuildIf(0, &ifTrue, &ifFalse);
344 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700345 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700346 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700347 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700348 ifTrue->AddInstruction(inc1);
349 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
350 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700351 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700352 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700353 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700354 ifFalse->AddInstruction(inc2);
355 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
356 // Merge over a phi.
357 HInstruction* store = InsertArrayStore(induc_, 0);
358 PerformInductionVarAnalysis();
359
Aart Bik471a2032015-09-04 18:22:11 -0700360 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700361}
362
363TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
364 // Setup:
365 // k = 0;
366 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700367 // a[k] = 0;
368 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700369 // }
370 BuildLoopNest(1);
371 HInstruction* store = InsertArrayStore(induc_, 0);
372 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700373 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700374 InsertLocalStore(induc_, sub, 0);
375 PerformInductionVarAnalysis();
376
Aart Bik471a2032015-09-04 18:22:11 -0700377 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700378 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700379}
380
381TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
382 // Setup:
383 // k = 0;
384 // t = 100;
385 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700386 // a[k] = 0;
387 // k = t;
388 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700389 // }
390 BuildLoopNest(1);
391 HInstruction* store = InsertArrayStore(induc_, 0);
392 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
393 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700394 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700395 InsertLocalStore(tmp_, sub, 0);
396 PerformInductionVarAnalysis();
397
Aart Bik471a2032015-09-04 18:22:11 -0700398 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700399 GetInductionInfo(store->InputAt(1), 0).c_str());
400}
401
402TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
403 // Setup:
404 // k = 0;
405 // for (int i = 0; i < 100; i++) {
406 // t = k + 100;
407 // t = k - 100;
408 // t = k * 100;
409 // t = k << 1;
410 // t = - k;
411 // k = i << 1;
412 // }
413 BuildLoopNest(1);
414 HInstruction *add = InsertInstruction(
415 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
416 InsertLocalStore(tmp_, add, 0);
417 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700418 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700419 InsertLocalStore(tmp_, sub, 0);
420 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700421 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700422 InsertLocalStore(tmp_, mul, 0);
423 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700424 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700425 InsertLocalStore(tmp_, shl, 0);
426 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700427 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700428 InsertLocalStore(tmp_, neg, 0);
429 InsertLocalStore(
430 induc_,
431 InsertInstruction(
432 new (&allocator_)
433 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
434 PerformInductionVarAnalysis();
435
Aart Bik471a2032015-09-04 18:22:11 -0700436 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
437 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
438 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
439 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
440 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700441}
442
443TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
444 // Setup:
445 // k = 0;
446 // t = 100;
447 // for (int i = 0; i < 100; i++) {
448 // a[k] = 0;
449 // a[t] = 0;
450 // // Swap t <-> k.
451 // d = t;
452 // t = k;
453 // k = d;
454 // }
455 BuildLoopNest(1);
456 HInstruction* store1 = InsertArrayStore(induc_, 0);
457 HInstruction* store2 = InsertArrayStore(tmp_, 0);
458 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
459 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
460 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
461 PerformInductionVarAnalysis();
462
463 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
464 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
465}
466
467TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
468 // Setup:
469 // k = 0;
470 // for (int i = 0; i < 100; i++) {
471 // a[k] = 0;
472 // k = 1 - k;
473 // }
474 BuildLoopNest(1);
475 HInstruction* store = InsertArrayStore(induc_, 0);
476 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700477 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700478 InsertLocalStore(induc_, sub, 0);
479 PerformInductionVarAnalysis();
480
Aart Bik471a2032015-09-04 18:22:11 -0700481 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
482 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700483}
484
485TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
486 // Setup:
487 // k = 0;
488 // for (int i = 0; i < 100; i++) {
489 // k = 1 - k;
490 // t = k + 100;
491 // t = k - 100;
492 // t = k * 100;
493 // t = k << 1;
494 // t = - k;
495 // }
496 BuildLoopNest(1);
497 InsertLocalStore(
498 induc_,
499 InsertInstruction(new (&allocator_)
500 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
501 // Derived expressions.
502 HInstruction *add = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700503 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700504 InsertLocalStore(tmp_, add, 0);
505 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700506 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700507 InsertLocalStore(tmp_, sub, 0);
508 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700509 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700510 InsertLocalStore(tmp_, mul, 0);
511 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700512 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700513 InsertLocalStore(tmp_, shl, 0);
514 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700515 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700516 InsertLocalStore(tmp_, neg, 0);
517 PerformInductionVarAnalysis();
518
Aart Bik471a2032015-09-04 18:22:11 -0700519 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
520 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
521 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
522 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
523 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700524}
525
Aart Bikf475bee2015-09-16 12:50:25 -0700526TEST_F(InductionVarAnalysisTest, FindRange) {
527 // Setup:
528 // for (int i = 0; i < 100; i++) {
529 // k = i << 1;
530 // k = k + 1;
531 // a[k] = 0;
532 // }
533 BuildLoopNest(1);
534 HInstruction *shl = InsertInstruction(
535 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
536 InsertLocalStore(induc_, shl, 0);
537 HInstruction *add = InsertInstruction(
538 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
539 InsertLocalStore(induc_, add, 0);
540 HInstruction* store = InsertArrayStore(induc_, 0);
541 PerformInductionVarAnalysis();
542
543 EXPECT_STREQ("((2) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
544
545 InductionVarRange range(iva_);
546 InductionVarRange::Value v_min = range.GetMinInduction(store, store->InputAt(1));
547 InductionVarRange::Value v_max = range.GetMaxInduction(store, store->InputAt(1));
Aart Bik9401f532015-09-28 16:25:56 -0700548 ASSERT_TRUE(v_min.is_known);
Aart Bikf475bee2015-09-16 12:50:25 -0700549 EXPECT_EQ(0, v_min.a_constant);
550 EXPECT_EQ(1, v_min.b_constant);
Aart Bik9401f532015-09-28 16:25:56 -0700551 ASSERT_TRUE(v_max.is_known);
Aart Bikf475bee2015-09-16 12:50:25 -0700552 EXPECT_EQ(0, v_max.a_constant);
553 EXPECT_EQ(199, v_max.b_constant);
554}
555
Aart Bik30efb4e2015-07-30 12:14:31 -0700556TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
557 // Setup:
558 // k = 0;
559 // for (int i_0 = 0; i_0 < 100; i_0++) {
560 // ..
561 // for (int i_9 = 0; i_9 < 100; i_9++) {
562 // k = 1 + k;
563 // a[k] = 0;
564 // }
565 // ..
566 // }
567 BuildLoopNest(10);
568 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700569 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700570 InsertLocalStore(induc_, inc, 9);
571 HInstruction* store = InsertArrayStore(induc_, 9);
572 PerformInductionVarAnalysis();
573
Aart Bike609b7c2015-08-27 13:46:58 -0700574 // Avoid exact phi number, since that depends on the SSA building phase.
575 std::regex r("\\(\\(1\\) \\* i \\+ "
576 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700577
578 for (int d = 0; d < 10; d++) {
579 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700580 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700581 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700582 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700583 }
Aart Bik471a2032015-09-04 18:22:11 -0700584 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700585 // Trip-count.
Aart Bik9401f532015-09-28 16:25:56 -0700586 EXPECT_STREQ("(TC-loop:(100))",
587 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700588 }
589}
590
591} // namespace art