blob: cfd0b16f236e29dc7cc36b06fe27ba67cfaf3da7 [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());
Aart Bik471a2032015-09-04 18:22:11 -0700233 EXPECT_STREQ("((1) * i + (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 Bik471a2032015-09-04 18:22:11 -0700263 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
264 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
265 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
266 EXPECT_STREQ("((2) * i + (0))", 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 Bik471a2032015-09-04 18:22:11 -0700290 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700291 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700292 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700293 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 Bik471a2032015-09-04 18:22:11 -0700324 EXPECT_STREQ("((1) * i + (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 Bik471a2032015-09-04 18:22:11 -0700354 EXPECT_STREQ("((1) * i + (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 Bik471a2032015-09-04 18:22:11 -0700371 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700372 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 Bik471a2032015-09-04 18:22:11 -0700392 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700393 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
Aart Bik471a2032015-09-04 18:22:11 -0700430 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
431 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
432 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
433 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
434 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700435}
436
437TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
438 // Setup:
439 // k = 0;
440 // t = 100;
441 // for (int i = 0; i < 100; i++) {
442 // a[k] = 0;
443 // a[t] = 0;
444 // // Swap t <-> k.
445 // d = t;
446 // t = k;
447 // k = d;
448 // }
449 BuildLoopNest(1);
450 HInstruction* store1 = InsertArrayStore(induc_, 0);
451 HInstruction* store2 = InsertArrayStore(tmp_, 0);
452 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
453 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
454 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
455 PerformInductionVarAnalysis();
456
457 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
458 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
459}
460
461TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
462 // Setup:
463 // k = 0;
464 // for (int i = 0; i < 100; i++) {
465 // a[k] = 0;
466 // k = 1 - k;
467 // }
468 BuildLoopNest(1);
469 HInstruction* store = InsertArrayStore(induc_, 0);
470 HInstruction *sub = InsertInstruction(
471 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
472 InsertLocalStore(induc_, sub, 0);
473 PerformInductionVarAnalysis();
474
Aart Bik471a2032015-09-04 18:22:11 -0700475 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
476 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700477}
478
479TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
480 // Setup:
481 // k = 0;
482 // for (int i = 0; i < 100; i++) {
483 // k = 1 - k;
484 // t = k + 100;
485 // t = k - 100;
486 // t = k * 100;
487 // t = k << 1;
488 // t = - k;
489 // }
490 BuildLoopNest(1);
491 InsertLocalStore(
492 induc_,
493 InsertInstruction(new (&allocator_)
494 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
495 // Derived expressions.
496 HInstruction *add = InsertInstruction(
497 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
498 InsertLocalStore(tmp_, add, 0);
499 HInstruction *sub = InsertInstruction(
500 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
501 InsertLocalStore(tmp_, sub, 0);
502 HInstruction *mul = InsertInstruction(
503 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
504 InsertLocalStore(tmp_, mul, 0);
505 HInstruction *shl = InsertInstruction(
506 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
507 InsertLocalStore(tmp_, shl, 0);
508 HInstruction *neg = InsertInstruction(
509 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
510 InsertLocalStore(tmp_, neg, 0);
511 PerformInductionVarAnalysis();
512
Aart Bik471a2032015-09-04 18:22:11 -0700513 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
514 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
515 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
516 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
517 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700518}
519
520TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
521 // Setup:
522 // k = 0;
523 // for (int i_0 = 0; i_0 < 100; i_0++) {
524 // ..
525 // for (int i_9 = 0; i_9 < 100; i_9++) {
526 // k = 1 + k;
527 // a[k] = 0;
528 // }
529 // ..
530 // }
531 BuildLoopNest(10);
532 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700533 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700534 InsertLocalStore(induc_, inc, 9);
535 HInstruction* store = InsertArrayStore(induc_, 9);
536 PerformInductionVarAnalysis();
537
Aart Bike609b7c2015-08-27 13:46:58 -0700538 // Avoid exact phi number, since that depends on the SSA building phase.
539 std::regex r("\\(\\(1\\) \\* i \\+ "
540 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700541
542 for (int d = 0; d < 10; d++) {
543 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700544 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700545 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700546 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700547 }
Aart Bik471a2032015-09-04 18:22:11 -0700548 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700549 }
550}
551
552} // namespace art