blob: 80c15371dc5664d66190e3f6e4c7c7b6aa2f1154 [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"
Vladimir Markoe2727152019-10-10 10:46:42 +010020#include "base/macros.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070021#include "builder.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070022#include "induction_var_analysis.h"
23#include "nodes.h"
24#include "optimizing_unit_test.h"
25
Vladimir Markoe2727152019-10-10 10:46:42 +010026namespace art HIDDEN {
Aart Bik30efb4e2015-07-30 12:14:31 -070027
28/**
29 * Fixture class for the InductionVarAnalysis tests.
30 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010031class InductionVarAnalysisTest : public OptimizingUnitTest {
Aart Bik30efb4e2015-07-30 12:14:31 -070032 public:
Andreas Gamped9911ee2017-03-27 13:27:24 -070033 InductionVarAnalysisTest()
Vladimir Markoca6fff82017-10-03 14:49:14 +010034 : iva_(nullptr),
Andreas Gamped9911ee2017-03-27 13:27:24 -070035 entry_(nullptr),
36 return_(nullptr),
37 exit_(nullptr),
38 parameter_(nullptr),
39 constant0_(nullptr),
40 constant1_(nullptr),
41 constant2_(nullptr),
42 constant7_(nullptr),
43 constant100_(nullptr),
44 constantm1_(nullptr),
45 float_constant0_(nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010046 graph_ = CreateGraph();
Aart Bik30efb4e2015-07-30 12:14:31 -070047 }
48
49 ~InductionVarAnalysisTest() { }
50
51 // Builds single for-loop at depth d.
52 void BuildForLoop(int d, int n) {
53 ASSERT_LT(d, n);
Vladimir Markoca6fff82017-10-03 14:49:14 +010054 loop_preheader_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070055 graph_->AddBlock(loop_preheader_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +010056 loop_header_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070057 graph_->AddBlock(loop_header_[d]);
58 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
59 if (d < (n - 1)) {
60 BuildForLoop(d + 1, n);
61 }
Vladimir Markoca6fff82017-10-03 14:49:14 +010062 loop_body_[d] = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070063 graph_->AddBlock(loop_body_[d]);
64 loop_body_[d]->AddSuccessor(loop_header_[d]);
65 if (d < (n - 1)) {
66 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
67 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
68 } else {
69 loop_header_[d]->AddSuccessor(loop_body_[d]);
70 }
71 }
72
73 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
74 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
75 // populate the loop with instructions to set up interesting scenarios.
76 void BuildLoopNest(int n) {
77 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070078 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070079
80 // Build basic blocks with entry, nested loop, exit.
Vladimir Markoca6fff82017-10-03 14:49:14 +010081 entry_ = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070082 graph_->AddBlock(entry_);
83 BuildForLoop(0, n);
Vladimir Markoca6fff82017-10-03 14:49:14 +010084 return_ = new (GetAllocator()) HBasicBlock(graph_);
David Brazdildb51efb2015-11-06 01:36:20 +000085 graph_->AddBlock(return_);
Vladimir Markoca6fff82017-10-03 14:49:14 +010086 exit_ = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -070087 graph_->AddBlock(exit_);
88 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000089 loop_header_[0]->AddSuccessor(return_);
90 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070091 graph_->SetEntryBlock(entry_);
92 graph_->SetExitBlock(exit_);
93
94 // Provide entry and exit instructions.
Vladimir Markoca6fff82017-10-03 14:49:14 +010095 parameter_ = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010096 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070097 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070098 constant0_ = graph_->GetIntConstant(0);
99 constant1_ = graph_->GetIntConstant(1);
Aart Bikc071a012016-12-01 10:22:31 -0800100 constant2_ = graph_->GetIntConstant(2);
Aart Bikdf7822e2016-12-06 10:05:30 -0800101 constant7_ = graph_->GetIntConstant(7);
Aart Bike609b7c2015-08-27 13:46:58 -0700102 constant100_ = graph_->GetIntConstant(100);
Aart Bikd0a022d2016-12-13 11:22:31 -0800103 constantm1_ = graph_->GetIntConstant(-1);
David Brazdil15693bf2015-12-16 10:30:45 +0000104 float_constant0_ = graph_->GetFloatConstant(0.0f);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100105 return_->AddInstruction(new (GetAllocator()) HReturnVoid());
106 exit_->AddInstruction(new (GetAllocator()) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -0700107
108 // Provide loop instructions.
109 for (int d = 0; d < n; d++) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100110 basic_[d] = new (GetAllocator()) HPhi(GetAllocator(), d, 0, DataType::Type::kInt32);
111 loop_preheader_[d]->AddInstruction(new (GetAllocator()) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000112 loop_header_[d]->AddPhi(basic_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100113 HInstruction* compare = new (GetAllocator()) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700114 loop_header_[d]->AddInstruction(compare);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100115 loop_header_[d]->AddInstruction(new (GetAllocator()) HIf(compare));
116 increment_[d] = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700117 loop_body_[d]->AddInstruction(increment_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100118 loop_body_[d]->AddInstruction(new (GetAllocator()) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000119
120 basic_[d]->AddInput(constant0_);
121 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700122 }
123 }
124
125 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700126 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100127 HBasicBlock* cond = new (GetAllocator()) HBasicBlock(graph_);
128 HBasicBlock* ifTrue = new (GetAllocator()) HBasicBlock(graph_);
129 HBasicBlock* ifFalse = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700130 graph_->AddBlock(cond);
131 graph_->AddBlock(ifTrue);
132 graph_->AddBlock(ifFalse);
133 // Conditional split.
134 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
135 cond->AddSuccessor(ifTrue);
136 cond->AddSuccessor(ifFalse);
137 ifTrue->AddSuccessor(loop_body_[d]);
138 ifFalse->AddSuccessor(loop_body_[d]);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100139 cond->AddInstruction(new (GetAllocator()) HIf(parameter_));
Aart Bik30efb4e2015-07-30 12:14:31 -0700140 *ifT = ifTrue;
141 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000142
Vladimir Markoca6fff82017-10-03 14:49:14 +0100143 HPhi* select_phi = new (GetAllocator()) HPhi(GetAllocator(), -1, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000144 loop_body_[d]->AddPhi(select_phi);
145 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700146 }
147
148 // Inserts instruction right before increment at depth d.
149 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
150 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
151 return instruction;
152 }
153
David Brazdilbadd8262016-02-02 16:28:56 +0000154 // Inserts a phi to loop header at depth d and returns it.
155 HPhi* InsertLoopPhi(int vreg, int d) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100156 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), vreg, 0, DataType::Type::kInt32);
David Brazdilbadd8262016-02-02 16:28:56 +0000157 loop_header_[d]->AddPhi(phi);
158 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700159 }
160
David Brazdilbadd8262016-02-02 16:28:56 +0000161 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700162 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000163 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000164 // ArraySet is given a float value in order to avoid SsaBuilder typing
165 // it from the array's non-existent reference type info.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100166 return InsertInstruction(new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100167 parameter_, subscript, float_constant0_, DataType::Type::kFloat32, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700168 }
169
Aart Bike609b7c2015-08-27 13:46:58 -0700170 // Returns induction information of instruction in loop at depth d.
171 std::string GetInductionInfo(HInstruction* instruction, int d) {
172 return HInductionVarAnalysis::InductionToString(
173 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700174 }
175
Aart Bik009cace2016-09-16 10:15:19 -0700176 // Returns induction information of the trip-count of loop at depth d.
177 std::string GetTripCount(int d) {
178 HInstruction* control = loop_header_[d]->GetLastInstruction();
179 DCHECK(control->IsIf());
180 return GetInductionInfo(control, d);
181 }
182
Aart Bik78296912016-03-25 13:14:53 -0700183 // Returns true if instructions have identical induction.
184 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
185 return HInductionVarAnalysis::InductionEqual(
186 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
187 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
188 }
189
Aart Bike6bd0272016-12-16 13:57:52 -0800190 // Returns true for narrowing linear induction.
191 bool IsNarrowingLinear(HInstruction* instruction) {
192 return HInductionVarAnalysis::IsNarrowingLinear(
193 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction));
194 }
195
Aart Bik30efb4e2015-07-30 12:14:31 -0700196 // Performs InductionVarAnalysis (after proper set up).
197 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000198 graph_->BuildDominatorTree();
Vladimir Markoca6fff82017-10-03 14:49:14 +0100199 iva_ = new (GetAllocator()) HInductionVarAnalysis(graph_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700200 iva_->Run();
201 }
202
203 // General building fields.
Aart Bik30efb4e2015-07-30 12:14:31 -0700204 HGraph* graph_;
205 HInductionVarAnalysis* iva_;
206
207 // Fixed basic blocks and instructions.
208 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000209 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700210 HBasicBlock* exit_;
211 HInstruction* parameter_; // "this"
212 HInstruction* constant0_;
213 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800214 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800215 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700216 HInstruction* constant100_;
Aart Bikd0a022d2016-12-13 11:22:31 -0800217 HInstruction* constantm1_;
David Brazdil15693bf2015-12-16 10:30:45 +0000218 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700219
220 // Loop specifics.
221 HBasicBlock* loop_preheader_[10];
222 HBasicBlock* loop_header_[10];
223 HBasicBlock* loop_body_[10];
224 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000225 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700226};
227
228//
229// The actual InductionVarAnalysis tests.
230//
231
232TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
233 // Setup:
234 // for (int i_0 = 0; i_0 < 100; i_0++) {
235 // ..
236 // for (int i_9 = 0; i_9 < 100; i_9++) {
237 // }
238 // ..
239 // }
240 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000241 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700242
Aart Bik30efb4e2015-07-30 12:14:31 -0700243 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
244 for (int d = 0; d < 1; d++) {
245 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
246 (d == 0) ? nullptr
247 : loop_header_[d - 1]->GetLoopInformation());
248 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
249 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
250 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
251 loop_body_[d]->GetLoopInformation());
252 }
253 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
254}
255
Aart Bike609b7c2015-08-27 13:46:58 -0700256TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700257 // Setup:
258 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700259 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 // }
261 BuildLoopNest(1);
262 HInstruction* store = InsertArrayStore(basic_[0], 0);
263 PerformInductionVarAnalysis();
264
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100265 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
266 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700267
Aart Bik78296912016-03-25 13:14:53 -0700268 // Offset matters!
269 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
270
Aart Bikd14c5952015-09-08 15:25:15 -0700271 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700272 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700273}
274
Aart Bike609b7c2015-08-27 13:46:58 -0700275TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700276 // Setup:
277 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800278 // t = 100 + i;
279 // t = 100 - i;
280 // t = 100 * i;
281 // t = i << 1;
282 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700283 // }
284 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700285 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100286 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700287 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100288 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700289 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100290 new (GetAllocator()) HMul(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700291 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100292 new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700293 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100294 new (GetAllocator()) HNeg(DataType::Type::kInt32, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700295 PerformInductionVarAnalysis();
296
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100297 EXPECT_STREQ("((1) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
298 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
299 EXPECT_STREQ("((100) * i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
300 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl, 0).c_str());
301 EXPECT_STREQ("(( - (1)) * i + (0)):Int32", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700302}
303
304TEST_F(InductionVarAnalysisTest, FindChainInduction) {
305 // Setup:
306 // k = 0;
307 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700308 // k = k + 100;
309 // a[k] = 0;
310 // k = k - 1;
311 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700312 // }
313 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800314 HPhi* k_header = InsertLoopPhi(0, 0);
315 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000316
Aart Bik7dc96932016-10-12 10:01:05 -0700317 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100318 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000319 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700320 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100321 new (GetAllocator()) HSub(DataType::Type::kInt32, add, constant1_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000322 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800323 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700324 PerformInductionVarAnalysis();
325
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100326 EXPECT_STREQ("(((100) - (1)) * i + (0)):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800327 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100328 EXPECT_STREQ("(((100) - (1)) * i + (100)):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700329 GetInductionInfo(store1->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100330 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700331 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700332}
333
334TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
335 // Setup:
336 // k = 0;
337 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700338 // if () k = k + 1;
339 // else k = k + 1;
340 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700341 // }
342 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000343 HPhi* k_header = InsertLoopPhi(0, 0);
344 k_header->AddInput(constant0_);
345
Aart Bik30efb4e2015-07-30 12:14:31 -0700346 HBasicBlock* ifTrue;
347 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000348 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
349
Aart Bik30efb4e2015-07-30 12:14:31 -0700350 // True-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100351 HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700352 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000353 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700354 // False-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100355 HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700356 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000357 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700358 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000359 HInstruction* store = InsertArrayStore(k_body, 0);
360 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700361 PerformInductionVarAnalysis();
362
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100363 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
364 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700365
366 // Both increments get same induction.
367 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
368 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700369}
370
371TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
372 // Setup:
373 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700374 // if () k = i + 1;
375 // else k = i + 1;
376 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700377 // }
378 BuildLoopNest(1);
379 HBasicBlock* ifTrue;
380 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000381 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
382
Aart Bik30efb4e2015-07-30 12:14:31 -0700383 // True-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100384 HInstruction* inc1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700385 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000386 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700387 // False-branch.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100388 HInstruction* inc2 = new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700389 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000390 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700391 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000392 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700393 PerformInductionVarAnalysis();
394
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100395 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800396
397 // Both increments get same induction.
398 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
399 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
400}
401
Aart Bikdf7822e2016-12-06 10:05:30 -0800402TEST_F(InductionVarAnalysisTest, AddLinear) {
403 // Setup:
404 // for (int i = 0; i < 100; i++) {
405 // t1 = i + i;
406 // t2 = 7 + i;
407 // t3 = t1 + t2;
408 // }
409 BuildLoopNest(1);
410
411 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100412 new (GetAllocator()) HAdd(DataType::Type::kInt32, basic_[0], basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800413 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100414 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant7_, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800415 HInstruction* add3 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100416 new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, add2), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800417 PerformInductionVarAnalysis();
418
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100419 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(basic_[0], 0).c_str());
420 EXPECT_STREQ("(((1) + (1)) * i + (0)):Int32", GetInductionInfo(add1, 0).c_str());
421 EXPECT_STREQ("((1) * i + (7)):Int32", GetInductionInfo(add2, 0).c_str());
422 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):Int32", GetInductionInfo(add3, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800423}
424
425TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
426 // Setup:
427 // k = 1;
428 // for (int i = 0; i < 100; i++) {
429 // t = i * 2;
430 // t = 100 + t
431 // k = t + k; // polynomial
432 // }
433 BuildLoopNest(1);
434 HPhi* k_header = InsertLoopPhi(0, 0);
435 k_header->AddInput(constant1_);
436
437 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100438 new (GetAllocator()) HMul(DataType::Type::kInt32, basic_[0], constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800439 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100440 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant100_, mul), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800441 HInstruction* pol = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100442 new (GetAllocator()) HAdd(DataType::Type::kInt32, add, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800443 k_header->AddInput(pol);
444 PerformInductionVarAnalysis();
445
446 // Note, only the phi in the cycle and the base linear induction are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100447 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800448 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100449 EXPECT_STREQ("((2) * i + (100)):Int32", GetInductionInfo(add, 0).c_str());
Aart Bikdf7822e2016-12-06 10:05:30 -0800450 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
451}
452
453TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
454 // Setup:
455 // k = 1;
456 // for (int i = 0; i < 100; i++) {
457 // t = k + 100;
458 // t = k - 1;
459 // t = - t
460 // t = k * 2;
461 // t = k << 2;
462 // k = k + i; // polynomial
463 // }
464 BuildLoopNest(1);
465 HPhi* k_header = InsertLoopPhi(0, 0);
466 k_header->AddInput(constant1_);
467
468 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100469 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800470 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100471 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800472 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100473 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800474 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100475 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800476 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100477 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800478 HInstruction* pol = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100479 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800480 k_header->AddInput(pol);
481 PerformInductionVarAnalysis();
482
483 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100484 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (1)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800485 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100486 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) + (100))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800487 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100488 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800489 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100490 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):Int32) + ((1) - (1))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800491 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100492 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):Int32) + (2)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800493 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100494 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):Int32) + (4)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800495 GetInductionInfo(shl, 0).c_str());
496 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
497}
498
499TEST_F(InductionVarAnalysisTest, AddPolynomial) {
500 // Setup:
501 // k = 7;
502 // for (int i = 0; i < 100; i++) {
503 // t = k + k;
504 // t = t + k;
505 // k = k + i
506 // }
507 BuildLoopNest(1);
508 HPhi* k_header = InsertLoopPhi(0, 0);
509 k_header->AddInput(constant7_);
510
511 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100512 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800513 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100514 new (GetAllocator()) HAdd(DataType::Type::kInt32, add1, k_header), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800515 HInstruction* add3 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100516 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, basic_[0]), 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800517 k_header->AddInput(add3);
518 PerformInductionVarAnalysis();
519
520 // Note, only the phi in the cycle and added-derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100521 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):Int32) + (7)):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800522 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100523 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):Int32) + ((7) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800524 GetInductionInfo(add1, 0).c_str());
525 EXPECT_STREQ(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100526 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):Int32) + (((7) + (7)) + (7))):Int32",
Aart Bikdf7822e2016-12-06 10:05:30 -0800527 GetInductionInfo(add2, 0).c_str());
528 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
529}
530
Aart Bikc071a012016-12-01 10:22:31 -0800531TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
532 // Setup:
533 // k = 1;
534 // for (int i = 0; i < 100; i++) {
535 // k = k * 100; // geometric (x 100)
536 // }
537 BuildLoopNest(1);
538 HPhi* k_header = InsertLoopPhi(0, 0);
539 k_header->AddInput(constant1_);
540
541 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100542 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800543 k_header->AddInput(mul);
544 PerformInductionVarAnalysis();
545
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100546 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
547 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800548}
549
550TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
551 // Setup:
552 // k = 1;
553 // for (int i = 0; i < 100; i++) {
554 // t = k + 1;
555 // k = k << 1; // geometric (x 2)
556 // t = k + 100;
557 // t = k - 1;
558 // t = - t;
559 // t = k * 2;
560 // t = k << 2;
561 // }
562 BuildLoopNest(1);
563 HPhi* k_header = InsertLoopPhi(0, 0);
564 k_header->AddInput(constant1_);
565
566 HInstruction* add1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100567 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800568 HInstruction* shl1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100569 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800570 HInstruction* add2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100571 new (GetAllocator()) HAdd(DataType::Type::kInt32, shl1, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800572 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100573 new (GetAllocator()) HSub(DataType::Type::kInt32, shl1, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800574 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100575 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800576 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100577 new (GetAllocator()) HMul(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800578 HInstruction* shl2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100579 new (GetAllocator()) HShl(DataType::Type::kInt32, shl1, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800580 k_header->AddInput(shl1);
581 PerformInductionVarAnalysis();
582
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100583 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
584 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):Int32", GetInductionInfo(add1, 0).c_str());
585 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):Int32", GetInductionInfo(shl1, 0).c_str());
586 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):Int32", GetInductionInfo(add2, 0).c_str());
587 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
588 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800589 GetInductionInfo(neg, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100590 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):Int32", GetInductionInfo(mul, 0).c_str());
591 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800592}
593
594TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
595 // Setup:
596 // k = 1;
597 // for (int i = 0; i < 100; i++) {
598 // t = k + 100;
599 // t = k - 1;
600 // t = - t
601 // t = k * 2;
602 // t = k << 2;
603 // k = k / 100; // geometric (/ 100)
604 // }
605 BuildLoopNest(1);
606 HPhi* k_header = InsertLoopPhi(0, 0);
607 k_header->AddInput(constant1_);
608
609 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100610 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800611 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100612 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800613 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100614 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800615 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100616 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800617 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100618 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800619 HInstruction* div = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100620 new (GetAllocator()) HDiv(DataType::Type::kInt32, k_header, constant100_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800621 k_header->AddInput(div);
622 PerformInductionVarAnalysis();
623
624 // Note, only the phi in the cycle and direct additive derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100625 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
626 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):Int32", GetInductionInfo(add, 0).c_str());
627 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800628 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
629 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
630 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
631 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
632}
633
Aart Bikd0a022d2016-12-13 11:22:31 -0800634TEST_F(InductionVarAnalysisTest, FindGeometricShrInduction) {
635 // Setup:
636 // k = 100;
637 // for (int i = 0; i < 100; i++) {
638 // k = k >> 1; // geometric (/ 2)
639 // }
640 BuildLoopNest(1);
641 HPhi* k_header = InsertLoopPhi(0, 0);
642 k_header->AddInput(constant100_);
643
644 HInstruction* shr = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100645 new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800646 k_header->AddInput(shr);
647 PerformInductionVarAnalysis();
648
649 // Note, only the phi in the cycle is classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100650 EXPECT_STREQ("geo((100) * 2 ^ -i + (0)):Int32", GetInductionInfo(k_header, 0).c_str());
Aart Bikd0a022d2016-12-13 11:22:31 -0800651 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
652}
653
654TEST_F(InductionVarAnalysisTest, FindNotGeometricShrInduction) {
655 // Setup:
656 // k = -1;
657 // for (int i = 0; i < 100; i++) {
658 // k = k >> 1; // initial value is negative
659 // }
660 BuildLoopNest(1);
661 HPhi* k_header = InsertLoopPhi(0, 0);
662 k_header->AddInput(constantm1_);
663
664 HInstruction* shr = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100665 new (GetAllocator()) HShr(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikd0a022d2016-12-13 11:22:31 -0800666 k_header->AddInput(shr);
667 PerformInductionVarAnalysis();
668
669 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
670 EXPECT_STREQ("", GetInductionInfo(shr, 0).c_str());
671}
672
Aart Bikdf7822e2016-12-06 10:05:30 -0800673TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800674 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800675 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800676 // for (int i = 0; i < 100; i++) {
677 // t = k + 100;
678 // t = k - 1;
679 // t = -t
680 // t = k * 2;
681 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800682 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800683 // }
684 BuildLoopNest(1);
685 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800686 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800687
688 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100689 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800690 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100691 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800692 HInstruction* neg = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100693 new (GetAllocator()) HNeg(DataType::Type::kInt32, sub), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800694 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100695 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800696 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100697 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant2_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800698 HInstruction* rem = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100699 new (GetAllocator()) HRem(DataType::Type::kInt32, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800700 k_header->AddInput(rem);
701 PerformInductionVarAnalysis();
702
Aart Bikdf7822e2016-12-06 10:05:30 -0800703 // Note, only the phi in the cycle and derived are classified.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100704 EXPECT_STREQ("wrap((100), ((100) % (7))):Int32", GetInductionInfo(k_header, 0).c_str());
705 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):Int32",
706 GetInductionInfo(add, 0).c_str());
707 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):Int32",
708 GetInductionInfo(sub, 0).c_str());
709 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):Int32",
710 GetInductionInfo(neg, 0).c_str());
711 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):Int32",
712 GetInductionInfo(mul, 0).c_str());
713 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):Int32",
714 GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800715 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700716}
717
718TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
719 // Setup:
720 // k = 0;
721 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700722 // a[k] = 0;
723 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700724 // }
725 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800726 HPhi* k_header = InsertLoopPhi(0, 0);
727 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000728
Aart Bikc071a012016-12-01 10:22:31 -0800729 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700730 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100731 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800732 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700733 PerformInductionVarAnalysis();
734
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100735 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800736 GetInductionInfo(k_header, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100737 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700738 GetInductionInfo(store->InputAt(1), 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100739 EXPECT_STREQ("(( - (1)) * i + (100)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700740}
741
742TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
743 // Setup:
744 // k = 0;
745 // t = 100;
746 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700747 // a[k] = 0;
748 // k = t;
749 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700750 // }
751 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800752 HPhi* k_header = InsertLoopPhi(0, 0);
753 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000754 HPhi* t = InsertLoopPhi(1, 0);
755 t->AddInput(constant100_);
756
Aart Bikc071a012016-12-01 10:22:31 -0800757 HInstruction* store = InsertArrayStore(k_header, 0);
758 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700759 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100760 new (GetAllocator()) HSub(DataType::Type::kInt32, constant100_, basic_[0], 0), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000761 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700762 PerformInductionVarAnalysis();
763
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100764 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):Int32):Int32):Int32",
Aart Bike609b7c2015-08-27 13:46:58 -0700765 GetInductionInfo(store->InputAt(1), 0).c_str());
766}
767
768TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
769 // Setup:
770 // k = 0;
771 // for (int i = 0; i < 100; i++) {
772 // t = k + 100;
773 // t = k - 100;
774 // t = k * 100;
775 // t = k << 1;
776 // t = - k;
777 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800778 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700779 // }
780 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800781 HPhi* k_header = InsertLoopPhi(0, 0);
782 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000783
Aart Bik7dc96932016-10-12 10:01:05 -0700784 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100785 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700786 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100787 new (GetAllocator()) HSub(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700788 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100789 new (GetAllocator()) HMul(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800790 HInstruction* shl1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100791 new (GetAllocator()) HShl(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800792 HInstruction* neg1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100793 new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800794 HInstruction* shl2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100795 new (GetAllocator()) HShl(DataType::Type::kInt32, basic_[0], constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800796 HInstruction* neg2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100797 new (GetAllocator()) HNeg(DataType::Type::kInt32, shl2), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800798 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700799 PerformInductionVarAnalysis();
800
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100801 EXPECT_STREQ("wrap((100), ((2) * i + (100)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700802 GetInductionInfo(add, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100803 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700804 GetInductionInfo(sub, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100805 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):Int32):Int32",
Aart Bik0d345cf2016-03-16 10:49:38 -0700806 GetInductionInfo(mul, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100807 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800808 GetInductionInfo(shl1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100809 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):Int32):Int32",
Aart Bikc071a012016-12-01 10:22:31 -0800810 GetInductionInfo(neg1, 0).c_str());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100811 EXPECT_STREQ("((2) * i + (0)):Int32", GetInductionInfo(shl2, 0).c_str());
812 EXPECT_STREQ("(( - (2)) * i + (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700813}
814
815TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
816 // Setup:
817 // k = 0;
818 // t = 100;
819 // for (int i = 0; i < 100; i++) {
820 // a[k] = 0;
821 // a[t] = 0;
822 // // Swap t <-> k.
823 // d = t;
824 // t = k;
825 // k = d;
826 // }
827 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800828 HPhi* k_header = InsertLoopPhi(0, 0);
829 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000830 HPhi* t = InsertLoopPhi(1, 0);
831 t->AddInput(constant100_);
832
Aart Bikc071a012016-12-01 10:22:31 -0800833 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000834 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800835 k_header->AddInput(t);
836 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700837 PerformInductionVarAnalysis();
838
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100839 EXPECT_STREQ("periodic((0), (100)):Int32", GetInductionInfo(store1->InputAt(1), 0).c_str());
840 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700841}
842
843TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
844 // Setup:
845 // k = 0;
846 // for (int i = 0; i < 100; i++) {
847 // a[k] = 0;
848 // k = 1 - k;
849 // }
850 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800851 HPhi* k_header = InsertLoopPhi(0, 0);
852 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000853
Aart Bikc071a012016-12-01 10:22:31 -0800854 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700855 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100856 new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800857 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700858 PerformInductionVarAnalysis();
859
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100860 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
861 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700862}
863
Aart Bik7dc96932016-10-12 10:01:05 -0700864TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
865 // Setup:
866 // k = 0;
867 // for (int i = 0; i < 100; i++) {
868 // a[k] = 0;
869 // k = k ^ 1;
870 // }
871 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800872 HPhi* k_header = InsertLoopPhi(0, 0);
873 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700874
Aart Bikc071a012016-12-01 10:22:31 -0800875 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700876 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100877 new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800878 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700879 PerformInductionVarAnalysis();
880
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100881 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(store->InputAt(1), 0).c_str());
882 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700883}
884
Aart Bik639cc8c2016-10-18 13:03:31 -0700885TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
886 // Setup:
887 // k = 1;
888 // for (int i = 0; i < 100; i++) {
889 // k = 1 ^ k;
890 // }
891 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800892 HPhi* k_header = InsertLoopPhi(0, 0);
893 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700894
895 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100896 new (GetAllocator()) HXor(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800897 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700898 PerformInductionVarAnalysis();
899
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100900 EXPECT_STREQ("periodic((1), ((1) ^ (1))):Int32", GetInductionInfo(k_header, 0).c_str());
901 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700902}
903
Aart Bik7dc96932016-10-12 10:01:05 -0700904TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
905 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700906 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700907 // for (int i = 0; i < 100; i++) {
908 // k = k ^ 100;
909 // }
910 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800911 HPhi* k_header = InsertLoopPhi(0, 0);
912 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700913
914 HInstruction* x = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +0100915 new (GetAllocator()) HXor(DataType::Type::kInt32, k_header, constant100_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800916 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700917 PerformInductionVarAnalysis();
918
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100919 EXPECT_STREQ("periodic((1), ((1) ^ (100))):Int32", GetInductionInfo(k_header, 0).c_str());
920 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):Int32", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700921}
922
923TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
924 // Setup:
925 // k = 0;
926 // for (int i = 0; i < 100; i++) {
927 // k = (k == 0);
928 // }
929 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800930 HPhi* k_header = InsertLoopPhi(0, 0);
931 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700932
Vladimir Markoca6fff82017-10-03 14:49:14 +0100933 HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(k_header, constant0_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800934 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700935 PerformInductionVarAnalysis();
936
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100937 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
938 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700939}
940
941TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
942 // Setup:
943 // k = 0;
944 // for (int i = 0; i < 100; i++) {
945 // k = (0 == k);
946 // }
947 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800948 HPhi* k_header = InsertLoopPhi(0, 0);
949 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700950
Vladimir Markoca6fff82017-10-03 14:49:14 +0100951 HInstruction* x = InsertInstruction(new (GetAllocator()) HEqual(constant0_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800952 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700953 PerformInductionVarAnalysis();
954
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100955 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
956 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700957}
958
959TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
960 // Setup:
961 // k = 0;
962 // for (int i = 0; i < 100; i++) {
963 // k = (k != 1);
964 // }
965 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800966 HPhi* k_header = InsertLoopPhi(0, 0);
967 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700968
Vladimir Markoca6fff82017-10-03 14:49:14 +0100969 HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(k_header, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800970 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700971 PerformInductionVarAnalysis();
972
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100973 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
974 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700975}
976
977TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
978 // Setup:
979 // k = 0;
980 // for (int i = 0; i < 100; i++) {
981 // k = (1 != k);
982 // }
983 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800984 HPhi* k_header = InsertLoopPhi(0, 0);
985 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700986
Vladimir Markoca6fff82017-10-03 14:49:14 +0100987 HInstruction* x = InsertInstruction(new (GetAllocator()) HNotEqual(constant1_, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800988 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700989 PerformInductionVarAnalysis();
990
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100991 EXPECT_STREQ("periodic((0), (1)):Bool", GetInductionInfo(k_header, 0).c_str());
992 EXPECT_STREQ("periodic((1), (0)):Bool", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700993}
994
Aart Bike609b7c2015-08-27 13:46:58 -0700995TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
996 // Setup:
997 // k = 0;
998 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800999 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -07001000 // k = 1 - k;
1001 // t = k + 100;
1002 // t = k - 100;
1003 // t = k * 100;
1004 // t = k << 1;
1005 // t = - k;
1006 // }
1007 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +00001008 HPhi* k_header = InsertLoopPhi(0, 0);
1009 k_header->AddInput(constant0_);
1010
Aart Bikc071a012016-12-01 10:22:31 -08001011 HInstruction* neg1 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001012 new (GetAllocator()) HNeg(DataType::Type::kInt32, k_header), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001013 HInstruction* idiom = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001014 new (GetAllocator()) HSub(DataType::Type::kInt32, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001015 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001016 new (GetAllocator()) HAdd(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001017 HInstruction* sub = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001018 new (GetAllocator()) HSub(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001019 HInstruction* mul = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001020 new (GetAllocator()) HMul(DataType::Type::kInt32, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -07001021 HInstruction* shl = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001022 new (GetAllocator()) HShl(DataType::Type::kInt32, idiom, constant1_), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001023 HInstruction* neg2 = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001024 new (GetAllocator()) HNeg(DataType::Type::kInt32, idiom), 0);
Aart Bikc071a012016-12-01 10:22:31 -08001025 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -07001026 PerformInductionVarAnalysis();
1027
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001028 EXPECT_STREQ("periodic((0), (1)):Int32", GetInductionInfo(k_header, 0).c_str());
1029 EXPECT_STREQ("periodic((0), ( - (1))):Int32", GetInductionInfo(neg1, 0).c_str());
1030 EXPECT_STREQ("periodic((1), (0)):Int32", GetInductionInfo(idiom, 0).c_str());
1031 EXPECT_STREQ("periodic(((1) + (100)), (100)):Int32", GetInductionInfo(add, 0).c_str());
1032 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):Int32", GetInductionInfo(sub, 0).c_str());
1033 EXPECT_STREQ("periodic((100), (0)):Int32", GetInductionInfo(mul, 0).c_str());
1034 EXPECT_STREQ("periodic((2), (0)):Int32", GetInductionInfo(shl, 0).c_str());
1035 EXPECT_STREQ("periodic(( - (1)), (0)):Int32", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001036}
1037
1038TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
1039 // Setup:
1040 // k = 0;
1041 // for (int i_0 = 0; i_0 < 100; i_0++) {
1042 // ..
1043 // for (int i_9 = 0; i_9 < 100; i_9++) {
1044 // k = 1 + k;
1045 // a[k] = 0;
1046 // }
1047 // ..
1048 // }
1049 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +00001050
Aart Bikc071a012016-12-01 10:22:31 -08001051 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +00001052 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001053 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +00001054 }
1055
Aart Bik7dc96932016-10-12 10:01:05 -07001056 HInstruction* inc = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001057 new (GetAllocator()) HAdd(DataType::Type::kInt32, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +00001058 HInstruction* store = InsertArrayStore(inc, 9);
1059
1060 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -08001061 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
1062 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001063 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001064 PerformInductionVarAnalysis();
1065
Aart Bike609b7c2015-08-27 13:46:58 -07001066 // Avoid exact phi number, since that depends on the SSA building phase.
1067 std::regex r("\\(\\(1\\) \\* i \\+ "
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001068 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):Int32");
Aart Bik30efb4e2015-07-30 12:14:31 -07001069
1070 for (int d = 0; d < 10; d++) {
1071 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001072 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001073 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001074 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001075 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001076 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001077 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001078 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001079 }
1080}
1081
Aart Bik78296912016-03-25 13:14:53 -07001082TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1083 // Setup:
1084 // for (int i = 0; i < 100; i++) {
1085 // k = (byte) i;
1086 // a[k] = 0;
1087 // a[i] = 0;
1088 // }
1089 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001090 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001091 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bik78296912016-03-25 13:14:53 -07001092 HInstruction* store1 = InsertArrayStore(conv, 0);
1093 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1094 PerformInductionVarAnalysis();
1095
Aart Bike6bd0272016-12-16 13:57:52 -08001096 // Regular int induction (i) is transferred over conversion into byte induction (k).
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001097 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
1098 EXPECT_STREQ("((1) * i + (0)):Int32", GetInductionInfo(store2->InputAt(1), 0).c_str());
1099 EXPECT_STREQ("((1) * i + (1)):Int32", GetInductionInfo(increment_[0], 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001100
Aart Bike6bd0272016-12-16 13:57:52 -08001101 // Narrowing detected.
1102 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1103 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1)));
1104
Aart Bik78296912016-03-25 13:14:53 -07001105 // Type matters!
1106 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1107
1108 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001109 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001110}
1111
Aart Bikcc42be02016-10-20 16:14:16 -07001112TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1113 // Setup:
1114 // for (int i = 0; i < 100; i++) {
1115 // k = (byte) i;
1116 // a[k] = 0;
1117 // k = k + 1
1118 // a[k] = 0;
1119 // }
1120 BuildLoopNest(1);
1121 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001122 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, basic_[0], kNoDexPc), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001123 HInstruction* store1 = InsertArrayStore(conv, 0);
1124 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001125 new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bikcc42be02016-10-20 16:14:16 -07001126 HInstruction* store2 = InsertArrayStore(add, 0);
1127
1128 PerformInductionVarAnalysis();
1129
Aart Bike6bd0272016-12-16 13:57:52 -08001130 // Byte induction (k) is detected, but it does not transfer over the addition,
1131 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001132 EXPECT_STREQ("((1) * i + (0)):Int8", GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001133 EXPECT_STREQ("", GetInductionInfo(store2->InputAt(1), 0).c_str());
1134
1135 // Narrowing detected.
1136 EXPECT_TRUE(IsNarrowingLinear(store1->InputAt(1)));
1137 EXPECT_FALSE(IsNarrowingLinear(store2->InputAt(1))); // works for null
1138}
1139
1140TEST_F(InductionVarAnalysisTest, ByteInduction) {
1141 // Setup:
1142 // k = -128;
1143 // for (int i = 0; i < 100; i++) {
1144 // k = k + 1;
1145 // k = (byte) k;
1146 // }
1147 BuildLoopNest(1);
1148 HPhi* k_header = InsertLoopPhi(0, 0);
1149 k_header->AddInput(graph_->GetIntConstant(-128));
1150
1151 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001152 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001153 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001154 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001155 k_header->AddInput(conv);
1156 PerformInductionVarAnalysis();
1157
1158 // Byte induction (k) is detected, but it does not transfer over the addition,
1159 // since this may yield out-of-type values.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001160 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(k_header, 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001161 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1162
1163 // Narrowing detected.
1164 EXPECT_TRUE(IsNarrowingLinear(k_header));
1165 EXPECT_FALSE(IsNarrowingLinear(add)); // works for null
1166}
1167
1168TEST_F(InductionVarAnalysisTest, NoByteInduction1) {
1169 // Setup:
1170 // k = -129; / does not fit!
1171 // for (int i = 0; i < 100; i++) {
1172 // k = k + 1;
1173 // k = (byte) k;
1174 // }
1175 BuildLoopNest(1);
1176 HPhi* k_header = InsertLoopPhi(0, 0);
1177 k_header->AddInput(graph_->GetIntConstant(-129));
1178
1179 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001180 new (GetAllocator()) HAdd(DataType::Type::kInt32, k_header, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001181 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001182 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, add, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001183 k_header->AddInput(conv);
1184 PerformInductionVarAnalysis();
1185
1186 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1187 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
1188}
1189
1190TEST_F(InductionVarAnalysisTest, NoByteInduction2) {
1191 // Setup:
1192 // k = 0;
1193 // for (int i = 0; i < 100; i++) {
1194 // k = (byte) k; // conversion not done last!
1195 // k = k + 1;
1196 // }
1197 BuildLoopNest(1);
1198 HPhi* k_header = InsertLoopPhi(0, 0);
1199 k_header->AddInput(constant0_);
1200
1201 HInstruction* conv = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001202 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, k_header, kNoDexPc), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001203 HInstruction* add = InsertInstruction(
Vladimir Markoca6fff82017-10-03 14:49:14 +01001204 new (GetAllocator()) HAdd(DataType::Type::kInt32, conv, constant1_), 0);
Aart Bike6bd0272016-12-16 13:57:52 -08001205 k_header->AddInput(add);
1206 PerformInductionVarAnalysis();
1207
1208 EXPECT_STREQ("", GetInductionInfo(k_header, 0).c_str());
1209 EXPECT_STREQ("", GetInductionInfo(add, 0).c_str());
Aart Bikcc42be02016-10-20 16:14:16 -07001210}
1211
Aart Bik0d345cf2016-03-16 10:49:38 -07001212TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1213 // Setup:
1214 // for (byte i = -128; i < 127; i++) { // just fits!
1215 // }
1216 BuildLoopNest(1);
1217 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1218 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1219 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001220 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001221 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001222 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1223 basic_[0]->ReplaceInput(conv, 1);
1224 PerformInductionVarAnalysis();
1225
Aart Bike6bd0272016-12-16 13:57:52 -08001226 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001227 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001228 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1229
1230 // Narrowing detected.
1231 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1232 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1233
Aart Bik0d345cf2016-03-16 10:49:38 -07001234 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001235 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001236}
1237
1238TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1239 // Setup:
1240 // for (byte i = -128; i < 128; i++) { // infinite loop!
1241 // }
1242 BuildLoopNest(1);
1243 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1244 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1245 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001246 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001247 new (GetAllocator()) HTypeConversion(DataType::Type::kInt8, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001248 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1249 basic_[0]->ReplaceInput(conv, 1);
1250 PerformInductionVarAnalysis();
1251
Aart Bike6bd0272016-12-16 13:57:52 -08001252 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001253 EXPECT_STREQ("((1) * i + (-128)):Int8", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001254 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1255
1256 // Narrowing detected.
1257 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1258 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1259
Aart Bik0d345cf2016-03-16 10:49:38 -07001260 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001261 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001262}
1263
1264TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1265 // Setup:
1266 // for (short i = -32768; i < 32767; i++) { // just fits!
1267 // }
1268 BuildLoopNest(1);
1269 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1270 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1271 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001272 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001273 new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001274 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1275 basic_[0]->ReplaceInput(conv, 1);
1276 PerformInductionVarAnalysis();
1277
Aart Bike6bd0272016-12-16 13:57:52 -08001278 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001279 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001280 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1281
1282 // Narrowing detected.
1283 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1284 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1285
Aart Bik0d345cf2016-03-16 10:49:38 -07001286 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001287 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001288}
1289
1290TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1291 // Setup:
1292 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1293 // }
1294 BuildLoopNest(1);
1295 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1296 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1297 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001298 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001299 new (GetAllocator()) HTypeConversion(DataType::Type::kInt16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001300 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1301 basic_[0]->ReplaceInput(conv, 1);
1302 PerformInductionVarAnalysis();
1303
Aart Bike6bd0272016-12-16 13:57:52 -08001304 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001305 EXPECT_STREQ("((1) * i + (-32768)):Int16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001306 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1307
1308 // Narrowing detected.
1309 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1310 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1311
Aart Bik0d345cf2016-03-16 10:49:38 -07001312 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001313 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001314}
1315
1316TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1317 // Setup:
1318 // for (char i = 0; i < 65535; i++) { // just fits!
1319 // }
1320 BuildLoopNest(1);
1321 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1322 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001323 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001324 new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001325 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1326 basic_[0]->ReplaceInput(conv, 1);
1327 PerformInductionVarAnalysis();
1328
Aart Bike6bd0272016-12-16 13:57:52 -08001329 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001330 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001331 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1332
1333 // Narrowing detected.
1334 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1335 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1336
Aart Bik0d345cf2016-03-16 10:49:38 -07001337 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001338 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001339}
1340
1341TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1342 // Setup:
1343 // for (char i = 0; i < 65536; i++) { // infinite loop!
1344 // }
1345 BuildLoopNest(1);
1346 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1347 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
Aart Bike6bd0272016-12-16 13:57:52 -08001348 HInstruction* conv =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001349 new (GetAllocator()) HTypeConversion(DataType::Type::kUint16, increment_[0], kNoDexPc);
Aart Bik0d345cf2016-03-16 10:49:38 -07001350 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1351 basic_[0]->ReplaceInput(conv, 1);
1352 PerformInductionVarAnalysis();
1353
Aart Bike6bd0272016-12-16 13:57:52 -08001354 // Recorded at the phi, but not transferred to increment.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001355 EXPECT_STREQ("((1) * i + (0)):Uint16", GetInductionInfo(basic_[0], 0).c_str());
Aart Bike6bd0272016-12-16 13:57:52 -08001356 EXPECT_STREQ("", GetInductionInfo(increment_[0], 0).c_str());
1357
1358 // Narrowing detected.
1359 EXPECT_TRUE(IsNarrowingLinear(basic_[0]));
1360 EXPECT_FALSE(IsNarrowingLinear(increment_[0])); // works for null
1361
Aart Bik0d345cf2016-03-16 10:49:38 -07001362 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001363 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001364}
1365
Aart Bik30efb4e2015-07-30 12:14:31 -07001366} // namespace art