blob: 3425b882605db132599ec8f8e6abf03977425832 [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);
87 constant100_ = graph_->GetIntConstant(100);
David Brazdil15693bf2015-12-16 10:30:45 +000088 float_constant0_ = graph_->GetFloatConstant(0.0f);
David Brazdildb51efb2015-11-06 01:36:20 +000089 return_->AddInstruction(new (&allocator_) HReturnVoid());
Aart Bike609b7c2015-08-27 13:46:58 -070090 exit_->AddInstruction(new (&allocator_) HExit());
Aart Bik30efb4e2015-07-30 12:14:31 -070091
92 // Provide loop instructions.
93 for (int d = 0; d < n; d++) {
David Brazdilbadd8262016-02-02 16:28:56 +000094 basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, Primitive::kPrimInt);
David Brazdil4833f5a2015-12-16 10:37:39 +000095 loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +000096 loop_header_[d]->AddPhi(basic_[d]);
97 HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
Aart Bik30efb4e2015-07-30 12:14:31 -070098 loop_header_[d]->AddInstruction(compare);
99 loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
David Brazdilbadd8262016-02-02 16:28:56 +0000100 increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[d], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700101 loop_body_[d]->AddInstruction(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700102 loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
David Brazdilbadd8262016-02-02 16:28:56 +0000103
104 basic_[d]->AddInput(constant0_);
105 basic_[d]->AddInput(increment_[d]);
Aart Bik30efb4e2015-07-30 12:14:31 -0700106 }
107 }
108
109 // Builds if-statement at depth d.
Aart Bik7dc96932016-10-12 10:01:05 -0700110 HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock** ifF) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700111 HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
112 HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
113 HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
114 graph_->AddBlock(cond);
115 graph_->AddBlock(ifTrue);
116 graph_->AddBlock(ifFalse);
117 // Conditional split.
118 loop_header_[d]->ReplaceSuccessor(loop_body_[d], cond);
119 cond->AddSuccessor(ifTrue);
120 cond->AddSuccessor(ifFalse);
121 ifTrue->AddSuccessor(loop_body_[d]);
122 ifFalse->AddSuccessor(loop_body_[d]);
123 cond->AddInstruction(new (&allocator_) HIf(parameter_));
124 *ifT = ifTrue;
125 *ifF = ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000126
127 HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, Primitive::kPrimInt);
128 loop_body_[d]->AddPhi(select_phi);
129 return select_phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700130 }
131
132 // Inserts instruction right before increment at depth d.
133 HInstruction* InsertInstruction(HInstruction* instruction, int d) {
134 loop_body_[d]->InsertInstructionBefore(instruction, increment_[d]);
135 return instruction;
136 }
137
David Brazdilbadd8262016-02-02 16:28:56 +0000138 // Inserts a phi to loop header at depth d and returns it.
139 HPhi* InsertLoopPhi(int vreg, int d) {
140 HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, Primitive::kPrimInt);
141 loop_header_[d]->AddPhi(phi);
142 return phi;
Aart Bik30efb4e2015-07-30 12:14:31 -0700143 }
144
David Brazdilbadd8262016-02-02 16:28:56 +0000145 // Inserts an array store with given `subscript` at depth d to
Aart Bik30efb4e2015-07-30 12:14:31 -0700146 // enable tests to inspect the computed induction at that point easily.
David Brazdilbadd8262016-02-02 16:28:56 +0000147 HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
David Brazdil15693bf2015-12-16 10:30:45 +0000148 // ArraySet is given a float value in order to avoid SsaBuilder typing
149 // it from the array's non-existent reference type info.
Aart Bik30efb4e2015-07-30 12:14:31 -0700150 return InsertInstruction(new (&allocator_) HArraySet(
David Brazdilbadd8262016-02-02 16:28:56 +0000151 parameter_, subscript, float_constant0_, Primitive::kPrimFloat, 0), d);
Aart Bik30efb4e2015-07-30 12:14:31 -0700152 }
153
Aart Bike609b7c2015-08-27 13:46:58 -0700154 // Returns induction information of instruction in loop at depth d.
155 std::string GetInductionInfo(HInstruction* instruction, int d) {
156 return HInductionVarAnalysis::InductionToString(
157 iva_->LookupInfo(loop_body_[d]->GetLoopInformation(), instruction));
Aart Bik30efb4e2015-07-30 12:14:31 -0700158 }
159
Aart Bik009cace2016-09-16 10:15:19 -0700160 // Returns induction information of the trip-count of loop at depth d.
161 std::string GetTripCount(int d) {
162 HInstruction* control = loop_header_[d]->GetLastInstruction();
163 DCHECK(control->IsIf());
164 return GetInductionInfo(control, d);
165 }
166
Aart Bik78296912016-03-25 13:14:53 -0700167 // Returns true if instructions have identical induction.
168 bool HaveSameInduction(HInstruction* instruction1, HInstruction* instruction2) {
169 return HInductionVarAnalysis::InductionEqual(
170 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction1),
171 iva_->LookupInfo(loop_body_[0]->GetLoopInformation(), instruction2));
172 }
173
Aart Bik30efb4e2015-07-30 12:14:31 -0700174 // Performs InductionVarAnalysis (after proper set up).
175 void PerformInductionVarAnalysis() {
David Brazdilbadd8262016-02-02 16:28:56 +0000176 graph_->BuildDominatorTree();
Aart Bik30efb4e2015-07-30 12:14:31 -0700177 iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
178 iva_->Run();
179 }
180
181 // General building fields.
182 ArenaPool pool_;
183 ArenaAllocator allocator_;
184 HGraph* graph_;
185 HInductionVarAnalysis* iva_;
186
187 // Fixed basic blocks and instructions.
188 HBasicBlock* entry_;
David Brazdildb51efb2015-11-06 01:36:20 +0000189 HBasicBlock* return_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700190 HBasicBlock* exit_;
191 HInstruction* parameter_; // "this"
192 HInstruction* constant0_;
193 HInstruction* constant1_;
194 HInstruction* constant100_;
David Brazdil15693bf2015-12-16 10:30:45 +0000195 HInstruction* float_constant0_;
Aart Bik30efb4e2015-07-30 12:14:31 -0700196
197 // Loop specifics.
198 HBasicBlock* loop_preheader_[10];
199 HBasicBlock* loop_header_[10];
200 HBasicBlock* loop_body_[10];
201 HInstruction* increment_[10];
David Brazdilbadd8262016-02-02 16:28:56 +0000202 HPhi* basic_[10]; // "vreg_d", the "i_d"
Aart Bik30efb4e2015-07-30 12:14:31 -0700203};
204
205//
206// The actual InductionVarAnalysis tests.
207//
208
209TEST_F(InductionVarAnalysisTest, ProperLoopSetup) {
210 // Setup:
211 // for (int i_0 = 0; i_0 < 100; i_0++) {
212 // ..
213 // for (int i_9 = 0; i_9 < 100; i_9++) {
214 // }
215 // ..
216 // }
217 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000218 graph_->BuildDominatorTree();
Aart Bik0d345cf2016-03-16 10:49:38 -0700219
Aart Bik30efb4e2015-07-30 12:14:31 -0700220 ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
221 for (int d = 0; d < 1; d++) {
222 ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
223 (d == 0) ? nullptr
224 : loop_header_[d - 1]->GetLoopInformation());
225 ASSERT_NE(loop_header_[d]->GetLoopInformation(), nullptr);
226 ASSERT_NE(loop_body_[d]->GetLoopInformation(), nullptr);
227 ASSERT_EQ(loop_header_[d]->GetLoopInformation(),
228 loop_body_[d]->GetLoopInformation());
229 }
230 ASSERT_EQ(exit_->GetLoopInformation(), nullptr);
231}
232
Aart Bike609b7c2015-08-27 13:46:58 -0700233TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700234 // Setup:
235 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700236 // a[i] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700237 // }
238 BuildLoopNest(1);
239 HInstruction* store = InsertArrayStore(basic_[0], 0);
240 PerformInductionVarAnalysis();
241
Aart Bik0d345cf2016-03-16 10:49:38 -0700242 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
243 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700244
Aart Bik78296912016-03-25 13:14:53 -0700245 // Offset matters!
246 EXPECT_FALSE(HaveSameInduction(store->InputAt(1), increment_[0]));
247
Aart Bikd14c5952015-09-08 15:25:15 -0700248 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700249 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700250}
251
Aart Bike609b7c2015-08-27 13:46:58 -0700252TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700253 // Setup:
254 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700255 // k = 100 + i;
256 // k = 100 - i;
257 // k = 100 * i;
258 // k = i << 1;
259 // k = - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700260 // }
261 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700262 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000263 new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700264 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000265 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700266 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000267 new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700268 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000269 new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700270 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000271 new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700272 PerformInductionVarAnalysis();
273
Aart Bik0d345cf2016-03-16 10:49:38 -0700274 EXPECT_STREQ("((1) * i + (100)):PrimInt", GetInductionInfo(add, 0).c_str());
275 EXPECT_STREQ("(( - (1)) * i + (100)):PrimInt", GetInductionInfo(sub, 0).c_str());
276 EXPECT_STREQ("((100) * i + (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
277 EXPECT_STREQ("((2) * i + (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
278 EXPECT_STREQ("(( - (1)) * i + (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700279}
280
281TEST_F(InductionVarAnalysisTest, FindChainInduction) {
282 // Setup:
283 // k = 0;
284 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700285 // k = k + 100;
286 // a[k] = 0;
287 // k = k - 1;
288 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700289 // }
290 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000291 HPhi* k = InsertLoopPhi(0, 0);
292 k->AddInput(constant0_);
293
Aart Bik7dc96932016-10-12 10:01:05 -0700294 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000295 new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
296 HInstruction* store1 = InsertArrayStore(add, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700297 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000298 new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
299 HInstruction* store2 = InsertArrayStore(sub, 0);
300 k->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700301 PerformInductionVarAnalysis();
302
Aart Bik0d345cf2016-03-16 10:49:38 -0700303 EXPECT_STREQ("(((100) - (1)) * i + (100)):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700304 GetInductionInfo(store1->InputAt(1), 0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700305 EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1))):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700306 GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700307}
308
309TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
310 // Setup:
311 // k = 0;
312 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700313 // if () k = k + 1;
314 // else k = k + 1;
315 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700316 // }
317 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000318 HPhi* k_header = InsertLoopPhi(0, 0);
319 k_header->AddInput(constant0_);
320
Aart Bik30efb4e2015-07-30 12:14:31 -0700321 HBasicBlock* ifTrue;
322 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000323 HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
324
Aart Bik30efb4e2015-07-30 12:14:31 -0700325 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000326 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700327 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000328 k_body->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700329 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000330 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700331 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000332 k_body->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700333 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000334 HInstruction* store = InsertArrayStore(k_body, 0);
335 k_header->AddInput(k_body);
Aart Bik30efb4e2015-07-30 12:14:31 -0700336 PerformInductionVarAnalysis();
337
Aart Bik0d345cf2016-03-16 10:49:38 -0700338 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700339
340 // Both increments get same induction.
341 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc1));
342 EXPECT_TRUE(HaveSameInduction(store->InputAt(1), inc2));
Aart Bik30efb4e2015-07-30 12:14:31 -0700343}
344
345TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
346 // Setup:
347 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700348 // if () k = i + 1;
349 // else k = i + 1;
350 // a[k] = 0;
Aart Bik30efb4e2015-07-30 12:14:31 -0700351 // }
352 BuildLoopNest(1);
353 HBasicBlock* ifTrue;
354 HBasicBlock* ifFalse;
David Brazdilbadd8262016-02-02 16:28:56 +0000355 HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
356
Aart Bik30efb4e2015-07-30 12:14:31 -0700357 // True-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000358 HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700359 ifTrue->AddInstruction(inc1);
David Brazdilbadd8262016-02-02 16:28:56 +0000360 k->AddInput(inc1);
Aart Bik30efb4e2015-07-30 12:14:31 -0700361 // False-branch.
David Brazdilbadd8262016-02-02 16:28:56 +0000362 HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
Aart Bik30efb4e2015-07-30 12:14:31 -0700363 ifFalse->AddInstruction(inc2);
David Brazdilbadd8262016-02-02 16:28:56 +0000364 k->AddInput(inc2);
Aart Bik30efb4e2015-07-30 12:14:31 -0700365 // Merge over a phi.
David Brazdilbadd8262016-02-02 16:28:56 +0000366 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik30efb4e2015-07-30 12:14:31 -0700367 PerformInductionVarAnalysis();
368
Aart Bik0d345cf2016-03-16 10:49:38 -0700369 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700370}
371
372TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
373 // Setup:
374 // k = 0;
375 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700376 // a[k] = 0;
377 // k = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700378 // }
379 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000380 HPhi* k = InsertLoopPhi(0, 0);
381 k->AddInput(constant0_);
382
383 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700384 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000385 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
386 k->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700387 PerformInductionVarAnalysis();
388
Aart Bik0d345cf2016-03-16 10:49:38 -0700389 EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700390 GetInductionInfo(store->InputAt(1), 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700391}
392
393TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
394 // Setup:
395 // k = 0;
396 // t = 100;
397 // for (int i = 0; i < 100; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700398 // a[k] = 0;
399 // k = t;
400 // t = 100 - i;
Aart Bik30efb4e2015-07-30 12:14:31 -0700401 // }
402 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000403 HPhi* k = InsertLoopPhi(0, 0);
404 k->AddInput(constant0_);
405 HPhi* t = InsertLoopPhi(1, 0);
406 t->AddInput(constant100_);
407
408 HInstruction* store = InsertArrayStore(k, 0);
409 k->AddInput(t);
Aart Bik7dc96932016-10-12 10:01:05 -0700410 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000411 new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
412 t->AddInput(sub);
Aart Bik30efb4e2015-07-30 12:14:31 -0700413 PerformInductionVarAnalysis();
414
Aart Bik0d345cf2016-03-16 10:49:38 -0700415 EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100)):PrimInt):PrimInt):PrimInt",
Aart Bike609b7c2015-08-27 13:46:58 -0700416 GetInductionInfo(store->InputAt(1), 0).c_str());
417}
418
419TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
420 // Setup:
421 // k = 0;
422 // for (int i = 0; i < 100; i++) {
423 // t = k + 100;
424 // t = k - 100;
425 // t = k * 100;
426 // t = k << 1;
427 // t = - k;
428 // k = i << 1;
429 // }
430 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000431 HPhi* k = InsertLoopPhi(0, 0);
432 k->AddInput(constant0_);
433
Aart Bik7dc96932016-10-12 10:01:05 -0700434 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000435 new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700436 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000437 new (&allocator_) HSub(Primitive::kPrimInt, k, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700438 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000439 new (&allocator_) HMul(Primitive::kPrimInt, k, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700440 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000441 new (&allocator_) HShl(Primitive::kPrimInt, k, constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700442 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000443 new (&allocator_) HNeg(Primitive::kPrimInt, k), 0);
444 k->AddInput(
445 InsertInstruction(new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0));
Aart Bike609b7c2015-08-27 13:46:58 -0700446 PerformInductionVarAnalysis();
447
Aart Bik0d345cf2016-03-16 10:49:38 -0700448 EXPECT_STREQ("wrap((100), ((2) * i + (100)):PrimInt):PrimInt",
449 GetInductionInfo(add, 0).c_str());
450 EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))):PrimInt):PrimInt",
451 GetInductionInfo(sub, 0).c_str());
452 EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)):PrimInt):PrimInt",
453 GetInductionInfo(mul, 0).c_str());
454 EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)):PrimInt):PrimInt",
455 GetInductionInfo(shl, 0).c_str());
456 EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)):PrimInt):PrimInt",
457 GetInductionInfo(neg, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700458}
459
460TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
461 // Setup:
462 // k = 0;
463 // t = 100;
464 // for (int i = 0; i < 100; i++) {
465 // a[k] = 0;
466 // a[t] = 0;
467 // // Swap t <-> k.
468 // d = t;
469 // t = k;
470 // k = d;
471 // }
472 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000473 HPhi* k = InsertLoopPhi(0, 0);
474 k->AddInput(constant0_);
475 HPhi* t = InsertLoopPhi(1, 0);
476 t->AddInput(constant100_);
477
478 HInstruction* store1 = InsertArrayStore(k, 0);
479 HInstruction* store2 = InsertArrayStore(t, 0);
480 k->AddInput(t);
481 t->AddInput(k);
Aart Bike609b7c2015-08-27 13:46:58 -0700482 PerformInductionVarAnalysis();
483
Aart Bik0d345cf2016-03-16 10:49:38 -0700484 EXPECT_STREQ("periodic((0), (100)):PrimInt", GetInductionInfo(store1->InputAt(1), 0).c_str());
485 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700486}
487
488TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
489 // Setup:
490 // k = 0;
491 // for (int i = 0; i < 100; i++) {
492 // a[k] = 0;
493 // k = 1 - k;
494 // }
495 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000496 HPhi* k = InsertLoopPhi(0, 0);
497 k->AddInput(constant0_);
498
499 HInstruction* store = InsertArrayStore(k, 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700500 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000501 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k), 0);
502 k->AddInput(sub);
Aart Bike609b7c2015-08-27 13:46:58 -0700503 PerformInductionVarAnalysis();
504
Aart Bik0d345cf2016-03-16 10:49:38 -0700505 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
506 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(sub, 0).c_str());
Aart Bike609b7c2015-08-27 13:46:58 -0700507}
508
Aart Bik7dc96932016-10-12 10:01:05 -0700509TEST_F(InductionVarAnalysisTest, FindXorPeriodicInduction) {
510 // Setup:
511 // k = 0;
512 // for (int i = 0; i < 100; i++) {
513 // a[k] = 0;
514 // k = k ^ 1;
515 // }
516 BuildLoopNest(1);
517 HPhi* k = InsertLoopPhi(0, 0);
518 k->AddInput(constant0_);
519
520 HInstruction* store = InsertArrayStore(k, 0);
521 HInstruction* x = InsertInstruction(
522 new (&allocator_) HXor(Primitive::kPrimInt, k, constant1_), 0);
523 k->AddInput(x);
524 PerformInductionVarAnalysis();
525
526 EXPECT_STREQ("periodic((0), (1)):PrimInt", GetInductionInfo(store->InputAt(1), 0).c_str());
527 EXPECT_STREQ("periodic((1), (0)):PrimInt", GetInductionInfo(x, 0).c_str());
528}
529
Aart Bik639cc8c2016-10-18 13:03:31 -0700530TEST_F(InductionVarAnalysisTest, FindXorConstantLeftPeriodicInduction) {
531 // Setup:
532 // k = 1;
533 // for (int i = 0; i < 100; i++) {
534 // k = 1 ^ k;
535 // }
536 BuildLoopNest(1);
537 HPhi* k = InsertLoopPhi(0, 0);
538 k->AddInput(constant1_);
539
540 HInstruction* x = InsertInstruction(
541 new (&allocator_) HXor(Primitive::kPrimInt, constant1_, k), 0);
542 k->AddInput(x);
543 PerformInductionVarAnalysis();
544
545 EXPECT_STREQ("periodic(((1) ^ (1)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
546}
547
Aart Bik7dc96932016-10-12 10:01:05 -0700548TEST_F(InductionVarAnalysisTest, FindXor100PeriodicInduction) {
549 // Setup:
Aart Bik639cc8c2016-10-18 13:03:31 -0700550 // k = 1;
Aart Bik7dc96932016-10-12 10:01:05 -0700551 // for (int i = 0; i < 100; i++) {
552 // k = k ^ 100;
553 // }
554 BuildLoopNest(1);
555 HPhi* k = InsertLoopPhi(0, 0);
Aart Bik639cc8c2016-10-18 13:03:31 -0700556 k->AddInput(constant1_);
Aart Bik7dc96932016-10-12 10:01:05 -0700557
558 HInstruction* x = InsertInstruction(
559 new (&allocator_) HXor(Primitive::kPrimInt, k, constant100_), 0);
560 k->AddInput(x);
561 PerformInductionVarAnalysis();
562
Aart Bik639cc8c2016-10-18 13:03:31 -0700563 EXPECT_STREQ("periodic(((1) ^ (100)), (1)):PrimInt", GetInductionInfo(x, 0).c_str());
564}
565
566TEST_F(InductionVarAnalysisTest, FindBooleanEqPeriodicInduction) {
567 // Setup:
568 // k = 0;
569 // for (int i = 0; i < 100; i++) {
570 // k = (k == 0);
571 // }
572 BuildLoopNest(1);
573 HPhi* k = InsertLoopPhi(0, 0);
574 k->AddInput(constant0_);
575
576 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(k, constant0_), 0);
577 k->AddInput(x);
578 PerformInductionVarAnalysis();
579
580 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
581}
582
583TEST_F(InductionVarAnalysisTest, FindBooleanEqConstantLeftPeriodicInduction) {
584 // Setup:
585 // k = 0;
586 // for (int i = 0; i < 100; i++) {
587 // k = (0 == k);
588 // }
589 BuildLoopNest(1);
590 HPhi* k = InsertLoopPhi(0, 0);
591 k->AddInput(constant0_);
592
593 HInstruction* x = InsertInstruction(new (&allocator_) HEqual(constant0_, k), 0);
594 k->AddInput(x);
595 PerformInductionVarAnalysis();
596
597 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
598}
599
600TEST_F(InductionVarAnalysisTest, FindBooleanNePeriodicInduction) {
601 // Setup:
602 // k = 0;
603 // for (int i = 0; i < 100; i++) {
604 // k = (k != 1);
605 // }
606 BuildLoopNest(1);
607 HPhi* k = InsertLoopPhi(0, 0);
608 k->AddInput(constant0_);
609
610 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(k, constant1_), 0);
611 k->AddInput(x);
612 PerformInductionVarAnalysis();
613
614 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
615}
616
617TEST_F(InductionVarAnalysisTest, FindBooleanNeConstantLeftPeriodicInduction) {
618 // Setup:
619 // k = 0;
620 // for (int i = 0; i < 100; i++) {
621 // k = (1 != k);
622 // }
623 BuildLoopNest(1);
624 HPhi* k = InsertLoopPhi(0, 0);
625 k->AddInput(constant0_);
626
627 HInstruction* x = InsertInstruction(new (&allocator_) HNotEqual(constant1_, k), 0);
628 k->AddInput(x);
629 PerformInductionVarAnalysis();
630
631 EXPECT_STREQ("periodic((1), (0)):PrimBoolean", GetInductionInfo(x, 0).c_str());
Aart Bik7dc96932016-10-12 10:01:05 -0700632}
633
Aart Bike609b7c2015-08-27 13:46:58 -0700634TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
635 // Setup:
636 // k = 0;
637 // for (int i = 0; i < 100; i++) {
638 // k = 1 - k;
639 // t = k + 100;
640 // t = k - 100;
641 // t = k * 100;
642 // t = k << 1;
643 // t = - k;
644 // }
645 BuildLoopNest(1);
David Brazdilbadd8262016-02-02 16:28:56 +0000646 HPhi* k_header = InsertLoopPhi(0, 0);
647 k_header->AddInput(constant0_);
648
649 HInstruction* k_body = InsertInstruction(
650 new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
651 k_header->AddInput(k_body);
652
Aart Bike609b7c2015-08-27 13:46:58 -0700653 // Derived expressions.
Aart Bik7dc96932016-10-12 10:01:05 -0700654 HInstruction* add = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000655 new (&allocator_) HAdd(Primitive::kPrimInt, k_body, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700656 HInstruction* sub = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000657 new (&allocator_) HSub(Primitive::kPrimInt, k_body, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700658 HInstruction* mul = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000659 new (&allocator_) HMul(Primitive::kPrimInt, k_body, constant100_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700660 HInstruction* shl = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000661 new (&allocator_) HShl(Primitive::kPrimInt, k_body, constant1_), 0);
Aart Bik7dc96932016-10-12 10:01:05 -0700662 HInstruction* neg = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000663 new (&allocator_) HNeg(Primitive::kPrimInt, k_body), 0);
Aart Bike609b7c2015-08-27 13:46:58 -0700664 PerformInductionVarAnalysis();
665
Aart Bik0d345cf2016-03-16 10:49:38 -0700666 EXPECT_STREQ("periodic(((1) + (100)), (100)):PrimInt", GetInductionInfo(add, 0).c_str());
667 EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100))):PrimInt", GetInductionInfo(sub, 0).c_str());
668 EXPECT_STREQ("periodic((100), (0)):PrimInt", GetInductionInfo(mul, 0).c_str());
669 EXPECT_STREQ("periodic((2), (0)):PrimInt", GetInductionInfo(shl, 0).c_str());
670 EXPECT_STREQ("periodic(( - (1)), (0)):PrimInt", GetInductionInfo(neg, 0).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700671}
672
673TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
674 // Setup:
675 // k = 0;
676 // for (int i_0 = 0; i_0 < 100; i_0++) {
677 // ..
678 // for (int i_9 = 0; i_9 < 100; i_9++) {
679 // k = 1 + k;
680 // a[k] = 0;
681 // }
682 // ..
683 // }
684 BuildLoopNest(10);
David Brazdilbadd8262016-02-02 16:28:56 +0000685
686 HPhi* k[10];
687 for (int d = 0; d < 10; d++) {
688 k[d] = InsertLoopPhi(0, d);
689 }
690
Aart Bik7dc96932016-10-12 10:01:05 -0700691 HInstruction* inc = InsertInstruction(
David Brazdilbadd8262016-02-02 16:28:56 +0000692 new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k[9]), 9);
693 HInstruction* store = InsertArrayStore(inc, 9);
694
695 for (int d = 0; d < 10; d++) {
David Brazdil6dd10fa2016-02-15 17:14:31 +0000696 k[d]->AddInput((d != 0) ? k[d - 1] : constant0_);
David Brazdilbadd8262016-02-02 16:28:56 +0000697 k[d]->AddInput((d != 9) ? k[d + 1] : inc);
698 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700699 PerformInductionVarAnalysis();
700
Aart Bike609b7c2015-08-27 13:46:58 -0700701 // Avoid exact phi number, since that depends on the SSA building phase.
702 std::regex r("\\(\\(1\\) \\* i \\+ "
Aart Bik0d345cf2016-03-16 10:49:38 -0700703 "\\(\\(1\\) \\+ \\(\\d+:Phi\\)\\)\\):PrimInt");
Aart Bik30efb4e2015-07-30 12:14:31 -0700704
705 for (int d = 0; d < 10; d++) {
706 if (d == 9) {
Aart Bike609b7c2015-08-27 13:46:58 -0700707 EXPECT_TRUE(std::regex_match(GetInductionInfo(store->InputAt(1), d), r));
Aart Bik30efb4e2015-07-30 12:14:31 -0700708 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700709 EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700710 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700711 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[d], d).c_str());
Aart Bikd14c5952015-09-08 15:25:15 -0700712 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700713 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(d).c_str());
Aart Bik30efb4e2015-07-30 12:14:31 -0700714 }
715}
716
Aart Bik78296912016-03-25 13:14:53 -0700717TEST_F(InductionVarAnalysisTest, ByteInductionIntLoopControl) {
718 // Setup:
719 // for (int i = 0; i < 100; i++) {
720 // k = (byte) i;
721 // a[k] = 0;
722 // a[i] = 0;
723 // }
724 BuildLoopNest(1);
Aart Bik7dc96932016-10-12 10:01:05 -0700725 HInstruction* conv = InsertInstruction(
Aart Bik78296912016-03-25 13:14:53 -0700726 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
727 HInstruction* store1 = InsertArrayStore(conv, 0);
728 HInstruction* store2 = InsertArrayStore(basic_[0], 0);
729 PerformInductionVarAnalysis();
730
731 // Regular int induction (i) is "transferred" over conversion into byte induction (k).
732 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
733 EXPECT_STREQ("((1) * i + (0)):PrimInt", GetInductionInfo(store2->InputAt(1), 0).c_str());
734 EXPECT_STREQ("((1) * i + (1)):PrimInt", GetInductionInfo(increment_[0], 0).c_str());
735
736 // Type matters!
737 EXPECT_FALSE(HaveSameInduction(store1->InputAt(1), store2->InputAt(1)));
738
739 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700740 EXPECT_STREQ("((100) (TC-loop) ((0) < (100)))", GetTripCount(0).c_str());
Aart Bik78296912016-03-25 13:14:53 -0700741}
742
Aart Bikcc42be02016-10-20 16:14:16 -0700743TEST_F(InductionVarAnalysisTest, ByteInductionDerivedIntLoopControl) {
744 // Setup:
745 // for (int i = 0; i < 100; i++) {
746 // k = (byte) i;
747 // a[k] = 0;
748 // k = k + 1
749 // a[k] = 0;
750 // }
751 BuildLoopNest(1);
752 HInstruction* conv = InsertInstruction(
753 new (&allocator_) HTypeConversion(Primitive::kPrimByte, basic_[0], -1), 0);
754 HInstruction* store1 = InsertArrayStore(conv, 0);
755 HInstruction* add = InsertInstruction(
756 new (&allocator_) HAdd(Primitive::kPrimInt, conv, constant1_), 0);
757 HInstruction* store2 = InsertArrayStore(add, 0);
758
759 PerformInductionVarAnalysis();
760
761 // Byte induction (k) is "transferred" over conversion into addition (k + 1).
762 // This means only values within byte range can be trusted (even though
763 // addition can jump out of the range of course).
764 EXPECT_STREQ("((1) * i + (0)):PrimByte", GetInductionInfo(store1->InputAt(1), 0).c_str());
765 EXPECT_STREQ("((1) * i + (1)):PrimByte", GetInductionInfo(store2->InputAt(1), 0).c_str());
766}
767
Aart Bik0d345cf2016-03-16 10:49:38 -0700768TEST_F(InductionVarAnalysisTest, ByteLoopControl1) {
769 // Setup:
770 // for (byte i = -128; i < 127; i++) { // just fits!
771 // }
772 BuildLoopNest(1);
773 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
774 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
775 ifs->ReplaceInput(graph_->GetIntConstant(127), 1);
776 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
777 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
778 basic_[0]->ReplaceInput(conv, 1);
779 PerformInductionVarAnalysis();
780
781 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
782 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700783 EXPECT_STREQ("(((127) - (-128)) (TC-loop) ((-128) < (127)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700784}
785
786TEST_F(InductionVarAnalysisTest, ByteLoopControl2) {
787 // Setup:
788 // for (byte i = -128; i < 128; i++) { // infinite loop!
789 // }
790 BuildLoopNest(1);
791 basic_[0]->ReplaceInput(graph_->GetIntConstant(-128), 0);
792 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
793 ifs->ReplaceInput(graph_->GetIntConstant(128), 1);
794 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimByte, increment_[0], -1);
795 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
796 basic_[0]->ReplaceInput(conv, 1);
797 PerformInductionVarAnalysis();
798
799 EXPECT_STREQ("((1) * i + ((-128) + (1))):PrimByte", GetInductionInfo(increment_[0], 0).c_str());
800 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -0700801 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700802}
803
804TEST_F(InductionVarAnalysisTest, ShortLoopControl1) {
805 // Setup:
806 // for (short i = -32768; i < 32767; i++) { // just fits!
807 // }
808 BuildLoopNest(1);
809 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
810 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
811 ifs->ReplaceInput(graph_->GetIntConstant(32767), 1);
812 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
813 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
814 basic_[0]->ReplaceInput(conv, 1);
815 PerformInductionVarAnalysis();
816
817 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
818 GetInductionInfo(increment_[0], 0).c_str());
819 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700820 EXPECT_STREQ("(((32767) - (-32768)) (TC-loop) ((-32768) < (32767)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700821}
822
823TEST_F(InductionVarAnalysisTest, ShortLoopControl2) {
824 // Setup:
825 // for (short i = -32768; i < 32768; i++) { // infinite loop!
826 // }
827 BuildLoopNest(1);
828 basic_[0]->ReplaceInput(graph_->GetIntConstant(-32768), 0);
829 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
830 ifs->ReplaceInput(graph_->GetIntConstant(32768), 1);
831 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimShort, increment_[0], -1);
832 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
833 basic_[0]->ReplaceInput(conv, 1);
834 PerformInductionVarAnalysis();
835
836 EXPECT_STREQ("((1) * i + ((-32768) + (1))):PrimShort",
837 GetInductionInfo(increment_[0], 0).c_str());
838 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -0700839 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700840}
841
842TEST_F(InductionVarAnalysisTest, CharLoopControl1) {
843 // Setup:
844 // for (char i = 0; i < 65535; i++) { // just fits!
845 // }
846 BuildLoopNest(1);
847 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
848 ifs->ReplaceInput(graph_->GetIntConstant(65535), 1);
849 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
850 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
851 basic_[0]->ReplaceInput(conv, 1);
852 PerformInductionVarAnalysis();
853
854 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
855 // Trip-count.
Aart Bik009cace2016-09-16 10:15:19 -0700856 EXPECT_STREQ("((65535) (TC-loop) ((0) < (65535)))", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700857}
858
859TEST_F(InductionVarAnalysisTest, CharLoopControl2) {
860 // Setup:
861 // for (char i = 0; i < 65536; i++) { // infinite loop!
862 // }
863 BuildLoopNest(1);
864 HInstruction* ifs = loop_header_[0]->GetLastInstruction()->GetPrevious();
865 ifs->ReplaceInput(graph_->GetIntConstant(65536), 1);
866 HInstruction* conv = new(&allocator_) HTypeConversion(Primitive::kPrimChar, increment_[0], -1);
867 loop_body_[0]->InsertInstructionBefore(conv, increment_[0]->GetNext());
868 basic_[0]->ReplaceInput(conv, 1);
869 PerformInductionVarAnalysis();
870
871 EXPECT_STREQ("((1) * i + (1)):PrimChar", GetInductionInfo(increment_[0], 0).c_str());
872 // Trip-count undefined.
Aart Bik009cace2016-09-16 10:15:19 -0700873 EXPECT_STREQ("", GetTripCount(0).c_str());
Aart Bik0d345cf2016-03-16 10:49:38 -0700874}
875
Aart Bik30efb4e2015-07-30 12:14:31 -0700876} // namespace art