blob: 29a1845658c601c239cdfd50c09ed4ba5b7dd1dc [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"
Aart Bik30efb4e2015-07-30 12:14:31 -070021#include "induction_var_analysis.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24
25namespace art {
26
27/**
28 * Fixture class for the InductionVarAnalysis tests.
29 */
David Brazdil4833f5a2015-12-16 10:37:39 +000030class InductionVarAnalysisTest : public CommonCompilerTest {
Aart Bik30efb4e2015-07-30 12:14:31 -070031 public:
32 InductionVarAnalysisTest() : pool_(), allocator_(&pool_) {
33 graph_ = CreateGraph(&allocator_);
34 }
35
36 ~InductionVarAnalysisTest() { }
37
38 // Builds single for-loop at depth d.
39 void BuildForLoop(int d, int n) {
40 ASSERT_LT(d, n);
41 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
42 graph_->AddBlock(loop_preheader_[d]);
43 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
44 graph_->AddBlock(loop_header_[d]);
45 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
46 if (d < (n - 1)) {
47 BuildForLoop(d + 1, n);
48 }
49 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
50 graph_->AddBlock(loop_body_[d]);
51 loop_body_[d]->AddSuccessor(loop_header_[d]);
52 if (d < (n - 1)) {
53 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
54 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
55 } else {
56 loop_header_[d]->AddSuccessor(loop_body_[d]);
57 }
58 }
59
60 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
61 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
62 // populate the loop with instructions to set up interesting scenarios.
63 void BuildLoopNest(int n) {
64 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070065 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070066
67 // Build basic blocks with entry, nested loop, exit.
68 entry_ = new (&allocator_) HBasicBlock(graph_);
69 graph_->AddBlock(entry_);
70 BuildForLoop(0, n);
David Brazdildb51efb2015-11-06 01:36:20 +000071 return_ = new (&allocator_) HBasicBlock(graph_);
72 graph_->AddBlock(return_);
Aart Bik30efb4e2015-07-30 12:14:31 -070073 exit_ = new (&allocator_) HBasicBlock(graph_);
74 graph_->AddBlock(exit_);
75 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000076 loop_header_[0]->AddSuccessor(return_);
77 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070078 graph_->SetEntryBlock(entry_);
79 graph_->SetExitBlock(exit_);
80
81 // Provide entry and exit instructions.
Calin Juravlee6e3bea2015-10-14 13:53:10 +000082 parameter_ = new (&allocator_) HParameterValue(
83 graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070084 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070085 constant0_ = graph_->GetIntConstant(0);
86 constant1_ = graph_->GetIntConstant(1);
87 constant100_ = graph_->GetIntConstant(100);
David Brazdil15693bf2015-12-16 10:30:45 +000088 float_constant0_ = graph_->GetFloatConstant(0.0f);
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_));
David Brazdil4833f5a2015-12-16 10:37:39 +0000105 loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
Aart Bike609b7c2015-08-27 13:46:58 -0700106 HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700107 loop_header_[d]->AddInstruction(load);
Aart Bikd14c5952015-09-08 15:25:15 -0700108 HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700109 loop_header_[d]->AddInstruction(compare);
110 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
111 load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
112 loop_body_[d]->AddInstruction(load);
Aart Bike609b7c2015-08-27 13:46:58 -0700113 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700114 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bike609b7c2015-08-27 13:46:58 -0700115 loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
Aart Bik30efb4e2015-07-30 12:14:31 -0700116 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
117 }
118 }
119
120 // Builds if-statement at depth d.
121 void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
122 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
123 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
124 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
125 graph_->AddBlock(cond);
126 graph_->AddBlock(ifTrue);
127 graph_->AddBlock(ifFalse);
128 // Conditional split.
129 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
130 cond->AddSuccessor(ifTrue);
131 cond->AddSuccessor(ifFalse);
132 ifTrue->AddSuccessor(loop_body_[d]);
133 ifFalse->AddSuccessor(loop_body_[d]);
134 cond->AddInstruction(new (&allocator_) HIf(parameter_));
135 *ifT = ifTrue;
136 *ifF = ifFalse;
137 }
138
139 // Inserts instruction right before increment at depth d.
140 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
141 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
142 return instruction;
143 }
144
145 // Inserts local load at depth d.
146 HInstruction* InsertLocalLoad(HLocal* local, int d) {
Aart Bike609b7c2015-08-27 13:46:58 -0700147 return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700148 }
149
150 // Inserts local store at depth d.
151 HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
152 return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
153 }
154
155 // Inserts an array store with given local as subscript at depth d to
156 // enable tests to inspect the computed induction at that point easily.
157 HInstruction* InsertArrayStore(HLocal* subscript, int d) {
158 HInstruction* load = InsertInstruction(
159 new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
David Brazdil15693bf2015-12-16 10:30:45 +0000160 // ArraySet is given a float value in order to avoid SsaBuilder typing
161 // it from the array's non-existent reference type info.
Aart Bik30efb4e2015-07-30 12:14:31 -0700162 return InsertInstruction(new (&allocator_) HArraySet(
David Brazdil15693bf2015-12-16 10:30:45 +0000163 parameter_, load, float_constant0_, Primitive::kPrimFloat, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700164 }
165
Aart Bike609b7c2015-08-27 13:46:58 -0700166 // Returns induction information of instruction in loop at depth d.
167 std::string GetInductionInfo(HInstruction* instruction, int d) {
168 return HInductionVarAnalysis::InductionToString(
169 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700170 }
171
172 // Performs InductionVarAnalysis (after proper set up).
173 void PerformInductionVarAnalysis() {
David Brazdil4833f5a2015-12-16 10:37:39 +0000174 TransformToSsa(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700175 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
176 iva_->Run();
177 }
178
179 // General building fields.
180 ArenaPool pool_;
181 ArenaAllocator allocator_;
182 HGraph* graph_;
183 HInductionVarAnalysis* iva_;
184
185 // Fixed basic blocks and instructions.
186 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000187 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700188 HBasicBlock* exit_;
189 HInstruction* parameter_; // "this"
190 HInstruction* constant0_;
191 HInstruction* constant1_;
192 HInstruction* constant100_;
David Brazdil15693bf2015-12-16 10:30:45 +0000193 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700194 HLocal* induc_; // "vreg_n", the "k"
195 HLocal* tmp_; // "vreg_n+1"
Aart Bike609b7c2015-08-27 13:46:58 -0700196 HLocal* dum_; // "vreg_n+2"
Aart Bik30efb4e2015-07-30 12:14:31 -0700197
198 // Loop specifics.
199 HBasicBlock* loop_preheader_[10];
200 HBasicBlock* loop_header_[10];
201 HBasicBlock* loop_body_[10];
202 HInstruction* increment_[10];
203 HLocal* basic_[10]; // "vreg_d", the "i_d"
204};
205
206//
207// The actual InductionVarAnalysis tests.
208//
209
210TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
211 // Setup:
212 // for (int i_0 = 0; i_0 < 100; i_0++) {
213 // ..
214 // for (int i_9 = 0; i_9 < 100; i_9++) {
215 // }
216 // ..
217 // }
218 BuildLoopNest(10);
David Brazdil4833f5a2015-12-16 10:37:39 +0000219 TransformToSsa(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700220 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
221 for (int d = 0; d < 1; d++) {
222 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
223 (d == 0) ? nullptr
224 : loop_header_[d - 1]->GetLoopInformation());
225 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
226 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
227 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
228 loop_body_[d]->GetLoopInformation());
229 }
230 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
231}
232
Aart Bike609b7c2015-08-27 13:46:58 -0700233TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700234 // Setup:
235 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700236 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700237 // }
238 BuildLoopNest(1);
239 HInstruction* store = InsertArrayStore(basic_[0], 0);
240 PerformInductionVarAnalysis();
241
Aart Bike609b7c2015-08-27 13:46:58 -0700242 EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700243 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700244
245 // Trip-count.
Aart Bik22f05872015-10-27 15:56:28 -0700246 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700247 GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700248}
249
Aart Bike609b7c2015-08-27 13:46:58 -0700250TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700251 // Setup:
252 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700253 // k = 100 + i;
254 // k = 100 - i;
255 // k = 100 * i;
256 // k = i << 1;
257 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700258 // }
259 BuildLoopNest(1);
260 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700261 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700262 InsertLocalStore(induc_, add, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700264 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700265 InsertLocalStore(induc_, sub, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700266 HInstruction *mul = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700267 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700268 InsertLocalStore(induc_, mul, 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700269 HInstruction *shl = InsertInstruction(
270 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
271 InsertLocalStore(induc_, shl, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700272 HInstruction *neg = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700273 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700274 InsertLocalStore(induc_, neg, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700275 PerformInductionVarAnalysis();
276
Aart Bik471a2032015-09-04 18:22:11 -0700277 EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
278 EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
279 EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
280 EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
281 EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700282}
283
284TEST_F(InductionVarAnalysisTest, FindChainInduction) {
285 // Setup:
286 // k = 0;
287 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700288 // k = k + 100;
289 // a[k] = 0;
290 // k = k - 1;
291 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700292 // }
293 BuildLoopNest(1);
294 HInstruction *add = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700295 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700296 InsertLocalStore(induc_, add, 0);
297 HInstruction* store1 = InsertArrayStore(induc_, 0);
298 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700299 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700300 InsertLocalStore(induc_, sub, 0);
301 HInstruction* store2 = InsertArrayStore(induc_, 0);
302 PerformInductionVarAnalysis();
303
Aart Bik471a2032015-09-04 18:22:11 -0700304 EXPECT_STREQ("(((100) - (1)) * i + (100))",
Aart Bike609b7c2015-08-27 13:46:58 -0700305 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik471a2032015-09-04 18:22:11 -0700306 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700307 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700308}
309
310TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
311 // Setup:
312 // k = 0;
313 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700314 // if () k = k + 1;
315 // else k = k + 1;
316 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700317 // }
318 BuildLoopNest(1);
319 HBasicBlock* ifTrue;
320 HBasicBlock* ifFalse;
321 BuildIf(0, &ifTrue, &ifFalse);
322 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700323 HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700324 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700325 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700326 ifTrue->AddInstruction(inc1);
327 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
328 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700329 HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700330 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700331 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700332 ifFalse->AddInstruction(inc2);
333 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
334 // Merge over a phi.
335 HInstruction* store = InsertArrayStore(induc_, 0);
336 PerformInductionVarAnalysis();
337
Aart Bik471a2032015-09-04 18:22:11 -0700338 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700339}
340
341TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
342 // Setup:
343 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700344 // if () k = i + 1;
345 // else k = i + 1;
346 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700347 // }
348 BuildLoopNest(1);
349 HBasicBlock* ifTrue;
350 HBasicBlock* ifFalse;
351 BuildIf(0, &ifTrue, &ifFalse);
352 // True-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700353 HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700354 ifTrue->AddInstruction(load1);
Aart Bike609b7c2015-08-27 13:46:58 -0700355 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700356 ifTrue->AddInstruction(inc1);
357 ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
358 // False-branch.
Aart Bike609b7c2015-08-27 13:46:58 -0700359 HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
Aart Bik30efb4e2015-07-30 12:14:31 -0700360 ifFalse->AddInstruction(load2);
Aart Bike609b7c2015-08-27 13:46:58 -0700361 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700362 ifFalse->AddInstruction(inc2);
363 ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
364 // Merge over a phi.
365 HInstruction* store = InsertArrayStore(induc_, 0);
366 PerformInductionVarAnalysis();
367
Aart Bik471a2032015-09-04 18:22:11 -0700368 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700369}
370
371TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
372 // Setup:
373 // k = 0;
374 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700375 // a[k] = 0;
376 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700377 // }
378 BuildLoopNest(1);
379 HInstruction* store = InsertArrayStore(induc_, 0);
380 HInstruction *sub = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700381 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700382 InsertLocalStore(induc_, sub, 0);
383 PerformInductionVarAnalysis();
384
Aart Bik471a2032015-09-04 18:22:11 -0700385 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
Aart Bike609b7c2015-08-27 13:46:58 -0700386 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700387}
388
389TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
390 // Setup:
391 // k = 0;
392 // t = 100;
393 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700394 // a[k] = 0;
395 // k = t;
396 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700397 // }
398 BuildLoopNest(1);
399 HInstruction* store = InsertArrayStore(induc_, 0);
400 InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
401 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700402 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700403 InsertLocalStore(tmp_, sub, 0);
404 PerformInductionVarAnalysis();
405
Aart Bik471a2032015-09-04 18:22:11 -0700406 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
Aart Bike609b7c2015-08-27 13:46:58 -0700407 GetInductionInfo(store->InputAt(1), 0).c_str());
408}
409
410TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
411 // Setup:
412 // k = 0;
413 // for (int i = 0; i < 100; i++) {
414 // t = k + 100;
415 // t = k - 100;
416 // t = k * 100;
417 // t = k << 1;
418 // t = - k;
419 // k = i << 1;
420 // }
421 BuildLoopNest(1);
422 HInstruction *add = InsertInstruction(
423 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
424 InsertLocalStore(tmp_, add, 0);
425 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700426 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700427 InsertLocalStore(tmp_, sub, 0);
428 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700429 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700430 InsertLocalStore(tmp_, mul, 0);
431 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700432 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700433 InsertLocalStore(tmp_, shl, 0);
434 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700435 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700436 InsertLocalStore(tmp_, neg, 0);
437 InsertLocalStore(
438 induc_,
439 InsertInstruction(
440 new (&allocator_)
441 HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
442 PerformInductionVarAnalysis();
443
Aart Bik471a2032015-09-04 18:22:11 -0700444 EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
445 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
446 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
447 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
448 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700449}
450
451TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
452 // Setup:
453 // k = 0;
454 // t = 100;
455 // for (int i = 0; i < 100; i++) {
456 // a[k] = 0;
457 // a[t] = 0;
458 // // Swap t <-> k.
459 // d = t;
460 // t = k;
461 // k = d;
462 // }
463 BuildLoopNest(1);
464 HInstruction* store1 = InsertArrayStore(induc_, 0);
465 HInstruction* store2 = InsertArrayStore(tmp_, 0);
466 InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
467 InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
468 InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
469 PerformInductionVarAnalysis();
470
471 EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
472 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(store2->InputAt(1), 0).c_str());
473}
474
475TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
476 // Setup:
477 // k = 0;
478 // for (int i = 0; i < 100; i++) {
479 // a[k] = 0;
480 // k = 1 - k;
481 // }
482 BuildLoopNest(1);
483 HInstruction* store = InsertArrayStore(induc_, 0);
484 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700485 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700486 InsertLocalStore(induc_, sub, 0);
487 PerformInductionVarAnalysis();
488
Aart Bik471a2032015-09-04 18:22:11 -0700489 EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
490 EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700491}
492
493TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
494 // Setup:
495 // k = 0;
496 // for (int i = 0; i < 100; i++) {
497 // k = 1 - k;
498 // t = k + 100;
499 // t = k - 100;
500 // t = k * 100;
501 // t = k << 1;
502 // t = - k;
503 // }
504 BuildLoopNest(1);
505 InsertLocalStore(
506 induc_,
507 InsertInstruction(new (&allocator_)
508 HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
509 // Derived expressions.
510 HInstruction *add = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700511 new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700512 InsertLocalStore(tmp_, add, 0);
513 HInstruction *sub = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700514 new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700515 InsertLocalStore(tmp_, sub, 0);
516 HInstruction *mul = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700517 new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700518 InsertLocalStore(tmp_, mul, 0);
519 HInstruction *shl = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700520 new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700521 InsertLocalStore(tmp_, shl, 0);
522 HInstruction *neg = InsertInstruction(
Aart Bikf475bee2015-09-16 12:50:25 -0700523 new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700524 InsertLocalStore(tmp_, neg, 0);
525 PerformInductionVarAnalysis();
526
Aart Bik471a2032015-09-04 18:22:11 -0700527 EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
528 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
529 EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
530 EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
531 EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700532}
533
534TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
535 // Setup:
536 // k = 0;
537 // for (int i_0 = 0; i_0 < 100; i_0++) {
538 // ..
539 // for (int i_9 = 0; i_9 < 100; i_9++) {
540 // k = 1 + k;
541 // a[k] = 0;
542 // }
543 // ..
544 // }
545 BuildLoopNest(10);
546 HInstruction *inc = InsertInstruction(
Aart Bike609b7c2015-08-27 13:46:58 -0700547 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
Aart Bik30efb4e2015-07-30 12:14:31 -0700548 InsertLocalStore(induc_, inc, 9);
549 HInstruction* store = InsertArrayStore(induc_, 9);
550 PerformInductionVarAnalysis();
551
Aart Bike609b7c2015-08-27 13:46:58 -0700552 // Avoid exact phi number, since that depends on the SSA building phase.
553 std::regex r("\\(\\(1\\) \\* i \\+ "
554 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\)");
Aart Bik30efb4e2015-07-30 12:14:31 -0700555
556 for (int d = 0; d < 10; d++) {
557 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700558 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700559 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700560 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700561 }
Aart Bik471a2032015-09-04 18:22:11 -0700562 EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700563 // Trip-count.
Aart Bik22f05872015-10-27 15:56:28 -0700564 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))",
Aart Bik9401f532015-09-28 16:25:56 -0700565 GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700566 }
567}
568
569} // namespace art