blob: 2d182f64831a358d4bab44490dfbbfd3b5758967 [file] [log] [blame]
Aart Bik30efb4e2015-07-30 12:14:31 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <regex>
18
19#include "base/arena_allocator.h"
20#include "builder.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070021#include "induction_var_analysis.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24
25namespace art {
26
27/**
28 * Fixture class for the InductionVarAnalysis tests.
29 */
David Brazdil4833f5a2015-12-16 10:37:39 +000030class InductionVarAnalysisTest : public CommonCompilerTest {
Aart Bik30efb4e2015-07-30 12:14:31 -070031 public:
32 InductionVarAnalysisTest() : pool_(), allocator_(&pool_) {
33 graph_ = CreateGraph(&allocator_);
34 }
35
36 ~InductionVarAnalysisTest() { }
37
38 // Builds single for-loop at depth d.
39 void BuildForLoop(int d, int n) {
40 ASSERT_LT(d, n);
41 loop_preheader_[d] = new (&allocator_) HBasicBlock(graph_);
42 graph_->AddBlock(loop_preheader_[d]);
43 loop_header_[d] = new (&allocator_) HBasicBlock(graph_);
44 graph_->AddBlock(loop_header_[d]);
45 loop_preheader_[d]->AddSuccessor(loop_header_[d]);
46 if (d < (n - 1)) {
47 BuildForLoop(d + 1, n);
48 }
49 loop_body_[d] = new (&allocator_) HBasicBlock(graph_);
50 graph_->AddBlock(loop_body_[d]);
51 loop_body_[d]->AddSuccessor(loop_header_[d]);
52 if (d < (n - 1)) {
53 loop_header_[d]->AddSuccessor(loop_preheader_[d + 1]);
54 loop_header_[d + 1]->AddSuccessor(loop_body_[d]);
55 } else {
56 loop_header_[d]->AddSuccessor(loop_body_[d]);
57 }
58 }
59
60 // Builds a n-nested loop in CFG where each loop at depth 0 <= d < n
61 // is defined as "for (int i_d = 0; i_d < 100; i_d++)". Tests can further
62 // populate the loop with instructions to set up interesting scenarios.
63 void BuildLoopNest(int n) {
64 ASSERT_LE(n, 10);
Aart Bike609b7c2015-08-27 13:46:58 -070065 graph_->SetNumberOfVRegs(n + 3);
Aart Bik30efb4e2015-07-30 12:14:31 -070066
67 // Build basic blocks with entry, nested loop, exit.
68 entry_ = new (&allocator_) HBasicBlock(graph_);
69 graph_->AddBlock(entry_);
70 BuildForLoop(0, n);
David Brazdildb51efb2015-11-06 01:36:20 +000071 return_ = new (&allocator_) HBasicBlock(graph_);
72 graph_->AddBlock(return_);
Aart Bik30efb4e2015-07-30 12:14:31 -070073 exit_ = new (&allocator_) HBasicBlock(graph_);
74 graph_->AddBlock(exit_);
75 entry_->AddSuccessor(loop_preheader_[0]);
David Brazdildb51efb2015-11-06 01:36:20 +000076 loop_header_[0]->AddSuccessor(return_);
77 return_->AddSuccessor(exit_);
Aart Bik30efb4e2015-07-30 12:14:31 -070078 graph_->SetEntryBlock(entry_);
79 graph_->SetExitBlock(exit_);
80
81 // Provide entry and exit instructions.
Calin Juravlee6e3bea2015-10-14 13:53:10 +000082 parameter_ = new (&allocator_) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -080083 graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
Aart Bik30efb4e2015-07-30 12:14:31 -070084 entry_->AddInstruction(parameter_);
Aart Bike609b7c2015-08-27 13:46:58 -070085 constant0_ = graph_->GetIntConstant(0);
86 constant1_ = graph_->GetIntConstant(1);
Aart Bikc071a012016-12-01 10:22:31 -080087 constant2_ = graph_->GetIntConstant(2);
Aart Bikdf7822e2016-12-06 10:05:30 -080088 constant7_ = graph_->GetIntConstant(7);
Aart Bike609b7c2015-08-27 13:46:58 -070089 constant100_ = graph_->GetIntConstant(100);
David Brazdil15693bf2015-12-16 10:30:45 +000090 float_constant0_ = graph_->GetFloatConstant(0.0f);
David Brazdildb51efb2015-11-06 01:36:20 +000091 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bike609b7c2015-08-27 13:46:58 -070092 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070093
94 // Provide loop instructions.
95 for (int d = 0; d < n; d++) {
David Brazdilbadd8262016-02-02 16:28:56 +000096 basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, Primitive::kPrimInt);
David Brazdil4833f5a2015-12-16 10:37:39 +000097 loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +000098 loop_header_[d]->AddPhi(basic_[d]);
99 HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700100 loop_header_[d]->AddInstruction(compare);
101 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
David Brazdilbadd8262016-02-02 16:28:56 +0000102 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700103 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700104 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000105
106 basic_[d]->AddInput(constant0_);
107 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700108 }
109 }
110
111 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700112 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700113 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
114 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
115 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
116 graph_->AddBlock(cond);
117 graph_->AddBlock(ifTrue);
118 graph_->AddBlock(ifFalse);
119 // Conditional split.
120 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
121 cond->AddSuccessor(ifTrue);
122 cond->AddSuccessor(ifFalse);
123 ifTrue->AddSuccessor(loop_body_[d]);
124 ifFalse->AddSuccessor(loop_body_[d]);
125 cond->AddInstruction(new (&allocator_) HIf(parameter_));
126 *ifT = ifTrue;
127 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000128
129 HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, Primitive::kPrimInt);
130 loop_body_[d]->AddPhi(select_phi);
131 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700132 }
133
134 // Inserts instruction right before increment at depth d.
135 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
136 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
137 return instruction;
138 }
139
David Brazdilbadd8262016-02-02 16:28:56 +0000140 // Inserts a phi to loop header at depth d and returns it.
141 HPhi* InsertLoopPhi(int vreg, int d) {
142 HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, Primitive::kPrimInt);
143 loop_header_[d]->AddPhi(phi);
144 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700145 }
146
David Brazdilbadd8262016-02-02 16:28:56 +0000147 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700148 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000149 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000150 // ArraySet is given a float value in order to avoid SsaBuilder typing
151 // it from the array's non-existent reference type info.
Aart Bik30efb4e2015-07-30 12:14:31 -0700152 return InsertInstruction(new (&allocator_) HArraySet(
David Brazdilbadd8262016-02-02 16:28:56 +0000153 parameter_, subscript, float_constant0_, Primitive::kPrimFloat, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700154 }
155
Aart Bike609b7c2015-08-27 13:46:58 -0700156 // Returns induction information of instruction in loop at depth d.
157 std::string GetInductionInfo(HInstruction* instruction, int d) {
158 return HInductionVarAnalysis::InductionToString(
159 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700160 }
161
Aart Bik009cace2016-09-16 10:15:19 -0700162 // Returns induction information of the trip-count of loop at depth d.
163 std::string GetTripCount(int d) {
164 HInstruction* control = loop_header_[d]->GetLastInstruction();
165 DCHECK(control->IsIf());
166 return GetInductionInfo(control, d);
167 }
168
Aart Bik78296912016-03-25 13:14:53 -0700169 // Returns true if instructions have identical induction.
170 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
171 return HInductionVarAnalysis::InductionEqual(
172 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
173 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
174 }
175
Aart Bik30efb4e2015-07-30 12:14:31 -0700176 // Performs InductionVarAnalysis (after proper set up).
177 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000178 graph_->BuildDominatorTree();
Aart Bik30efb4e2015-07-30 12:14:31 -0700179 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
180 iva_->Run();
181 }
182
183 // General building fields.
184 ArenaPool pool_;
185 ArenaAllocator allocator_;
186 HGraph* graph_;
187 HInductionVarAnalysis* iva_;
188
189 // Fixed basic blocks and instructions.
190 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000191 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700192 HBasicBlock* exit_;
193 HInstruction* parameter_; // "this"
194 HInstruction* constant0_;
195 HInstruction* constant1_;
Aart Bikc071a012016-12-01 10:22:31 -0800196 HInstruction* constant2_;
Aart Bikdf7822e2016-12-06 10:05:30 -0800197 HInstruction* constant7_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700198 HInstruction* constant100_;
David Brazdil15693bf2015-12-16 10:30:45 +0000199 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700200
201 // Loop specifics.
202 HBasicBlock* loop_preheader_[10];
203 HBasicBlock* loop_header_[10];
204 HBasicBlock* loop_body_[10];
205 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000206 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700207};
208
209//
210// The actual InductionVarAnalysis tests.
211//
212
213TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
214 // Setup:
215 // for (int i_0 = 0; i_0 < 100; i_0++) {
216 // ..
217 // for (int i_9 = 0; i_9 < 100; i_9++) {
218 // }
219 // ..
220 // }
221 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000222 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700223
Aart Bik30efb4e2015-07-30 12:14:31 -0700224 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
225 for (int d = 0; d < 1; d++) {
226 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
227 (d == 0) ? nullptr
228 : loop_header_[d - 1]->GetLoopInformation());
229 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
230 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
231 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
232 loop_body_[d]->GetLoopInformation());
233 }
234 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
235}
236
Aart Bike609b7c2015-08-27 13:46:58 -0700237TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700238 // Setup:
239 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700240 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700241 // }
242 BuildLoopNest(1);
243 HInstruction* store = InsertArrayStore(basic_[0], 0);
244 PerformInductionVarAnalysis();
245
Aart Bik0d345cf2016-03-16 10:49:38 -0700246 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
247 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700248
Aart Bik78296912016-03-25 13:14:53 -0700249 // Offset matters!
250 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
251
Aart Bikd14c5952015-09-08 15:25:15 -0700252 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700253 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700254}
255
Aart Bike609b7c2015-08-27 13:46:58 -0700256TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700257 // Setup:
258 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800259 // t = 100 + i;
260 // t = 100 - i;
261 // t = 100 * i;
262 // t = i << 1;
263 // t = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700264 // }
265 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700266 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000267 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700268 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000269 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700270 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000271 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700272 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000273 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700274 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000275 new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700276 PerformInductionVarAnalysis();
277
Aart Bik0d345cf2016-03-16 10:49:38 -0700278 EXPECT_STREQ("((1) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
279 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
280 EXPECT_STREQ("((100) * i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
281 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
282 EXPECT_STREQ("(( - (1)) * i + (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700283}
284
285TEST_F(InductionVarAnalysisTest, FindChainInduction) {
286 // Setup:
287 // k = 0;
288 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700289 // k = k + 100;
290 // a[k] = 0;
291 // k = k - 1;
292 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700293 // }
294 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800295 HPhi* k_header = InsertLoopPhi(0, 0);
296 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000297
Aart Bik7dc96932016-10-12 10:01:05 -0700298 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800299 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000300 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700301 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000302 new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
303 HInstruction* store2 = InsertArrayStore(sub, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800304 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700305 PerformInductionVarAnalysis();
306
Aart Bikc071a012016-12-01 10:22:31 -0800307 EXPECT_STREQ("(((100) - (1)) * i + (0)):PrimInt",
308 GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700309 EXPECT_STREQ("(((100) - (1)) * i + (100)):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700310 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700311 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700312 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700313}
314
315TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
316 // Setup:
317 // k = 0;
318 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700319 // if () k = k + 1;
320 // else k = k + 1;
321 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700322 // }
323 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000324 HPhi* k_header = InsertLoopPhi(0, 0);
325 k_header->AddInput(constant0_);
326
Aart Bik30efb4e2015-07-30 12:14:31 -0700327 HBasicBlock* ifTrue;
328 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000329 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
330
Aart Bik30efb4e2015-07-30 12:14:31 -0700331 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000332 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700333 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000334 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700335 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000336 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700337 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000338 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700339 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000340 HInstruction* store = InsertArrayStore(k_body, 0);
341 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700342 PerformInductionVarAnalysis();
343
Aart Bikc071a012016-12-01 10:22:31 -0800344 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700345 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700346
347 // Both increments get same induction.
348 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
349 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700350}
351
352TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
353 // Setup:
354 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700355 // if () k = i + 1;
356 // else k = i + 1;
357 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700358 // }
359 BuildLoopNest(1);
360 HBasicBlock* ifTrue;
361 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000362 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
363
Aart Bik30efb4e2015-07-30 12:14:31 -0700364 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000365 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700366 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000367 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700368 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000369 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700370 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000371 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700372 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000373 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700374 PerformInductionVarAnalysis();
375
Aart Bik0d345cf2016-03-16 10:49:38 -0700376 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800377
378 // Both increments get same induction.
379 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
380 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
381}
382
Aart Bikdf7822e2016-12-06 10:05:30 -0800383TEST_F(InductionVarAnalysisTest, AddLinear) {
384 // Setup:
385 // for (int i = 0; i < 100; i++) {
386 // t1 = i + i;
387 // t2 = 7 + i;
388 // t3 = t1 + t2;
389 // }
390 BuildLoopNest(1);
391
392 HInstruction* add1 = InsertInstruction(
393 new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], basic_[0]), 0);
394 HInstruction* add2 = InsertInstruction(
395 new (&allocator_) HAdd(Primitive::kPrimInt, constant7_, basic_[0]), 0);
396 HInstruction* add3 = InsertInstruction(
397 new (&allocator_) HAdd(Primitive::kPrimInt, add1, add2), 0);
398 PerformInductionVarAnalysis();
399
400 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(basic_[0], 0).c_str());
401 EXPECT_STREQ("(((1) + (1)) * i + (0)):PrimInt", GetInductionInfo(add1, 0).c_str());
402 EXPECT_STREQ("((1) * i + (7)):PrimInt", GetInductionInfo(add2, 0).c_str());
403 EXPECT_STREQ("((((1) + (1)) + (1)) * i + (7)):PrimInt", GetInductionInfo(add3, 0).c_str());
404}
405
406TEST_F(InductionVarAnalysisTest, FindPolynomialInduction) {
407 // Setup:
408 // k = 1;
409 // for (int i = 0; i < 100; i++) {
410 // t = i * 2;
411 // t = 100 + t
412 // k = t + k; // polynomial
413 // }
414 BuildLoopNest(1);
415 HPhi* k_header = InsertLoopPhi(0, 0);
416 k_header->AddInput(constant1_);
417
418 HInstruction* mul = InsertInstruction(
419 new (&allocator_) HMul(Primitive::kPrimInt, basic_[0], constant2_), 0);
420 HInstruction* add = InsertInstruction(
421 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, mul), 0);
422 HInstruction* pol = InsertInstruction(
423 new (&allocator_) HAdd(Primitive::kPrimInt, add, k_header), 0);
424 k_header->AddInput(pol);
425 PerformInductionVarAnalysis();
426
427 // Note, only the phi in the cycle and the base linear induction are classified.
428 EXPECT_STREQ("poly(sum_lt(((2) * i + (100)):PrimInt) + (1)):PrimInt",
429 GetInductionInfo(k_header, 0).c_str());
430 EXPECT_STREQ("((2) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
431 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
432}
433
434TEST_F(InductionVarAnalysisTest, FindPolynomialInductionAndDerived) {
435 // Setup:
436 // k = 1;
437 // for (int i = 0; i < 100; i++) {
438 // t = k + 100;
439 // t = k - 1;
440 // t = - t
441 // t = k * 2;
442 // t = k << 2;
443 // k = k + i; // polynomial
444 // }
445 BuildLoopNest(1);
446 HPhi* k_header = InsertLoopPhi(0, 0);
447 k_header->AddInput(constant1_);
448
449 HInstruction* add = InsertInstruction(
450 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
451 HInstruction* sub = InsertInstruction(
452 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
453 HInstruction* neg = InsertInstruction(
454 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
455 HInstruction* mul = InsertInstruction(
456 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
457 HInstruction* shl = InsertInstruction(
458 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
459 HInstruction* pol = InsertInstruction(
460 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
461 k_header->AddInput(pol);
462 PerformInductionVarAnalysis();
463
464 // Note, only the phi in the cycle and derived are classified.
465 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (1)):PrimInt",
466 GetInductionInfo(k_header, 0).c_str());
467 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) + (100))):PrimInt",
468 GetInductionInfo(add, 0).c_str());
469 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
470 GetInductionInfo(sub, 0).c_str());
471 EXPECT_STREQ("poly(sum_lt((( - (1)) * i + (0)):PrimInt) + ((1) - (1))):PrimInt",
472 GetInductionInfo(neg, 0).c_str());
473 EXPECT_STREQ("poly(sum_lt(((2) * i + (0)):PrimInt) + (2)):PrimInt",
474 GetInductionInfo(mul, 0).c_str());
475 EXPECT_STREQ("poly(sum_lt(((4) * i + (0)):PrimInt) + (4)):PrimInt",
476 GetInductionInfo(shl, 0).c_str());
477 EXPECT_STREQ("", GetInductionInfo(pol, 0).c_str());
478}
479
480TEST_F(InductionVarAnalysisTest, AddPolynomial) {
481 // Setup:
482 // k = 7;
483 // for (int i = 0; i < 100; i++) {
484 // t = k + k;
485 // t = t + k;
486 // k = k + i
487 // }
488 BuildLoopNest(1);
489 HPhi* k_header = InsertLoopPhi(0, 0);
490 k_header->AddInput(constant7_);
491
492 HInstruction* add1 = InsertInstruction(
493 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, k_header), 0);
494 HInstruction* add2 = InsertInstruction(
495 new (&allocator_) HAdd(Primitive::kPrimInt, add1, k_header), 0);
496 HInstruction* add3 = InsertInstruction(
497 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, basic_[0]), 0);
498 k_header->AddInput(add3);
499 PerformInductionVarAnalysis();
500
501 // Note, only the phi in the cycle and added-derived are classified.
502 EXPECT_STREQ("poly(sum_lt(((1) * i + (0)):PrimInt) + (7)):PrimInt",
503 GetInductionInfo(k_header, 0).c_str());
504 EXPECT_STREQ("poly(sum_lt((((1) + (1)) * i + (0)):PrimInt) + ((7) + (7))):PrimInt",
505 GetInductionInfo(add1, 0).c_str());
506 EXPECT_STREQ(
507 "poly(sum_lt(((((1) + (1)) + (1)) * i + (0)):PrimInt) + (((7) + (7)) + (7))):PrimInt",
508 GetInductionInfo(add2, 0).c_str());
509 EXPECT_STREQ("", GetInductionInfo(add3, 0).c_str());
510}
511
Aart Bikc071a012016-12-01 10:22:31 -0800512TEST_F(InductionVarAnalysisTest, FindGeometricMulInduction) {
513 // Setup:
514 // k = 1;
515 // for (int i = 0; i < 100; i++) {
516 // k = k * 100; // geometric (x 100)
517 // }
518 BuildLoopNest(1);
519 HPhi* k_header = InsertLoopPhi(0, 0);
520 k_header->AddInput(constant1_);
521
522 HInstruction* mul = InsertInstruction(
523 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
524 k_header->AddInput(mul);
525 PerformInductionVarAnalysis();
526
527 EXPECT_STREQ("geo((1) * 100 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
528 EXPECT_STREQ("geo((100) * 100 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
529}
530
531TEST_F(InductionVarAnalysisTest, FindGeometricShlInductionAndDerived) {
532 // Setup:
533 // k = 1;
534 // for (int i = 0; i < 100; i++) {
535 // t = k + 1;
536 // k = k << 1; // geometric (x 2)
537 // t = k + 100;
538 // t = k - 1;
539 // t = - t;
540 // t = k * 2;
541 // t = k << 2;
542 // }
543 BuildLoopNest(1);
544 HPhi* k_header = InsertLoopPhi(0, 0);
545 k_header->AddInput(constant1_);
546
547 HInstruction* add1 = InsertInstruction(
548 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_), 0);
549 HInstruction* shl1 = InsertInstruction(
550 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
551 HInstruction* add2 = InsertInstruction(
552 new (&allocator_) HAdd(Primitive::kPrimInt, shl1, constant100_), 0);
553 HInstruction* sub = InsertInstruction(
554 new (&allocator_) HSub(Primitive::kPrimInt, shl1, constant1_), 0);
555 HInstruction* neg = InsertInstruction(
556 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
557 HInstruction* mul = InsertInstruction(
558 new (&allocator_) HMul(Primitive::kPrimInt, shl1, constant2_), 0);
559 HInstruction* shl2 = InsertInstruction(
560 new (&allocator_) HShl(Primitive::kPrimInt, shl1, constant2_), 0);
561 k_header->AddInput(shl1);
562 PerformInductionVarAnalysis();
563
564 EXPECT_STREQ("geo((1) * 2 ^ i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
565 EXPECT_STREQ("geo((1) * 2 ^ i + (1)):PrimInt", GetInductionInfo(add1, 0).c_str());
566 EXPECT_STREQ("geo((2) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl1, 0).c_str());
567 EXPECT_STREQ("geo((2) * 2 ^ i + (100)):PrimInt", GetInductionInfo(add2, 0).c_str());
568 EXPECT_STREQ("geo((2) * 2 ^ i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
569 EXPECT_STREQ("geo(( - (2)) * 2 ^ i + ( - ((0) - (1)))):PrimInt",
570 GetInductionInfo(neg, 0).c_str());
571 EXPECT_STREQ("geo(((2) * (2)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
572 EXPECT_STREQ("geo(((2) * (4)) * 2 ^ i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
573}
574
575TEST_F(InductionVarAnalysisTest, FindGeometricDivInductionAndDerived) {
576 // Setup:
577 // k = 1;
578 // for (int i = 0; i < 100; i++) {
579 // t = k + 100;
580 // t = k - 1;
581 // t = - t
582 // t = k * 2;
583 // t = k << 2;
584 // k = k / 100; // geometric (/ 100)
585 // }
586 BuildLoopNest(1);
587 HPhi* k_header = InsertLoopPhi(0, 0);
588 k_header->AddInput(constant1_);
589
590 HInstruction* add = InsertInstruction(
591 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
592 HInstruction* sub = InsertInstruction(
593 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
594 HInstruction* neg = InsertInstruction(
595 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
596 HInstruction* mul = InsertInstruction(
597 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
598 HInstruction* shl = InsertInstruction(
599 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
600 HInstruction* div = InsertInstruction(
601 new (&allocator_) HDiv(Primitive::kPrimInt, k_header, constant100_, kNoDexPc), 0);
602 k_header->AddInput(div);
603 PerformInductionVarAnalysis();
604
605 // Note, only the phi in the cycle and direct additive derived are classified.
606 EXPECT_STREQ("geo((1) * 100 ^ -i + (0)):PrimInt", GetInductionInfo(k_header, 0).c_str());
607 EXPECT_STREQ("geo((1) * 100 ^ -i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
608 EXPECT_STREQ("geo((1) * 100 ^ -i + ((0) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
609 EXPECT_STREQ("", GetInductionInfo(neg, 0).c_str());
610 EXPECT_STREQ("", GetInductionInfo(mul, 0).c_str());
611 EXPECT_STREQ("", GetInductionInfo(shl, 0).c_str());
612 EXPECT_STREQ("", GetInductionInfo(div, 0).c_str());
613}
614
Aart Bikdf7822e2016-12-06 10:05:30 -0800615TEST_F(InductionVarAnalysisTest, FindRemWrapAroundInductionAndDerived) {
Aart Bikc071a012016-12-01 10:22:31 -0800616 // Setup:
Aart Bikdf7822e2016-12-06 10:05:30 -0800617 // k = 100;
Aart Bikc071a012016-12-01 10:22:31 -0800618 // for (int i = 0; i < 100; i++) {
619 // t = k + 100;
620 // t = k - 1;
621 // t = -t
622 // t = k * 2;
623 // t = k << 2;
Aart Bikdf7822e2016-12-06 10:05:30 -0800624 // k = k % 7;
Aart Bikc071a012016-12-01 10:22:31 -0800625 // }
626 BuildLoopNest(1);
627 HPhi* k_header = InsertLoopPhi(0, 0);
Aart Bikdf7822e2016-12-06 10:05:30 -0800628 k_header->AddInput(constant100_);
Aart Bikc071a012016-12-01 10:22:31 -0800629
630 HInstruction* add = InsertInstruction(
631 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
632 HInstruction* sub = InsertInstruction(
633 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant1_), 0);
634 HInstruction* neg = InsertInstruction(
635 new (&allocator_) HNeg(Primitive::kPrimInt, sub), 0);
636 HInstruction* mul = InsertInstruction(
637 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant2_), 0);
638 HInstruction* shl = InsertInstruction(
639 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant2_), 0);
640 HInstruction* rem = InsertInstruction(
Aart Bikdf7822e2016-12-06 10:05:30 -0800641 new (&allocator_) HRem(Primitive::kPrimInt, k_header, constant7_, kNoDexPc), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800642 k_header->AddInput(rem);
643 PerformInductionVarAnalysis();
644
Aart Bikdf7822e2016-12-06 10:05:30 -0800645 // Note, only the phi in the cycle and derived are classified.
646 EXPECT_STREQ("wrap((100), ((100) % (7))):PrimInt", GetInductionInfo(k_header, 0).c_str());
647 EXPECT_STREQ("wrap(((100) + (100)), (((100) % (7)) + (100))):PrimInt", GetInductionInfo(add, 0).c_str());
648 EXPECT_STREQ("wrap(((100) - (1)), (((100) % (7)) - (1))):PrimInt", GetInductionInfo(sub, 0).c_str());
649 EXPECT_STREQ("wrap(( - ((100) - (1))), ( - (((100) % (7)) - (1)))):PrimInt", GetInductionInfo(neg, 0).c_str());
650 EXPECT_STREQ("wrap(((100) * (2)), (((100) % (7)) * (2))):PrimInt", GetInductionInfo(mul, 0).c_str());
651 EXPECT_STREQ("wrap(((100) * (4)), (((100) % (7)) * (4))):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800652 EXPECT_STREQ("", GetInductionInfo(rem, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700653}
654
655TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
656 // Setup:
657 // k = 0;
658 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700659 // a[k] = 0;
660 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700661 // }
662 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800663 HPhi* k_header = InsertLoopPhi(0, 0);
664 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000665
Aart Bikc071a012016-12-01 10:22:31 -0800666 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700667 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000668 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bikc071a012016-12-01 10:22:31 -0800669 k_header->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700670 PerformInductionVarAnalysis();
671
Aart Bik0d345cf2016-03-16 10:49:38 -0700672 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800673 GetInductionInfo(k_header, 0).c_str());
674 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700675 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800676 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700677}
678
679TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
680 // Setup:
681 // k = 0;
682 // t = 100;
683 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700684 // a[k] = 0;
685 // k = t;
686 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700687 // }
688 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800689 HPhi* k_header = InsertLoopPhi(0, 0);
690 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000691 HPhi* t = InsertLoopPhi(1, 0);
692 t->AddInput(constant100_);
693
Aart Bikc071a012016-12-01 10:22:31 -0800694 HInstruction* store = InsertArrayStore(k_header, 0);
695 k_header->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700696 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000697 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
698 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700699 PerformInductionVarAnalysis();
700
Aart Bik0d345cf2016-03-16 10:49:38 -0700701 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):PrimInt):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700702 GetInductionInfo(store->InputAt(1), 0).c_str());
703}
704
705TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
706 // Setup:
707 // k = 0;
708 // for (int i = 0; i < 100; i++) {
709 // t = k + 100;
710 // t = k - 100;
711 // t = k * 100;
712 // t = k << 1;
713 // t = - k;
714 // k = i << 1;
Aart Bikc071a012016-12-01 10:22:31 -0800715 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700716 // }
717 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800718 HPhi* k_header = InsertLoopPhi(0, 0);
719 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000720
Aart Bik7dc96932016-10-12 10:01:05 -0700721 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800722 new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700723 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800724 new (&allocator_) HSub(Primitive::kPrimInt, k_header, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700725 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800726 new (&allocator_) HMul(Primitive::kPrimInt, k_header, constant100_), 0);
727 HInstruction* shl1 = InsertInstruction(
728 new (&allocator_) HShl(Primitive::kPrimInt, k_header, constant1_), 0);
729 HInstruction* neg1 = InsertInstruction(
730 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
731 HInstruction* shl2 = InsertInstruction(
732 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
733 HInstruction* neg2 = InsertInstruction(
734 new (&allocator_) HNeg(Primitive::kPrimInt, shl2), 0);
735 k_header->AddInput(shl2);
Aart Bike609b7c2015-08-27 13:46:58 -0700736 PerformInductionVarAnalysis();
737
Aart Bik0d345cf2016-03-16 10:49:38 -0700738 EXPECT_STREQ("wrap((100), ((2) * i + (100)):PrimInt):PrimInt",
739 GetInductionInfo(add, 0).c_str());
740 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):PrimInt):PrimInt",
741 GetInductionInfo(sub, 0).c_str());
742 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):PrimInt):PrimInt",
743 GetInductionInfo(mul, 0).c_str());
744 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800745 GetInductionInfo(shl1, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700746 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):PrimInt):PrimInt",
Aart Bikc071a012016-12-01 10:22:31 -0800747 GetInductionInfo(neg1, 0).c_str());
748 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl2, 0).c_str());
749 EXPECT_STREQ("(( - (2)) * i + (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700750}
751
752TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
753 // Setup:
754 // k = 0;
755 // t = 100;
756 // for (int i = 0; i < 100; i++) {
757 // a[k] = 0;
758 // a[t] = 0;
759 // // Swap t <-> k.
760 // d = t;
761 // t = k;
762 // k = d;
763 // }
764 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800765 HPhi* k_header = InsertLoopPhi(0, 0);
766 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000767 HPhi* t = InsertLoopPhi(1, 0);
768 t->AddInput(constant100_);
769
Aart Bikc071a012016-12-01 10:22:31 -0800770 HInstruction* store1 = InsertArrayStore(k_header, 0);
David Brazdilbadd8262016-02-02 16:28:56 +0000771 HInstruction* store2 = InsertArrayStore(t, 0);
Aart Bikc071a012016-12-01 10:22:31 -0800772 k_header->AddInput(t);
773 t->AddInput(k_header);
Aart Bike609b7c2015-08-27 13:46:58 -0700774 PerformInductionVarAnalysis();
775
Aart Bik0d345cf2016-03-16 10:49:38 -0700776 EXPECT_STREQ("periodic((0), (100)):PrimInt", GetInductionInfo(store1->InputAt(1), 0).c_str());
777 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700778}
779
780TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
781 // Setup:
782 // k = 0;
783 // for (int i = 0; i < 100; i++) {
784 // a[k] = 0;
785 // k = 1 - k;
786 // }
787 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800788 HPhi* k_header = InsertLoopPhi(0, 0);
789 k_header->AddInput(constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000790
Aart Bikc071a012016-12-01 10:22:31 -0800791 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700792 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800793 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
794 k_header->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700795 PerformInductionVarAnalysis();
796
Aart Bik0d345cf2016-03-16 10:49:38 -0700797 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
798 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700799}
800
Aart Bik7dc96932016-10-12 10:01:05 -0700801TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
802 // Setup:
803 // k = 0;
804 // for (int i = 0; i < 100; i++) {
805 // a[k] = 0;
806 // k = k ^ 1;
807 // }
808 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800809 HPhi* k_header = InsertLoopPhi(0, 0);
810 k_header->AddInput(constant0_);
Aart Bik7dc96932016-10-12 10:01:05 -0700811
Aart Bikc071a012016-12-01 10:22:31 -0800812 HInstruction* store = InsertArrayStore(k_header, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700813 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800814 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant1_), 0);
815 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700816 PerformInductionVarAnalysis();
817
818 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
819 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
820}
821
Aart Bik639cc8c2016-10-18 13:03:31 -0700822TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
823 // Setup:
824 // k = 1;
825 // for (int i = 0; i < 100; i++) {
826 // k = 1 ^ k;
827 // }
828 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800829 HPhi* k_header = InsertLoopPhi(0, 0);
830 k_header->AddInput(constant1_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700831
832 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800833 new (&allocator_) HXor(Primitive::kPrimInt, constant1_, k_header), 0);
834 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700835 PerformInductionVarAnalysis();
836
Aart Bikc071a012016-12-01 10:22:31 -0800837 EXPECT_STREQ("periodic((1), ((1) ^ (1))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700838 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
839}
840
Aart Bik7dc96932016-10-12 10:01:05 -0700841TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
842 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700843 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700844 // for (int i = 0; i < 100; i++) {
845 // k = k ^ 100;
846 // }
847 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800848 HPhi* k_header = InsertLoopPhi(0, 0);
849 k_header->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700850
851 HInstruction* x = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800852 new (&allocator_) HXor(Primitive::kPrimInt, k_header, constant100_), 0);
853 k_header->AddInput(x);
Aart Bik7dc96932016-10-12 10:01:05 -0700854 PerformInductionVarAnalysis();
855
Aart Bikc071a012016-12-01 10:22:31 -0800856 EXPECT_STREQ("periodic((1), ((1) ^ (100))):PrimInt", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700857 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
858}
859
860TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
861 // Setup:
862 // k = 0;
863 // for (int i = 0; i < 100; i++) {
864 // k = (k == 0);
865 // }
866 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800867 HPhi* k_header = InsertLoopPhi(0, 0);
868 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700869
Aart Bikc071a012016-12-01 10:22:31 -0800870 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(k_header, constant0_), 0);
871 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700872 PerformInductionVarAnalysis();
873
Aart Bikc071a012016-12-01 10:22:31 -0800874 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700875 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
876}
877
878TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
879 // Setup:
880 // k = 0;
881 // for (int i = 0; i < 100; i++) {
882 // k = (0 == k);
883 // }
884 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800885 HPhi* k_header = InsertLoopPhi(0, 0);
886 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700887
Aart Bikc071a012016-12-01 10:22:31 -0800888 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(constant0_, k_header), 0);
889 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700890 PerformInductionVarAnalysis();
891
Aart Bikc071a012016-12-01 10:22:31 -0800892 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700893 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
894}
895
896TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
897 // Setup:
898 // k = 0;
899 // for (int i = 0; i < 100; i++) {
900 // k = (k != 1);
901 // }
902 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800903 HPhi* k_header = InsertLoopPhi(0, 0);
904 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700905
Aart Bikc071a012016-12-01 10:22:31 -0800906 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(k_header, constant1_), 0);
907 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700908 PerformInductionVarAnalysis();
909
Aart Bikc071a012016-12-01 10:22:31 -0800910 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700911 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
912}
913
914TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
915 // Setup:
916 // k = 0;
917 // for (int i = 0; i < 100; i++) {
918 // k = (1 != k);
919 // }
920 BuildLoopNest(1);
Aart Bikc071a012016-12-01 10:22:31 -0800921 HPhi* k_header = InsertLoopPhi(0, 0);
922 k_header->AddInput(constant0_);
Aart Bik639cc8c2016-10-18 13:03:31 -0700923
Aart Bikc071a012016-12-01 10:22:31 -0800924 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(constant1_, k_header), 0);
925 k_header->AddInput(x);
Aart Bik639cc8c2016-10-18 13:03:31 -0700926 PerformInductionVarAnalysis();
927
Aart Bikc071a012016-12-01 10:22:31 -0800928 EXPECT_STREQ("periodic((0), (1)):PrimBoolean", GetInductionInfo(k_header, 0).c_str());
Aart Bik639cc8c2016-10-18 13:03:31 -0700929 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700930}
931
Aart Bike609b7c2015-08-27 13:46:58 -0700932TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
933 // Setup:
934 // k = 0;
935 // for (int i = 0; i < 100; i++) {
Aart Bikc071a012016-12-01 10:22:31 -0800936 // t = - k;
Aart Bike609b7c2015-08-27 13:46:58 -0700937 // k = 1 - k;
938 // t = k + 100;
939 // t = k - 100;
940 // t = k * 100;
941 // t = k << 1;
942 // t = - k;
943 // }
944 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000945 HPhi* k_header = InsertLoopPhi(0, 0);
946 k_header->AddInput(constant0_);
947
Aart Bikc071a012016-12-01 10:22:31 -0800948 HInstruction* neg1 = InsertInstruction(
949 new (&allocator_) HNeg(Primitive::kPrimInt, k_header), 0);
950 HInstruction* idiom = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000951 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700952 HInstruction* add = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800953 new (&allocator_) HAdd(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700954 HInstruction* sub = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800955 new (&allocator_) HSub(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700956 HInstruction* mul = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800957 new (&allocator_) HMul(Primitive::kPrimInt, idiom, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700958 HInstruction* shl = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800959 new (&allocator_) HShl(Primitive::kPrimInt, idiom, constant1_), 0);
960 HInstruction* neg2 = InsertInstruction(
961 new (&allocator_) HNeg(Primitive::kPrimInt, idiom), 0);
962 k_header->AddInput(idiom);
Aart Bike609b7c2015-08-27 13:46:58 -0700963 PerformInductionVarAnalysis();
964
Aart Bikc071a012016-12-01 10:22:31 -0800965 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(k_header, 0).c_str());
966 EXPECT_STREQ("periodic((0), ( - (1))):PrimInt", GetInductionInfo(neg1, 0).c_str());
967 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(idiom, 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700968 EXPECT_STREQ("periodic(((1) + (100)), (100)):PrimInt", GetInductionInfo(add, 0).c_str());
969 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):PrimInt", GetInductionInfo(sub, 0).c_str());
970 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
971 EXPECT_STREQ("periodic((2), (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
Aart Bikc071a012016-12-01 10:22:31 -0800972 EXPECT_STREQ("periodic(( - (1)), (0)):PrimInt", GetInductionInfo(neg2, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700973}
974
975TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
976 // Setup:
977 // k = 0;
978 // for (int i_0 = 0; i_0 < 100; i_0++) {
979 // ..
980 // for (int i_9 = 0; i_9 < 100; i_9++) {
981 // k = 1 + k;
982 // a[k] = 0;
983 // }
984 // ..
985 // }
986 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000987
Aart Bikc071a012016-12-01 10:22:31 -0800988 HPhi* k_header[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000989 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -0800990 k_header[d] = InsertLoopPhi(0, d);
David Brazdilbadd8262016-02-02 16:28:56 +0000991 }
992
Aart Bik7dc96932016-10-12 10:01:05 -0700993 HInstruction* inc = InsertInstruction(
Aart Bikc071a012016-12-01 10:22:31 -0800994 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k_header[9]), 9);
David Brazdilbadd8262016-02-02 16:28:56 +0000995 HInstruction* store = InsertArrayStore(inc, 9);
996
997 for (int d = 0; d < 10; d++) {
Aart Bikc071a012016-12-01 10:22:31 -0800998 k_header[d]->AddInput((d != 0) ? k_header[d - 1] : constant0_);
999 k_header[d]->AddInput((d != 9) ? k_header[d + 1] : inc);
David Brazdilbadd8262016-02-02 16:28:56 +00001000 }
Aart Bik30efb4e2015-07-30 12:14:31 -07001001 PerformInductionVarAnalysis();
1002
Aart Bike609b7c2015-08-27 13:46:58 -07001003 // Avoid exact phi number, since that depends on the SSA building phase.
1004 std::regex r("\\(\\(1\\) \\* i \\+ "
Aart Bik0d345cf2016-03-16 10:49:38 -07001005 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):PrimInt");
Aart Bik30efb4e2015-07-30 12:14:31 -07001006
1007 for (int d = 0; d < 10; d++) {
1008 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -07001009 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -07001010 } else {
Aart Bike609b7c2015-08-27 13:46:58 -07001011 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001012 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001013 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -07001014 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001015 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -07001016 }
1017}
1018
Aart Bik78296912016-03-25 13:14:53 -07001019TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
1020 // Setup:
1021 // for (int i = 0; i < 100; i++) {
1022 // k = (byte) i;
1023 // a[k] = 0;
1024 // a[i] = 0;
1025 // }
1026 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -07001027 HInstruction* conv = InsertInstruction(
Aart Bik78296912016-03-25 13:14:53 -07001028 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
1029 HInstruction* store1 = InsertArrayStore(conv, 0);
1030 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
1031 PerformInductionVarAnalysis();
1032
1033 // Regular int induction (i) is "transferred" over conversion into byte induction (k).
1034 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
1035 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
1036 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
1037
1038 // Type matters!
1039 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
1040
1041 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001042 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -07001043}
1044
Aart Bikcc42be02016-10-20 16:14:16 -07001045TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
1046 // Setup:
1047 // for (int i = 0; i < 100; i++) {
1048 // k = (byte) i;
1049 // a[k] = 0;
1050 // k = k + 1
1051 // a[k] = 0;
1052 // }
1053 BuildLoopNest(1);
1054 HInstruction* conv = InsertInstruction(
1055 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
1056 HInstruction* store1 = InsertArrayStore(conv, 0);
1057 HInstruction* add = InsertInstruction(
1058 new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
1059 HInstruction* store2 = InsertArrayStore(add, 0);
1060
1061 PerformInductionVarAnalysis();
1062
1063 // Byte induction (k) is "transferred" over conversion into addition (k + 1).
1064 // This means only values within byte range can be trusted (even though
1065 // addition can jump out of the range of course).
1066 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
1067 EXPECT_STREQ("((1) * i + (1)):PrimByte", GetInductionInfo(store2->InputAt(1), 0).c_str());
1068}
1069
Aart Bik0d345cf2016-03-16 10:49:38 -07001070TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
1071 // Setup:
1072 // for (byte i = -128; i < 127; i++) { // just fits!
1073 // }
1074 BuildLoopNest(1);
1075 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1076 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1077 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
1078 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
1079 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1080 basic_[0]->ReplaceInput(conv, 1);
1081 PerformInductionVarAnalysis();
1082
1083 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
1084 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001085 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001086}
1087
1088TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
1089 // Setup:
1090 // for (byte i = -128; i < 128; i++) { // infinite loop!
1091 // }
1092 BuildLoopNest(1);
1093 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
1094 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1095 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
1096 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
1097 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1098 basic_[0]->ReplaceInput(conv, 1);
1099 PerformInductionVarAnalysis();
1100
1101 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
1102 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001103 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001104}
1105
1106TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
1107 // Setup:
1108 // for (short i = -32768; i < 32767; i++) { // just fits!
1109 // }
1110 BuildLoopNest(1);
1111 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1112 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1113 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
1114 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
1115 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1116 basic_[0]->ReplaceInput(conv, 1);
1117 PerformInductionVarAnalysis();
1118
1119 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
1120 GetInductionInfo(increment_[0], 0).c_str());
1121 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001122 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001123}
1124
1125TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
1126 // Setup:
1127 // for (short i = -32768; i < 32768; i++) { // infinite loop!
1128 // }
1129 BuildLoopNest(1);
1130 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
1131 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1132 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
1133 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
1134 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1135 basic_[0]->ReplaceInput(conv, 1);
1136 PerformInductionVarAnalysis();
1137
1138 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
1139 GetInductionInfo(increment_[0], 0).c_str());
1140 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001141 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001142}
1143
1144TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
1145 // Setup:
1146 // for (char i = 0; i < 65535; i++) { // just fits!
1147 // }
1148 BuildLoopNest(1);
1149 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1150 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
1151 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
1152 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1153 basic_[0]->ReplaceInput(conv, 1);
1154 PerformInductionVarAnalysis();
1155
1156 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
1157 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -07001158 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001159}
1160
1161TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
1162 // Setup:
1163 // for (char i = 0; i < 65536; i++) { // infinite loop!
1164 // }
1165 BuildLoopNest(1);
1166 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
1167 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
1168 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
1169 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
1170 basic_[0]->ReplaceInput(conv, 1);
1171 PerformInductionVarAnalysis();
1172
1173 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
1174 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -07001175 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -07001176}
1177
Aart Bik30efb4e2015-07-30 12:14:31 -07001178} // namespace art