blob: fca1ca55e5a4fb2f840d55aa1194e4aab573f986 [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.
Aart Bike609b7c2015-08-27 13:46:58 -070080 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.
236 EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700237}
238
Aart Bike609b7c2015-08-27 13:46:58 -0700239TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700240 // Setup:
241 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700242 // k = 100 + i;
243 // k = 100 - i;
244 // k = 100 * i;
245 // k = i << 1;
246 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700247 // }
248 BuildLoopNest(1);
249 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700250 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700251 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700252 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700253 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700255 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700256 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700257 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700258 HInstruction *shl = InsertInstruction(
259 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
260 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700261 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700262 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700264 PerformInductionVarAnalysis();
265
Aart Bik471a2032015-09-04 18:22:11 -0700266 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
267 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
268 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
269 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
270 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700271}
272
273TEST_F(InductionVarAnalysisTest, FindChainInduction) {
274 // Setup:
275 // k = 0;
276 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700277 // k = k + 100;
278 // a[k] = 0;
279 // k = k - 1;
280 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700281 // }
282 BuildLoopNest(1);
283 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700284 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700285 InsertLocalStore(induc_, add, 0);
286 HInstruction* store1 = InsertArrayStore(induc_, 0);
287 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700288 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700289 InsertLocalStore(induc_, sub, 0);
290 HInstruction* store2 = InsertArrayStore(induc_, 0);
291 PerformInductionVarAnalysis();
292
Aart Bik471a2032015-09-04 18:22:11 -0700293 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700294 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700295 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700296 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700297}
298
299TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
300 // Setup:
301 // k = 0;
302 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700303 // if () k = k + 1;
304 // else k = k + 1;
305 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700306 // }
307 BuildLoopNest(1);
308 HBasicBlock* ifTrue;
309 HBasicBlock* ifFalse;
310 BuildIf(0, &ifTrue, &ifFalse);
311 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700312 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700313 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700314 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700315 ifTrue->AddInstruction(inc1);
316 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
317 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700318 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700319 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700320 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700321 ifFalse->AddInstruction(inc2);
322 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
323 // Merge over a phi.
324 HInstruction* store = InsertArrayStore(induc_, 0);
325 PerformInductionVarAnalysis();
326
Aart Bik471a2032015-09-04 18:22:11 -0700327 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700328}
329
330TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
331 // Setup:
332 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700333 // if () k = i + 1;
334 // else k = i + 1;
335 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700336 // }
337 BuildLoopNest(1);
338 HBasicBlock* ifTrue;
339 HBasicBlock* ifFalse;
340 BuildIf(0, &ifTrue, &ifFalse);
341 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700342 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700343 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700344 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700345 ifTrue->AddInstruction(inc1);
346 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
347 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700348 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700349 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700350 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700351 ifFalse->AddInstruction(inc2);
352 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
353 // Merge over a phi.
354 HInstruction* store = InsertArrayStore(induc_, 0);
355 PerformInductionVarAnalysis();
356
Aart Bik471a2032015-09-04 18:22:11 -0700357 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700358}
359
360TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
361 // Setup:
362 // k = 0;
363 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700364 // a[k] = 0;
365 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700366 // }
367 BuildLoopNest(1);
368 HInstruction* store = InsertArrayStore(induc_, 0);
369 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700370 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700371 InsertLocalStore(induc_, sub, 0);
372 PerformInductionVarAnalysis();
373
Aart Bik471a2032015-09-04 18:22:11 -0700374 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700375 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700376}
377
378TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
379 // Setup:
380 // k = 0;
381 // t = 100;
382 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700383 // a[k] = 0;
384 // k = t;
385 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700386 // }
387 BuildLoopNest(1);
388 HInstruction* store = InsertArrayStore(induc_, 0);
389 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
390 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700391 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700392 InsertLocalStore(tmp_, sub, 0);
393 PerformInductionVarAnalysis();
394
Aart Bik471a2032015-09-04 18:22:11 -0700395 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700396 GetInductionInfo(store->InputAt(1), 0).c_str());
397}
398
399TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
400 // Setup:
401 // k = 0;
402 // for (int i = 0; i < 100; i++) {
403 // t = k + 100;
404 // t = k - 100;
405 // t = k * 100;
406 // t = k << 1;
407 // t = - k;
408 // k = i << 1;
409 // }
410 BuildLoopNest(1);
411 HInstruction *add = InsertInstruction(
412 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
413 InsertLocalStore(tmp_, add, 0);
414 HInstruction *sub = InsertInstruction(
415 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
416 InsertLocalStore(tmp_, sub, 0);
417 HInstruction *mul = InsertInstruction(
418 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
419 InsertLocalStore(tmp_, mul, 0);
420 HInstruction *shl = InsertInstruction(
421 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
422 InsertLocalStore(tmp_, shl, 0);
423 HInstruction *neg = InsertInstruction(
424 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
425 InsertLocalStore(tmp_, neg, 0);
426 InsertLocalStore(
427 induc_,
428 InsertInstruction(
429 new (&allocator_)
430 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
431 PerformInductionVarAnalysis();
432
Aart Bik471a2032015-09-04 18:22:11 -0700433 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
434 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
435 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
436 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
437 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700438}
439
440TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
441 // Setup:
442 // k = 0;
443 // t = 100;
444 // for (int i = 0; i < 100; i++) {
445 // a[k] = 0;
446 // a[t] = 0;
447 // // Swap t <-> k.
448 // d = t;
449 // t = k;
450 // k = d;
451 // }
452 BuildLoopNest(1);
453 HInstruction* store1 = InsertArrayStore(induc_, 0);
454 HInstruction* store2 = InsertArrayStore(tmp_, 0);
455 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
456 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
457 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
458 PerformInductionVarAnalysis();
459
460 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
461 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
462}
463
464TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
465 // Setup:
466 // k = 0;
467 // for (int i = 0; i < 100; i++) {
468 // a[k] = 0;
469 // k = 1 - k;
470 // }
471 BuildLoopNest(1);
472 HInstruction* store = InsertArrayStore(induc_, 0);
473 HInstruction *sub = InsertInstruction(
474 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
475 InsertLocalStore(induc_, sub, 0);
476 PerformInductionVarAnalysis();
477
Aart Bik471a2032015-09-04 18:22:11 -0700478 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
479 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700480}
481
482TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
483 // Setup:
484 // k = 0;
485 // for (int i = 0; i < 100; i++) {
486 // k = 1 - k;
487 // t = k + 100;
488 // t = k - 100;
489 // t = k * 100;
490 // t = k << 1;
491 // t = - k;
492 // }
493 BuildLoopNest(1);
494 InsertLocalStore(
495 induc_,
496 InsertInstruction(new (&allocator_)
497 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
498 // Derived expressions.
499 HInstruction *add = InsertInstruction(
500 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
501 InsertLocalStore(tmp_, add, 0);
502 HInstruction *sub = InsertInstruction(
503 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
504 InsertLocalStore(tmp_, sub, 0);
505 HInstruction *mul = InsertInstruction(
506 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
507 InsertLocalStore(tmp_, mul, 0);
508 HInstruction *shl = InsertInstruction(
509 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
510 InsertLocalStore(tmp_, shl, 0);
511 HInstruction *neg = InsertInstruction(
512 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
513 InsertLocalStore(tmp_, neg, 0);
514 PerformInductionVarAnalysis();
515
Aart Bik471a2032015-09-04 18:22:11 -0700516 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
517 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
518 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
519 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
520 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700521}
522
523TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
524 // Setup:
525 // k = 0;
526 // for (int i_0 = 0; i_0 < 100; i_0++) {
527 // ..
528 // for (int i_9 = 0; i_9 < 100; i_9++) {
529 // k = 1 + k;
530 // a[k] = 0;
531 // }
532 // ..
533 // }
534 BuildLoopNest(10);
535 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700536 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700537 InsertLocalStore(induc_, inc, 9);
538 HInstruction* store = InsertArrayStore(induc_, 9);
539 PerformInductionVarAnalysis();
540
Aart Bike609b7c2015-08-27 13:46:58 -0700541 // Avoid exact phi number, since that depends on the SSA building phase.
542 std::regex r("\\(\\(1\\) \\* i \\+ "
543 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700544
545 for (int d = 0; d < 10; d++) {
546 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700547 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700548 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700549 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700550 }
Aart Bik471a2032015-09-04 18:22:11 -0700551 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700552 // Trip-count.
553 EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700554 }
555}
556
557} // namespace art