blob: fd1e334bb6c9cbacae7b1611c45c67c0cea5f4a0 [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"
23#include "nodes.h"
24#include "optimizing_unit_test.h"
25
26namespace art {
27
28/**
29 * Fixture class for the InductionVarAnalysis tests.
30 */
31class InductionVarAnalysisTest : public testing::Test {
32 public:
33 InductionVarAnalysisTest() : pool_(), allocator_(&pool_) {
34 graph_ = CreateGraph(&allocator_);
35 }
36
37 ~InductionVarAnalysisTest() { }
38
39 // Builds single for-loop at depth d.
40 void BuildForLoop(int d, int n) {
41 ASSERT_LT(d, n);
42 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
43 graph_->AddBlock(loop_preheader_[d]);
44 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
45 graph_->AddBlock(loop_header_[d]);
46 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
47 if (d < (n - 1)) {
48 BuildForLoop(d + 1, n);
49 }
50 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
51 graph_->AddBlock(loop_body_[d]);
52 loop_body_[d]->AddSuccessor(loop_header_[d]);
53 if (d < (n - 1)) {
54 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
55 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
56 } else {
57 loop_header_[d]->AddSuccessor(loop_body_[d]);
58 }
59 }
60
61 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
62 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
63 // populate the loop with instructions to set up interesting scenarios.
64 void BuildLoopNest(int n) {
65 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070066 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070067
68 // Build basic blocks with entry, nested loop, exit.
69 entry_ = new (&allocator_) HBasicBlock(graph_);
70 graph_->AddBlock(entry_);
71 BuildForLoop(0, n);
72 exit_ = new (&allocator_) HBasicBlock(graph_);
73 graph_->AddBlock(exit_);
74 entry_->AddSuccessor(loop_preheader_[0]);
75 loop_header_[0]->AddSuccessor(exit_);
76 graph_->SetEntryBlock(entry_);
77 graph_->SetExitBlock(exit_);
78
79 // Provide entry and exit instructions.
Calin Juravlec05aca72015-10-13 13:10:33 +000080 parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070081 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070082 constant0_ = graph_->GetIntConstant(0);
83 constant1_ = graph_->GetIntConstant(1);
84 constant100_ = graph_->GetIntConstant(100);
Aart Bik30efb4e2015-07-30 12:14:31 -070085 induc_ = new (&allocator_) HLocal(n);
86 entry_->AddInstruction(induc_);
87 entry_->AddInstruction(new (&allocator_) HStoreLocal(induc_, constant0_));
88 tmp_ = new (&allocator_) HLocal(n + 1);
89 entry_->AddInstruction(tmp_);
90 entry_->AddInstruction(new (&allocator_) HStoreLocal(tmp_, constant100_));
Aart Bike609b7c2015-08-27 13:46:58 -070091 dum_ = new (&allocator_) HLocal(n + 2);
92 entry_->AddInstruction(dum_);
93 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++) {
97 basic_[d] = new (&allocator_) HLocal(d);
98 entry_->AddInstruction(basic_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -070099 loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
100 HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700101 loop_header_[d]->AddInstruction(load);
Aart Bikd14c5952015-09-08 15:25:15 -0700102 HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700103 loop_header_[d]->AddInstruction(compare);
104 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
105 load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
106 loop_body_[d]->AddInstruction(load);
Aart Bike609b7c2015-08-27 13:46:58 -0700107 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700108 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700109 loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
Aart Bik30efb4e2015-07-30 12:14:31 -0700110 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
111 }
112 }
113
114 // Builds if-statement at depth d.
115 void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
116 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
117 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
118 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
119 graph_->AddBlock(cond);
120 graph_->AddBlock(ifTrue);
121 graph_->AddBlock(ifFalse);
122 // Conditional split.
123 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
124 cond->AddSuccessor(ifTrue);
125 cond->AddSuccessor(ifFalse);
126 ifTrue->AddSuccessor(loop_body_[d]);
127 ifFalse->AddSuccessor(loop_body_[d]);
128 cond->AddInstruction(new (&allocator_) HIf(parameter_));
129 *ifT = ifTrue;
130 *ifF = ifFalse;
131 }
132
133 // Inserts instruction right before increment at depth d.
134 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
135 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
136 return instruction;
137 }
138
139 // Inserts local load at depth d.
140 HInstruction* InsertLocalLoad(HLocal* local, int d) {
Aart Bike609b7c2015-08-27 13:46:58 -0700141 return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700142 }
143
144 // Inserts local store at depth d.
145 HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
146 return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
147 }
148
149 // Inserts an array store with given local as subscript at depth d to
150 // enable tests to inspect the computed induction at that point easily.
151 HInstruction* InsertArrayStore(HLocal* subscript, int d) {
152 HInstruction* load = InsertInstruction(
153 new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
154 return InsertInstruction(new (&allocator_) HArraySet(
155 parameter_, load, constant0_, Primitive::kPrimInt, 0), d);
156 }
157
Aart Bike609b7c2015-08-27 13:46:58 -0700158 // Returns induction information of instruction in loop at depth d.
159 std::string GetInductionInfo(HInstruction* instruction, int d) {
160 return HInductionVarAnalysis::InductionToString(
161 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700162 }
163
164 // Performs InductionVarAnalysis (after proper set up).
165 void PerformInductionVarAnalysis() {
166 ASSERT_TRUE(graph_->TryBuildingSsa());
167 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
168 iva_->Run();
169 }
170
171 // General building fields.
172 ArenaPool pool_;
173 ArenaAllocator allocator_;
174 HGraph* graph_;
175 HInductionVarAnalysis* iva_;
176
177 // Fixed basic blocks and instructions.
178 HBasicBlock* entry_;
179 HBasicBlock* exit_;
180 HInstruction* parameter_; // "this"
181 HInstruction* constant0_;
182 HInstruction* constant1_;
183 HInstruction* constant100_;
184 HLocal* induc_; // "vreg_n", the "k"
185 HLocal* tmp_; // "vreg_n+1"
Aart Bike609b7c2015-08-27 13:46:58 -0700186 HLocal* dum_; // "vreg_n+2"
Aart Bik30efb4e2015-07-30 12:14:31 -0700187
188 // Loop specifics.
189 HBasicBlock* loop_preheader_[10];
190 HBasicBlock* loop_header_[10];
191 HBasicBlock* loop_body_[10];
192 HInstruction* increment_[10];
193 HLocal* basic_[10]; // "vreg_d", the "i_d"
194};
195
196//
197// The actual InductionVarAnalysis tests.
198//
199
200TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
201 // Setup:
202 // for (int i_0 = 0; i_0 < 100; i_0++) {
203 // ..
204 // for (int i_9 = 0; i_9 < 100; i_9++) {
205 // }
206 // ..
207 // }
208 BuildLoopNest(10);
209 ASSERT_TRUE(graph_->TryBuildingSsa());
210 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
211 for (int d = 0; d < 1; d++) {
212 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
213 (d == 0) ? nullptr
214 : loop_header_[d - 1]->GetLoopInformation());
215 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
216 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
217 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
218 loop_body_[d]->GetLoopInformation());
219 }
220 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
221}
222
Aart Bike609b7c2015-08-27 13:46:58 -0700223TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700224 // Setup:
225 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700226 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700227 // }
228 BuildLoopNest(1);
229 HInstruction* store = InsertArrayStore(basic_[0], 0);
230 PerformInductionVarAnalysis();
231
Aart Bike609b7c2015-08-27 13:46:58 -0700232 EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700233 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700234
235 // Trip-count.
Aart Bik9401f532015-09-28 16:25:56 -0700236 EXPECT_STREQ("(TC-loop:(100))",
237 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
524TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
525 // Setup:
526 // k = 0;
527 // for (int i_0 = 0; i_0 < 100; i_0++) {
528 // ..
529 // for (int i_9 = 0; i_9 < 100; i_9++) {
530 // k = 1 + k;
531 // a[k] = 0;
532 // }
533 // ..
534 // }
535 BuildLoopNest(10);
536 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700537 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700538 InsertLocalStore(induc_, inc, 9);
539 HInstruction* store = InsertArrayStore(induc_, 9);
540 PerformInductionVarAnalysis();
541
Aart Bike609b7c2015-08-27 13:46:58 -0700542 // Avoid exact phi number, since that depends on the SSA building phase.
543 std::regex r("\\(\\(1\\) \\* i \\+ "
544 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700545
546 for (int d = 0; d < 10; d++) {
547 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700548 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700549 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700550 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700551 }
Aart Bik471a2032015-09-04 18:22:11 -0700552 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700553 // Trip-count.
Aart Bik9401f532015-09-28 16:25:56 -0700554 EXPECT_STREQ("(TC-loop:(100))",
555 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700556 }
557}
558
559} // namespace art