blob: 5de94f43c94fdbc447d259edc2e9ae8a9d05dc2c [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);
David Brazdildb51efb2015-11-06 01:36:20 +000072 return_ = new (&allocator_) HBasicBlock(graph_);
73 graph_->AddBlock(return_);
Aart Bik30efb4e2015-07-30 12:14:31 -070074 exit_ = new (&allocator_) HBasicBlock(graph_);
75 graph_->AddBlock(exit_);
76 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000077 loop_header_[0]->AddSuccessor(return_);
78 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070079 graph_->SetEntryBlock(entry_);
80 graph_->SetExitBlock(exit_);
81
82 // Provide entry and exit instructions.
Calin Juravlee6e3bea2015-10-14 13:53:10 +000083 parameter_ = new (&allocator_) HParameterValue(
84 graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070085 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070086 constant0_ = graph_->GetIntConstant(0);
87 constant1_ = graph_->GetIntConstant(1);
88 constant100_ = graph_->GetIntConstant(100);
Aart Bik30efb4e2015-07-30 12:14:31 -070089 induc_ = new (&allocator_) HLocal(n);
90 entry_->AddInstruction(induc_);
91 entry_->AddInstruction(new (&allocator_) HStoreLocal(induc_, constant0_));
92 tmp_ = new (&allocator_) HLocal(n + 1);
93 entry_->AddInstruction(tmp_);
94 entry_->AddInstruction(new (&allocator_) HStoreLocal(tmp_, constant100_));
Aart Bike609b7c2015-08-27 13:46:58 -070095 dum_ = new (&allocator_) HLocal(n + 2);
96 entry_->AddInstruction(dum_);
David Brazdildb51efb2015-11-06 01:36:20 +000097 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bike609b7c2015-08-27 13:46:58 -070098 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070099
100 // Provide loop instructions.
101 for (int d = 0; d < n; d++) {
102 basic_[d] = new (&allocator_) HLocal(d);
103 entry_->AddInstruction(basic_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700104 loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
105 HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700106 loop_header_[d]->AddInstruction(load);
Aart Bikd14c5952015-09-08 15:25:15 -0700107 HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700108 loop_header_[d]->AddInstruction(compare);
109 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
110 load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
111 loop_body_[d]->AddInstruction(load);
Aart Bike609b7c2015-08-27 13:46:58 -0700112 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700113 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700114 loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
Aart Bik30efb4e2015-07-30 12:14:31 -0700115 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
116 }
117 }
118
119 // Builds if-statement at depth d.
120 void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
121 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
122 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
123 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
124 graph_->AddBlock(cond);
125 graph_->AddBlock(ifTrue);
126 graph_->AddBlock(ifFalse);
127 // Conditional split.
128 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
129 cond->AddSuccessor(ifTrue);
130 cond->AddSuccessor(ifFalse);
131 ifTrue->AddSuccessor(loop_body_[d]);
132 ifFalse->AddSuccessor(loop_body_[d]);
133 cond->AddInstruction(new (&allocator_) HIf(parameter_));
134 *ifT = ifTrue;
135 *ifF = ifFalse;
136 }
137
138 // Inserts instruction right before increment at depth d.
139 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
140 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
141 return instruction;
142 }
143
144 // Inserts local load at depth d.
145 HInstruction* InsertLocalLoad(HLocal* local, int d) {
Aart Bike609b7c2015-08-27 13:46:58 -0700146 return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700147 }
148
149 // Inserts local store at depth d.
150 HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
151 return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
152 }
153
154 // Inserts an array store with given local as subscript at depth d to
155 // enable tests to inspect the computed induction at that point easily.
156 HInstruction* InsertArrayStore(HLocal* subscript, int d) {
157 HInstruction* load = InsertInstruction(
158 new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
159 return InsertInstruction(new (&allocator_) HArraySet(
160 parameter_, load, constant0_, Primitive::kPrimInt, 0), d);
161 }
162
Aart Bike609b7c2015-08-27 13:46:58 -0700163 // Returns induction information of instruction in loop at depth d.
164 std::string GetInductionInfo(HInstruction* instruction, int d) {
165 return HInductionVarAnalysis::InductionToString(
166 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700167 }
168
169 // Performs InductionVarAnalysis (after proper set up).
170 void PerformInductionVarAnalysis() {
171 ASSERT_TRUE(graph_->TryBuildingSsa());
172 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
173 iva_->Run();
174 }
175
176 // General building fields.
177 ArenaPool pool_;
178 ArenaAllocator allocator_;
179 HGraph* graph_;
180 HInductionVarAnalysis* iva_;
181
182 // Fixed basic blocks and instructions.
183 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000184 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700185 HBasicBlock* exit_;
186 HInstruction* parameter_; // "this"
187 HInstruction* constant0_;
188 HInstruction* constant1_;
189 HInstruction* constant100_;
190 HLocal* induc_; // "vreg_n", the "k"
191 HLocal* tmp_; // "vreg_n+1"
Aart Bike609b7c2015-08-27 13:46:58 -0700192 HLocal* dum_; // "vreg_n+2"
Aart Bik30efb4e2015-07-30 12:14:31 -0700193
194 // Loop specifics.
195 HBasicBlock* loop_preheader_[10];
196 HBasicBlock* loop_header_[10];
197 HBasicBlock* loop_body_[10];
198 HInstruction* increment_[10];
199 HLocal* basic_[10]; // "vreg_d", the "i_d"
200};
201
202//
203// The actual InductionVarAnalysis tests.
204//
205
206TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
207 // Setup:
208 // for (int i_0 = 0; i_0 < 100; i_0++) {
209 // ..
210 // for (int i_9 = 0; i_9 < 100; i_9++) {
211 // }
212 // ..
213 // }
214 BuildLoopNest(10);
215 ASSERT_TRUE(graph_->TryBuildingSsa());
216 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
217 for (int d = 0; d < 1; d++) {
218 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
219 (d == 0) ? nullptr
220 : loop_header_[d - 1]->GetLoopInformation());
221 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
222 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
223 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
224 loop_body_[d]->GetLoopInformation());
225 }
226 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
227}
228
Aart Bike609b7c2015-08-27 13:46:58 -0700229TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700230 // Setup:
231 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700232 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700233 // }
234 BuildLoopNest(1);
235 HInstruction* store = InsertArrayStore(basic_[0], 0);
236 PerformInductionVarAnalysis();
237
Aart Bike609b7c2015-08-27 13:46:58 -0700238 EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700239 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700240
241 // Trip-count.
Aart Bik22f05872015-10-27 15:56:28 -0700242 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700243 GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700244}
245
Aart Bike609b7c2015-08-27 13:46:58 -0700246TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700247 // Setup:
248 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700249 // k = 100 + i;
250 // k = 100 - i;
251 // k = 100 * i;
252 // k = i << 1;
253 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 // }
255 BuildLoopNest(1);
256 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700257 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700259 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700260 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700261 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700262 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700263 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700264 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700265 HInstruction *shl = InsertInstruction(
266 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
267 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700268 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700269 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700270 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700271 PerformInductionVarAnalysis();
272
Aart Bik471a2032015-09-04 18:22:11 -0700273 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
274 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
275 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
276 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
277 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700278}
279
280TEST_F(InductionVarAnalysisTest, FindChainInduction) {
281 // Setup:
282 // k = 0;
283 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700284 // k = k + 100;
285 // a[k] = 0;
286 // k = k - 1;
287 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700288 // }
289 BuildLoopNest(1);
290 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700291 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700292 InsertLocalStore(induc_, add, 0);
293 HInstruction* store1 = InsertArrayStore(induc_, 0);
294 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700295 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700296 InsertLocalStore(induc_, sub, 0);
297 HInstruction* store2 = InsertArrayStore(induc_, 0);
298 PerformInductionVarAnalysis();
299
Aart Bik471a2032015-09-04 18:22:11 -0700300 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700301 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700302 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700303 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700304}
305
306TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
307 // Setup:
308 // k = 0;
309 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700310 // if () k = k + 1;
311 // else k = k + 1;
312 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700313 // }
314 BuildLoopNest(1);
315 HBasicBlock* ifTrue;
316 HBasicBlock* ifFalse;
317 BuildIf(0, &ifTrue, &ifFalse);
318 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700319 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700320 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700321 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700322 ifTrue->AddInstruction(inc1);
323 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
324 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700325 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700326 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700327 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700328 ifFalse->AddInstruction(inc2);
329 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
330 // Merge over a phi.
331 HInstruction* store = InsertArrayStore(induc_, 0);
332 PerformInductionVarAnalysis();
333
Aart Bik471a2032015-09-04 18:22:11 -0700334 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700335}
336
337TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
338 // Setup:
339 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700340 // if () k = i + 1;
341 // else k = i + 1;
342 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700343 // }
344 BuildLoopNest(1);
345 HBasicBlock* ifTrue;
346 HBasicBlock* ifFalse;
347 BuildIf(0, &ifTrue, &ifFalse);
348 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700349 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700350 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700351 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700352 ifTrue->AddInstruction(inc1);
353 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
354 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700355 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700356 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700357 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700358 ifFalse->AddInstruction(inc2);
359 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
360 // Merge over a phi.
361 HInstruction* store = InsertArrayStore(induc_, 0);
362 PerformInductionVarAnalysis();
363
Aart Bik471a2032015-09-04 18:22:11 -0700364 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700365}
366
367TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
368 // Setup:
369 // k = 0;
370 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700371 // a[k] = 0;
372 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700373 // }
374 BuildLoopNest(1);
375 HInstruction* store = InsertArrayStore(induc_, 0);
376 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700377 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700378 InsertLocalStore(induc_, sub, 0);
379 PerformInductionVarAnalysis();
380
Aart Bik471a2032015-09-04 18:22:11 -0700381 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700382 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700383}
384
385TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
386 // Setup:
387 // k = 0;
388 // t = 100;
389 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700390 // a[k] = 0;
391 // k = t;
392 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700393 // }
394 BuildLoopNest(1);
395 HInstruction* store = InsertArrayStore(induc_, 0);
396 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
397 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700398 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700399 InsertLocalStore(tmp_, sub, 0);
400 PerformInductionVarAnalysis();
401
Aart Bik471a2032015-09-04 18:22:11 -0700402 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700403 GetInductionInfo(store->InputAt(1), 0).c_str());
404}
405
406TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
407 // Setup:
408 // k = 0;
409 // for (int i = 0; i < 100; i++) {
410 // t = k + 100;
411 // t = k - 100;
412 // t = k * 100;
413 // t = k << 1;
414 // t = - k;
415 // k = i << 1;
416 // }
417 BuildLoopNest(1);
418 HInstruction *add = InsertInstruction(
419 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
420 InsertLocalStore(tmp_, add, 0);
421 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700422 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700423 InsertLocalStore(tmp_, sub, 0);
424 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700425 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700426 InsertLocalStore(tmp_, mul, 0);
427 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700428 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700429 InsertLocalStore(tmp_, shl, 0);
430 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700431 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700432 InsertLocalStore(tmp_, neg, 0);
433 InsertLocalStore(
434 induc_,
435 InsertInstruction(
436 new (&allocator_)
437 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
438 PerformInductionVarAnalysis();
439
Aart Bik471a2032015-09-04 18:22:11 -0700440 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
441 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
442 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
443 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
444 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700445}
446
447TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
448 // Setup:
449 // k = 0;
450 // t = 100;
451 // for (int i = 0; i < 100; i++) {
452 // a[k] = 0;
453 // a[t] = 0;
454 // // Swap t <-> k.
455 // d = t;
456 // t = k;
457 // k = d;
458 // }
459 BuildLoopNest(1);
460 HInstruction* store1 = InsertArrayStore(induc_, 0);
461 HInstruction* store2 = InsertArrayStore(tmp_, 0);
462 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
463 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
464 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
465 PerformInductionVarAnalysis();
466
467 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
468 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
469}
470
471TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
472 // Setup:
473 // k = 0;
474 // for (int i = 0; i < 100; i++) {
475 // a[k] = 0;
476 // k = 1 - k;
477 // }
478 BuildLoopNest(1);
479 HInstruction* store = InsertArrayStore(induc_, 0);
480 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700481 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700482 InsertLocalStore(induc_, sub, 0);
483 PerformInductionVarAnalysis();
484
Aart Bik471a2032015-09-04 18:22:11 -0700485 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
486 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700487}
488
489TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
490 // Setup:
491 // k = 0;
492 // for (int i = 0; i < 100; i++) {
493 // k = 1 - k;
494 // t = k + 100;
495 // t = k - 100;
496 // t = k * 100;
497 // t = k << 1;
498 // t = - k;
499 // }
500 BuildLoopNest(1);
501 InsertLocalStore(
502 induc_,
503 InsertInstruction(new (&allocator_)
504 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
505 // Derived expressions.
506 HInstruction *add = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700507 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700508 InsertLocalStore(tmp_, add, 0);
509 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700510 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700511 InsertLocalStore(tmp_, sub, 0);
512 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700513 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700514 InsertLocalStore(tmp_, mul, 0);
515 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700516 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700517 InsertLocalStore(tmp_, shl, 0);
518 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700519 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700520 InsertLocalStore(tmp_, neg, 0);
521 PerformInductionVarAnalysis();
522
Aart Bik471a2032015-09-04 18:22:11 -0700523 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
524 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
525 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
526 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
527 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700528}
529
530TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
531 // Setup:
532 // k = 0;
533 // for (int i_0 = 0; i_0 < 100; i_0++) {
534 // ..
535 // for (int i_9 = 0; i_9 < 100; i_9++) {
536 // k = 1 + k;
537 // a[k] = 0;
538 // }
539 // ..
540 // }
541 BuildLoopNest(10);
542 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700543 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700544 InsertLocalStore(induc_, inc, 9);
545 HInstruction* store = InsertArrayStore(induc_, 9);
546 PerformInductionVarAnalysis();
547
Aart Bike609b7c2015-08-27 13:46:58 -0700548 // Avoid exact phi number, since that depends on the SSA building phase.
549 std::regex r("\\(\\(1\\) \\* i \\+ "
550 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700551
552 for (int d = 0; d < 10; d++) {
553 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700554 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700555 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700556 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700557 }
Aart Bik471a2032015-09-04 18:22:11 -0700558 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700559 // Trip-count.
Aart Bik22f05872015-10-27 15:56:28 -0700560 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700561 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700562 }
563}
564
565} // namespace art