blob: 53c8044a0bf9c00dbf9fde4ed3ab0f1e0a85ab81 [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:
Andreas Gamped9911ee2017-03-27 13:27:24 -070032 InductionVarAnalysisTest()
33 : pool_(),
34 allocator_(&pool_),
35 iva_(nullptr),
36 entry_(nullptr),
37 return_(nullptr),
38 exit_(nullptr),
39 parameter_(nullptr),
40 constant0_(nullptr),
41 constant1_(nullptr),
42 constant2_(nullptr),
43 constant7_(nullptr),
44 constant100_(nullptr),
45 constantm1_(nullptr),
46 float_constant0_(nullptr) {
Aart Bik30efb4e2015-07-30 12:14:31 -070047 graph_ = CreateGraph(&allocator_);
48 }
49
50 ~InductionVarAnalysisTest() { }
51
52 // Builds single for-loop at depth d.
53 void BuildForLoop(int d, int n) {
54 ASSERT_LT(d, n);
55 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
56 graph_->AddBlock(loop_preheader_[d]);
57 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
58 graph_->AddBlock(loop_header_[d]);
59 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
60 if (d < (n - 1)) {
61 BuildForLoop(d + 1, n);
62 }
63 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
64 graph_->AddBlock(loop_body_[d]);
65 loop_body_[d]->AddSuccessor(loop_header_[d]);
66 if (d < (n - 1)) {
67 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
68 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
69 } else {
70 loop_header_[d]->AddSuccessor(loop_body_[d]);
71 }
72 }
73
74 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
75 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
76 // populate the loop with instructions to set up interesting scenarios.
77 void BuildLoopNest(int n) {
78 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070079 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070080
81 // Build basic blocks with entry, nested loop, exit.
82 entry_ = new (&allocator_) HBasicBlock(graph_);
83 graph_->AddBlock(entry_);
84 BuildForLoop(0, n);
David Brazdildb51efb2015-11-06 01:36:20 +000085 return_ = new (&allocator_) HBasicBlock(graph_);
86 graph_->AddBlock(return_);
Aart Bik30efb4e2015-07-30 12:14:31 -070087 exit_ = new (&allocator_) HBasicBlock(graph_);
88 graph_->AddBlock(exit_);
89 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000090 loop_header_[0]->AddSuccessor(return_);
91 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070092 graph_->SetEntryBlock(entry_);
93 graph_->SetExitBlock(exit_);
94
95 // Provide entry and exit instructions.
Calin Juravlee6e3bea2015-10-14 13:53:10 +000096 parameter_ = new (&allocator_) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010097 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070098 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070099 constant0_ = graph_->GetIntConstant(0);
100 constant1_ = graph_->GetIntConstant(1);
Aart Bikc071a012016-12-01 10:22:31 -0800101 constant2_ = graph_->GetIntConstant(2);
Aart Bikdf7822e2016-12-06 10:05:30 -0800102 constant7_ = graph_->GetIntConstant(7);
Aart Bike609b7c2015-08-27 13:46:58 -0700103 constant100_ = graph_->GetIntConstant(100);
Aart Bikd0a022d2016-12-13 11:22:31 -0800104 constantm1_ = graph_->GetIntConstant(-1);
David Brazdil15693bf2015-12-16 10:30:45 +0000105 float_constant0_ = graph_->GetFloatConstant(0.0f);
David Brazdildb51efb2015-11-06 01:36:20 +0000106 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bike609b7c2015-08-27 13:46:58 -0700107 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -0700108
109 // Provide loop instructions.
110 for (int d = 0; d < n; d++) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100111 basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, DataType::Type::kInt32);
David Brazdil4833f5a2015-12-16 10:37:39 +0000112 loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000113 loop_header_[d]->AddPhi(basic_[d]);
114 HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700115 loop_header_[d]->AddInstruction(compare);
116 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100117 increment_[d] = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700118 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700119 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000120
121 basic_[d]->AddInput(constant0_);
122 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700123 }
124 }
125
126 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700127 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700128 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
129 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
130 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
131 graph_->AddBlock(cond);
132 graph_->AddBlock(ifTrue);
133 graph_->AddBlock(ifFalse);
134 // Conditional split.
135 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
136 cond->AddSuccessor(ifTrue);
137 cond->AddSuccessor(ifFalse);
138 ifTrue->AddSuccessor(loop_body_[d]);
139 ifFalse->AddSuccessor(loop_body_[d]);
140 cond->AddInstruction(new (&allocator_) HIf(parameter_));
141 *ifT = ifTrue;
142 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000143
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100144 HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000145 loop_body_[d]->AddPhi(select_phi);
146 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700147 }
148
149 // Inserts instruction right before increment at depth d.
150 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
151 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
152 return instruction;
153 }
154
David Brazdilbadd8262016-02-02 16:28:56 +0000155 // Inserts a phi to loop header at depth d and returns it.
156 HPhi* InsertLoopPhi(int vreg, int d) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100157 HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000158 loop_header_[d]->AddPhi(phi);
159 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700160 }
161
David Brazdilbadd8262016-02-02 16:28:56 +0000162 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700163 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000164 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000165 // ArraySet is given a float value in order to avoid SsaBuilder typing
166 // it from the array's non-existent reference type info.
Aart Bik30efb4e2015-07-30 12:14:31 -0700167 return InsertInstruction(new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100168 parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700169 }
170
Aart Bike609b7c2015-08-27 13:46:58 -0700171 // Returns induction information of instruction in loop at depth d.
172 std::string GetInductionInfo(HInstruction* instruction, int d) {
173 return HInductionVarAnalysis::InductionToString(
174 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700175 }
176
Aart Bik009cace2016-09-16 10:15:19 -0700177 // Returns induction information of the trip-count of loop at depth d.
178 std::string GetTripCount(int d) {
179 HInstruction* control = loop_header_[d]->GetLastInstruction();
180 DCHECK(control->IsIf());
181 return GetInductionInfo(control, d);
182 }
183
Aart Bik78296912016-03-25 13:14:53 -0700184 // Returns true if instructions have identical induction.
185 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
186 return HInductionVarAnalysis::InductionEqual(
187 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
188 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
189 }
190
Aart Bike6bd0272016-12-16 13:57:52 -0800191 // Returns true for narrowing linear induction.
192 bool IsNarrowingLinear(HInstruction* instruction) {
193 return HInductionVarAnalysis::IsNarrowingLinear(
194 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction));
195 }
196
Aart Bik30efb4e2015-07-30 12:14:31 -0700197 // Performs InductionVarAnalysis (after proper set up).
198 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000199 graph_->BuildDominatorTree();
Aart Bik30efb4e2015-07-30 12:14:31 -0700200 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
201 iva_->Run();
202 }
203
204 // General building fields.
205 ArenaPool pool_;
206 ArenaAllocator allocator_;
207 HGraph* graph_;
208 HInductionVarAnalysis* iva_;
209
210 // Fixed basic blocks and instructions.
211 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000212 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700213 HBasicBlock* exit_;
214 HInstruction* parameter_; // "this"
215 HInstruction* constant0_;
216 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800217 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800218 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700219 HInstruction* constant100_;
Aart Bikd0a022d2016-12-13 11:22:31 -0800220 HInstruction* constantm1_;
David Brazdil15693bf2015-12-16 10:30:45 +0000221 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700222
223 // Loop specifics.
224 HBasicBlock* loop_preheader_[10];
225 HBasicBlock* loop_header_[10];
226 HBasicBlock* loop_body_[10];
227 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000228 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700229};
230
231//
232// The actual InductionVarAnalysis tests.
233//
234
235TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
236 // Setup:
237 // for (int i_0 = 0; i_0 < 100; i_0++) {
238 // ..
239 // for (int i_9 = 0; i_9 < 100; i_9++) {
240 // }
241 // ..
242 // }
243 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000244 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700245
Aart Bik30efb4e2015-07-30 12:14:31 -0700246 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
247 for (int d = 0; d < 1; d++) {
248 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
249 (d == 0) ? nullptr
250 : loop_header_[d - 1]->GetLoopInformation());
251 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
252 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
253 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
254 loop_body_[d]->GetLoopInformation());
255 }
256 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
257}
258
Aart Bike609b7c2015-08-27 13:46:58 -0700259TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 // Setup:
261 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700262 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 // }
264 BuildLoopNest(1);
265 HInstruction* store = InsertArrayStore(basic_[0], 0);
266 PerformInductionVarAnalysis();
267
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100268 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
269 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700270
Aart Bik78296912016-03-25 13:14:53 -0700271 // Offset matters!
272 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
273
Aart Bikd14c5952015-09-08 15:25:15 -0700274 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700275 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700276}
277
Aart Bike609b7c2015-08-27 13:46:58 -0700278TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700279 // Setup:
280 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800281 // t = 100 + i;
282 // t = 100 - i;
283 // t = 100 * i;
284 // t = i << 1;
285 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700286 // }
287 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700288 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100289 new (&allocator_) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700290 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100291 new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700292 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100293 new (&allocator_) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700294 HInstruction* shl = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100295 new (&allocator_) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700296 HInstruction* neg = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100297 new (&allocator_) HNeg(DataType::Type::kInt32, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700298 PerformInductionVarAnalysis();
299
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100300 EXPECT_STREQ("((1) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
301 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
302 EXPECT_STREQ("((100) * i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
303 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl, 0).c_str());
304 EXPECT_STREQ("(( - (1)) * i + (0)):Int32", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700305}
306
307TEST_F(InductionVarAnalysisTest, FindChainInduction) {
308 // Setup:
309 // k = 0;
310 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700311 // k = k + 100;
312 // a[k] = 0;
313 // k = k - 1;
314 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700315 // }
316 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800317 HPhi* k_header = InsertLoopPhi(0, 0);
318 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000319
Aart Bik7dc96932016-10-12 10:01:05 -0700320 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100321 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000322 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700323 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100324 new (&allocator_) HSub(DataType::Type::kInt32, add, constant1_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000325 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800326 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700327 PerformInductionVarAnalysis();
328
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100329 EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800330 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100331 EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700332 GetInductionInfo(store1->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100333 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700334 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700335}
336
337TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
338 // Setup:
339 // k = 0;
340 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700341 // if () k = k + 1;
342 // else k = k + 1;
343 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700344 // }
345 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000346 HPhi* k_header = InsertLoopPhi(0, 0);
347 k_header->AddInput(constant0_);
348
Aart Bik30efb4e2015-07-30 12:14:31 -0700349 HBasicBlock* ifTrue;
350 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000351 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
352
Aart Bik30efb4e2015-07-30 12:14:31 -0700353 // True-branch.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100354 HInstruction* inc1 = new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700355 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000356 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700357 // False-branch.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100358 HInstruction* inc2 = new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700359 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000360 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700361 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000362 HInstruction* store = InsertArrayStore(k_body, 0);
363 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700364 PerformInductionVarAnalysis();
365
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100366 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
367 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700368
369 // Both increments get same induction.
370 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
371 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700372}
373
374TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
375 // Setup:
376 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700377 // if () k = i + 1;
378 // else k = i + 1;
379 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700380 // }
381 BuildLoopNest(1);
382 HBasicBlock* ifTrue;
383 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000384 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
385
Aart Bik30efb4e2015-07-30 12:14:31 -0700386 // True-branch.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100387 HInstruction* inc1 = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700388 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000389 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700390 // False-branch.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100391 HInstruction* inc2 = new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700392 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000393 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700394 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000395 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700396 PerformInductionVarAnalysis();
397
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100398 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800399
400 // Both increments get same induction.
401 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
402 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
403}
404
Aart Bikdf7822e2016-12-06 10:05:30 -0800405TEST_F(InductionVarAnalysisTest, AddLinear) {
406 // Setup:
407 // for (int i = 0; i < 100; i++) {
408 // t1 = i + i;
409 // t2 = 7 + i;
410 // t3 = t1 + t2;
411 // }
412 BuildLoopNest(1);
413
414 HInstruction* add1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100415 new (&allocator_) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800416 HInstruction* add2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100417 new (&allocator_) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800418 HInstruction* add3 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100419 new (&allocator_) HAdd(DataType::Type::kInt32, add1, add2), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800420 PerformInductionVarAnalysis();
421
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100422 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(basic_[0], 0).c_str());
423 EXPECT_STREQ("(((1) + (1)) * i + (0)):Int32", GetInductionInfo(add1, 0).c_str());
424 EXPECT_STREQ("((1) * i + (7)):Int32", GetInductionInfo(add2, 0).c_str());
425 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):Int32", GetInductionInfo(add3, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800426}
427
428TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
429 // Setup:
430 // k = 1;
431 // for (int i = 0; i < 100; i++) {
432 // t = i * 2;
433 // t = 100 + t
434 // k = t + k; // polynomial
435 // }
436 BuildLoopNest(1);
437 HPhi* k_header = InsertLoopPhi(0, 0);
438 k_header->AddInput(constant1_);
439
440 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100441 new (&allocator_) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800442 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100443 new (&allocator_) HAdd(DataType::Type::kInt32, constant100_, mul), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800444 HInstruction* pol = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100445 new (&allocator_) HAdd(DataType::Type::kInt32, add, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800446 k_header->AddInput(pol);
447 PerformInductionVarAnalysis();
448
449 // Note, only the phi in the cycle and the base linear induction are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100450 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800451 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100452 EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800453 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
454}
455
456TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
457 // Setup:
458 // k = 1;
459 // for (int i = 0; i < 100; i++) {
460 // t = k + 100;
461 // t = k - 1;
462 // t = - t
463 // t = k * 2;
464 // t = k << 2;
465 // k = k + i; // polynomial
466 // }
467 BuildLoopNest(1);
468 HPhi* k_header = InsertLoopPhi(0, 0);
469 k_header->AddInput(constant1_);
470
471 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100472 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800473 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100474 new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800475 HInstruction* neg = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100476 new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800477 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100478 new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800479 HInstruction* shl = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100480 new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800481 HInstruction* pol = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100482 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800483 k_header->AddInput(pol);
484 PerformInductionVarAnalysis();
485
486 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100487 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800488 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100489 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800490 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100491 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800492 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100493 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800494 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100495 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800496 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100497 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800498 GetInductionInfo(shl, 0).c_str());
499 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
500}
501
502TEST_F(InductionVarAnalysisTest, AddPolynomial) {
503 // Setup:
504 // k = 7;
505 // for (int i = 0; i < 100; i++) {
506 // t = k + k;
507 // t = t + k;
508 // k = k + i
509 // }
510 BuildLoopNest(1);
511 HPhi* k_header = InsertLoopPhi(0, 0);
512 k_header->AddInput(constant7_);
513
514 HInstruction* add1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100515 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800516 HInstruction* add2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100517 new (&allocator_) HAdd(DataType::Type::kInt32, add1, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800518 HInstruction* add3 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100519 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800520 k_header->AddInput(add3);
521 PerformInductionVarAnalysis();
522
523 // Note, only the phi in the cycle and added-derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100524 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800525 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100526 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800527 GetInductionInfo(add1, 0).c_str());
528 EXPECT_STREQ(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100529 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800530 GetInductionInfo(add2, 0).c_str());
531 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
532}
533
Aart Bikc071a012016-12-01 10:22:31 -0800534TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
535 // Setup:
536 // k = 1;
537 // for (int i = 0; i < 100; i++) {
538 // k = k * 100; // geometric (x 100)
539 // }
540 BuildLoopNest(1);
541 HPhi* k_header = InsertLoopPhi(0, 0);
542 k_header->AddInput(constant1_);
543
544 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100545 new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800546 k_header->AddInput(mul);
547 PerformInductionVarAnalysis();
548
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100549 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
550 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800551}
552
553TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
554 // Setup:
555 // k = 1;
556 // for (int i = 0; i < 100; i++) {
557 // t = k + 1;
558 // k = k << 1; // geometric (x 2)
559 // t = k + 100;
560 // t = k - 1;
561 // t = - t;
562 // t = k * 2;
563 // t = k << 2;
564 // }
565 BuildLoopNest(1);
566 HPhi* k_header = InsertLoopPhi(0, 0);
567 k_header->AddInput(constant1_);
568
569 HInstruction* add1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100570 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800571 HInstruction* shl1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100572 new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800573 HInstruction* add2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100574 new (&allocator_) HAdd(DataType::Type::kInt32, shl1, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800575 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100576 new (&allocator_) HSub(DataType::Type::kInt32, shl1, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800577 HInstruction* neg = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100578 new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800579 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100580 new (&allocator_) HMul(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800581 HInstruction* shl2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100582 new (&allocator_) HShl(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800583 k_header->AddInput(shl1);
584 PerformInductionVarAnalysis();
585
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100586 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
587 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):Int32", GetInductionInfo(add1, 0).c_str());
588 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):Int32", GetInductionInfo(shl1, 0).c_str());
589 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):Int32", GetInductionInfo(add2, 0).c_str());
590 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
591 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800592 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100593 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
594 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800595}
596
597TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
598 // Setup:
599 // k = 1;
600 // for (int i = 0; i < 100; i++) {
601 // t = k + 100;
602 // t = k - 1;
603 // t = - t
604 // t = k * 2;
605 // t = k << 2;
606 // k = k / 100; // geometric (/ 100)
607 // }
608 BuildLoopNest(1);
609 HPhi* k_header = InsertLoopPhi(0, 0);
610 k_header->AddInput(constant1_);
611
612 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100613 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800614 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100615 new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800616 HInstruction* neg = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100617 new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800618 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100619 new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800620 HInstruction* shl = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100621 new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800622 HInstruction* div = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100623 new (&allocator_) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800624 k_header->AddInput(div);
625 PerformInductionVarAnalysis();
626
627 // Note, only the phi in the cycle and direct additive derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100628 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
629 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):Int32", GetInductionInfo(add, 0).c_str());
630 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800631 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
632 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
633 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
634 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
635}
636
Aart Bikd0a022d2016-12-13 11:22:31 -0800637TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
638 // Setup:
639 // k = 100;
640 // for (int i = 0; i < 100; i++) {
641 // k = k >> 1; // geometric (/ 2)
642 // }
643 BuildLoopNest(1);
644 HPhi* k_header = InsertLoopPhi(0, 0);
645 k_header->AddInput(constant100_);
646
647 HInstruction* shr = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100648 new (&allocator_) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800649 k_header->AddInput(shr);
650 PerformInductionVarAnalysis();
651
652 // Note, only the phi in the cycle is classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100653 EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
Aart Bikd0a022d2016-12-13 11:22:31 -0800654 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
655}
656
657TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
658 // Setup:
659 // k = -1;
660 // for (int i = 0; i < 100; i++) {
661 // k = k >> 1; // initial value is negative
662 // }
663 BuildLoopNest(1);
664 HPhi* k_header = InsertLoopPhi(0, 0);
665 k_header->AddInput(constantm1_);
666
667 HInstruction* shr = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100668 new (&allocator_) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800669 k_header->AddInput(shr);
670 PerformInductionVarAnalysis();
671
672 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
673 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
674}
675
Aart Bikdf7822e2016-12-06 10:05:30 -0800676TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800677 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800678 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800679 // for (int i = 0; i < 100; i++) {
680 // t = k + 100;
681 // t = k - 1;
682 // t = -t
683 // t = k * 2;
684 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800685 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800686 // }
687 BuildLoopNest(1);
688 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800689 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800690
691 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100692 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800693 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100694 new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800695 HInstruction* neg = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100696 new (&allocator_) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800697 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100698 new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800699 HInstruction* shl = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100700 new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800701 HInstruction* rem = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100702 new (&allocator_) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800703 k_header->AddInput(rem);
704 PerformInductionVarAnalysis();
705
Aart Bikdf7822e2016-12-06 10:05:30 -0800706 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100707 EXPECT_STREQ("wrap((100), ((100) % (7))):Int32", GetInductionInfo(k_header, 0).c_str());
708 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):Int32",
709 GetInductionInfo(add, 0).c_str());
710 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):Int32",
711 GetInductionInfo(sub, 0).c_str());
712 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):Int32",
713 GetInductionInfo(neg, 0).c_str());
714 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):Int32",
715 GetInductionInfo(mul, 0).c_str());
716 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):Int32",
717 GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800718 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700719}
720
721TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
722 // Setup:
723 // k = 0;
724 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700725 // a[k] = 0;
726 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700727 // }
728 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800729 HPhi* k_header = InsertLoopPhi(0, 0);
730 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000731
Aart Bikc071a012016-12-01 10:22:31 -0800732 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700733 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100734 new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800735 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700736 PerformInductionVarAnalysis();
737
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100738 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800739 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100740 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700741 GetInductionInfo(store->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100742 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700743}
744
745TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
746 // Setup:
747 // k = 0;
748 // t = 100;
749 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700750 // a[k] = 0;
751 // k = t;
752 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700753 // }
754 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800755 HPhi* k_header = InsertLoopPhi(0, 0);
756 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000757 HPhi* t = InsertLoopPhi(1, 0);
758 t->AddInput(constant100_);
759
Aart Bikc071a012016-12-01 10:22:31 -0800760 HInstruction* store = InsertArrayStore(k_header, 0);
761 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700762 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100763 new (&allocator_) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000764 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700765 PerformInductionVarAnalysis();
766
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100767 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700768 GetInductionInfo(store->InputAt(1), 0).c_str());
769}
770
771TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
772 // Setup:
773 // k = 0;
774 // for (int i = 0; i < 100; i++) {
775 // t = k + 100;
776 // t = k - 100;
777 // t = k * 100;
778 // t = k << 1;
779 // t = - k;
780 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800781 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700782 // }
783 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800784 HPhi* k_header = InsertLoopPhi(0, 0);
785 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000786
Aart Bik7dc96932016-10-12 10:01:05 -0700787 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100788 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700789 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100790 new (&allocator_) HSub(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700791 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100792 new (&allocator_) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800793 HInstruction* shl1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100794 new (&allocator_) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800795 HInstruction* neg1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100796 new (&allocator_) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800797 HInstruction* shl2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100798 new (&allocator_) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800799 HInstruction* neg2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100800 new (&allocator_) HNeg(DataType::Type::kInt32, shl2), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800801 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700802 PerformInductionVarAnalysis();
803
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100804 EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700805 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100806 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700807 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100808 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700809 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100810 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800811 GetInductionInfo(shl1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100812 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800813 GetInductionInfo(neg1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100814 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
815 EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700816}
817
818TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
819 // Setup:
820 // k = 0;
821 // t = 100;
822 // for (int i = 0; i < 100; i++) {
823 // a[k] = 0;
824 // a[t] = 0;
825 // // Swap t <-> k.
826 // d = t;
827 // t = k;
828 // k = d;
829 // }
830 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800831 HPhi* k_header = InsertLoopPhi(0, 0);
832 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000833 HPhi* t = InsertLoopPhi(1, 0);
834 t->AddInput(constant100_);
835
Aart Bikc071a012016-12-01 10:22:31 -0800836 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000837 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800838 k_header->AddInput(t);
839 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700840 PerformInductionVarAnalysis();
841
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100842 EXPECT_STREQ("periodic((0), (100)):Int32", GetInductionInfo(store1->InputAt(1), 0).c_str());
843 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700844}
845
846TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
847 // Setup:
848 // k = 0;
849 // for (int i = 0; i < 100; i++) {
850 // a[k] = 0;
851 // k = 1 - k;
852 // }
853 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800854 HPhi* k_header = InsertLoopPhi(0, 0);
855 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000856
Aart Bikc071a012016-12-01 10:22:31 -0800857 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700858 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100859 new (&allocator_) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800860 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700861 PerformInductionVarAnalysis();
862
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100863 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
864 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700865}
866
Aart Bik7dc96932016-10-12 10:01:05 -0700867TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
868 // Setup:
869 // k = 0;
870 // for (int i = 0; i < 100; i++) {
871 // a[k] = 0;
872 // k = k ^ 1;
873 // }
874 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800875 HPhi* k_header = InsertLoopPhi(0, 0);
876 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700877
Aart Bikc071a012016-12-01 10:22:31 -0800878 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700879 HInstruction* x = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100880 new (&allocator_) HXor(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800881 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700882 PerformInductionVarAnalysis();
883
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100884 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
885 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700886}
887
Aart Bik639cc8c2016-10-18 13:03:31 -0700888TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
889 // Setup:
890 // k = 1;
891 // for (int i = 0; i < 100; i++) {
892 // k = 1 ^ k;
893 // }
894 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800895 HPhi* k_header = InsertLoopPhi(0, 0);
896 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700897
898 HInstruction* x = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100899 new (&allocator_) HXor(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800900 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700901 PerformInductionVarAnalysis();
902
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100903 EXPECT_STREQ("periodic((1), ((1) ^ (1))):Int32", GetInductionInfo(k_header, 0).c_str());
904 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700905}
906
Aart Bik7dc96932016-10-12 10:01:05 -0700907TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
908 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700909 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700910 // for (int i = 0; i < 100; i++) {
911 // k = k ^ 100;
912 // }
913 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800914 HPhi* k_header = InsertLoopPhi(0, 0);
915 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700916
917 HInstruction* x = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100918 new (&allocator_) HXor(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800919 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700920 PerformInductionVarAnalysis();
921
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100922 EXPECT_STREQ("periodic((1), ((1) ^ (100))):Int32", GetInductionInfo(k_header, 0).c_str());
923 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700924}
925
926TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
927 // Setup:
928 // k = 0;
929 // for (int i = 0; i < 100; i++) {
930 // k = (k == 0);
931 // }
932 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800933 HPhi* k_header = InsertLoopPhi(0, 0);
934 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700935
Aart Bikc071a012016-12-01 10:22:31 -0800936 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(k_header, constant0_), 0);
937 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700938 PerformInductionVarAnalysis();
939
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100940 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
941 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700942}
943
944TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
945 // Setup:
946 // k = 0;
947 // for (int i = 0; i < 100; i++) {
948 // k = (0 == k);
949 // }
950 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800951 HPhi* k_header = InsertLoopPhi(0, 0);
952 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700953
Aart Bikc071a012016-12-01 10:22:31 -0800954 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(constant0_, k_header), 0);
955 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700956 PerformInductionVarAnalysis();
957
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100958 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
959 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700960}
961
962TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
963 // Setup:
964 // k = 0;
965 // for (int i = 0; i < 100; i++) {
966 // k = (k != 1);
967 // }
968 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800969 HPhi* k_header = InsertLoopPhi(0, 0);
970 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700971
Aart Bikc071a012016-12-01 10:22:31 -0800972 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(k_header, constant1_), 0);
973 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700974 PerformInductionVarAnalysis();
975
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100976 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
977 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700978}
979
980TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
981 // Setup:
982 // k = 0;
983 // for (int i = 0; i < 100; i++) {
984 // k = (1 != k);
985 // }
986 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800987 HPhi* k_header = InsertLoopPhi(0, 0);
988 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700989
Aart Bikc071a012016-12-01 10:22:31 -0800990 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(constant1_, k_header), 0);
991 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700992 PerformInductionVarAnalysis();
993
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100994 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
995 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700996}
997
Aart Bike609b7c2015-08-27 13:46:58 -0700998TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
999 // Setup:
1000 // k = 0;
1001 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -08001002 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -07001003 // k = 1 - k;
1004 // t = k + 100;
1005 // t = k - 100;
1006 // t = k * 100;
1007 // t = k << 1;
1008 // t = - k;
1009 // }
1010 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +00001011 HPhi* k_header = InsertLoopPhi(0, 0);
1012 k_header->AddInput(constant0_);
1013
Aart Bikc071a012016-12-01 10:22:31 -08001014 HInstruction* neg1 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001015 new (&allocator_) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001016 HInstruction* idiom = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001017 new (&allocator_) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001018 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001019 new (&allocator_) HAdd(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001020 HInstruction* sub = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001021 new (&allocator_) HSub(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001022 HInstruction* mul = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001023 new (&allocator_) HMul(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001024 HInstruction* shl = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001025 new (&allocator_) HShl(DataType::Type::kInt32, idiom, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001026 HInstruction* neg2 = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001027 new (&allocator_) HNeg(DataType::Type::kInt32, idiom), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001028 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -07001029 PerformInductionVarAnalysis();
1030
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001031 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(k_header, 0).c_str());
1032 EXPECT_STREQ("periodic((0), ( - (1))):Int32", GetInductionInfo(neg1, 0).c_str());
1033 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(idiom, 0).c_str());
1034 EXPECT_STREQ("periodic(((1) + (100)), (100)):Int32", GetInductionInfo(add, 0).c_str());
1035 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):Int32", GetInductionInfo(sub, 0).c_str());
1036 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(mul, 0).c_str());
1037 EXPECT_STREQ("periodic((2), (0)):Int32", GetInductionInfo(shl, 0).c_str());
1038 EXPECT_STREQ("periodic(( - (1)), (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001039}
1040
1041TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
1042 // Setup:
1043 // k = 0;
1044 // for (int i_0 = 0; i_0 < 100; i_0++) {
1045 // ..
1046 // for (int i_9 = 0; i_9 < 100; i_9++) {
1047 // k = 1 + k;
1048 // a[k] = 0;
1049 // }
1050 // ..
1051 // }
1052 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +00001053
Aart Bikc071a012016-12-01 10:22:31 -08001054 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +00001055 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001056 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +00001057 }
1058
Aart Bik7dc96932016-10-12 10:01:05 -07001059 HInstruction* inc = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001060 new (&allocator_) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +00001061 HInstruction* store = InsertArrayStore(inc, 9);
1062
1063 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001064 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
1065 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001066 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001067 PerformInductionVarAnalysis();
1068
Aart Bike609b7c2015-08-27 13:46:58 -07001069 // Avoid exact phi number, since that depends on the SSA building phase.
1070 std::regex r("\\(\\(1\\) \\* i \\+ "
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001071 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32");
Aart Bik30efb4e2015-07-30 12:14:31 -07001072
1073 for (int d = 0; d < 10; d++) {
1074 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001075 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001076 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001077 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001078 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001079 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001080 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001081 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001082 }
1083}
1084
Aart Bik78296912016-03-25 13:14:53 -07001085TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1086 // Setup:
1087 // for (int i = 0; i < 100; i++) {
1088 // k = (byte) i;
1089 // a[k] = 0;
1090 // a[i] = 0;
1091 // }
1092 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001093 HInstruction* conv = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001094 new (&allocator_) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bik78296912016-03-25 13:14:53 -07001095 HInstruction* store1 = InsertArrayStore(conv, 0);
1096 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1097 PerformInductionVarAnalysis();
1098
Aart Bike6bd0272016-12-16 13:57:52 -08001099 // Regular int induction (i) is transferred over conversion into byte induction (k).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001100 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
1101 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
1102 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001103
Aart Bike6bd0272016-12-16 13:57:52 -08001104 // Narrowing detected.
1105 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1106 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));
1107
Aart Bik78296912016-03-25 13:14:53 -07001108 // Type matters!
1109 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1110
1111 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001112 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001113}
1114
Aart Bikcc42be02016-10-20 16:14:16 -07001115TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1116 // Setup:
1117 // for (int i = 0; i < 100; i++) {
1118 // k = (byte) i;
1119 // a[k] = 0;
1120 // k = k + 1
1121 // a[k] = 0;
1122 // }
1123 BuildLoopNest(1);
1124 HInstruction* conv = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001125 new (&allocator_) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001126 HInstruction* store1 = InsertArrayStore(conv, 0);
1127 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001128 new (&allocator_) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001129 HInstruction* store2 = InsertArrayStore(add, 0);
1130
1131 PerformInductionVarAnalysis();
1132
Aart Bike6bd0272016-12-16 13:57:52 -08001133 // Byte induction (k) is detected, but it does not transfer over the addition,
1134 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001135 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001136 EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
1137
1138 // Narrowing detected.
1139 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1140 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1))); // works for null
1141}
1142
1143TEST_F(InductionVarAnalysisTest, ByteInduction) {
1144 // Setup:
1145 // k = -128;
1146 // for (int i = 0; i < 100; i++) {
1147 // k = k + 1;
1148 // k = (byte) k;
1149 // }
1150 BuildLoopNest(1);
1151 HPhi* k_header = InsertLoopPhi(0, 0);
1152 k_header->AddInput(graph_->GetIntConstant(-128));
1153
1154 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001155 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001156 HInstruction* conv = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001157 new (&allocator_) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001158 k_header->AddInput(conv);
1159 PerformInductionVarAnalysis();
1160
1161 // Byte induction (k) is detected, but it does not transfer over the addition,
1162 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001163 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001164 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1165
1166 // Narrowing detected.
1167 EXPECT_TRUE(IsNarrowingLinear(k_header));
1168 EXPECT_FALSE(IsNarrowingLinear(add)); // works for null
1169}
1170
1171TEST_F(InductionVarAnalysisTest, NoByteInduction1) {
1172 // Setup:
1173 // k = -129; / does not fit!
1174 // for (int i = 0; i < 100; i++) {
1175 // k = k + 1;
1176 // k = (byte) k;
1177 // }
1178 BuildLoopNest(1);
1179 HPhi* k_header = InsertLoopPhi(0, 0);
1180 k_header->AddInput(graph_->GetIntConstant(-129));
1181
1182 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001183 new (&allocator_) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001184 HInstruction* conv = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001185 new (&allocator_) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001186 k_header->AddInput(conv);
1187 PerformInductionVarAnalysis();
1188
1189 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1190 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1191}
1192
1193TEST_F(InductionVarAnalysisTest, NoByteInduction2) {
1194 // Setup:
1195 // k = 0;
1196 // for (int i = 0; i < 100; i++) {
1197 // k = (byte) k; // conversion not done last!
1198 // k = k + 1;
1199 // }
1200 BuildLoopNest(1);
1201 HPhi* k_header = InsertLoopPhi(0, 0);
1202 k_header->AddInput(constant0_);
1203
1204 HInstruction* conv = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001205 new (&allocator_) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001206 HInstruction* add = InsertInstruction(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001207 new (&allocator_) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001208 k_header->AddInput(add);
1209 PerformInductionVarAnalysis();
1210
1211 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1212 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
Aart Bikcc42be02016-10-20 16:14:16 -07001213}
1214
Aart Bik0d345cf2016-03-16 10:49:38 -07001215TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1216 // Setup:
1217 // for (byte i = -128; i < 127; i++) { // just fits!
1218 // }
1219 BuildLoopNest(1);
1220 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1221 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1222 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001223 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001224 new (&allocator_) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001225 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1226 basic_[0]->ReplaceInput(conv, 1);
1227 PerformInductionVarAnalysis();
1228
Aart Bike6bd0272016-12-16 13:57:52 -08001229 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001230 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001231 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1232
1233 // Narrowing detected.
1234 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1235 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1236
Aart Bik0d345cf2016-03-16 10:49:38 -07001237 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001238 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001239}
1240
1241TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1242 // Setup:
1243 // for (byte i = -128; i < 128; i++) { // infinite loop!
1244 // }
1245 BuildLoopNest(1);
1246 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1247 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1248 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001249 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001250 new (&allocator_) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001251 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1252 basic_[0]->ReplaceInput(conv, 1);
1253 PerformInductionVarAnalysis();
1254
Aart Bike6bd0272016-12-16 13:57:52 -08001255 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001256 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001257 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1258
1259 // Narrowing detected.
1260 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1261 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1262
Aart Bik0d345cf2016-03-16 10:49:38 -07001263 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001264 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001265}
1266
1267TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1268 // Setup:
1269 // for (short i = -32768; i < 32767; i++) { // just fits!
1270 // }
1271 BuildLoopNest(1);
1272 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1273 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1274 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001275 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001276 new (&allocator_) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001277 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1278 basic_[0]->ReplaceInput(conv, 1);
1279 PerformInductionVarAnalysis();
1280
Aart Bike6bd0272016-12-16 13:57:52 -08001281 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001282 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001283 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1284
1285 // Narrowing detected.
1286 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1287 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1288
Aart Bik0d345cf2016-03-16 10:49:38 -07001289 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001290 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001291}
1292
1293TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1294 // Setup:
1295 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1296 // }
1297 BuildLoopNest(1);
1298 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1299 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1300 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001301 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001302 new (&allocator_) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001303 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1304 basic_[0]->ReplaceInput(conv, 1);
1305 PerformInductionVarAnalysis();
1306
Aart Bike6bd0272016-12-16 13:57:52 -08001307 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001308 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001309 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1310
1311 // Narrowing detected.
1312 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1313 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1314
Aart Bik0d345cf2016-03-16 10:49:38 -07001315 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001316 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001317}
1318
1319TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1320 // Setup:
1321 // for (char i = 0; i < 65535; i++) { // just fits!
1322 // }
1323 BuildLoopNest(1);
1324 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1325 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001326 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001327 new (&allocator_) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001328 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1329 basic_[0]->ReplaceInput(conv, 1);
1330 PerformInductionVarAnalysis();
1331
Aart Bike6bd0272016-12-16 13:57:52 -08001332 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001333 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001334 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1335
1336 // Narrowing detected.
1337 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1338 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1339
Aart Bik0d345cf2016-03-16 10:49:38 -07001340 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001341 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001342}
1343
1344TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1345 // Setup:
1346 // for (char i = 0; i < 65536; i++) { // infinite loop!
1347 // }
1348 BuildLoopNest(1);
1349 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1350 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001351 HInstruction* conv =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001352 new (&allocator_) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001353 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1354 basic_[0]->ReplaceInput(conv, 1);
1355 PerformInductionVarAnalysis();
1356
Aart Bike6bd0272016-12-16 13:57:52 -08001357 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001358 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001359 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1360
1361 // Narrowing detected.
1362 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1363 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1364
Aart Bik0d345cf2016-03-16 10:49:38 -07001365 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001366 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001367}
1368
Aart Bik30efb4e2015-07-30 12:14:31 -07001369} // namespace art