blob: 8b38414de0c7457b2897dfe3768274934093140d [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
Aart Bike609b7c2015-08-27 13:46:58 -070045/**
46 * Returns true for 32/64-bit integral constant, passing its value as output parameter.
47 */
48static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
49 if (instruction->IsIntConstant()) {
50 *value = instruction->AsIntConstant()->GetValue();
51 return true;
52 } else if (instruction->IsLongConstant()) {
53 *value = instruction->AsLongConstant()->GetValue();
54 return true;
55 }
56 return false;
57}
58
59/**
60 * Returns a string representation of an instruction
61 * (for testing and debugging only).
62 */
63static std::string InstructionToString(HInstruction* instruction) {
64 if (instruction->IsIntConstant()) {
65 return std::to_string(instruction->AsIntConstant()->GetValue());
66 } else if (instruction->IsLongConstant()) {
67 return std::to_string(instruction->AsLongConstant()->GetValue()) + "L";
68 }
69 return std::to_string(instruction->GetId()) + ":" + instruction->DebugName();
70}
71
Aart Bik30efb4e2015-07-30 12:14:31 -070072//
73// Class methods.
74//
75
76HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph)
77 : HOptimization(graph, kInductionPassName),
78 global_depth_(0),
79 stack_(graph->GetArena()->Adapter()),
80 scc_(graph->GetArena()->Adapter()),
Aart Bike609b7c2015-08-27 13:46:58 -070081 map_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
82 cycle_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
83 induction_(std::less<HLoopInformation*>(), graph->GetArena()->Adapter()) {
Aart Bik30efb4e2015-07-30 12:14:31 -070084}
85
86void HInductionVarAnalysis::Run() {
Aart Bike609b7c2015-08-27 13:46:58 -070087 // Detects sequence variables (generalized induction variables) during an inner-loop-first
88 // traversal of all loops using Gerlek's algorithm. The order is only relevant if outer
89 // loops would use induction information of inner loops (not currently done).
Aart Bik30efb4e2015-07-30 12:14:31 -070090 for (HPostOrderIterator it_graph(*graph_); !it_graph.Done(); it_graph.Advance()) {
91 HBasicBlock* graph_block = it_graph.Current();
92 if (graph_block->IsLoopHeader()) {
93 VisitLoop(graph_block->GetLoopInformation());
94 }
95 }
96}
97
98void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
99 // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
100 // algorithm. Due to the descendant-first nature, classification happens "on-demand".
101 global_depth_ = 0;
Aart Bike609b7c2015-08-27 13:46:58 -0700102 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700103 map_.clear();
104
105 for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
106 HBasicBlock* loop_block = it_loop.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700107 DCHECK(loop_block->IsInLoop());
Aart Bik30efb4e2015-07-30 12:14:31 -0700108 if (loop_block->GetLoopInformation() != loop) {
109 continue; // Inner loops already visited.
110 }
111 // Visit phi-operations and instructions.
112 for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
113 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700114 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700115 VisitNode(loop, instruction);
116 }
117 }
118 for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
119 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700120 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700121 VisitNode(loop, instruction);
122 }
123 }
124 }
125
Aart Bike609b7c2015-08-27 13:46:58 -0700126 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700127 map_.clear();
128}
129
130void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700131 const uint32_t d1 = ++global_depth_;
Aart Bike609b7c2015-08-27 13:46:58 -0700132 map_.Put(instruction, NodeInfo(d1));
Aart Bik30efb4e2015-07-30 12:14:31 -0700133 stack_.push_back(instruction);
134
135 // Visit all descendants.
136 uint32_t low = d1;
137 for (size_t i = 0, count = instruction->InputCount(); i < count; ++i) {
138 low = std::min(low, VisitDescendant(loop, instruction->InputAt(i)));
139 }
140
141 // Lower or found SCC?
142 if (low < d1) {
Aart Bike609b7c2015-08-27 13:46:58 -0700143 map_.find(instruction)->second.depth = low;
Aart Bik30efb4e2015-07-30 12:14:31 -0700144 } else {
145 scc_.clear();
146 cycle_.clear();
147
148 // Pop the stack to build the SCC for classification.
149 while (!stack_.empty()) {
150 HInstruction* x = stack_.back();
151 scc_.push_back(x);
152 stack_.pop_back();
Aart Bike609b7c2015-08-27 13:46:58 -0700153 map_.find(x)->second.done = true;
Aart Bik30efb4e2015-07-30 12:14:31 -0700154 if (x == instruction) {
155 break;
156 }
157 }
158
159 // Classify the SCC.
160 if (scc_.size() == 1 && !IsEntryPhi(loop, scc_[0])) {
161 ClassifyTrivial(loop, scc_[0]);
162 } else {
163 ClassifyNonTrivial(loop);
164 }
165
166 scc_.clear();
167 cycle_.clear();
168 }
169}
170
171uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
172 // If the definition is either outside the loop (loop invariant entry value)
173 // or assigned in inner loop (inner exit value), the traversal stops.
174 HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
175 if (otherLoop != loop) {
176 return global_depth_;
177 }
178
179 // Inspect descendant node.
Aart Bike609b7c2015-08-27 13:46:58 -0700180 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700181 VisitNode(loop, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700182 return map_.find(instruction)->second.depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700183 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700184 auto it = map_.find(instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700185 return it->second.done ? global_depth_ : it->second.depth;
186 }
187}
188
189void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
190 InductionInfo* info = nullptr;
191 if (instruction->IsPhi()) {
192 for (size_t i = 1, count = instruction->InputCount(); i < count; i++) {
193 info = TransferPhi(LookupInfo(loop, instruction->InputAt(0)),
194 LookupInfo(loop, instruction->InputAt(i)));
195 }
196 } else if (instruction->IsAdd()) {
197 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
198 LookupInfo(loop, instruction->InputAt(1)), kAdd);
199 } else if (instruction->IsSub()) {
200 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
201 LookupInfo(loop, instruction->InputAt(1)), kSub);
202 } else if (instruction->IsMul()) {
203 info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
204 LookupInfo(loop, instruction->InputAt(1)));
Aart Bike609b7c2015-08-27 13:46:58 -0700205 } else if (instruction->IsShl()) {
206 info = TransferShl(LookupInfo(loop, instruction->InputAt(0)),
207 LookupInfo(loop, instruction->InputAt(1)),
208 instruction->InputAt(0)->GetType());
Aart Bik30efb4e2015-07-30 12:14:31 -0700209 } else if (instruction->IsNeg()) {
210 info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
Aart Bike609b7c2015-08-27 13:46:58 -0700211 } else if (instruction->IsBoundsCheck()) {
212 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
213 } else if (instruction->IsTypeConversion()) {
214 HTypeConversion* conversion = instruction->AsTypeConversion();
215 // TODO: accept different conversion scenarios.
216 if (conversion->GetResultType() == conversion->GetInputType()) {
217 info = LookupInfo(loop, conversion->GetInput());
218 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700219 }
220
221 // Successfully classified?
222 if (info != nullptr) {
223 AssignInfo(loop, instruction, info);
224 }
225}
226
227void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
228 const size_t size = scc_.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700229 DCHECK_GE(size, 1u);
Aart Bik30efb4e2015-07-30 12:14:31 -0700230 HInstruction* phi = scc_[size - 1];
231 if (!IsEntryPhi(loop, phi)) {
232 return;
233 }
234 HInstruction* external = phi->InputAt(0);
235 HInstruction* internal = phi->InputAt(1);
236 InductionInfo* initial = LookupInfo(loop, external);
237 if (initial == nullptr || initial->induction_class != kInvariant) {
238 return;
239 }
240
241 // Singleton entry-phi-operation may be a wrap-around induction.
242 if (size == 1) {
243 InductionInfo* update = LookupInfo(loop, internal);
244 if (update != nullptr) {
Aart Bike609b7c2015-08-27 13:46:58 -0700245 AssignInfo(loop, phi, NewInduction(kWrapAround, initial, update));
Aart Bik30efb4e2015-07-30 12:14:31 -0700246 }
247 return;
248 }
249
250 // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700251 // temporary meaning to its nodes, seeded from the phi instruction and back.
Aart Bik30efb4e2015-07-30 12:14:31 -0700252 for (size_t i = 0; i < size - 1; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700253 HInstruction* instruction = scc_[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700254 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700255 if (instruction->IsPhi()) {
256 update = SolvePhi(loop, phi, instruction);
257 } else if (instruction->IsAdd()) {
258 update = SolveAddSub(
259 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
260 } else if (instruction->IsSub()) {
261 update = SolveAddSub(
262 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
Aart Bik30efb4e2015-07-30 12:14:31 -0700263 }
264 if (update == nullptr) {
265 return;
266 }
Aart Bike609b7c2015-08-27 13:46:58 -0700267 cycle_.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700268 }
269
Aart Bike609b7c2015-08-27 13:46:58 -0700270 // Success if the internal link received a meaning.
271 auto it = cycle_.find(internal);
272 if (it != cycle_.end()) {
273 InductionInfo* induction = it->second;
274 switch (induction->induction_class) {
275 case kInvariant:
276 // Classify phi (last element in scc_) and then the rest of the cycle "on-demand".
277 // Statements are scanned in the Tarjan SCC order, with phi first.
278 AssignInfo(loop, phi, NewInduction(kLinear, induction, initial));
279 for (size_t i = 0; i < size - 1; i++) {
280 ClassifyTrivial(loop, scc_[i]);
281 }
282 break;
283 case kPeriodic:
284 // Classify all elements in the cycle with the found periodic induction while rotating
285 // each first element to the end. Lastly, phi (last element in scc_) is classified.
286 // Statements are scanned in the reverse Tarjan SCC order, with phi last.
287 for (size_t i = 2; i <= size; i++) {
288 AssignInfo(loop, scc_[size - i], induction);
289 induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
290 }
291 AssignInfo(loop, phi, induction);
292 break;
293 default:
294 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700295 }
296 }
297}
298
Aart Bike609b7c2015-08-27 13:46:58 -0700299HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
300 InductionInfo* induction,
301 InductionInfo* last) {
302 // Rotates a periodic induction of the form
303 // (a, b, c, d, e)
304 // into
305 // (b, c, d, e, a)
306 // in preparation of assigning this to the previous variable in the sequence.
307 if (induction->induction_class == kInvariant) {
308 return NewInduction(kPeriodic, induction, last);
309 }
310 return NewInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
311}
312
Aart Bik30efb4e2015-07-30 12:14:31 -0700313HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(InductionInfo* a,
314 InductionInfo* b) {
315 // Transfer over a phi: if both inputs are identical, result is input.
316 if (InductionEqual(a, b)) {
317 return a;
318 }
319 return nullptr;
320}
321
322HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
323 InductionInfo* b,
324 InductionOp op) {
Aart Bike609b7c2015-08-27 13:46:58 -0700325 // Transfer over an addition or subtraction: any invariant, linear, wrap-around, or periodic
326 // can be combined with an invariant to yield a similar result. Even two linear inputs can
327 // be combined. All other combinations fail, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700328 if (a != nullptr && b != nullptr) {
329 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bike609b7c2015-08-27 13:46:58 -0700330 return NewInvariantOp(op, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700331 } else if (a->induction_class == kLinear && b->induction_class == kLinear) {
Aart Bike609b7c2015-08-27 13:46:58 -0700332 return NewInduction(
333 kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
334 } else if (a->induction_class == kInvariant) {
335 InductionInfo* new_a = b->op_a;
336 InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
337 if (b->induction_class != kLinear) {
338 DCHECK(b->induction_class == kWrapAround || b->induction_class == kPeriodic);
339 new_a = TransferAddSub(a, new_a, op);
340 } else if (op == kSub) { // Negation required.
341 new_a = TransferNeg(new_a);
342 }
343 return NewInduction(b->induction_class, new_a, new_b);
344 } else if (b->induction_class == kInvariant) {
345 InductionInfo* new_a = a->op_a;
346 InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
347 if (a->induction_class != kLinear) {
348 DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
349 new_a = TransferAddSub(new_a, b, op);
350 }
351 return NewInduction(a->induction_class, new_a, new_b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700352 }
353 }
354 return nullptr;
355}
356
357HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
358 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700359 // Transfer over a multiplication: any invariant, linear, wrap-around, or periodic
360 // can be multiplied with an invariant to yield a similar but multiplied result.
361 // Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700362 if (a != nullptr && b != nullptr) {
363 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bike609b7c2015-08-27 13:46:58 -0700364 return NewInvariantOp(kMul, a, b);
365 } else if (a->induction_class == kInvariant) {
366 return NewInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
367 } else if (b->induction_class == kInvariant) {
368 return NewInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
369 }
370 }
371 return nullptr;
372}
373
374HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
375 InductionInfo* b,
376 Primitive::Type t) {
377 // Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
378 if (a != nullptr && b != nullptr && b->induction_class == kInvariant && b->operation == kFetch) {
379 int64_t value = -1;
380 // Obtain the constant needed for the multiplication. This yields an existing instruction
381 // if the constants is already there. Otherwise, this has a side effect on the HIR.
382 // The restriction on the shift factor avoids generating a negative constant
383 // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
384 // for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
385 if (IsIntAndGet(b->fetch, &value)) {
386 if (t == Primitive::kPrimInt && 0 <= value && value < 31) {
387 return TransferMul(a, NewInvariantFetch(graph_->GetIntConstant(1 << value)));
388 } else if (t == Primitive::kPrimLong && 0 <= value && value < 63) {
389 return TransferMul(a, NewInvariantFetch(graph_->GetLongConstant(1L << value)));
390 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700391 }
392 }
393 return nullptr;
394}
395
396HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
Aart Bike609b7c2015-08-27 13:46:58 -0700397 // Transfer over a unary negation: an invariant, linear, wrap-around, or periodic input
398 // yields a similar but negated induction as result.
Aart Bik30efb4e2015-07-30 12:14:31 -0700399 if (a != nullptr) {
400 if (a->induction_class == kInvariant) {
Aart Bike609b7c2015-08-27 13:46:58 -0700401 return NewInvariantOp(kNeg, nullptr, a);
Aart Bik30efb4e2015-07-30 12:14:31 -0700402 }
Aart Bike609b7c2015-08-27 13:46:58 -0700403 return NewInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
Aart Bik30efb4e2015-07-30 12:14:31 -0700404 }
405 return nullptr;
406}
407
Aart Bike609b7c2015-08-27 13:46:58 -0700408HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HLoopInformation* loop,
409 HInstruction* phi,
410 HInstruction* instruction) {
411 // Solve within a cycle over a phi: identical inputs are combined into that input as result.
412 const size_t count = instruction->InputCount();
413 DCHECK_GT(count, 0u);
414 auto ita = cycle_.find(instruction->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700415 if (ita != cycle_.end()) {
416 InductionInfo* a = ita->second;
417 for (size_t i = 1; i < count; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700418 auto itb = cycle_.find(instruction->InputAt(i));
419 if (itb == cycle_.end() || !HInductionVarAnalysis::InductionEqual(a, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700420 return nullptr;
421 }
422 }
423 return a;
424 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700425
Aart Bike609b7c2015-08-27 13:46:58 -0700426 // Solve within a cycle over another entry-phi: add invariants into a periodic.
427 if (IsEntryPhi(loop, instruction)) {
428 InductionInfo* a = LookupInfo(loop, instruction->InputAt(0));
429 if (a != nullptr && a->induction_class == kInvariant) {
430 if (instruction->InputAt(1) == phi) {
431 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
432 return NewInduction(kPeriodic, a, initial);
433 }
434 auto it = cycle_.find(instruction->InputAt(1));
435 if (it != cycle_.end()) {
436 InductionInfo* b = it->second;
437 if (b->induction_class == kPeriodic) {
438 return NewInduction(kPeriodic, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700439 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700440 }
441 }
442 }
Aart Bike609b7c2015-08-27 13:46:58 -0700443
Aart Bik30efb4e2015-07-30 12:14:31 -0700444 return nullptr;
445}
446
Aart Bike609b7c2015-08-27 13:46:58 -0700447HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
448 HInstruction* phi,
449 HInstruction* instruction,
450 HInstruction* x,
451 HInstruction* y,
452 InductionOp op,
453 bool is_first_call) {
454 // Solve within a cycle over an addition or subtraction: adding or subtracting an
455 // invariant value, seeded from phi, keeps adding to the stride of the induction.
456 InductionInfo* b = LookupInfo(loop, y);
457 if (b != nullptr && b->induction_class == kInvariant) {
458 if (x == phi) {
459 return (op == kAdd) ? b : NewInvariantOp(kNeg, nullptr, b);
460 }
461 auto it = cycle_.find(x);
462 if (it != cycle_.end()) {
463 InductionInfo* a = it->second;
464 if (a->induction_class == kInvariant) {
465 return NewInvariantOp(op, a, b);
466 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700467 }
468 }
Aart Bike609b7c2015-08-27 13:46:58 -0700469
470 // Try some alternatives before failing.
471 if (op == kAdd) {
472 // Try the other way around for an addition if considered for first time.
473 if (is_first_call) {
474 return SolveAddSub(loop, phi, instruction, y, x, op, false);
475 }
476 } else if (op == kSub) {
477 // Solve within a tight cycle for a periodic idiom k = c - k;
478 if (y == phi && instruction == phi->InputAt(1)) {
479 InductionInfo* a = LookupInfo(loop, x);
480 if (a != nullptr && a->induction_class == kInvariant) {
481 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
482 return NewInduction(kPeriodic, NewInvariantOp(kSub, a, initial), initial);
483 }
484 }
485 }
486
Aart Bik30efb4e2015-07-30 12:14:31 -0700487 return nullptr;
488}
489
490void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
491 HInstruction* instruction,
492 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -0700493 auto it = induction_.find(loop);
494 if (it == induction_.end()) {
495 it = induction_.Put(loop,
496 ArenaSafeMap<HInstruction*, InductionInfo*>(
497 std::less<HInstruction*>(), graph_->GetArena()->Adapter()));
498 }
499 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700500}
501
Aart Bike609b7c2015-08-27 13:46:58 -0700502HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
503 HInstruction* instruction) {
504 auto it = induction_.find(loop);
505 if (it != induction_.end()) {
506 auto loop_it = it->second.find(instruction);
507 if (loop_it != it->second.end()) {
508 return loop_it->second;
509 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700510 }
Aart Bike609b7c2015-08-27 13:46:58 -0700511 if (IsLoopInvariant(loop, instruction)) {
512 InductionInfo* info = NewInvariantFetch(instruction);
513 AssignInfo(loop, instruction, info);
514 return info;
515 }
516 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -0700517}
518
519bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
520 InductionInfo* info2) {
521 // Test structural equality only, without accounting for simplifications.
522 if (info1 != nullptr && info2 != nullptr) {
523 return
524 info1->induction_class == info2->induction_class &&
525 info1->operation == info2->operation &&
526 info1->fetch == info2->fetch &&
527 InductionEqual(info1->op_a, info2->op_a) &&
528 InductionEqual(info1->op_b, info2->op_b);
529 }
530 // Otherwise only two nullptrs are considered equal.
531 return info1 == info2;
532}
533
534std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
535 if (info != nullptr) {
536 if (info->induction_class == kInvariant) {
537 std::string inv = "(";
538 inv += InductionToString(info->op_a);
539 switch (info->operation) {
Aart Bike609b7c2015-08-27 13:46:58 -0700540 case kNop: inv += " @ "; break;
541 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700542 case kSub:
Aart Bike609b7c2015-08-27 13:46:58 -0700543 case kNeg: inv += " - "; break;
544 case kMul: inv += " * "; break;
545 case kDiv: inv += " / "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700546 case kFetch:
Aart Bike609b7c2015-08-27 13:46:58 -0700547 DCHECK(info->fetch);
548 inv += InstructionToString(info->fetch);
Aart Bik30efb4e2015-07-30 12:14:31 -0700549 break;
550 }
551 inv += InductionToString(info->op_b);
552 return inv + ")";
553 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700554 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700555 if (info->induction_class == kLinear) {
556 return "(" + InductionToString(info->op_a) + " * i + " +
557 InductionToString(info->op_b) + ")";
558 } else if (info->induction_class == kWrapAround) {
559 return "wrap(" + InductionToString(info->op_a) + ", " +
560 InductionToString(info->op_b) + ")";
561 } else if (info->induction_class == kPeriodic) {
562 return "periodic(" + InductionToString(info->op_a) + ", " +
563 InductionToString(info->op_b) + ")";
564 }
565 }
566 }
567 return "";
568}
569
570} // namespace art