blob: b7262f6b29c041a7ea9cc64ec78e80f1aa7e98bf [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 Juravlee6e3bea2015-10-14 13:53:10 +000080 parameter_ = new (&allocator_) HParameterValue(
81 graph_->GetDexFile(), 0, 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 Bik22f05872015-10-27 15:56:28 -0700237 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700238 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
525TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
526 // Setup:
527 // k = 0;
528 // for (int i_0 = 0; i_0 < 100; i_0++) {
529 // ..
530 // for (int i_9 = 0; i_9 < 100; i_9++) {
531 // k = 1 + k;
532 // a[k] = 0;
533 // }
534 // ..
535 // }
536 BuildLoopNest(10);
537 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700538 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700539 InsertLocalStore(induc_, inc, 9);
540 HInstruction* store = InsertArrayStore(induc_, 9);
541 PerformInductionVarAnalysis();
542
Aart Bike609b7c2015-08-27 13:46:58 -0700543 // Avoid exact phi number, since that depends on the SSA building phase.
544 std::regex r("\\(\\(1\\) \\* i \\+ "
545 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700546
547 for (int d = 0; d < 10; d++) {
548 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700549 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700550 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700551 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700552 }
Aart Bik471a2032015-09-04 18:22:11 -0700553 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700554 // Trip-count.
Aart Bik22f05872015-10-27 15:56:28 -0700555 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700556 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700557 }
558}
559
560} // namespace art