blob: b569fbe53ab93c9c521c51fa63c1a4a49c8ffaaa [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 Bike609b7c2015-08-27 13:46:58 -0700102 HInstruction* compare = new (&allocator_) HGreaterThanOrEqual(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());
233 EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700234}
235
Aart Bike609b7c2015-08-27 13:46:58 -0700236TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700237 // Setup:
238 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700239 // k = 100 + i;
240 // k = 100 - i;
241 // k = 100 * i;
242 // k = i << 1;
243 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700244 // }
245 BuildLoopNest(1);
246 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700247 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700248 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700249 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700250 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700251 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700252 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700253 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700255 HInstruction *shl = InsertInstruction(
256 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
257 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700259 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700261 PerformInductionVarAnalysis();
262
Aart Bike609b7c2015-08-27 13:46:58 -0700263 EXPECT_STREQ("((1) * i + ((100) + (0)))", GetInductionInfo(add, 0).c_str());
264 EXPECT_STREQ("(( - (1)) * i + ((100) - (0)))", GetInductionInfo(sub, 0).c_str());
265 EXPECT_STREQ("(((100) * (1)) * i + ((100) * (0)))", GetInductionInfo(mul, 0).c_str());
266 EXPECT_STREQ("(((1) * (2)) * i + ((0) * (2)))", GetInductionInfo(shl, 0).c_str());
267 EXPECT_STREQ("(( - (1)) * i + ( - (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700268}
269
270TEST_F(InductionVarAnalysisTest, FindChainInduction) {
271 // Setup:
272 // k = 0;
273 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700274 // k = k + 100;
275 // a[k] = 0;
276 // k = k - 1;
277 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700278 // }
279 BuildLoopNest(1);
280 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700281 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700282 InsertLocalStore(induc_, add, 0);
283 HInstruction* store1 = InsertArrayStore(induc_, 0);
284 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700285 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700286 InsertLocalStore(induc_, sub, 0);
287 HInstruction* store2 = InsertArrayStore(induc_, 0);
288 PerformInductionVarAnalysis();
289
Aart Bike609b7c2015-08-27 13:46:58 -0700290 EXPECT_STREQ("(((100) - (1)) * i + ((0) + (100)))",
291 GetInductionInfo(store1->InputAt(1), 0).c_str());
292 EXPECT_STREQ("(((100) - (1)) * i + (((0) + (100)) - (1)))",
293 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700294}
295
296TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
297 // Setup:
298 // k = 0;
299 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700300 // if () k = k + 1;
301 // else k = k + 1;
302 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700303 // }
304 BuildLoopNest(1);
305 HBasicBlock* ifTrue;
306 HBasicBlock* ifFalse;
307 BuildIf(0, &ifTrue, &ifFalse);
308 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700309 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700310 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700311 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700312 ifTrue->AddInstruction(inc1);
313 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
314 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700315 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700316 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700317 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700318 ifFalse->AddInstruction(inc2);
319 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
320 // Merge over a phi.
321 HInstruction* store = InsertArrayStore(induc_, 0);
322 PerformInductionVarAnalysis();
323
Aart Bike609b7c2015-08-27 13:46:58 -0700324 EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700325}
326
327TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
328 // Setup:
329 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700330 // if () k = i + 1;
331 // else k = i + 1;
332 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700333 // }
334 BuildLoopNest(1);
335 HBasicBlock* ifTrue;
336 HBasicBlock* ifFalse;
337 BuildIf(0, &ifTrue, &ifFalse);
338 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700339 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700340 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700341 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700342 ifTrue->AddInstruction(inc1);
343 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
344 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700345 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700346 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700347 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700348 ifFalse->AddInstruction(inc2);
349 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
350 // Merge over a phi.
351 HInstruction* store = InsertArrayStore(induc_, 0);
352 PerformInductionVarAnalysis();
353
Aart Bike609b7c2015-08-27 13:46:58 -0700354 EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700355}
356
357TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
358 // Setup:
359 // k = 0;
360 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700361 // a[k] = 0;
362 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700363 // }
364 BuildLoopNest(1);
365 HInstruction* store = InsertArrayStore(induc_, 0);
366 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700367 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700368 InsertLocalStore(induc_, sub, 0);
369 PerformInductionVarAnalysis();
370
Aart Bike609b7c2015-08-27 13:46:58 -0700371 EXPECT_STREQ("wrap((0), (( - (1)) * i + ((100) - (0))))",
372 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700373}
374
375TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
376 // Setup:
377 // k = 0;
378 // t = 100;
379 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700380 // a[k] = 0;
381 // k = t;
382 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700383 // }
384 BuildLoopNest(1);
385 HInstruction* store = InsertArrayStore(induc_, 0);
386 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
387 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700388 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700389 InsertLocalStore(tmp_, sub, 0);
390 PerformInductionVarAnalysis();
391
Aart Bike609b7c2015-08-27 13:46:58 -0700392 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + ((100) - (0)))))",
393 GetInductionInfo(store->InputAt(1), 0).c_str());
394}
395
396TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
397 // Setup:
398 // k = 0;
399 // for (int i = 0; i < 100; i++) {
400 // t = k + 100;
401 // t = k - 100;
402 // t = k * 100;
403 // t = k << 1;
404 // t = - k;
405 // k = i << 1;
406 // }
407 BuildLoopNest(1);
408 HInstruction *add = InsertInstruction(
409 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
410 InsertLocalStore(tmp_, add, 0);
411 HInstruction *sub = InsertInstruction(
412 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
413 InsertLocalStore(tmp_, sub, 0);
414 HInstruction *mul = InsertInstruction(
415 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
416 InsertLocalStore(tmp_, mul, 0);
417 HInstruction *shl = InsertInstruction(
418 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
419 InsertLocalStore(tmp_, shl, 0);
420 HInstruction *neg = InsertInstruction(
421 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
422 InsertLocalStore(tmp_, neg, 0);
423 InsertLocalStore(
424 induc_,
425 InsertInstruction(
426 new (&allocator_)
427 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
428 PerformInductionVarAnalysis();
429
430 EXPECT_STREQ("wrap(((0) + (100)), (((1) * (2)) * i + (((0) * (2)) + (100))))",
431 GetInductionInfo(add, 0).c_str());
432 EXPECT_STREQ("wrap(((0) - (100)), (((1) * (2)) * i + (((0) * (2)) - (100))))",
433 GetInductionInfo(sub, 0).c_str());
434 EXPECT_STREQ("wrap(((0) * (100)), ((((1) * (2)) * (100)) * i + (((0) * (2)) * (100))))",
435 GetInductionInfo(mul, 0).c_str());
436 EXPECT_STREQ("wrap(((0) * (2)), ((((1) * (2)) * (2)) * i + (((0) * (2)) * (2))))",
437 GetInductionInfo(shl, 0).c_str());
438 EXPECT_STREQ("wrap(( - (0)), (( - ((1) * (2))) * i + ( - ((0) * (2)))))",
439 GetInductionInfo(neg, 0).c_str());
440}
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(
476 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
477 InsertLocalStore(induc_, sub, 0);
478 PerformInductionVarAnalysis();
479
480 EXPECT_STREQ("periodic((0), ((1) - (0)))", GetInductionInfo(store->InputAt(1), 0).c_str());
481 EXPECT_STREQ("periodic(((1) - (0)), (0))", GetInductionInfo(sub, 0).c_str());
482}
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(
502 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
503 InsertLocalStore(tmp_, add, 0);
504 HInstruction *sub = InsertInstruction(
505 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
506 InsertLocalStore(tmp_, sub, 0);
507 HInstruction *mul = InsertInstruction(
508 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
509 InsertLocalStore(tmp_, mul, 0);
510 HInstruction *shl = InsertInstruction(
511 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
512 InsertLocalStore(tmp_, shl, 0);
513 HInstruction *neg = InsertInstruction(
514 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
515 InsertLocalStore(tmp_, neg, 0);
516 PerformInductionVarAnalysis();
517
518 EXPECT_STREQ("periodic((((1) - (0)) + (100)), ((0) + (100)))", GetInductionInfo(add, 0).c_str());
519 EXPECT_STREQ("periodic((((1) - (0)) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
520 EXPECT_STREQ("periodic((((1) - (0)) * (100)), ((0) * (100)))", GetInductionInfo(mul, 0).c_str());
521 EXPECT_STREQ("periodic((((1) - (0)) * (2)), ((0) * (2)))", GetInductionInfo(shl, 0).c_str());
522 EXPECT_STREQ("periodic(( - ((1) - (0))), ( - (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 Bike609b7c2015-08-27 13:46:58 -0700553 EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(increment_[d], d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700554 }
555}
556
557} // namespace art