blob: 3f5a6e7993e3b2156ebf3648de30e7b9b5db731b [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 "induction_var_analysis.h"
18
19namespace art {
20
21/**
22 * Returns true if instruction is invariant within the given loop.
23 */
24static bool IsLoopInvariant(HLoopInformation* loop, HInstruction* instruction) {
25 HLoopInformation* other_loop = instruction->GetBlock()->GetLoopInformation();
26 if (other_loop != loop) {
27 // If instruction does not occur in same loop, it is invariant
28 // if it appears in an outer loop (including no loop at all).
29 return other_loop == nullptr || loop->IsIn(*other_loop);
30 }
31 return false;
32}
33
34/**
35 * Returns true if instruction is proper entry-phi-operation for given loop
36 * (referred to as mu-operation in Gerlek's paper).
37 */
38static bool IsEntryPhi(HLoopInformation* loop, HInstruction* instruction) {
39 return
40 instruction->IsPhi() &&
41 instruction->InputCount() == 2 &&
42 instruction->GetBlock() == loop->GetHeader();
43}
44
45//
46// Class methods.
47//
48
49HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph)
50 : HOptimization(graph, kInductionPassName),
51 global_depth_(0),
52 stack_(graph->GetArena()->Adapter()),
53 scc_(graph->GetArena()->Adapter()),
Aart Bike609b7c2015-08-27 13:46:58 -070054 map_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
55 cycle_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
56 induction_(std::less<HLoopInformation*>(), graph->GetArena()->Adapter()) {
Aart Bik30efb4e2015-07-30 12:14:31 -070057}
58
59void HInductionVarAnalysis::Run() {
Aart Bike609b7c2015-08-27 13:46:58 -070060 // Detects sequence variables (generalized induction variables) during an inner-loop-first
61 // traversal of all loops using Gerlek's algorithm. The order is only relevant if outer
62 // loops would use induction information of inner loops (not currently done).
Aart Bik30efb4e2015-07-30 12:14:31 -070063 for (HPostOrderIterator it_graph(*graph_); !it_graph.Done(); it_graph.Advance()) {
64 HBasicBlock* graph_block = it_graph.Current();
65 if (graph_block->IsLoopHeader()) {
66 VisitLoop(graph_block->GetLoopInformation());
67 }
68 }
69}
70
71void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
72 // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
73 // algorithm. Due to the descendant-first nature, classification happens "on-demand".
74 global_depth_ = 0;
Aart Bike609b7c2015-08-27 13:46:58 -070075 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -070076 map_.clear();
77
78 for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
79 HBasicBlock* loop_block = it_loop.Current();
Aart Bike609b7c2015-08-27 13:46:58 -070080 DCHECK(loop_block->IsInLoop());
Aart Bik30efb4e2015-07-30 12:14:31 -070081 if (loop_block->GetLoopInformation() != loop) {
82 continue; // Inner loops already visited.
83 }
84 // Visit phi-operations and instructions.
85 for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
86 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -070087 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -070088 VisitNode(loop, instruction);
89 }
90 }
91 for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
92 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -070093 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -070094 VisitNode(loop, instruction);
95 }
96 }
97 }
98
Aart Bike609b7c2015-08-27 13:46:58 -070099 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700100 map_.clear();
Aart Bikd14c5952015-09-08 15:25:15 -0700101
102 // Determine the loop's trip count.
103 VisitControl(loop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700104}
105
106void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700107 const uint32_t d1 = ++global_depth_;
Aart Bike609b7c2015-08-27 13:46:58 -0700108 map_.Put(instruction, NodeInfo(d1));
Aart Bik30efb4e2015-07-30 12:14:31 -0700109 stack_.push_back(instruction);
110
111 // Visit all descendants.
112 uint32_t low = d1;
113 for (size_t i = 0, count = instruction->InputCount(); i < count; ++i) {
114 low = std::min(low, VisitDescendant(loop, instruction->InputAt(i)));
115 }
116
117 // Lower or found SCC?
118 if (low < d1) {
Aart Bike609b7c2015-08-27 13:46:58 -0700119 map_.find(instruction)->second.depth = low;
Aart Bik30efb4e2015-07-30 12:14:31 -0700120 } else {
121 scc_.clear();
122 cycle_.clear();
123
124 // Pop the stack to build the SCC for classification.
125 while (!stack_.empty()) {
126 HInstruction* x = stack_.back();
127 scc_.push_back(x);
128 stack_.pop_back();
Aart Bike609b7c2015-08-27 13:46:58 -0700129 map_.find(x)->second.done = true;
Aart Bik30efb4e2015-07-30 12:14:31 -0700130 if (x == instruction) {
131 break;
132 }
133 }
134
135 // Classify the SCC.
136 if (scc_.size() == 1 && !IsEntryPhi(loop, scc_[0])) {
137 ClassifyTrivial(loop, scc_[0]);
138 } else {
139 ClassifyNonTrivial(loop);
140 }
141
142 scc_.clear();
143 cycle_.clear();
144 }
145}
146
147uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
148 // If the definition is either outside the loop (loop invariant entry value)
149 // or assigned in inner loop (inner exit value), the traversal stops.
150 HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
151 if (otherLoop != loop) {
152 return global_depth_;
153 }
154
155 // Inspect descendant node.
Aart Bike609b7c2015-08-27 13:46:58 -0700156 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700157 VisitNode(loop, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700158 return map_.find(instruction)->second.depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700159 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700160 auto it = map_.find(instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700161 return it->second.done ? global_depth_ : it->second.depth;
162 }
163}
164
165void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
166 InductionInfo* info = nullptr;
167 if (instruction->IsPhi()) {
168 for (size_t i = 1, count = instruction->InputCount(); i < count; i++) {
169 info = TransferPhi(LookupInfo(loop, instruction->InputAt(0)),
170 LookupInfo(loop, instruction->InputAt(i)));
171 }
172 } else if (instruction->IsAdd()) {
173 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
174 LookupInfo(loop, instruction->InputAt(1)), kAdd);
175 } else if (instruction->IsSub()) {
176 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
177 LookupInfo(loop, instruction->InputAt(1)), kSub);
178 } else if (instruction->IsMul()) {
179 info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
180 LookupInfo(loop, instruction->InputAt(1)));
Aart Bike609b7c2015-08-27 13:46:58 -0700181 } else if (instruction->IsShl()) {
182 info = TransferShl(LookupInfo(loop, instruction->InputAt(0)),
183 LookupInfo(loop, instruction->InputAt(1)),
184 instruction->InputAt(0)->GetType());
Aart Bik30efb4e2015-07-30 12:14:31 -0700185 } else if (instruction->IsNeg()) {
186 info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
Aart Bike609b7c2015-08-27 13:46:58 -0700187 } else if (instruction->IsBoundsCheck()) {
188 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
189 } else if (instruction->IsTypeConversion()) {
190 HTypeConversion* conversion = instruction->AsTypeConversion();
191 // TODO: accept different conversion scenarios.
192 if (conversion->GetResultType() == conversion->GetInputType()) {
193 info = LookupInfo(loop, conversion->GetInput());
194 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700195 }
196
197 // Successfully classified?
198 if (info != nullptr) {
199 AssignInfo(loop, instruction, info);
200 }
201}
202
203void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
204 const size_t size = scc_.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700205 DCHECK_GE(size, 1u);
Aart Bik30efb4e2015-07-30 12:14:31 -0700206 HInstruction* phi = scc_[size - 1];
207 if (!IsEntryPhi(loop, phi)) {
208 return;
209 }
210 HInstruction* external = phi->InputAt(0);
211 HInstruction* internal = phi->InputAt(1);
212 InductionInfo* initial = LookupInfo(loop, external);
213 if (initial == nullptr || initial->induction_class != kInvariant) {
214 return;
215 }
216
217 // Singleton entry-phi-operation may be a wrap-around induction.
218 if (size == 1) {
219 InductionInfo* update = LookupInfo(loop, internal);
220 if (update != nullptr) {
Aart Bik471a2032015-09-04 18:22:11 -0700221 AssignInfo(loop, phi, CreateInduction(kWrapAround, initial, update));
Aart Bik30efb4e2015-07-30 12:14:31 -0700222 }
223 return;
224 }
225
226 // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700227 // temporary meaning to its nodes, seeded from the phi instruction and back.
Aart Bik30efb4e2015-07-30 12:14:31 -0700228 for (size_t i = 0; i < size - 1; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700229 HInstruction* instruction = scc_[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700230 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700231 if (instruction->IsPhi()) {
232 update = SolvePhi(loop, phi, instruction);
233 } else if (instruction->IsAdd()) {
234 update = SolveAddSub(
235 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
236 } else if (instruction->IsSub()) {
237 update = SolveAddSub(
238 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
Aart Bik30efb4e2015-07-30 12:14:31 -0700239 }
240 if (update == nullptr) {
241 return;
242 }
Aart Bike609b7c2015-08-27 13:46:58 -0700243 cycle_.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700244 }
245
Aart Bike609b7c2015-08-27 13:46:58 -0700246 // Success if the internal link received a meaning.
247 auto it = cycle_.find(internal);
248 if (it != cycle_.end()) {
249 InductionInfo* induction = it->second;
250 switch (induction->induction_class) {
251 case kInvariant:
252 // Classify phi (last element in scc_) and then the rest of the cycle "on-demand".
253 // Statements are scanned in the Tarjan SCC order, with phi first.
Aart Bik471a2032015-09-04 18:22:11 -0700254 AssignInfo(loop, phi, CreateInduction(kLinear, induction, initial));
Aart Bike609b7c2015-08-27 13:46:58 -0700255 for (size_t i = 0; i < size - 1; i++) {
256 ClassifyTrivial(loop, scc_[i]);
257 }
258 break;
259 case kPeriodic:
260 // Classify all elements in the cycle with the found periodic induction while rotating
261 // each first element to the end. Lastly, phi (last element in scc_) is classified.
262 // Statements are scanned in the reverse Tarjan SCC order, with phi last.
263 for (size_t i = 2; i <= size; i++) {
264 AssignInfo(loop, scc_[size - i], induction);
265 induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
266 }
267 AssignInfo(loop, phi, induction);
268 break;
269 default:
270 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700271 }
272 }
273}
274
Aart Bike609b7c2015-08-27 13:46:58 -0700275HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
276 InductionInfo* induction,
277 InductionInfo* last) {
278 // Rotates a periodic induction of the form
279 // (a, b, c, d, e)
280 // into
281 // (b, c, d, e, a)
282 // in preparation of assigning this to the previous variable in the sequence.
283 if (induction->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700284 return CreateInduction(kPeriodic, induction, last);
Aart Bike609b7c2015-08-27 13:46:58 -0700285 }
Aart Bik471a2032015-09-04 18:22:11 -0700286 return CreateInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
Aart Bike609b7c2015-08-27 13:46:58 -0700287}
288
Aart Bik30efb4e2015-07-30 12:14:31 -0700289HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(InductionInfo* a,
290 InductionInfo* b) {
291 // Transfer over a phi: if both inputs are identical, result is input.
292 if (InductionEqual(a, b)) {
293 return a;
294 }
295 return nullptr;
296}
297
298HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
299 InductionInfo* b,
300 InductionOp op) {
Aart Bike609b7c2015-08-27 13:46:58 -0700301 // Transfer over an addition or subtraction: any invariant, linear, wrap-around, or periodic
302 // can be combined with an invariant to yield a similar result. Even two linear inputs can
303 // be combined. All other combinations fail, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700304 if (a != nullptr && b != nullptr) {
305 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700306 return CreateInvariantOp(op, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700307 } else if (a->induction_class == kLinear && b->induction_class == kLinear) {
Aart Bik471a2032015-09-04 18:22:11 -0700308 return CreateInduction(
Aart Bike609b7c2015-08-27 13:46:58 -0700309 kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
310 } else if (a->induction_class == kInvariant) {
311 InductionInfo* new_a = b->op_a;
312 InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
313 if (b->induction_class != kLinear) {
314 DCHECK(b->induction_class == kWrapAround || b->induction_class == kPeriodic);
315 new_a = TransferAddSub(a, new_a, op);
316 } else if (op == kSub) { // Negation required.
317 new_a = TransferNeg(new_a);
318 }
Aart Bik471a2032015-09-04 18:22:11 -0700319 return CreateInduction(b->induction_class, new_a, new_b);
Aart Bike609b7c2015-08-27 13:46:58 -0700320 } else if (b->induction_class == kInvariant) {
321 InductionInfo* new_a = a->op_a;
322 InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
323 if (a->induction_class != kLinear) {
324 DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
325 new_a = TransferAddSub(new_a, b, op);
326 }
Aart Bik471a2032015-09-04 18:22:11 -0700327 return CreateInduction(a->induction_class, new_a, new_b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700328 }
329 }
330 return nullptr;
331}
332
333HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
334 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700335 // Transfer over a multiplication: any invariant, linear, wrap-around, or periodic
336 // can be multiplied with an invariant to yield a similar but multiplied result.
337 // Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700338 if (a != nullptr && b != nullptr) {
339 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700340 return CreateInvariantOp(kMul, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700341 } else if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700342 return CreateInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
Aart Bike609b7c2015-08-27 13:46:58 -0700343 } else if (b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700344 return CreateInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
Aart Bike609b7c2015-08-27 13:46:58 -0700345 }
346 }
347 return nullptr;
348}
349
350HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
351 InductionInfo* b,
Aart Bikd14c5952015-09-08 15:25:15 -0700352 Primitive::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700353 // Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
Aart Bik471a2032015-09-04 18:22:11 -0700354 int64_t value = -1;
355 if (a != nullptr && IsIntAndGet(b, &value)) {
Aart Bike609b7c2015-08-27 13:46:58 -0700356 // Obtain the constant needed for the multiplication. This yields an existing instruction
357 // if the constants is already there. Otherwise, this has a side effect on the HIR.
358 // The restriction on the shift factor avoids generating a negative constant
359 // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
360 // for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
Aart Bikd14c5952015-09-08 15:25:15 -0700361 if ((type == Primitive::kPrimInt && 0 <= value && value < 31) ||
362 (type == Primitive::kPrimLong && 0 <= value && value < 63)) {
363 return TransferMul(a, CreateConstant(1 << value, type));
Aart Bik30efb4e2015-07-30 12:14:31 -0700364 }
365 }
366 return nullptr;
367}
368
369HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
Aart Bike609b7c2015-08-27 13:46:58 -0700370 // Transfer over a unary negation: an invariant, linear, wrap-around, or periodic input
371 // yields a similar but negated induction as result.
Aart Bik30efb4e2015-07-30 12:14:31 -0700372 if (a != nullptr) {
373 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700374 return CreateInvariantOp(kNeg, nullptr, a);
Aart Bik30efb4e2015-07-30 12:14:31 -0700375 }
Aart Bik471a2032015-09-04 18:22:11 -0700376 return CreateInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
Aart Bik30efb4e2015-07-30 12:14:31 -0700377 }
378 return nullptr;
379}
380
Aart Bike609b7c2015-08-27 13:46:58 -0700381HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HLoopInformation* loop,
382 HInstruction* phi,
383 HInstruction* instruction) {
384 // Solve within a cycle over a phi: identical inputs are combined into that input as result.
385 const size_t count = instruction->InputCount();
386 DCHECK_GT(count, 0u);
387 auto ita = cycle_.find(instruction->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700388 if (ita != cycle_.end()) {
389 InductionInfo* a = ita->second;
390 for (size_t i = 1; i < count; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700391 auto itb = cycle_.find(instruction->InputAt(i));
392 if (itb == cycle_.end() || !HInductionVarAnalysis::InductionEqual(a, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700393 return nullptr;
394 }
395 }
396 return a;
397 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700398
Aart Bike609b7c2015-08-27 13:46:58 -0700399 // Solve within a cycle over another entry-phi: add invariants into a periodic.
400 if (IsEntryPhi(loop, instruction)) {
401 InductionInfo* a = LookupInfo(loop, instruction->InputAt(0));
402 if (a != nullptr && a->induction_class == kInvariant) {
403 if (instruction->InputAt(1) == phi) {
404 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700405 return CreateInduction(kPeriodic, a, initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700406 }
407 auto it = cycle_.find(instruction->InputAt(1));
408 if (it != cycle_.end()) {
409 InductionInfo* b = it->second;
410 if (b->induction_class == kPeriodic) {
Aart Bik471a2032015-09-04 18:22:11 -0700411 return CreateInduction(kPeriodic, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700412 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700413 }
414 }
415 }
Aart Bike609b7c2015-08-27 13:46:58 -0700416
Aart Bik30efb4e2015-07-30 12:14:31 -0700417 return nullptr;
418}
419
Aart Bike609b7c2015-08-27 13:46:58 -0700420HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
421 HInstruction* phi,
422 HInstruction* instruction,
423 HInstruction* x,
424 HInstruction* y,
425 InductionOp op,
426 bool is_first_call) {
427 // Solve within a cycle over an addition or subtraction: adding or subtracting an
428 // invariant value, seeded from phi, keeps adding to the stride of the induction.
429 InductionInfo* b = LookupInfo(loop, y);
430 if (b != nullptr && b->induction_class == kInvariant) {
431 if (x == phi) {
Aart Bik471a2032015-09-04 18:22:11 -0700432 return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700433 }
434 auto it = cycle_.find(x);
435 if (it != cycle_.end()) {
436 InductionInfo* a = it->second;
437 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700438 return CreateInvariantOp(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700439 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700440 }
441 }
Aart Bike609b7c2015-08-27 13:46:58 -0700442
443 // Try some alternatives before failing.
444 if (op == kAdd) {
445 // Try the other way around for an addition if considered for first time.
446 if (is_first_call) {
447 return SolveAddSub(loop, phi, instruction, y, x, op, false);
448 }
449 } else if (op == kSub) {
450 // Solve within a tight cycle for a periodic idiom k = c - k;
451 if (y == phi && instruction == phi->InputAt(1)) {
452 InductionInfo* a = LookupInfo(loop, x);
453 if (a != nullptr && a->induction_class == kInvariant) {
454 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700455 return CreateInduction(kPeriodic, CreateInvariantOp(kSub, a, initial), initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700456 }
457 }
458 }
459
Aart Bik30efb4e2015-07-30 12:14:31 -0700460 return nullptr;
461}
462
Aart Bikd14c5952015-09-08 15:25:15 -0700463void HInductionVarAnalysis::VisitControl(HLoopInformation* loop) {
464 HInstruction* control = loop->GetHeader()->GetLastInstruction();
465 if (control->IsIf()) {
466 HIf* ifs = control->AsIf();
467 HBasicBlock* if_true = ifs->IfTrueSuccessor();
468 HBasicBlock* if_false = ifs->IfFalseSuccessor();
469 HInstruction* if_expr = ifs->InputAt(0);
470 // Determine if loop has following structure in header.
471 // loop-header: ....
472 // if (condition) goto X
473 if (if_expr->IsCondition()) {
474 HCondition* condition = if_expr->AsCondition();
475 InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
476 InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
477 Primitive::Type type = condition->InputAt(0)->GetType();
478 // Determine if the loop control uses integral arithmetic and an if-exit (X outside) or an
479 // if-iterate (X inside), always expressed as if-iterate when passing into VisitCondition().
480 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
481 // Loop control is not 32/64-bit integral.
482 } else if (a == nullptr || b == nullptr) {
483 // Loop control is not a sequence.
484 } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
485 VisitCondition(loop, a, b, type, condition->GetOppositeCondition());
486 } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
487 VisitCondition(loop, a, b, type, condition->GetCondition());
488 }
489 }
490 }
491}
492
493void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
494 InductionInfo* a,
495 InductionInfo* b,
496 Primitive::Type type,
497 IfCondition cmp) {
498 if (a->induction_class == kInvariant && b->induction_class == kLinear) {
499 // Swap conditions (e.g. U > i is same as i < U).
500 switch (cmp) {
501 case kCondLT: VisitCondition(loop, b, a, type, kCondGT); break;
502 case kCondLE: VisitCondition(loop, b, a, type, kCondGE); break;
503 case kCondGT: VisitCondition(loop, b, a, type, kCondLT); break;
504 case kCondGE: VisitCondition(loop, b, a, type, kCondLE); break;
505 default: break;
506 }
507 } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
508 // Normalize a linear loop control with a constant, nonzero stride:
509 // stride > 0, either i < U or i <= U
510 // stride < 0, either i > U or i >= U
511 InductionInfo* stride = a->op_a;
512 InductionInfo* lo_val = a->op_b;
513 InductionInfo* hi_val = b;
514 int64_t value = -1;
515 if (IsIntAndGet(stride, &value)) {
516 if ((value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
517 (value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
518 bool is_strict = cmp == kCondLT || cmp == kCondGT;
519 VisitTripCount(loop, lo_val, hi_val, stride, value, type, is_strict);
520 }
521 }
522 }
523}
524
525void HInductionVarAnalysis::VisitTripCount(HLoopInformation* loop,
526 InductionInfo* lo_val,
527 InductionInfo* hi_val,
528 InductionInfo* stride,
529 int32_t stride_value,
530 Primitive::Type type,
531 bool is_strict) {
532 // Any loop of the general form:
533 //
534 // for (i = L; i <= U; i += S) // S > 0
535 // or for (i = L; i >= U; i += S) // S < 0
536 // .. i ..
537 //
538 // can be normalized into:
539 //
540 // for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
541 // .. L + S * n ..
542 //
543 // NOTE: The TC (trip-count) expression is only valid if the top-test path is taken at
544 // least once. Otherwise TC is 0. Also, the expression assumes the loop does not
545 // have any early-exits. Otherwise, TC is an upper bound.
546 //
547 bool cancels = is_strict && abs(stride_value) == 1; // compensation cancels conversion?
548 if (!cancels) {
549 // Convert exclusive integral inequality into inclusive integral inequality,
550 // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
551 if (is_strict) {
552 const InductionOp op = stride_value > 0 ? kSub : kAdd;
553 hi_val = CreateInvariantOp(op, hi_val, CreateConstant(1, type));
554 }
555 // Compensate for stride.
556 hi_val = CreateInvariantOp(kAdd, hi_val, stride);
557 }
558
559 // Assign the trip-count expression to the loop control. Clients that use the information
560 // should be aware that due to the L <= U assumption, the expression is only valid in the
561 // loop-body proper, and not yet in the loop-header. If the loop has any early exits, the
562 // trip-count forms a conservative upper bound on the number of loop iterations.
563 InductionInfo* trip_count =
564 CreateInvariantOp(kDiv, CreateInvariantOp(kSub, hi_val, lo_val), stride);
565 AssignInfo(loop, loop->GetHeader()->GetLastInstruction(), trip_count);
566}
567
Aart Bik30efb4e2015-07-30 12:14:31 -0700568void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
569 HInstruction* instruction,
570 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -0700571 auto it = induction_.find(loop);
572 if (it == induction_.end()) {
573 it = induction_.Put(loop,
574 ArenaSafeMap<HInstruction*, InductionInfo*>(
575 std::less<HInstruction*>(), graph_->GetArena()->Adapter()));
576 }
577 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700578}
579
Aart Bike609b7c2015-08-27 13:46:58 -0700580HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
581 HInstruction* instruction) {
582 auto it = induction_.find(loop);
583 if (it != induction_.end()) {
584 auto loop_it = it->second.find(instruction);
585 if (loop_it != it->second.end()) {
586 return loop_it->second;
587 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700588 }
Aart Bike609b7c2015-08-27 13:46:58 -0700589 if (IsLoopInvariant(loop, instruction)) {
Aart Bik471a2032015-09-04 18:22:11 -0700590 InductionInfo* info = CreateInvariantFetch(instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700591 AssignInfo(loop, instruction, info);
592 return info;
593 }
594 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -0700595}
596
Aart Bikd14c5952015-09-08 15:25:15 -0700597HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
598 Primitive::Type type) {
599 if (type == Primitive::kPrimInt) {
600 return CreateInvariantFetch(graph_->GetIntConstant(value));
601 }
602 DCHECK_EQ(type, Primitive::kPrimLong);
603 return CreateInvariantFetch(graph_->GetLongConstant(value));
604}
605
Aart Bik471a2032015-09-04 18:22:11 -0700606HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
607 InductionOp op,
608 InductionInfo* a,
609 InductionInfo* b) {
610 // Perform some light-weight simplifications during construction of a new invariant.
611 // This often safes memory and yields a more concise representation of the induction.
612 // More exhaustive simplifications are done by later phases once induction nodes are
613 // translated back into HIR code (e.g. by loop optimizations or BCE).
614 int64_t value = -1;
615 if (IsIntAndGet(a, &value)) {
616 if (value == 0) {
617 // Simplify 0 + b = b, 0 * b = 0.
618 if (op == kAdd) {
619 return b;
620 } else if (op == kMul) {
621 return a;
622 }
Aart Bikd14c5952015-09-08 15:25:15 -0700623 } else if (op == kMul) {
624 // Simplify 1 * b = b, -1 * b = -b
625 if (value == 1) {
626 return b;
627 } else if (value == -1) {
628 op = kNeg;
629 a = nullptr;
630 }
Aart Bik471a2032015-09-04 18:22:11 -0700631 }
632 }
633 if (IsIntAndGet(b, &value)) {
634 if (value == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700635 // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, -0 = 0.
Aart Bik471a2032015-09-04 18:22:11 -0700636 if (op == kAdd || op == kSub) {
637 return a;
638 } else if (op == kMul || op == kNeg) {
639 return b;
640 }
Aart Bikd14c5952015-09-08 15:25:15 -0700641 } else if (op == kMul || op == kDiv) {
642 // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
643 if (value == 1) {
644 return a;
645 } else if (value == -1) {
646 op = kNeg;
647 b = a;
648 a = nullptr;
649 }
Aart Bik471a2032015-09-04 18:22:11 -0700650 }
651 } else if (b->operation == kNeg) {
Aart Bikd14c5952015-09-08 15:25:15 -0700652 // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
653 if (op == kAdd) {
654 op = kSub;
655 b = b->op_b;
656 } else if (op == kSub) {
657 op = kAdd;
658 b = b->op_b;
659 } else if (op == kNeg) {
660 return b->op_b;
Aart Bik471a2032015-09-04 18:22:11 -0700661 }
662 }
663 return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
664}
665
Aart Bik30efb4e2015-07-30 12:14:31 -0700666bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
667 InductionInfo* info2) {
668 // Test structural equality only, without accounting for simplifications.
669 if (info1 != nullptr && info2 != nullptr) {
670 return
671 info1->induction_class == info2->induction_class &&
672 info1->operation == info2->operation &&
673 info1->fetch == info2->fetch &&
674 InductionEqual(info1->op_a, info2->op_a) &&
675 InductionEqual(info1->op_b, info2->op_b);
676 }
677 // Otherwise only two nullptrs are considered equal.
678 return info1 == info2;
679}
680
Aart Bik471a2032015-09-04 18:22:11 -0700681bool HInductionVarAnalysis::IsIntAndGet(InductionInfo* info, int64_t* value) {
682 if (info != nullptr && info->induction_class == kInvariant && info->operation == kFetch) {
683 DCHECK(info->fetch);
684 if (info->fetch->IsIntConstant()) {
685 *value = info->fetch->AsIntConstant()->GetValue();
686 return true;
687 } else if (info->fetch->IsLongConstant()) {
688 *value = info->fetch->AsLongConstant()->GetValue();
689 return true;
690 }
691 }
692 return false;
693}
694
Aart Bik30efb4e2015-07-30 12:14:31 -0700695std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
696 if (info != nullptr) {
697 if (info->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700698 int64_t value = -1;
Aart Bik30efb4e2015-07-30 12:14:31 -0700699 std::string inv = "(";
700 inv += InductionToString(info->op_a);
701 switch (info->operation) {
Aart Bike609b7c2015-08-27 13:46:58 -0700702 case kNop: inv += " @ "; break;
703 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700704 case kSub:
Aart Bike609b7c2015-08-27 13:46:58 -0700705 case kNeg: inv += " - "; break;
706 case kMul: inv += " * "; break;
707 case kDiv: inv += " / "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700708 case kFetch:
Aart Bike609b7c2015-08-27 13:46:58 -0700709 DCHECK(info->fetch);
Aart Bik471a2032015-09-04 18:22:11 -0700710 if (IsIntAndGet(info, &value)) {
711 inv += std::to_string(value);
712 } else {
713 inv += std::to_string(info->fetch->GetId()) + ":" + info->fetch->DebugName();
714 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700715 break;
716 }
717 inv += InductionToString(info->op_b);
718 return inv + ")";
719 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700720 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700721 if (info->induction_class == kLinear) {
722 return "(" + InductionToString(info->op_a) + " * i + " +
723 InductionToString(info->op_b) + ")";
724 } else if (info->induction_class == kWrapAround) {
725 return "wrap(" + InductionToString(info->op_a) + ", " +
726 InductionToString(info->op_b) + ")";
727 } else if (info->induction_class == kPeriodic) {
728 return "periodic(" + InductionToString(info->op_a) + ", " +
729 InductionToString(info->op_b) + ")";
730 }
731 }
732 }
733 return "";
734}
735
736} // namespace art