blob: 20492e7152c6835a931a918ab8f791df72f6891f [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.
Aart Bik9401f532015-09-28 16:25:56 -0700237 EXPECT_STREQ("(TC-loop:(100))",
238 GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700239}
240
Aart Bike609b7c2015-08-27 13:46:58 -0700241TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700242 // Setup:
243 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700244 // k = 100 + i;
245 // k = 100 - i;
246 // k = 100 * i;
247 // k = i << 1;
248 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700249 // }
250 BuildLoopNest(1);
251 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700252 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700253 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700255 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700256 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700257 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700258 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700259 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700260 HInstruction *shl = InsertInstruction(
261 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
262 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700264 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700265 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700266 PerformInductionVarAnalysis();
267
Aart Bik471a2032015-09-04 18:22:11 -0700268 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
269 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
270 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
271 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
272 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700273}
274
275TEST_F(InductionVarAnalysisTest, FindChainInduction) {
276 // Setup:
277 // k = 0;
278 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700279 // k = k + 100;
280 // a[k] = 0;
281 // k = k - 1;
282 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700283 // }
284 BuildLoopNest(1);
285 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700286 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700287 InsertLocalStore(induc_, add, 0);
288 HInstruction* store1 = InsertArrayStore(induc_, 0);
289 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700290 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700291 InsertLocalStore(induc_, sub, 0);
292 HInstruction* store2 = InsertArrayStore(induc_, 0);
293 PerformInductionVarAnalysis();
294
Aart Bik471a2032015-09-04 18:22:11 -0700295 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700296 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700297 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700298 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700299}
300
301TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
302 // Setup:
303 // k = 0;
304 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700305 // if () k = k + 1;
306 // else k = k + 1;
307 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700308 // }
309 BuildLoopNest(1);
310 HBasicBlock* ifTrue;
311 HBasicBlock* ifFalse;
312 BuildIf(0, &ifTrue, &ifFalse);
313 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700314 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700315 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700316 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700317 ifTrue->AddInstruction(inc1);
318 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
319 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700320 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700321 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700322 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700323 ifFalse->AddInstruction(inc2);
324 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
325 // Merge over a phi.
326 HInstruction* store = InsertArrayStore(induc_, 0);
327 PerformInductionVarAnalysis();
328
Aart Bik471a2032015-09-04 18:22:11 -0700329 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700330}
331
332TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
333 // Setup:
334 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700335 // if () k = i + 1;
336 // else k = i + 1;
337 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700338 // }
339 BuildLoopNest(1);
340 HBasicBlock* ifTrue;
341 HBasicBlock* ifFalse;
342 BuildIf(0, &ifTrue, &ifFalse);
343 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700344 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700345 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700346 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700347 ifTrue->AddInstruction(inc1);
348 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
349 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700350 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700351 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700352 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700353 ifFalse->AddInstruction(inc2);
354 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
355 // Merge over a phi.
356 HInstruction* store = InsertArrayStore(induc_, 0);
357 PerformInductionVarAnalysis();
358
Aart Bik471a2032015-09-04 18:22:11 -0700359 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700360}
361
362TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
363 // Setup:
364 // k = 0;
365 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700366 // a[k] = 0;
367 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700368 // }
369 BuildLoopNest(1);
370 HInstruction* store = InsertArrayStore(induc_, 0);
371 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700372 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700373 InsertLocalStore(induc_, sub, 0);
374 PerformInductionVarAnalysis();
375
Aart Bik471a2032015-09-04 18:22:11 -0700376 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700377 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700378}
379
380TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
381 // Setup:
382 // k = 0;
383 // t = 100;
384 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700385 // a[k] = 0;
386 // k = t;
387 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700388 // }
389 BuildLoopNest(1);
390 HInstruction* store = InsertArrayStore(induc_, 0);
391 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
392 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700393 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700394 InsertLocalStore(tmp_, sub, 0);
395 PerformInductionVarAnalysis();
396
Aart Bik471a2032015-09-04 18:22:11 -0700397 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700398 GetInductionInfo(store->InputAt(1), 0).c_str());
399}
400
401TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
402 // Setup:
403 // k = 0;
404 // for (int i = 0; i < 100; i++) {
405 // t = k + 100;
406 // t = k - 100;
407 // t = k * 100;
408 // t = k << 1;
409 // t = - k;
410 // k = i << 1;
411 // }
412 BuildLoopNest(1);
413 HInstruction *add = InsertInstruction(
414 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
415 InsertLocalStore(tmp_, add, 0);
416 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700417 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700418 InsertLocalStore(tmp_, sub, 0);
419 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700420 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700421 InsertLocalStore(tmp_, mul, 0);
422 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700423 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700424 InsertLocalStore(tmp_, shl, 0);
425 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700426 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700427 InsertLocalStore(tmp_, neg, 0);
428 InsertLocalStore(
429 induc_,
430 InsertInstruction(
431 new (&allocator_)
432 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
433 PerformInductionVarAnalysis();
434
Aart Bik471a2032015-09-04 18:22:11 -0700435 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
436 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
437 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
438 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
439 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700440}
441
442TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
443 // Setup:
444 // k = 0;
445 // t = 100;
446 // for (int i = 0; i < 100; i++) {
447 // a[k] = 0;
448 // a[t] = 0;
449 // // Swap t <-> k.
450 // d = t;
451 // t = k;
452 // k = d;
453 // }
454 BuildLoopNest(1);
455 HInstruction* store1 = InsertArrayStore(induc_, 0);
456 HInstruction* store2 = InsertArrayStore(tmp_, 0);
457 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
458 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
459 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
460 PerformInductionVarAnalysis();
461
462 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
463 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
464}
465
466TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
467 // Setup:
468 // k = 0;
469 // for (int i = 0; i < 100; i++) {
470 // a[k] = 0;
471 // k = 1 - k;
472 // }
473 BuildLoopNest(1);
474 HInstruction* store = InsertArrayStore(induc_, 0);
475 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700476 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700477 InsertLocalStore(induc_, sub, 0);
478 PerformInductionVarAnalysis();
479
Aart Bik471a2032015-09-04 18:22:11 -0700480 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
481 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700482}
483
484TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
485 // Setup:
486 // k = 0;
487 // for (int i = 0; i < 100; i++) {
488 // k = 1 - k;
489 // t = k + 100;
490 // t = k - 100;
491 // t = k * 100;
492 // t = k << 1;
493 // t = - k;
494 // }
495 BuildLoopNest(1);
496 InsertLocalStore(
497 induc_,
498 InsertInstruction(new (&allocator_)
499 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
500 // Derived expressions.
501 HInstruction *add = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700502 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700503 InsertLocalStore(tmp_, add, 0);
504 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700505 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700506 InsertLocalStore(tmp_, sub, 0);
507 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700508 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700509 InsertLocalStore(tmp_, mul, 0);
510 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700511 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700512 InsertLocalStore(tmp_, shl, 0);
513 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700514 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700515 InsertLocalStore(tmp_, neg, 0);
516 PerformInductionVarAnalysis();
517
Aart Bik471a2032015-09-04 18:22:11 -0700518 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
519 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
520 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
521 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
522 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700523}
524
Aart Bikf475bee2015-09-16 12:50:25 -0700525TEST_F(InductionVarAnalysisTest, FindRange) {
526 // Setup:
527 // for (int i = 0; i < 100; i++) {
528 // k = i << 1;
529 // k = k + 1;
530 // a[k] = 0;
531 // }
532 BuildLoopNest(1);
533 HInstruction *shl = InsertInstruction(
534 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
535 InsertLocalStore(induc_, shl, 0);
536 HInstruction *add = InsertInstruction(
537 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
538 InsertLocalStore(induc_, add, 0);
539 HInstruction* store = InsertArrayStore(induc_, 0);
540 PerformInductionVarAnalysis();
541
542 EXPECT_STREQ("((2) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
543
544 InductionVarRange range(iva_);
545 InductionVarRange::Value v_min = range.GetMinInduction(store, store->InputAt(1));
546 InductionVarRange::Value v_max = range.GetMaxInduction(store, store->InputAt(1));
Aart Bik9401f532015-09-28 16:25:56 -0700547 ASSERT_TRUE(v_min.is_known);
Aart Bikf475bee2015-09-16 12:50:25 -0700548 EXPECT_EQ(0, v_min.a_constant);
549 EXPECT_EQ(1, v_min.b_constant);
Aart Bik9401f532015-09-28 16:25:56 -0700550 ASSERT_TRUE(v_max.is_known);
Aart Bikf475bee2015-09-16 12:50:25 -0700551 EXPECT_EQ(0, v_max.a_constant);
552 EXPECT_EQ(199, v_max.b_constant);
553}
554
Aart Bik30efb4e2015-07-30 12:14:31 -0700555TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
556 // Setup:
557 // k = 0;
558 // for (int i_0 = 0; i_0 < 100; i_0++) {
559 // ..
560 // for (int i_9 = 0; i_9 < 100; i_9++) {
561 // k = 1 + k;
562 // a[k] = 0;
563 // }
564 // ..
565 // }
566 BuildLoopNest(10);
567 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700568 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700569 InsertLocalStore(induc_, inc, 9);
570 HInstruction* store = InsertArrayStore(induc_, 9);
571 PerformInductionVarAnalysis();
572
Aart Bike609b7c2015-08-27 13:46:58 -0700573 // Avoid exact phi number, since that depends on the SSA building phase.
574 std::regex r("\\(\\(1\\) \\* i \\+ "
575 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700576
577 for (int d = 0; d < 10; d++) {
578 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700579 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700580 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700581 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700582 }
Aart Bik471a2032015-09-04 18:22:11 -0700583 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700584 // Trip-count.
Aart Bik9401f532015-09-28 16:25:56 -0700585 EXPECT_STREQ("(TC-loop:(100))",
586 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700587 }
588}
589
590} // namespace art