blob: e519e77f6085cc2a52ae8f11c92cc99058d66854 [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.
Aart Bike609b7c2015-08-27 13:46:58 -070081 parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070082 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070083 constant0_ = graph_->GetIntConstant(0);
84 constant1_ = graph_->GetIntConstant(1);
85 constant100_ = graph_->GetIntConstant(100);
Aart Bik30efb4e2015-07-30 12:14:31 -070086 induc_ = new (&allocator_) HLocal(n);
87 entry_->AddInstruction(induc_);
88 entry_->AddInstruction(new (&allocator_) HStoreLocal(induc_, constant0_));
89 tmp_ = new (&allocator_) HLocal(n + 1);
90 entry_->AddInstruction(tmp_);
91 entry_->AddInstruction(new (&allocator_) HStoreLocal(tmp_, constant100_));
Aart Bike609b7c2015-08-27 13:46:58 -070092 dum_ = new (&allocator_) HLocal(n + 2);
93 entry_->AddInstruction(dum_);
94 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070095
96 // Provide loop instructions.
97 for (int d = 0; d < n; d++) {
98 basic_[d] = new (&allocator_) HLocal(d);
99 entry_->AddInstruction(basic_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700100 loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
101 HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700102 loop_header_[d]->AddInstruction(load);
Aart Bikd14c5952015-09-08 15:25:15 -0700103 HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700104 loop_header_[d]->AddInstruction(compare);
105 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
106 load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
107 loop_body_[d]->AddInstruction(load);
Aart Bike609b7c2015-08-27 13:46:58 -0700108 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700109 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700110 loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
Aart Bik30efb4e2015-07-30 12:14:31 -0700111 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
112 }
113 }
114
115 // Builds if-statement at depth d.
116 void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
117 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
118 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
119 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
120 graph_->AddBlock(cond);
121 graph_->AddBlock(ifTrue);
122 graph_->AddBlock(ifFalse);
123 // Conditional split.
124 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
125 cond->AddSuccessor(ifTrue);
126 cond->AddSuccessor(ifFalse);
127 ifTrue->AddSuccessor(loop_body_[d]);
128 ifFalse->AddSuccessor(loop_body_[d]);
129 cond->AddInstruction(new (&allocator_) HIf(parameter_));
130 *ifT = ifTrue;
131 *ifF = ifFalse;
132 }
133
134 // Inserts instruction right before increment at depth d.
135 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
136 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
137 return instruction;
138 }
139
140 // Inserts local load at depth d.
141 HInstruction* InsertLocalLoad(HLocal* local, int d) {
Aart Bike609b7c2015-08-27 13:46:58 -0700142 return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700143 }
144
145 // Inserts local store at depth d.
146 HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
147 return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
148 }
149
150 // Inserts an array store with given local as subscript at depth d to
151 // enable tests to inspect the computed induction at that point easily.
152 HInstruction* InsertArrayStore(HLocal* subscript, int d) {
153 HInstruction* load = InsertInstruction(
154 new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
155 return InsertInstruction(new (&allocator_) HArraySet(
156 parameter_, load, constant0_, Primitive::kPrimInt, 0), d);
157 }
158
Aart Bike609b7c2015-08-27 13:46:58 -0700159 // Returns induction information of instruction in loop at depth d.
160 std::string GetInductionInfo(HInstruction* instruction, int d) {
161 return HInductionVarAnalysis::InductionToString(
162 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700163 }
164
165 // Performs InductionVarAnalysis (after proper set up).
166 void PerformInductionVarAnalysis() {
167 ASSERT_TRUE(graph_->TryBuildingSsa());
168 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
169 iva_->Run();
170 }
171
172 // General building fields.
173 ArenaPool pool_;
174 ArenaAllocator allocator_;
175 HGraph* graph_;
176 HInductionVarAnalysis* iva_;
177
178 // Fixed basic blocks and instructions.
179 HBasicBlock* entry_;
180 HBasicBlock* exit_;
181 HInstruction* parameter_; // "this"
182 HInstruction* constant0_;
183 HInstruction* constant1_;
184 HInstruction* constant100_;
185 HLocal* induc_; // "vreg_n", the "k"
186 HLocal* tmp_; // "vreg_n+1"
Aart Bike609b7c2015-08-27 13:46:58 -0700187 HLocal* dum_; // "vreg_n+2"
Aart Bik30efb4e2015-07-30 12:14:31 -0700188
189 // Loop specifics.
190 HBasicBlock* loop_preheader_[10];
191 HBasicBlock* loop_header_[10];
192 HBasicBlock* loop_body_[10];
193 HInstruction* increment_[10];
194 HLocal* basic_[10]; // "vreg_d", the "i_d"
195};
196
197//
198// The actual InductionVarAnalysis tests.
199//
200
201TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
202 // Setup:
203 // for (int i_0 = 0; i_0 < 100; i_0++) {
204 // ..
205 // for (int i_9 = 0; i_9 < 100; i_9++) {
206 // }
207 // ..
208 // }
209 BuildLoopNest(10);
210 ASSERT_TRUE(graph_->TryBuildingSsa());
211 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
212 for (int d = 0; d < 1; d++) {
213 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
214 (d == 0) ? nullptr
215 : loop_header_[d - 1]->GetLoopInformation());
216 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
217 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
218 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
219 loop_body_[d]->GetLoopInformation());
220 }
221 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
222}
223
Aart Bike609b7c2015-08-27 13:46:58 -0700224TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700225 // Setup:
226 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700227 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700228 // }
229 BuildLoopNest(1);
230 HInstruction* store = InsertArrayStore(basic_[0], 0);
231 PerformInductionVarAnalysis();
232
Aart Bike609b7c2015-08-27 13:46:58 -0700233 EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700234 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700235
236 // Trip-count.
237 EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700238}
239
Aart Bike609b7c2015-08-27 13:46:58 -0700240TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700241 // Setup:
242 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700243 // k = 100 + i;
244 // k = 100 - i;
245 // k = 100 * i;
246 // k = i << 1;
247 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700248 // }
249 BuildLoopNest(1);
250 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700251 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700252 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700253 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700254 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700255 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700256 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700257 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700259 HInstruction *shl = InsertInstruction(
260 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
261 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700262 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700263 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700264 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700265 PerformInductionVarAnalysis();
266
Aart Bik471a2032015-09-04 18:22:11 -0700267 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
268 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
269 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
270 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
271 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700272}
273
274TEST_F(InductionVarAnalysisTest, FindChainInduction) {
275 // Setup:
276 // k = 0;
277 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700278 // k = k + 100;
279 // a[k] = 0;
280 // k = k - 1;
281 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700282 // }
283 BuildLoopNest(1);
284 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700285 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700286 InsertLocalStore(induc_, add, 0);
287 HInstruction* store1 = InsertArrayStore(induc_, 0);
288 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700289 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700290 InsertLocalStore(induc_, sub, 0);
291 HInstruction* store2 = InsertArrayStore(induc_, 0);
292 PerformInductionVarAnalysis();
293
Aart Bik471a2032015-09-04 18:22:11 -0700294 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700295 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700296 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700297 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700298}
299
300TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
301 // Setup:
302 // k = 0;
303 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700304 // if () k = k + 1;
305 // else k = k + 1;
306 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700307 // }
308 BuildLoopNest(1);
309 HBasicBlock* ifTrue;
310 HBasicBlock* ifFalse;
311 BuildIf(0, &ifTrue, &ifFalse);
312 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700313 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700314 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700315 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700316 ifTrue->AddInstruction(inc1);
317 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
318 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700319 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700320 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700321 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700322 ifFalse->AddInstruction(inc2);
323 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
324 // Merge over a phi.
325 HInstruction* store = InsertArrayStore(induc_, 0);
326 PerformInductionVarAnalysis();
327
Aart Bik471a2032015-09-04 18:22:11 -0700328 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700329}
330
331TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
332 // Setup:
333 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700334 // if () k = i + 1;
335 // else k = i + 1;
336 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700337 // }
338 BuildLoopNest(1);
339 HBasicBlock* ifTrue;
340 HBasicBlock* ifFalse;
341 BuildIf(0, &ifTrue, &ifFalse);
342 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700343 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700344 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700345 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700346 ifTrue->AddInstruction(inc1);
347 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
348 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700349 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700350 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700351 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700352 ifFalse->AddInstruction(inc2);
353 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
354 // Merge over a phi.
355 HInstruction* store = InsertArrayStore(induc_, 0);
356 PerformInductionVarAnalysis();
357
Aart Bik471a2032015-09-04 18:22:11 -0700358 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700359}
360
361TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
362 // Setup:
363 // k = 0;
364 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700365 // a[k] = 0;
366 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700367 // }
368 BuildLoopNest(1);
369 HInstruction* store = InsertArrayStore(induc_, 0);
370 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700371 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700372 InsertLocalStore(induc_, sub, 0);
373 PerformInductionVarAnalysis();
374
Aart Bik471a2032015-09-04 18:22:11 -0700375 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700376 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700377}
378
379TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
380 // Setup:
381 // k = 0;
382 // t = 100;
383 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700384 // a[k] = 0;
385 // k = t;
386 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700387 // }
388 BuildLoopNest(1);
389 HInstruction* store = InsertArrayStore(induc_, 0);
390 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
391 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700392 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700393 InsertLocalStore(tmp_, sub, 0);
394 PerformInductionVarAnalysis();
395
Aart Bik471a2032015-09-04 18:22:11 -0700396 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700397 GetInductionInfo(store->InputAt(1), 0).c_str());
398}
399
400TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
401 // Setup:
402 // k = 0;
403 // for (int i = 0; i < 100; i++) {
404 // t = k + 100;
405 // t = k - 100;
406 // t = k * 100;
407 // t = k << 1;
408 // t = - k;
409 // k = i << 1;
410 // }
411 BuildLoopNest(1);
412 HInstruction *add = InsertInstruction(
413 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
414 InsertLocalStore(tmp_, add, 0);
415 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700416 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700417 InsertLocalStore(tmp_, sub, 0);
418 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700419 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700420 InsertLocalStore(tmp_, mul, 0);
421 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700422 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700423 InsertLocalStore(tmp_, shl, 0);
424 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700425 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700426 InsertLocalStore(tmp_, neg, 0);
427 InsertLocalStore(
428 induc_,
429 InsertInstruction(
430 new (&allocator_)
431 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
432 PerformInductionVarAnalysis();
433
Aart Bik471a2032015-09-04 18:22:11 -0700434 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
435 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
436 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
437 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
438 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700439}
440
441TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
442 // Setup:
443 // k = 0;
444 // t = 100;
445 // for (int i = 0; i < 100; i++) {
446 // a[k] = 0;
447 // a[t] = 0;
448 // // Swap t <-> k.
449 // d = t;
450 // t = k;
451 // k = d;
452 // }
453 BuildLoopNest(1);
454 HInstruction* store1 = InsertArrayStore(induc_, 0);
455 HInstruction* store2 = InsertArrayStore(tmp_, 0);
456 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
457 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
458 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
459 PerformInductionVarAnalysis();
460
461 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
462 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
463}
464
465TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
466 // Setup:
467 // k = 0;
468 // for (int i = 0; i < 100; i++) {
469 // a[k] = 0;
470 // k = 1 - k;
471 // }
472 BuildLoopNest(1);
473 HInstruction* store = InsertArrayStore(induc_, 0);
474 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700475 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700476 InsertLocalStore(induc_, sub, 0);
477 PerformInductionVarAnalysis();
478
Aart Bik471a2032015-09-04 18:22:11 -0700479 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
480 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700481}
482
483TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
484 // Setup:
485 // k = 0;
486 // for (int i = 0; i < 100; i++) {
487 // k = 1 - k;
488 // t = k + 100;
489 // t = k - 100;
490 // t = k * 100;
491 // t = k << 1;
492 // t = - k;
493 // }
494 BuildLoopNest(1);
495 InsertLocalStore(
496 induc_,
497 InsertInstruction(new (&allocator_)
498 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
499 // Derived expressions.
500 HInstruction *add = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700501 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700502 InsertLocalStore(tmp_, add, 0);
503 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700504 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700505 InsertLocalStore(tmp_, sub, 0);
506 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700507 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700508 InsertLocalStore(tmp_, mul, 0);
509 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700510 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700511 InsertLocalStore(tmp_, shl, 0);
512 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700513 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700514 InsertLocalStore(tmp_, neg, 0);
515 PerformInductionVarAnalysis();
516
Aart Bik471a2032015-09-04 18:22:11 -0700517 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
518 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
519 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
520 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
521 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700522}
523
Aart Bikf475bee2015-09-16 12:50:25 -0700524TEST_F(InductionVarAnalysisTest, FindRange) {
525 // Setup:
526 // for (int i = 0; i < 100; i++) {
527 // k = i << 1;
528 // k = k + 1;
529 // a[k] = 0;
530 // }
531 BuildLoopNest(1);
532 HInstruction *shl = InsertInstruction(
533 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
534 InsertLocalStore(induc_, shl, 0);
535 HInstruction *add = InsertInstruction(
536 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
537 InsertLocalStore(induc_, add, 0);
538 HInstruction* store = InsertArrayStore(induc_, 0);
539 PerformInductionVarAnalysis();
540
541 EXPECT_STREQ("((2) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
542
543 InductionVarRange range(iva_);
544 InductionVarRange::Value v_min = range.GetMinInduction(store, store->InputAt(1));
545 InductionVarRange::Value v_max = range.GetMaxInduction(store, store->InputAt(1));
546 EXPECT_EQ(0, v_min.a_constant);
547 EXPECT_EQ(1, v_min.b_constant);
548 EXPECT_EQ(0, v_max.a_constant);
549 EXPECT_EQ(199, v_max.b_constant);
550}
551
Aart Bik30efb4e2015-07-30 12:14:31 -0700552TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
553 // Setup:
554 // k = 0;
555 // for (int i_0 = 0; i_0 < 100; i_0++) {
556 // ..
557 // for (int i_9 = 0; i_9 < 100; i_9++) {
558 // k = 1 + k;
559 // a[k] = 0;
560 // }
561 // ..
562 // }
563 BuildLoopNest(10);
564 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700565 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700566 InsertLocalStore(induc_, inc, 9);
567 HInstruction* store = InsertArrayStore(induc_, 9);
568 PerformInductionVarAnalysis();
569
Aart Bike609b7c2015-08-27 13:46:58 -0700570 // Avoid exact phi number, since that depends on the SSA building phase.
571 std::regex r("\\(\\(1\\) \\* i \\+ "
572 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700573
574 for (int d = 0; d < 10; d++) {
575 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700576 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700577 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700578 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700579 }
Aart Bik471a2032015-09-04 18:22:11 -0700580 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700581 // Trip-count.
582 EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700583 }
584}
585
586} // namespace art