blob: 300ffbe03d9e6a440564ecf6acdf7ff724c474c9 [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();
101}
102
103void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700104 const uint32_t d1 = ++global_depth_;
Aart Bike609b7c2015-08-27 13:46:58 -0700105 map_.Put(instruction, NodeInfo(d1));
Aart Bik30efb4e2015-07-30 12:14:31 -0700106 stack_.push_back(instruction);
107
108 // Visit all descendants.
109 uint32_t low = d1;
110 for (size_t i = 0, count = instruction->InputCount(); i < count; ++i) {
111 low = std::min(low, VisitDescendant(loop, instruction->InputAt(i)));
112 }
113
114 // Lower or found SCC?
115 if (low < d1) {
Aart Bike609b7c2015-08-27 13:46:58 -0700116 map_.find(instruction)->second.depth = low;
Aart Bik30efb4e2015-07-30 12:14:31 -0700117 } else {
118 scc_.clear();
119 cycle_.clear();
120
121 // Pop the stack to build the SCC for classification.
122 while (!stack_.empty()) {
123 HInstruction* x = stack_.back();
124 scc_.push_back(x);
125 stack_.pop_back();
Aart Bike609b7c2015-08-27 13:46:58 -0700126 map_.find(x)->second.done = true;
Aart Bik30efb4e2015-07-30 12:14:31 -0700127 if (x == instruction) {
128 break;
129 }
130 }
131
132 // Classify the SCC.
133 if (scc_.size() == 1 && !IsEntryPhi(loop, scc_[0])) {
134 ClassifyTrivial(loop, scc_[0]);
135 } else {
136 ClassifyNonTrivial(loop);
137 }
138
139 scc_.clear();
140 cycle_.clear();
141 }
142}
143
144uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
145 // If the definition is either outside the loop (loop invariant entry value)
146 // or assigned in inner loop (inner exit value), the traversal stops.
147 HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
148 if (otherLoop != loop) {
149 return global_depth_;
150 }
151
152 // Inspect descendant node.
Aart Bike609b7c2015-08-27 13:46:58 -0700153 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700154 VisitNode(loop, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700155 return map_.find(instruction)->second.depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700156 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700157 auto it = map_.find(instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700158 return it->second.done ? global_depth_ : it->second.depth;
159 }
160}
161
162void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
163 InductionInfo* info = nullptr;
164 if (instruction->IsPhi()) {
165 for (size_t i = 1, count = instruction->InputCount(); i < count; i++) {
166 info = TransferPhi(LookupInfo(loop, instruction->InputAt(0)),
167 LookupInfo(loop, instruction->InputAt(i)));
168 }
169 } else if (instruction->IsAdd()) {
170 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
171 LookupInfo(loop, instruction->InputAt(1)), kAdd);
172 } else if (instruction->IsSub()) {
173 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
174 LookupInfo(loop, instruction->InputAt(1)), kSub);
175 } else if (instruction->IsMul()) {
176 info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
177 LookupInfo(loop, instruction->InputAt(1)));
Aart Bike609b7c2015-08-27 13:46:58 -0700178 } else if (instruction->IsShl()) {
179 info = TransferShl(LookupInfo(loop, instruction->InputAt(0)),
180 LookupInfo(loop, instruction->InputAt(1)),
181 instruction->InputAt(0)->GetType());
Aart Bik30efb4e2015-07-30 12:14:31 -0700182 } else if (instruction->IsNeg()) {
183 info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
Aart Bike609b7c2015-08-27 13:46:58 -0700184 } else if (instruction->IsBoundsCheck()) {
185 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
186 } else if (instruction->IsTypeConversion()) {
187 HTypeConversion* conversion = instruction->AsTypeConversion();
188 // TODO: accept different conversion scenarios.
189 if (conversion->GetResultType() == conversion->GetInputType()) {
190 info = LookupInfo(loop, conversion->GetInput());
191 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700192 }
193
194 // Successfully classified?
195 if (info != nullptr) {
196 AssignInfo(loop, instruction, info);
197 }
198}
199
200void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
201 const size_t size = scc_.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700202 DCHECK_GE(size, 1u);
Aart Bik30efb4e2015-07-30 12:14:31 -0700203 HInstruction* phi = scc_[size - 1];
204 if (!IsEntryPhi(loop, phi)) {
205 return;
206 }
207 HInstruction* external = phi->InputAt(0);
208 HInstruction* internal = phi->InputAt(1);
209 InductionInfo* initial = LookupInfo(loop, external);
210 if (initial == nullptr || initial->induction_class != kInvariant) {
211 return;
212 }
213
214 // Singleton entry-phi-operation may be a wrap-around induction.
215 if (size == 1) {
216 InductionInfo* update = LookupInfo(loop, internal);
217 if (update != nullptr) {
Aart Bik471a2032015-09-04 18:22:11 -0700218 AssignInfo(loop, phi, CreateInduction(kWrapAround, initial, update));
Aart Bik30efb4e2015-07-30 12:14:31 -0700219 }
220 return;
221 }
222
223 // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700224 // temporary meaning to its nodes, seeded from the phi instruction and back.
Aart Bik30efb4e2015-07-30 12:14:31 -0700225 for (size_t i = 0; i < size - 1; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700226 HInstruction* instruction = scc_[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700227 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700228 if (instruction->IsPhi()) {
229 update = SolvePhi(loop, phi, instruction);
230 } else if (instruction->IsAdd()) {
231 update = SolveAddSub(
232 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
233 } else if (instruction->IsSub()) {
234 update = SolveAddSub(
235 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
Aart Bik30efb4e2015-07-30 12:14:31 -0700236 }
237 if (update == nullptr) {
238 return;
239 }
Aart Bike609b7c2015-08-27 13:46:58 -0700240 cycle_.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700241 }
242
Aart Bike609b7c2015-08-27 13:46:58 -0700243 // Success if the internal link received a meaning.
244 auto it = cycle_.find(internal);
245 if (it != cycle_.end()) {
246 InductionInfo* induction = it->second;
247 switch (induction->induction_class) {
248 case kInvariant:
249 // Classify phi (last element in scc_) and then the rest of the cycle "on-demand".
250 // Statements are scanned in the Tarjan SCC order, with phi first.
Aart Bik471a2032015-09-04 18:22:11 -0700251 AssignInfo(loop, phi, CreateInduction(kLinear, induction, initial));
Aart Bike609b7c2015-08-27 13:46:58 -0700252 for (size_t i = 0; i < size - 1; i++) {
253 ClassifyTrivial(loop, scc_[i]);
254 }
255 break;
256 case kPeriodic:
257 // Classify all elements in the cycle with the found periodic induction while rotating
258 // each first element to the end. Lastly, phi (last element in scc_) is classified.
259 // Statements are scanned in the reverse Tarjan SCC order, with phi last.
260 for (size_t i = 2; i <= size; i++) {
261 AssignInfo(loop, scc_[size - i], induction);
262 induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
263 }
264 AssignInfo(loop, phi, induction);
265 break;
266 default:
267 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700268 }
269 }
270}
271
Aart Bike609b7c2015-08-27 13:46:58 -0700272HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
273 InductionInfo* induction,
274 InductionInfo* last) {
275 // Rotates a periodic induction of the form
276 // (a, b, c, d, e)
277 // into
278 // (b, c, d, e, a)
279 // in preparation of assigning this to the previous variable in the sequence.
280 if (induction->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700281 return CreateInduction(kPeriodic, induction, last);
Aart Bike609b7c2015-08-27 13:46:58 -0700282 }
Aart Bik471a2032015-09-04 18:22:11 -0700283 return CreateInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
Aart Bike609b7c2015-08-27 13:46:58 -0700284}
285
Aart Bik30efb4e2015-07-30 12:14:31 -0700286HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(InductionInfo* a,
287 InductionInfo* b) {
288 // Transfer over a phi: if both inputs are identical, result is input.
289 if (InductionEqual(a, b)) {
290 return a;
291 }
292 return nullptr;
293}
294
295HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
296 InductionInfo* b,
297 InductionOp op) {
Aart Bike609b7c2015-08-27 13:46:58 -0700298 // Transfer over an addition or subtraction: any invariant, linear, wrap-around, or periodic
299 // can be combined with an invariant to yield a similar result. Even two linear inputs can
300 // be combined. All other combinations fail, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700301 if (a != nullptr && b != nullptr) {
302 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700303 return CreateInvariantOp(op, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700304 } else if (a->induction_class == kLinear && b->induction_class == kLinear) {
Aart Bik471a2032015-09-04 18:22:11 -0700305 return CreateInduction(
Aart Bike609b7c2015-08-27 13:46:58 -0700306 kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
307 } else if (a->induction_class == kInvariant) {
308 InductionInfo* new_a = b->op_a;
309 InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
310 if (b->induction_class != kLinear) {
311 DCHECK(b->induction_class == kWrapAround || b->induction_class == kPeriodic);
312 new_a = TransferAddSub(a, new_a, op);
313 } else if (op == kSub) { // Negation required.
314 new_a = TransferNeg(new_a);
315 }
Aart Bik471a2032015-09-04 18:22:11 -0700316 return CreateInduction(b->induction_class, new_a, new_b);
Aart Bike609b7c2015-08-27 13:46:58 -0700317 } else if (b->induction_class == kInvariant) {
318 InductionInfo* new_a = a->op_a;
319 InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
320 if (a->induction_class != kLinear) {
321 DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
322 new_a = TransferAddSub(new_a, b, op);
323 }
Aart Bik471a2032015-09-04 18:22:11 -0700324 return CreateInduction(a->induction_class, new_a, new_b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700325 }
326 }
327 return nullptr;
328}
329
330HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
331 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700332 // Transfer over a multiplication: any invariant, linear, wrap-around, or periodic
333 // can be multiplied with an invariant to yield a similar but multiplied result.
334 // Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700335 if (a != nullptr && b != nullptr) {
336 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700337 return CreateInvariantOp(kMul, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700338 } else if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700339 return CreateInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
Aart Bike609b7c2015-08-27 13:46:58 -0700340 } else if (b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700341 return CreateInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
Aart Bike609b7c2015-08-27 13:46:58 -0700342 }
343 }
344 return nullptr;
345}
346
347HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
348 InductionInfo* b,
349 Primitive::Type t) {
350 // Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
Aart Bik471a2032015-09-04 18:22:11 -0700351 int64_t value = -1;
352 if (a != nullptr && IsIntAndGet(b, &value)) {
Aart Bike609b7c2015-08-27 13:46:58 -0700353 // Obtain the constant needed for the multiplication. This yields an existing instruction
354 // if the constants is already there. Otherwise, this has a side effect on the HIR.
355 // The restriction on the shift factor avoids generating a negative constant
356 // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
357 // for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
Aart Bik471a2032015-09-04 18:22:11 -0700358 if (t == Primitive::kPrimInt && 0 <= value && value < 31) {
359 return TransferMul(a, CreateInvariantFetch(graph_->GetIntConstant(1 << value)));
360 } else if (t == Primitive::kPrimLong && 0 <= value && value < 63) {
361 return TransferMul(a, CreateInvariantFetch(graph_->GetLongConstant(1L << value)));
Aart Bik30efb4e2015-07-30 12:14:31 -0700362 }
363 }
364 return nullptr;
365}
366
367HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
Aart Bike609b7c2015-08-27 13:46:58 -0700368 // Transfer over a unary negation: an invariant, linear, wrap-around, or periodic input
369 // yields a similar but negated induction as result.
Aart Bik30efb4e2015-07-30 12:14:31 -0700370 if (a != nullptr) {
371 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700372 return CreateInvariantOp(kNeg, nullptr, a);
Aart Bik30efb4e2015-07-30 12:14:31 -0700373 }
Aart Bik471a2032015-09-04 18:22:11 -0700374 return CreateInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
Aart Bik30efb4e2015-07-30 12:14:31 -0700375 }
376 return nullptr;
377}
378
Aart Bike609b7c2015-08-27 13:46:58 -0700379HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HLoopInformation* loop,
380 HInstruction* phi,
381 HInstruction* instruction) {
382 // Solve within a cycle over a phi: identical inputs are combined into that input as result.
383 const size_t count = instruction->InputCount();
384 DCHECK_GT(count, 0u);
385 auto ita = cycle_.find(instruction->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700386 if (ita != cycle_.end()) {
387 InductionInfo* a = ita->second;
388 for (size_t i = 1; i < count; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700389 auto itb = cycle_.find(instruction->InputAt(i));
390 if (itb == cycle_.end() || !HInductionVarAnalysis::InductionEqual(a, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700391 return nullptr;
392 }
393 }
394 return a;
395 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700396
Aart Bike609b7c2015-08-27 13:46:58 -0700397 // Solve within a cycle over another entry-phi: add invariants into a periodic.
398 if (IsEntryPhi(loop, instruction)) {
399 InductionInfo* a = LookupInfo(loop, instruction->InputAt(0));
400 if (a != nullptr && a->induction_class == kInvariant) {
401 if (instruction->InputAt(1) == phi) {
402 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700403 return CreateInduction(kPeriodic, a, initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700404 }
405 auto it = cycle_.find(instruction->InputAt(1));
406 if (it != cycle_.end()) {
407 InductionInfo* b = it->second;
408 if (b->induction_class == kPeriodic) {
Aart Bik471a2032015-09-04 18:22:11 -0700409 return CreateInduction(kPeriodic, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700410 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700411 }
412 }
413 }
Aart Bike609b7c2015-08-27 13:46:58 -0700414
Aart Bik30efb4e2015-07-30 12:14:31 -0700415 return nullptr;
416}
417
Aart Bike609b7c2015-08-27 13:46:58 -0700418HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
419 HInstruction* phi,
420 HInstruction* instruction,
421 HInstruction* x,
422 HInstruction* y,
423 InductionOp op,
424 bool is_first_call) {
425 // Solve within a cycle over an addition or subtraction: adding or subtracting an
426 // invariant value, seeded from phi, keeps adding to the stride of the induction.
427 InductionInfo* b = LookupInfo(loop, y);
428 if (b != nullptr && b->induction_class == kInvariant) {
429 if (x == phi) {
Aart Bik471a2032015-09-04 18:22:11 -0700430 return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700431 }
432 auto it = cycle_.find(x);
433 if (it != cycle_.end()) {
434 InductionInfo* a = it->second;
435 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700436 return CreateInvariantOp(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700437 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700438 }
439 }
Aart Bike609b7c2015-08-27 13:46:58 -0700440
441 // Try some alternatives before failing.
442 if (op == kAdd) {
443 // Try the other way around for an addition if considered for first time.
444 if (is_first_call) {
445 return SolveAddSub(loop, phi, instruction, y, x, op, false);
446 }
447 } else if (op == kSub) {
448 // Solve within a tight cycle for a periodic idiom k = c - k;
449 if (y == phi && instruction == phi->InputAt(1)) {
450 InductionInfo* a = LookupInfo(loop, x);
451 if (a != nullptr && a->induction_class == kInvariant) {
452 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700453 return CreateInduction(kPeriodic, CreateInvariantOp(kSub, a, initial), initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700454 }
455 }
456 }
457
Aart Bik30efb4e2015-07-30 12:14:31 -0700458 return nullptr;
459}
460
461void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
462 HInstruction* instruction,
463 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -0700464 auto it = induction_.find(loop);
465 if (it == induction_.end()) {
466 it = induction_.Put(loop,
467 ArenaSafeMap<HInstruction*, InductionInfo*>(
468 std::less<HInstruction*>(), graph_->GetArena()->Adapter()));
469 }
470 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700471}
472
Aart Bike609b7c2015-08-27 13:46:58 -0700473HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
474 HInstruction* instruction) {
475 auto it = induction_.find(loop);
476 if (it != induction_.end()) {
477 auto loop_it = it->second.find(instruction);
478 if (loop_it != it->second.end()) {
479 return loop_it->second;
480 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700481 }
Aart Bike609b7c2015-08-27 13:46:58 -0700482 if (IsLoopInvariant(loop, instruction)) {
Aart Bik471a2032015-09-04 18:22:11 -0700483 InductionInfo* info = CreateInvariantFetch(instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700484 AssignInfo(loop, instruction, info);
485 return info;
486 }
487 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -0700488}
489
Aart Bik471a2032015-09-04 18:22:11 -0700490HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
491 InductionOp op,
492 InductionInfo* a,
493 InductionInfo* b) {
494 // Perform some light-weight simplifications during construction of a new invariant.
495 // This often safes memory and yields a more concise representation of the induction.
496 // More exhaustive simplifications are done by later phases once induction nodes are
497 // translated back into HIR code (e.g. by loop optimizations or BCE).
498 int64_t value = -1;
499 if (IsIntAndGet(a, &value)) {
500 if (value == 0) {
501 // Simplify 0 + b = b, 0 * b = 0.
502 if (op == kAdd) {
503 return b;
504 } else if (op == kMul) {
505 return a;
506 }
507 } else if (value == 1 && op == kMul) {
508 // Simplify 1 * b = b.
509 return b;
510 }
511 }
512 if (IsIntAndGet(b, &value)) {
513 if (value == 0) {
514 // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, - 0 = 0.
515 if (op == kAdd || op == kSub) {
516 return a;
517 } else if (op == kMul || op == kNeg) {
518 return b;
519 }
520 } else if (value == 1 && (op == kMul || op == kDiv)) {
521 // Simplify a * 1 = a, a / 1 = a.
522 return a;
523 }
524 } else if (b->operation == kNeg) {
525 // Simplify a + (-b) = a - b, a - (-b) = a + b, - (-b) = b.
526 switch (op) {
527 case kAdd: op = kSub; b = b->op_b; break;
528 case kSub: op = kAdd; b = b->op_b; break;
529 case kNeg: return b->op_b;
530 default: break;
531 }
532 }
533 return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
534}
535
Aart Bik30efb4e2015-07-30 12:14:31 -0700536bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
537 InductionInfo* info2) {
538 // Test structural equality only, without accounting for simplifications.
539 if (info1 != nullptr && info2 != nullptr) {
540 return
541 info1->induction_class == info2->induction_class &&
542 info1->operation == info2->operation &&
543 info1->fetch == info2->fetch &&
544 InductionEqual(info1->op_a, info2->op_a) &&
545 InductionEqual(info1->op_b, info2->op_b);
546 }
547 // Otherwise only two nullptrs are considered equal.
548 return info1 == info2;
549}
550
Aart Bik471a2032015-09-04 18:22:11 -0700551bool HInductionVarAnalysis::IsIntAndGet(InductionInfo* info, int64_t* value) {
552 if (info != nullptr && info->induction_class == kInvariant && info->operation == kFetch) {
553 DCHECK(info->fetch);
554 if (info->fetch->IsIntConstant()) {
555 *value = info->fetch->AsIntConstant()->GetValue();
556 return true;
557 } else if (info->fetch->IsLongConstant()) {
558 *value = info->fetch->AsLongConstant()->GetValue();
559 return true;
560 }
561 }
562 return false;
563}
564
Aart Bik30efb4e2015-07-30 12:14:31 -0700565std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
566 if (info != nullptr) {
567 if (info->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700568 int64_t value = -1;
Aart Bik30efb4e2015-07-30 12:14:31 -0700569 std::string inv = "(";
570 inv += InductionToString(info->op_a);
571 switch (info->operation) {
Aart Bike609b7c2015-08-27 13:46:58 -0700572 case kNop: inv += " @ "; break;
573 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700574 case kSub:
Aart Bike609b7c2015-08-27 13:46:58 -0700575 case kNeg: inv += " - "; break;
576 case kMul: inv += " * "; break;
577 case kDiv: inv += " / "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700578 case kFetch:
Aart Bike609b7c2015-08-27 13:46:58 -0700579 DCHECK(info->fetch);
Aart Bik471a2032015-09-04 18:22:11 -0700580 if (IsIntAndGet(info, &value)) {
581 inv += std::to_string(value);
582 } else {
583 inv += std::to_string(info->fetch->GetId()) + ":" + info->fetch->DebugName();
584 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700585 break;
586 }
587 inv += InductionToString(info->op_b);
588 return inv + ")";
589 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700590 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700591 if (info->induction_class == kLinear) {
592 return "(" + InductionToString(info->op_a) + " * i + " +
593 InductionToString(info->op_b) + ")";
594 } else if (info->induction_class == kWrapAround) {
595 return "wrap(" + InductionToString(info->op_a) + ", " +
596 InductionToString(info->op_b) + ")";
597 } else if (info->induction_class == kPeriodic) {
598 return "periodic(" + InductionToString(info->op_a) + ", " +
599 InductionToString(info->op_b) + ")";
600 }
601 }
602 }
603 return "";
604}
605
606} // namespace art