blob: 4c11ad46435de98df1fb3e7ac47f5f473f8e0d27 [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
Igor Murashkin5573c372017-11-16 13:34:30 -080017#include <regex>
Aart Bik30efb4e2015-07-30 12:14:31 -070018
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
Vladimir Marko0a516052019-10-14 13:00:44 +000025namespace art {
Aart Bik30efb4e2015-07-30 12:14:31 -070026
27/**
28 * Fixture class for the InductionVarAnalysis tests.
29 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010030class InductionVarAnalysisTest : public OptimizingUnitTest {
Aart Bik30efb4e2015-07-30 12:14:31 -070031 public:
Andreas Gamped9911ee2017-03-27 13:27:24 -070032 InductionVarAnalysisTest()
Vladimir Markoca6fff82017-10-03 14:49:14 +010033 : iva_(nullptr),
Andreas Gamped9911ee2017-03-27 13:27:24 -070034 entry_(nullptr),
35 return_(nullptr),
36 exit_(nullptr),
37 parameter_(nullptr),
38 constant0_(nullptr),
39 constant1_(nullptr),
40 constant2_(nullptr),
41 constant7_(nullptr),
42 constant100_(nullptr),
43 constantm1_(nullptr),
44 float_constant0_(nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010045 graph_ = CreateGraph();
Aart Bik30efb4e2015-07-30 12:14:31 -070046 }
47
48 ~InductionVarAnalysisTest() { }
49
50 // Builds single for-loop at depth d.
51 void BuildForLoop(int d, int n) {
52 ASSERT_LT(d, n);
Vladimir Markoca6fff82017-10-03 14:49:14 +010053 loop_preheader_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070054 graph_->AddBlock(loop_preheader_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +010055 loop_header_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070056 graph_->AddBlock(loop_header_[d]);
57 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
58 if (d < (n - 1)) {
59 BuildForLoop(d + 1, n);
60 }
Vladimir Markoca6fff82017-10-03 14:49:14 +010061 loop_body_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070062 graph_->AddBlock(loop_body_[d]);
63 loop_body_[d]->AddSuccessor(loop_header_[d]);
64 if (d < (n - 1)) {
65 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
66 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
67 } else {
68 loop_header_[d]->AddSuccessor(loop_body_[d]);
69 }
70 }
71
72 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
73 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
74 // populate the loop with instructions to set up interesting scenarios.
75 void BuildLoopNest(int n) {
76 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070077 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070078
79 // Build basic blocks with entry, nested loop, exit.
Vladimir Markoca6fff82017-10-03 14:49:14 +010080 entry_ = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070081 graph_->AddBlock(entry_);
82 BuildForLoop(0, n);
Vladimir Markoca6fff82017-10-03 14:49:14 +010083 return_ = new (GetAllocator()) HBasicBlock(graph_);
David Brazdildb51efb2015-11-06 01:36:20 +000084 graph_->AddBlock(return_);
Vladimir Markoca6fff82017-10-03 14:49:14 +010085 exit_ = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070086 graph_->AddBlock(exit_);
87 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000088 loop_header_[0]->AddSuccessor(return_);
89 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070090 graph_->SetEntryBlock(entry_);
91 graph_->SetExitBlock(exit_);
92
93 // Provide entry and exit instructions.
Vladimir Markoca6fff82017-10-03 14:49:14 +010094 parameter_ = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010095 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070096 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070097 constant0_ = graph_->GetIntConstant(0);
98 constant1_ = graph_->GetIntConstant(1);
Aart Bikc071a012016-12-01 10:22:31 -080099 constant2_ = graph_->GetIntConstant(2);
Aart Bikdf7822e2016-12-06 10:05:30 -0800100 constant7_ = graph_->GetIntConstant(7);
Aart Bike609b7c2015-08-27 13:46:58 -0700101 constant100_ = graph_->GetIntConstant(100);
Aart Bikd0a022d2016-12-13 11:22:31 -0800102 constantm1_ = graph_->GetIntConstant(-1);
David Brazdil15693bf2015-12-16 10:30:45 +0000103 float_constant0_ = graph_->GetFloatConstant(0.0f);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100104 return_->AddInstruction(new (GetAllocator()) HReturnVoid());
105 exit_->AddInstruction(new (GetAllocator()) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -0700106
107 // Provide loop instructions.
108 for (int d = 0; d < n; d++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100109 basic_[d] = new (GetAllocator()) HPhi(GetAllocator(), d, 0, DataType::Type::kInt32);
110 loop_preheader_[d]->AddInstruction(new (GetAllocator()) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000111 loop_header_[d]->AddPhi(basic_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100112 HInstruction* compare = new (GetAllocator()) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700113 loop_header_[d]->AddInstruction(compare);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100114 loop_header_[d]->AddInstruction(new (GetAllocator()) HIf(compare));
115 increment_[d] = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700116 loop_body_[d]->AddInstruction(increment_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100117 loop_body_[d]->AddInstruction(new (GetAllocator()) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000118
119 basic_[d]->AddInput(constant0_);
120 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700121 }
122 }
123
124 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700125 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100126 HBasicBlock* cond = new (GetAllocator()) HBasicBlock(graph_);
127 HBasicBlock* ifTrue = new (GetAllocator()) HBasicBlock(graph_);
128 HBasicBlock* ifFalse = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700129 graph_->AddBlock(cond);
130 graph_->AddBlock(ifTrue);
131 graph_->AddBlock(ifFalse);
132 // Conditional split.
133 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
134 cond->AddSuccessor(ifTrue);
135 cond->AddSuccessor(ifFalse);
136 ifTrue->AddSuccessor(loop_body_[d]);
137 ifFalse->AddSuccessor(loop_body_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100138 cond->AddInstruction(new (GetAllocator()) HIf(parameter_));
Aart Bik30efb4e2015-07-30 12:14:31 -0700139 *ifT = ifTrue;
140 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000141
Vladimir Markoca6fff82017-10-03 14:49:14 +0100142 HPhi* select_phi = new (GetAllocator()) HPhi(GetAllocator(), -1, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000143 loop_body_[d]->AddPhi(select_phi);
144 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700145 }
146
147 // Inserts instruction right before increment at depth d.
148 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
149 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
150 return instruction;
151 }
152
David Brazdilbadd8262016-02-02 16:28:56 +0000153 // Inserts a phi to loop header at depth d and returns it.
154 HPhi* InsertLoopPhi(int vreg, int d) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100155 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), vreg, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000156 loop_header_[d]->AddPhi(phi);
157 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700158 }
159
David Brazdilbadd8262016-02-02 16:28:56 +0000160 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700161 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000162 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000163 // ArraySet is given a float value in order to avoid SsaBuilder typing
164 // it from the array's non-existent reference type info.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100165 return InsertInstruction(new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100166 parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700167 }
168
Aart Bike609b7c2015-08-27 13:46:58 -0700169 // Returns induction information of instruction in loop at depth d.
170 std::string GetInductionInfo(HInstruction* instruction, int d) {
171 return HInductionVarAnalysis::InductionToString(
172 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700173 }
174
Aart Bik009cace2016-09-16 10:15:19 -0700175 // Returns induction information of the trip-count of loop at depth d.
176 std::string GetTripCount(int d) {
177 HInstruction* control = loop_header_[d]->GetLastInstruction();
178 DCHECK(control->IsIf());
179 return GetInductionInfo(control, d);
180 }
181
Aart Bik78296912016-03-25 13:14:53 -0700182 // Returns true if instructions have identical induction.
183 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
184 return HInductionVarAnalysis::InductionEqual(
185 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
186 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
187 }
188
Aart Bike6bd0272016-12-16 13:57:52 -0800189 // Returns true for narrowing linear induction.
190 bool IsNarrowingLinear(HInstruction* instruction) {
191 return HInductionVarAnalysis::IsNarrowingLinear(
192 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction));
193 }
194
Aart Bik30efb4e2015-07-30 12:14:31 -0700195 // Performs InductionVarAnalysis (after proper set up).
196 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000197 graph_->BuildDominatorTree();
Vladimir Markoca6fff82017-10-03 14:49:14 +0100198 iva_ = new (GetAllocator()) HInductionVarAnalysis(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700199 iva_->Run();
200 }
201
202 // General building fields.
Aart Bik30efb4e2015-07-30 12:14:31 -0700203 HGraph* graph_;
204 HInductionVarAnalysis* iva_;
205
206 // Fixed basic blocks and instructions.
207 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000208 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700209 HBasicBlock* exit_;
210 HInstruction* parameter_; // "this"
211 HInstruction* constant0_;
212 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800213 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800214 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700215 HInstruction* constant100_;
Aart Bikd0a022d2016-12-13 11:22:31 -0800216 HInstruction* constantm1_;
David Brazdil15693bf2015-12-16 10:30:45 +0000217 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700218
219 // Loop specifics.
220 HBasicBlock* loop_preheader_[10];
221 HBasicBlock* loop_header_[10];
222 HBasicBlock* loop_body_[10];
223 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000224 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700225};
226
227//
228// The actual InductionVarAnalysis tests.
229//
230
231TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
232 // Setup:
233 // for (int i_0 = 0; i_0 < 100; i_0++) {
234 // ..
235 // for (int i_9 = 0; i_9 < 100; i_9++) {
236 // }
237 // ..
238 // }
239 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000240 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700241
Aart Bik30efb4e2015-07-30 12:14:31 -0700242 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
243 for (int d = 0; d < 1; d++) {
244 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
245 (d == 0) ? nullptr
246 : loop_header_[d - 1]->GetLoopInformation());
247 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
248 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
249 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
250 loop_body_[d]->GetLoopInformation());
251 }
252 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
253}
254
Aart Bike609b7c2015-08-27 13:46:58 -0700255TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700256 // Setup:
257 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700258 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700259 // }
260 BuildLoopNest(1);
261 HInstruction* store = InsertArrayStore(basic_[0], 0);
262 PerformInductionVarAnalysis();
263
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100264 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
265 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700266
Aart Bik78296912016-03-25 13:14:53 -0700267 // Offset matters!
268 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
269
Aart Bikd14c5952015-09-08 15:25:15 -0700270 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700271 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700272}
273
Aart Bike609b7c2015-08-27 13:46:58 -0700274TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700275 // Setup:
276 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800277 // t = 100 + i;
278 // t = 100 - i;
279 // t = 100 * i;
280 // t = i << 1;
281 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700282 // }
283 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700284 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100285 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700286 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100287 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700288 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100289 new (GetAllocator()) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700290 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100291 new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700292 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100293 new (GetAllocator()) HNeg(DataType::Type::kInt32, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700294 PerformInductionVarAnalysis();
295
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100296 EXPECT_STREQ("((1) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
297 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
298 EXPECT_STREQ("((100) * i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
299 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl, 0).c_str());
300 EXPECT_STREQ("(( - (1)) * i + (0)):Int32", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700301}
302
303TEST_F(InductionVarAnalysisTest, FindChainInduction) {
304 // Setup:
305 // k = 0;
306 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700307 // k = k + 100;
308 // a[k] = 0;
309 // k = k - 1;
310 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700311 // }
312 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800313 HPhi* k_header = InsertLoopPhi(0, 0);
314 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000315
Aart Bik7dc96932016-10-12 10:01:05 -0700316 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100317 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000318 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700319 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100320 new (GetAllocator()) HSub(DataType::Type::kInt32, add, constant1_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000321 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800322 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700323 PerformInductionVarAnalysis();
324
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100325 EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800326 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100327 EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700328 GetInductionInfo(store1->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100329 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700330 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700331}
332
333TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
334 // Setup:
335 // k = 0;
336 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700337 // if () k = k + 1;
338 // else k = k + 1;
339 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700340 // }
341 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000342 HPhi* k_header = InsertLoopPhi(0, 0);
343 k_header->AddInput(constant0_);
344
Aart Bik30efb4e2015-07-30 12:14:31 -0700345 HBasicBlock* ifTrue;
346 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000347 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
348
Aart Bik30efb4e2015-07-30 12:14:31 -0700349 // True-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100350 HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700351 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000352 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700353 // False-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100354 HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700355 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000356 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700357 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000358 HInstruction* store = InsertArrayStore(k_body, 0);
359 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700360 PerformInductionVarAnalysis();
361
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100362 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
363 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700364
365 // Both increments get same induction.
366 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
367 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700368}
369
370TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
371 // Setup:
372 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700373 // if () k = i + 1;
374 // else k = i + 1;
375 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700376 // }
377 BuildLoopNest(1);
378 HBasicBlock* ifTrue;
379 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000380 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
381
Aart Bik30efb4e2015-07-30 12:14:31 -0700382 // True-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100383 HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700384 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000385 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700386 // False-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100387 HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700388 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000389 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700390 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000391 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700392 PerformInductionVarAnalysis();
393
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100394 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800395
396 // Both increments get same induction.
397 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
398 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
399}
400
Aart Bikdf7822e2016-12-06 10:05:30 -0800401TEST_F(InductionVarAnalysisTest, AddLinear) {
402 // Setup:
403 // for (int i = 0; i < 100; i++) {
404 // t1 = i + i;
405 // t2 = 7 + i;
406 // t3 = t1 + t2;
407 // }
408 BuildLoopNest(1);
409
410 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100411 new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800412 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100413 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800414 HInstruction* add3 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100415 new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, add2), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800416 PerformInductionVarAnalysis();
417
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100418 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(basic_[0], 0).c_str());
419 EXPECT_STREQ("(((1) + (1)) * i + (0)):Int32", GetInductionInfo(add1, 0).c_str());
420 EXPECT_STREQ("((1) * i + (7)):Int32", GetInductionInfo(add2, 0).c_str());
421 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):Int32", GetInductionInfo(add3, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800422}
423
424TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
425 // Setup:
426 // k = 1;
427 // for (int i = 0; i < 100; i++) {
428 // t = i * 2;
429 // t = 100 + t
430 // k = t + k; // polynomial
431 // }
432 BuildLoopNest(1);
433 HPhi* k_header = InsertLoopPhi(0, 0);
434 k_header->AddInput(constant1_);
435
436 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100437 new (GetAllocator()) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800438 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100439 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, mul), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800440 HInstruction* pol = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100441 new (GetAllocator()) HAdd(DataType::Type::kInt32, add, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800442 k_header->AddInput(pol);
443 PerformInductionVarAnalysis();
444
445 // Note, only the phi in the cycle and the base linear induction are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100446 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800447 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100448 EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800449 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
450}
451
452TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
453 // Setup:
454 // k = 1;
455 // for (int i = 0; i < 100; i++) {
456 // t = k + 100;
457 // t = k - 1;
458 // t = - t
459 // t = k * 2;
460 // t = k << 2;
461 // k = k + i; // polynomial
462 // }
463 BuildLoopNest(1);
464 HPhi* k_header = InsertLoopPhi(0, 0);
465 k_header->AddInput(constant1_);
466
467 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100468 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800469 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100470 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800471 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100472 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800473 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100474 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800475 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100476 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800477 HInstruction* pol = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100478 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800479 k_header->AddInput(pol);
480 PerformInductionVarAnalysis();
481
482 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100483 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800484 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100485 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800486 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100487 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800488 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100489 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800490 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100491 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800492 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100493 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800494 GetInductionInfo(shl, 0).c_str());
495 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
496}
497
498TEST_F(InductionVarAnalysisTest, AddPolynomial) {
499 // Setup:
500 // k = 7;
501 // for (int i = 0; i < 100; i++) {
502 // t = k + k;
503 // t = t + k;
504 // k = k + i
505 // }
506 BuildLoopNest(1);
507 HPhi* k_header = InsertLoopPhi(0, 0);
508 k_header->AddInput(constant7_);
509
510 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100511 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800512 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100513 new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800514 HInstruction* add3 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100515 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800516 k_header->AddInput(add3);
517 PerformInductionVarAnalysis();
518
519 // Note, only the phi in the cycle and added-derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100520 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800521 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100522 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800523 GetInductionInfo(add1, 0).c_str());
524 EXPECT_STREQ(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100525 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800526 GetInductionInfo(add2, 0).c_str());
527 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
528}
529
Aart Bikc071a012016-12-01 10:22:31 -0800530TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
531 // Setup:
532 // k = 1;
533 // for (int i = 0; i < 100; i++) {
534 // k = k * 100; // geometric (x 100)
535 // }
536 BuildLoopNest(1);
537 HPhi* k_header = InsertLoopPhi(0, 0);
538 k_header->AddInput(constant1_);
539
540 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100541 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800542 k_header->AddInput(mul);
543 PerformInductionVarAnalysis();
544
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100545 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
546 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800547}
548
549TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
550 // Setup:
551 // k = 1;
552 // for (int i = 0; i < 100; i++) {
553 // t = k + 1;
554 // k = k << 1; // geometric (x 2)
555 // t = k + 100;
556 // t = k - 1;
557 // t = - t;
558 // t = k * 2;
559 // t = k << 2;
560 // }
561 BuildLoopNest(1);
562 HPhi* k_header = InsertLoopPhi(0, 0);
563 k_header->AddInput(constant1_);
564
565 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100566 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800567 HInstruction* shl1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100568 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800569 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100570 new (GetAllocator()) HAdd(DataType::Type::kInt32, shl1, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800571 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100572 new (GetAllocator()) HSub(DataType::Type::kInt32, shl1, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800573 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100574 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800575 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100576 new (GetAllocator()) HMul(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800577 HInstruction* shl2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100578 new (GetAllocator()) HShl(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800579 k_header->AddInput(shl1);
580 PerformInductionVarAnalysis();
581
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100582 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
583 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):Int32", GetInductionInfo(add1, 0).c_str());
584 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):Int32", GetInductionInfo(shl1, 0).c_str());
585 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):Int32", GetInductionInfo(add2, 0).c_str());
586 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
587 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800588 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100589 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
590 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800591}
592
593TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
594 // Setup:
595 // k = 1;
596 // for (int i = 0; i < 100; i++) {
597 // t = k + 100;
598 // t = k - 1;
599 // t = - t
600 // t = k * 2;
601 // t = k << 2;
602 // k = k / 100; // geometric (/ 100)
603 // }
604 BuildLoopNest(1);
605 HPhi* k_header = InsertLoopPhi(0, 0);
606 k_header->AddInput(constant1_);
607
608 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100609 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800610 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100611 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800612 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100613 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800614 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100615 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800616 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100617 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800618 HInstruction* div = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100619 new (GetAllocator()) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800620 k_header->AddInput(div);
621 PerformInductionVarAnalysis();
622
623 // Note, only the phi in the cycle and direct additive derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100624 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
625 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):Int32", GetInductionInfo(add, 0).c_str());
626 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800627 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
628 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
629 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
630 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
631}
632
Aart Bikd0a022d2016-12-13 11:22:31 -0800633TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
634 // Setup:
635 // k = 100;
636 // for (int i = 0; i < 100; i++) {
637 // k = k >> 1; // geometric (/ 2)
638 // }
639 BuildLoopNest(1);
640 HPhi* k_header = InsertLoopPhi(0, 0);
641 k_header->AddInput(constant100_);
642
643 HInstruction* shr = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100644 new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800645 k_header->AddInput(shr);
646 PerformInductionVarAnalysis();
647
648 // Note, only the phi in the cycle is classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100649 EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
Aart Bikd0a022d2016-12-13 11:22:31 -0800650 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
651}
652
653TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
654 // Setup:
655 // k = -1;
656 // for (int i = 0; i < 100; i++) {
657 // k = k >> 1; // initial value is negative
658 // }
659 BuildLoopNest(1);
660 HPhi* k_header = InsertLoopPhi(0, 0);
661 k_header->AddInput(constantm1_);
662
663 HInstruction* shr = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100664 new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800665 k_header->AddInput(shr);
666 PerformInductionVarAnalysis();
667
668 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
669 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
670}
671
Aart Bikdf7822e2016-12-06 10:05:30 -0800672TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800673 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800674 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800675 // for (int i = 0; i < 100; i++) {
676 // t = k + 100;
677 // t = k - 1;
678 // t = -t
679 // t = k * 2;
680 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800681 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800682 // }
683 BuildLoopNest(1);
684 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800685 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800686
687 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100688 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800689 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100690 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800691 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100692 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800693 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100694 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800695 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100696 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800697 HInstruction* rem = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100698 new (GetAllocator()) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800699 k_header->AddInput(rem);
700 PerformInductionVarAnalysis();
701
Aart Bikdf7822e2016-12-06 10:05:30 -0800702 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100703 EXPECT_STREQ("wrap((100), ((100) % (7))):Int32", GetInductionInfo(k_header, 0).c_str());
704 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):Int32",
705 GetInductionInfo(add, 0).c_str());
706 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):Int32",
707 GetInductionInfo(sub, 0).c_str());
708 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):Int32",
709 GetInductionInfo(neg, 0).c_str());
710 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):Int32",
711 GetInductionInfo(mul, 0).c_str());
712 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):Int32",
713 GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800714 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700715}
716
717TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
718 // Setup:
719 // k = 0;
720 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700721 // a[k] = 0;
722 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700723 // }
724 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800725 HPhi* k_header = InsertLoopPhi(0, 0);
726 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000727
Aart Bikc071a012016-12-01 10:22:31 -0800728 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700729 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100730 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800731 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700732 PerformInductionVarAnalysis();
733
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100734 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800735 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100736 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700737 GetInductionInfo(store->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100738 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700739}
740
741TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
742 // Setup:
743 // k = 0;
744 // t = 100;
745 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700746 // a[k] = 0;
747 // k = t;
748 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700749 // }
750 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800751 HPhi* k_header = InsertLoopPhi(0, 0);
752 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000753 HPhi* t = InsertLoopPhi(1, 0);
754 t->AddInput(constant100_);
755
Aart Bikc071a012016-12-01 10:22:31 -0800756 HInstruction* store = InsertArrayStore(k_header, 0);
757 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700758 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100759 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000760 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700761 PerformInductionVarAnalysis();
762
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100763 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700764 GetInductionInfo(store->InputAt(1), 0).c_str());
765}
766
767TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
768 // Setup:
769 // k = 0;
770 // for (int i = 0; i < 100; i++) {
771 // t = k + 100;
772 // t = k - 100;
773 // t = k * 100;
774 // t = k << 1;
775 // t = - k;
776 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800777 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700778 // }
779 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800780 HPhi* k_header = InsertLoopPhi(0, 0);
781 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000782
Aart Bik7dc96932016-10-12 10:01:05 -0700783 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100784 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700785 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100786 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700787 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100788 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800789 HInstruction* shl1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100790 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800791 HInstruction* neg1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100792 new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800793 HInstruction* shl2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100794 new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800795 HInstruction* neg2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100796 new (GetAllocator()) HNeg(DataType::Type::kInt32, shl2), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800797 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700798 PerformInductionVarAnalysis();
799
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100800 EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700801 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100802 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700803 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100804 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700805 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100806 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800807 GetInductionInfo(shl1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100808 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800809 GetInductionInfo(neg1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100810 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
811 EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700812}
813
814TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
815 // Setup:
816 // k = 0;
817 // t = 100;
818 // for (int i = 0; i < 100; i++) {
819 // a[k] = 0;
820 // a[t] = 0;
821 // // Swap t <-> k.
822 // d = t;
823 // t = k;
824 // k = d;
825 // }
826 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800827 HPhi* k_header = InsertLoopPhi(0, 0);
828 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000829 HPhi* t = InsertLoopPhi(1, 0);
830 t->AddInput(constant100_);
831
Aart Bikc071a012016-12-01 10:22:31 -0800832 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000833 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800834 k_header->AddInput(t);
835 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700836 PerformInductionVarAnalysis();
837
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100838 EXPECT_STREQ("periodic((0), (100)):Int32", GetInductionInfo(store1->InputAt(1), 0).c_str());
839 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700840}
841
842TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
843 // Setup:
844 // k = 0;
845 // for (int i = 0; i < 100; i++) {
846 // a[k] = 0;
847 // k = 1 - k;
848 // }
849 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800850 HPhi* k_header = InsertLoopPhi(0, 0);
851 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000852
Aart Bikc071a012016-12-01 10:22:31 -0800853 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700854 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100855 new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800856 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700857 PerformInductionVarAnalysis();
858
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100859 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
860 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700861}
862
Aart Bik7dc96932016-10-12 10:01:05 -0700863TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
864 // Setup:
865 // k = 0;
866 // for (int i = 0; i < 100; i++) {
867 // a[k] = 0;
868 // k = k ^ 1;
869 // }
870 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800871 HPhi* k_header = InsertLoopPhi(0, 0);
872 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700873
Aart Bikc071a012016-12-01 10:22:31 -0800874 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700875 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100876 new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800877 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700878 PerformInductionVarAnalysis();
879
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100880 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
881 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700882}
883
Aart Bik639cc8c2016-10-18 13:03:31 -0700884TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
885 // Setup:
886 // k = 1;
887 // for (int i = 0; i < 100; i++) {
888 // k = 1 ^ k;
889 // }
890 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800891 HPhi* k_header = InsertLoopPhi(0, 0);
892 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700893
894 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100895 new (GetAllocator()) HXor(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800896 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700897 PerformInductionVarAnalysis();
898
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100899 EXPECT_STREQ("periodic((1), ((1) ^ (1))):Int32", GetInductionInfo(k_header, 0).c_str());
900 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700901}
902
Aart Bik7dc96932016-10-12 10:01:05 -0700903TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
904 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700905 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700906 // for (int i = 0; i < 100; i++) {
907 // k = k ^ 100;
908 // }
909 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800910 HPhi* k_header = InsertLoopPhi(0, 0);
911 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700912
913 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100914 new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800915 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700916 PerformInductionVarAnalysis();
917
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100918 EXPECT_STREQ("periodic((1), ((1) ^ (100))):Int32", GetInductionInfo(k_header, 0).c_str());
919 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700920}
921
922TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
923 // Setup:
924 // k = 0;
925 // for (int i = 0; i < 100; i++) {
926 // k = (k == 0);
927 // }
928 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800929 HPhi* k_header = InsertLoopPhi(0, 0);
930 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700931
Vladimir Markoca6fff82017-10-03 14:49:14 +0100932 HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(k_header, constant0_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800933 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700934 PerformInductionVarAnalysis();
935
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100936 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
937 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700938}
939
940TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
941 // Setup:
942 // k = 0;
943 // for (int i = 0; i < 100; i++) {
944 // k = (0 == k);
945 // }
946 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800947 HPhi* k_header = InsertLoopPhi(0, 0);
948 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700949
Vladimir Markoca6fff82017-10-03 14:49:14 +0100950 HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(constant0_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800951 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700952 PerformInductionVarAnalysis();
953
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100954 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
955 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700956}
957
958TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
959 // Setup:
960 // k = 0;
961 // for (int i = 0; i < 100; i++) {
962 // k = (k != 1);
963 // }
964 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800965 HPhi* k_header = InsertLoopPhi(0, 0);
966 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700967
Vladimir Markoca6fff82017-10-03 14:49:14 +0100968 HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800969 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700970 PerformInductionVarAnalysis();
971
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100972 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
973 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700974}
975
976TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
977 // Setup:
978 // k = 0;
979 // for (int i = 0; i < 100; i++) {
980 // k = (1 != k);
981 // }
982 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800983 HPhi* k_header = InsertLoopPhi(0, 0);
984 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700985
Vladimir Markoca6fff82017-10-03 14:49:14 +0100986 HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800987 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700988 PerformInductionVarAnalysis();
989
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100990 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
991 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700992}
993
Aart Bike609b7c2015-08-27 13:46:58 -0700994TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
995 // Setup:
996 // k = 0;
997 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800998 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700999 // k = 1 - k;
1000 // t = k + 100;
1001 // t = k - 100;
1002 // t = k * 100;
1003 // t = k << 1;
1004 // t = - k;
1005 // }
1006 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +00001007 HPhi* k_header = InsertLoopPhi(0, 0);
1008 k_header->AddInput(constant0_);
1009
Aart Bikc071a012016-12-01 10:22:31 -08001010 HInstruction* neg1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001011 new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001012 HInstruction* idiom = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001013 new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001014 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001015 new (GetAllocator()) HAdd(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001016 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001017 new (GetAllocator()) HSub(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001018 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001019 new (GetAllocator()) HMul(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001020 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001021 new (GetAllocator()) HShl(DataType::Type::kInt32, idiom, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001022 HInstruction* neg2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001023 new (GetAllocator()) HNeg(DataType::Type::kInt32, idiom), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001024 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -07001025 PerformInductionVarAnalysis();
1026
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001027 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(k_header, 0).c_str());
1028 EXPECT_STREQ("periodic((0), ( - (1))):Int32", GetInductionInfo(neg1, 0).c_str());
1029 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(idiom, 0).c_str());
1030 EXPECT_STREQ("periodic(((1) + (100)), (100)):Int32", GetInductionInfo(add, 0).c_str());
1031 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):Int32", GetInductionInfo(sub, 0).c_str());
1032 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(mul, 0).c_str());
1033 EXPECT_STREQ("periodic((2), (0)):Int32", GetInductionInfo(shl, 0).c_str());
1034 EXPECT_STREQ("periodic(( - (1)), (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001035}
1036
1037TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
1038 // Setup:
1039 // k = 0;
1040 // for (int i_0 = 0; i_0 < 100; i_0++) {
1041 // ..
1042 // for (int i_9 = 0; i_9 < 100; i_9++) {
1043 // k = 1 + k;
1044 // a[k] = 0;
1045 // }
1046 // ..
1047 // }
1048 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +00001049
Aart Bikc071a012016-12-01 10:22:31 -08001050 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +00001051 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001052 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +00001053 }
1054
Aart Bik7dc96932016-10-12 10:01:05 -07001055 HInstruction* inc = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001056 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +00001057 HInstruction* store = InsertArrayStore(inc, 9);
1058
1059 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001060 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
1061 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001062 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001063 PerformInductionVarAnalysis();
1064
Aart Bike609b7c2015-08-27 13:46:58 -07001065 // Avoid exact phi number, since that depends on the SSA building phase.
1066 std::regex r("\\(\\(1\\) \\* i \\+ "
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001067 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32");
Aart Bik30efb4e2015-07-30 12:14:31 -07001068
1069 for (int d = 0; d < 10; d++) {
1070 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001071 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001072 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001073 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001074 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001075 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001076 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001077 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001078 }
1079}
1080
Aart Bik78296912016-03-25 13:14:53 -07001081TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1082 // Setup:
1083 // for (int i = 0; i < 100; i++) {
1084 // k = (byte) i;
1085 // a[k] = 0;
1086 // a[i] = 0;
1087 // }
1088 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001089 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001090 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bik78296912016-03-25 13:14:53 -07001091 HInstruction* store1 = InsertArrayStore(conv, 0);
1092 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1093 PerformInductionVarAnalysis();
1094
Aart Bike6bd0272016-12-16 13:57:52 -08001095 // Regular int induction (i) is transferred over conversion into byte induction (k).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001096 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
1097 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
1098 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001099
Aart Bike6bd0272016-12-16 13:57:52 -08001100 // Narrowing detected.
1101 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1102 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));
1103
Aart Bik78296912016-03-25 13:14:53 -07001104 // Type matters!
1105 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1106
1107 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001108 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001109}
1110
Aart Bikcc42be02016-10-20 16:14:16 -07001111TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1112 // Setup:
1113 // for (int i = 0; i < 100; i++) {
1114 // k = (byte) i;
1115 // a[k] = 0;
1116 // k = k + 1
1117 // a[k] = 0;
1118 // }
1119 BuildLoopNest(1);
1120 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001121 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001122 HInstruction* store1 = InsertArrayStore(conv, 0);
1123 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001124 new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001125 HInstruction* store2 = InsertArrayStore(add, 0);
1126
1127 PerformInductionVarAnalysis();
1128
Aart Bike6bd0272016-12-16 13:57:52 -08001129 // Byte induction (k) is detected, but it does not transfer over the addition,
1130 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001131 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001132 EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
1133
1134 // Narrowing detected.
1135 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1136 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1))); // works for null
1137}
1138
1139TEST_F(InductionVarAnalysisTest, ByteInduction) {
1140 // Setup:
1141 // k = -128;
1142 // for (int i = 0; i < 100; i++) {
1143 // k = k + 1;
1144 // k = (byte) k;
1145 // }
1146 BuildLoopNest(1);
1147 HPhi* k_header = InsertLoopPhi(0, 0);
1148 k_header->AddInput(graph_->GetIntConstant(-128));
1149
1150 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001151 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001152 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001153 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001154 k_header->AddInput(conv);
1155 PerformInductionVarAnalysis();
1156
1157 // Byte induction (k) is detected, but it does not transfer over the addition,
1158 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001159 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001160 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1161
1162 // Narrowing detected.
1163 EXPECT_TRUE(IsNarrowingLinear(k_header));
1164 EXPECT_FALSE(IsNarrowingLinear(add)); // works for null
1165}
1166
1167TEST_F(InductionVarAnalysisTest, NoByteInduction1) {
1168 // Setup:
1169 // k = -129; / does not fit!
1170 // for (int i = 0; i < 100; i++) {
1171 // k = k + 1;
1172 // k = (byte) k;
1173 // }
1174 BuildLoopNest(1);
1175 HPhi* k_header = InsertLoopPhi(0, 0);
1176 k_header->AddInput(graph_->GetIntConstant(-129));
1177
1178 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001179 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001180 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001181 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001182 k_header->AddInput(conv);
1183 PerformInductionVarAnalysis();
1184
1185 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1186 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1187}
1188
1189TEST_F(InductionVarAnalysisTest, NoByteInduction2) {
1190 // Setup:
1191 // k = 0;
1192 // for (int i = 0; i < 100; i++) {
1193 // k = (byte) k; // conversion not done last!
1194 // k = k + 1;
1195 // }
1196 BuildLoopNest(1);
1197 HPhi* k_header = InsertLoopPhi(0, 0);
1198 k_header->AddInput(constant0_);
1199
1200 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001201 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001202 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001203 new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001204 k_header->AddInput(add);
1205 PerformInductionVarAnalysis();
1206
1207 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1208 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
Aart Bikcc42be02016-10-20 16:14:16 -07001209}
1210
Aart Bik0d345cf2016-03-16 10:49:38 -07001211TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1212 // Setup:
1213 // for (byte i = -128; i < 127; i++) { // just fits!
1214 // }
1215 BuildLoopNest(1);
1216 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1217 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1218 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001219 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001220 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001221 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1222 basic_[0]->ReplaceInput(conv, 1);
1223 PerformInductionVarAnalysis();
1224
Aart Bike6bd0272016-12-16 13:57:52 -08001225 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001226 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001227 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1228
1229 // Narrowing detected.
1230 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1231 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1232
Aart Bik0d345cf2016-03-16 10:49:38 -07001233 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001234 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001235}
1236
1237TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1238 // Setup:
1239 // for (byte i = -128; i < 128; i++) { // infinite loop!
1240 // }
1241 BuildLoopNest(1);
1242 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1243 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1244 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001245 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001246 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001247 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1248 basic_[0]->ReplaceInput(conv, 1);
1249 PerformInductionVarAnalysis();
1250
Aart Bike6bd0272016-12-16 13:57:52 -08001251 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001252 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001253 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1254
1255 // Narrowing detected.
1256 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1257 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1258
Aart Bik0d345cf2016-03-16 10:49:38 -07001259 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001260 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001261}
1262
1263TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1264 // Setup:
1265 // for (short i = -32768; i < 32767; i++) { // just fits!
1266 // }
1267 BuildLoopNest(1);
1268 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1269 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1270 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001271 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001272 new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001273 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1274 basic_[0]->ReplaceInput(conv, 1);
1275 PerformInductionVarAnalysis();
1276
Aart Bike6bd0272016-12-16 13:57:52 -08001277 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001278 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001279 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1280
1281 // Narrowing detected.
1282 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1283 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1284
Aart Bik0d345cf2016-03-16 10:49:38 -07001285 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001286 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001287}
1288
1289TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1290 // Setup:
1291 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1292 // }
1293 BuildLoopNest(1);
1294 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1295 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1296 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001297 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001298 new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001299 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1300 basic_[0]->ReplaceInput(conv, 1);
1301 PerformInductionVarAnalysis();
1302
Aart Bike6bd0272016-12-16 13:57:52 -08001303 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001304 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001305 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1306
1307 // Narrowing detected.
1308 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1309 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1310
Aart Bik0d345cf2016-03-16 10:49:38 -07001311 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001312 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001313}
1314
1315TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1316 // Setup:
1317 // for (char i = 0; i < 65535; i++) { // just fits!
1318 // }
1319 BuildLoopNest(1);
1320 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1321 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001322 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001323 new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001324 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1325 basic_[0]->ReplaceInput(conv, 1);
1326 PerformInductionVarAnalysis();
1327
Aart Bike6bd0272016-12-16 13:57:52 -08001328 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001329 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001330 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1331
1332 // Narrowing detected.
1333 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1334 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1335
Aart Bik0d345cf2016-03-16 10:49:38 -07001336 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001337 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001338}
1339
1340TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1341 // Setup:
1342 // for (char i = 0; i < 65536; i++) { // infinite loop!
1343 // }
1344 BuildLoopNest(1);
1345 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1346 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001347 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001348 new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001349 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1350 basic_[0]->ReplaceInput(conv, 1);
1351 PerformInductionVarAnalysis();
1352
Aart Bike6bd0272016-12-16 13:57:52 -08001353 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001354 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001355 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1356
1357 // Narrowing detected.
1358 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1359 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1360
Aart Bik0d345cf2016-03-16 10:49:38 -07001361 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001362 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001363}
1364
Aart Bik30efb4e2015-07-30 12:14:31 -07001365} // namespace art