blob: 92c732c0c331c044885192f3f6258e8e7d0d466c [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"
Aart Bik22af3be2015-09-10 12:50:58 -070018#include "induction_var_range.h"
Aart Bik30efb4e2015-07-30 12:14:31 -070019
20namespace art {
21
22/**
23 * Returns true if instruction is invariant within the given loop.
24 */
25static bool IsLoopInvariant(HLoopInformation* loop, HInstruction* instruction) {
26 HLoopInformation* other_loop = instruction->GetBlock()->GetLoopInformation();
27 if (other_loop != loop) {
28 // If instruction does not occur in same loop, it is invariant
29 // if it appears in an outer loop (including no loop at all).
30 return other_loop == nullptr || loop->IsIn(*other_loop);
31 }
32 return false;
33}
34
35/**
36 * Returns true if instruction is proper entry-phi-operation for given loop
37 * (referred to as mu-operation in Gerlek's paper).
38 */
39static bool IsEntryPhi(HLoopInformation* loop, HInstruction* instruction) {
40 return
41 instruction->IsPhi() &&
42 instruction->InputCount() == 2 &&
43 instruction->GetBlock() == loop->GetHeader();
44}
45
Aart Bik22af3be2015-09-10 12:50:58 -070046/**
47 * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
48 * along dependences, viz. any of (a, b, c, d), (d, a, b, c) (c, d, a, b), (b, c, d, a) assuming
49 * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
50 * classification, the lexicographically first entry-phi is rotated to the front.
51 */
52static void RotateEntryPhiFirst(HLoopInformation* loop,
53 ArenaVector<HInstruction*>* scc,
54 ArenaVector<HInstruction*>* new_scc) {
55 // Find very first entry-phi.
56 const HInstructionList& phis = loop->GetHeader()->GetPhis();
57 HInstruction* phi = nullptr;
58 size_t phi_pos = -1;
59 const size_t size = scc->size();
60 for (size_t i = 0; i < size; i++) {
61 if (IsEntryPhi(loop, scc->at(i)) && (phi == nullptr || phis.FoundBefore(scc->at(i), phi))) {
62 phi = scc->at(i);
63 phi_pos = i;
64 }
65 }
66
67 // If found, bring that entry-phi to front.
68 if (phi != nullptr) {
69 new_scc->clear();
70 for (size_t i = 0; i < size; i++) {
71 DCHECK_LT(phi_pos, size);
72 new_scc->push_back(scc->at(phi_pos));
73 if (++phi_pos >= size) phi_pos = 0;
74 }
75 DCHECK_EQ(size, new_scc->size());
76 scc->swap(*new_scc);
77 }
78}
79
Aart Bik30efb4e2015-07-30 12:14:31 -070080//
81// Class methods.
82//
83
84HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph)
85 : HOptimization(graph, kInductionPassName),
86 global_depth_(0),
87 stack_(graph->GetArena()->Adapter()),
88 scc_(graph->GetArena()->Adapter()),
Aart Bike609b7c2015-08-27 13:46:58 -070089 map_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
90 cycle_(std::less<HInstruction*>(), graph->GetArena()->Adapter()),
91 induction_(std::less<HLoopInformation*>(), graph->GetArena()->Adapter()) {
Aart Bik30efb4e2015-07-30 12:14:31 -070092}
93
94void HInductionVarAnalysis::Run() {
Aart Bike609b7c2015-08-27 13:46:58 -070095 // Detects sequence variables (generalized induction variables) during an inner-loop-first
96 // traversal of all loops using Gerlek's algorithm. The order is only relevant if outer
97 // loops would use induction information of inner loops (not currently done).
Aart Bik30efb4e2015-07-30 12:14:31 -070098 for (HPostOrderIterator it_graph(*graph_); !it_graph.Done(); it_graph.Advance()) {
99 HBasicBlock* graph_block = it_graph.Current();
100 if (graph_block->IsLoopHeader()) {
101 VisitLoop(graph_block->GetLoopInformation());
102 }
103 }
104}
105
106void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
107 // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
108 // algorithm. Due to the descendant-first nature, classification happens "on-demand".
109 global_depth_ = 0;
Aart Bike609b7c2015-08-27 13:46:58 -0700110 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700111 map_.clear();
112
113 for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
114 HBasicBlock* loop_block = it_loop.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700115 DCHECK(loop_block->IsInLoop());
Aart Bik30efb4e2015-07-30 12:14:31 -0700116 if (loop_block->GetLoopInformation() != loop) {
117 continue; // Inner loops already visited.
118 }
119 // Visit phi-operations and instructions.
120 for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
121 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700122 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700123 VisitNode(loop, instruction);
124 }
125 }
126 for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
127 HInstruction* instruction = it.Current();
Aart Bike609b7c2015-08-27 13:46:58 -0700128 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700129 VisitNode(loop, instruction);
130 }
131 }
132 }
133
Aart Bike609b7c2015-08-27 13:46:58 -0700134 DCHECK(stack_.empty());
Aart Bik30efb4e2015-07-30 12:14:31 -0700135 map_.clear();
Aart Bikd14c5952015-09-08 15:25:15 -0700136
137 // Determine the loop's trip count.
138 VisitControl(loop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700139}
140
141void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700142 const uint32_t d1 = ++global_depth_;
Aart Bike609b7c2015-08-27 13:46:58 -0700143 map_.Put(instruction, NodeInfo(d1));
Aart Bik30efb4e2015-07-30 12:14:31 -0700144 stack_.push_back(instruction);
145
146 // Visit all descendants.
147 uint32_t low = d1;
148 for (size_t i = 0, count = instruction->InputCount(); i < count; ++i) {
149 low = std::min(low, VisitDescendant(loop, instruction->InputAt(i)));
150 }
151
152 // Lower or found SCC?
153 if (low < d1) {
Aart Bike609b7c2015-08-27 13:46:58 -0700154 map_.find(instruction)->second.depth = low;
Aart Bik30efb4e2015-07-30 12:14:31 -0700155 } else {
156 scc_.clear();
157 cycle_.clear();
158
159 // Pop the stack to build the SCC for classification.
160 while (!stack_.empty()) {
161 HInstruction* x = stack_.back();
162 scc_.push_back(x);
163 stack_.pop_back();
Aart Bike609b7c2015-08-27 13:46:58 -0700164 map_.find(x)->second.done = true;
Aart Bik30efb4e2015-07-30 12:14:31 -0700165 if (x == instruction) {
166 break;
167 }
168 }
169
170 // Classify the SCC.
171 if (scc_.size() == 1 && !IsEntryPhi(loop, scc_[0])) {
172 ClassifyTrivial(loop, scc_[0]);
173 } else {
174 ClassifyNonTrivial(loop);
175 }
176
177 scc_.clear();
178 cycle_.clear();
179 }
180}
181
182uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
183 // If the definition is either outside the loop (loop invariant entry value)
184 // or assigned in inner loop (inner exit value), the traversal stops.
185 HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
186 if (otherLoop != loop) {
187 return global_depth_;
188 }
189
190 // Inspect descendant node.
Aart Bike609b7c2015-08-27 13:46:58 -0700191 if (!IsVisitedNode(instruction)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700192 VisitNode(loop, instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700193 return map_.find(instruction)->second.depth;
Aart Bik30efb4e2015-07-30 12:14:31 -0700194 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700195 auto it = map_.find(instruction);
Aart Bik30efb4e2015-07-30 12:14:31 -0700196 return it->second.done ? global_depth_ : it->second.depth;
197 }
198}
199
200void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
201 InductionInfo* info = nullptr;
202 if (instruction->IsPhi()) {
203 for (size_t i = 1, count = instruction->InputCount(); i < count; i++) {
204 info = TransferPhi(LookupInfo(loop, instruction->InputAt(0)),
205 LookupInfo(loop, instruction->InputAt(i)));
206 }
207 } else if (instruction->IsAdd()) {
208 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
209 LookupInfo(loop, instruction->InputAt(1)), kAdd);
210 } else if (instruction->IsSub()) {
211 info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
212 LookupInfo(loop, instruction->InputAt(1)), kSub);
213 } else if (instruction->IsMul()) {
214 info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
215 LookupInfo(loop, instruction->InputAt(1)));
Aart Bike609b7c2015-08-27 13:46:58 -0700216 } else if (instruction->IsShl()) {
217 info = TransferShl(LookupInfo(loop, instruction->InputAt(0)),
218 LookupInfo(loop, instruction->InputAt(1)),
219 instruction->InputAt(0)->GetType());
Aart Bik30efb4e2015-07-30 12:14:31 -0700220 } else if (instruction->IsNeg()) {
221 info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
Aart Bike609b7c2015-08-27 13:46:58 -0700222 } else if (instruction->IsBoundsCheck()) {
223 info = LookupInfo(loop, instruction->InputAt(0)); // Pass-through.
224 } else if (instruction->IsTypeConversion()) {
225 HTypeConversion* conversion = instruction->AsTypeConversion();
226 // TODO: accept different conversion scenarios.
227 if (conversion->GetResultType() == conversion->GetInputType()) {
228 info = LookupInfo(loop, conversion->GetInput());
229 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700230 }
231
232 // Successfully classified?
233 if (info != nullptr) {
234 AssignInfo(loop, instruction, info);
235 }
236}
237
238void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
239 const size_t size = scc_.size();
Aart Bike609b7c2015-08-27 13:46:58 -0700240 DCHECK_GE(size, 1u);
Aart Bik22af3be2015-09-10 12:50:58 -0700241
242 // Rotate proper entry-phi to front.
243 if (size > 1) {
244 ArenaVector<HInstruction*> other(graph_->GetArena()->Adapter());
245 RotateEntryPhiFirst(loop, &scc_, &other);
246 }
247
248 // Analyze from phi onwards.
249 HInstruction* phi = scc_[0];
Aart Bik30efb4e2015-07-30 12:14:31 -0700250 if (!IsEntryPhi(loop, phi)) {
251 return;
252 }
253 HInstruction* external = phi->InputAt(0);
254 HInstruction* internal = phi->InputAt(1);
255 InductionInfo* initial = LookupInfo(loop, external);
256 if (initial == nullptr || initial->induction_class != kInvariant) {
257 return;
258 }
259
260 // Singleton entry-phi-operation may be a wrap-around induction.
261 if (size == 1) {
262 InductionInfo* update = LookupInfo(loop, internal);
263 if (update != nullptr) {
Aart Bik471a2032015-09-04 18:22:11 -0700264 AssignInfo(loop, phi, CreateInduction(kWrapAround, initial, update));
Aart Bik30efb4e2015-07-30 12:14:31 -0700265 }
266 return;
267 }
268
269 // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
Aart Bike609b7c2015-08-27 13:46:58 -0700270 // temporary meaning to its nodes, seeded from the phi instruction and back.
Aart Bik22af3be2015-09-10 12:50:58 -0700271 for (size_t i = 1; i < size; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700272 HInstruction* instruction = scc_[i];
Aart Bik30efb4e2015-07-30 12:14:31 -0700273 InductionInfo* update = nullptr;
Aart Bike609b7c2015-08-27 13:46:58 -0700274 if (instruction->IsPhi()) {
275 update = SolvePhi(loop, phi, instruction);
276 } else if (instruction->IsAdd()) {
277 update = SolveAddSub(
278 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
279 } else if (instruction->IsSub()) {
280 update = SolveAddSub(
281 loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
Aart Bik30efb4e2015-07-30 12:14:31 -0700282 }
283 if (update == nullptr) {
284 return;
285 }
Aart Bike609b7c2015-08-27 13:46:58 -0700286 cycle_.Put(instruction, update);
Aart Bik30efb4e2015-07-30 12:14:31 -0700287 }
288
Aart Bike609b7c2015-08-27 13:46:58 -0700289 // Success if the internal link received a meaning.
290 auto it = cycle_.find(internal);
291 if (it != cycle_.end()) {
292 InductionInfo* induction = it->second;
293 switch (induction->induction_class) {
294 case kInvariant:
Aart Bik22af3be2015-09-10 12:50:58 -0700295 // Classify first phi and then the rest of the cycle "on-demand".
296 // Statements are scanned in order.
Aart Bik471a2032015-09-04 18:22:11 -0700297 AssignInfo(loop, phi, CreateInduction(kLinear, induction, initial));
Aart Bik22af3be2015-09-10 12:50:58 -0700298 for (size_t i = 1; i < size; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700299 ClassifyTrivial(loop, scc_[i]);
300 }
301 break;
302 case kPeriodic:
Aart Bik22af3be2015-09-10 12:50:58 -0700303 // Classify all elements in the cycle with the found periodic induction while
304 // rotating each first element to the end. Lastly, phi is classified.
305 // Statements are scanned in reverse order.
306 for (size_t i = size - 1; i >= 1; i--) {
307 AssignInfo(loop, scc_[i], induction);
Aart Bike609b7c2015-08-27 13:46:58 -0700308 induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
309 }
310 AssignInfo(loop, phi, induction);
311 break;
312 default:
313 break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700314 }
315 }
316}
317
Aart Bike609b7c2015-08-27 13:46:58 -0700318HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
319 InductionInfo* induction,
320 InductionInfo* last) {
321 // Rotates a periodic induction of the form
322 // (a, b, c, d, e)
323 // into
324 // (b, c, d, e, a)
325 // in preparation of assigning this to the previous variable in the sequence.
326 if (induction->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700327 return CreateInduction(kPeriodic, induction, last);
Aart Bike609b7c2015-08-27 13:46:58 -0700328 }
Aart Bik471a2032015-09-04 18:22:11 -0700329 return CreateInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
Aart Bike609b7c2015-08-27 13:46:58 -0700330}
331
Aart Bik30efb4e2015-07-30 12:14:31 -0700332HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(InductionInfo* a,
333 InductionInfo* b) {
334 // Transfer over a phi: if both inputs are identical, result is input.
335 if (InductionEqual(a, b)) {
336 return a;
337 }
338 return nullptr;
339}
340
341HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
342 InductionInfo* b,
343 InductionOp op) {
Aart Bike609b7c2015-08-27 13:46:58 -0700344 // Transfer over an addition or subtraction: any invariant, linear, wrap-around, or periodic
345 // can be combined with an invariant to yield a similar result. Even two linear inputs can
346 // be combined. All other combinations fail, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700347 if (a != nullptr && b != nullptr) {
348 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700349 return CreateInvariantOp(op, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700350 } else if (a->induction_class == kLinear && b->induction_class == kLinear) {
Aart Bik471a2032015-09-04 18:22:11 -0700351 return CreateInduction(
Aart Bike609b7c2015-08-27 13:46:58 -0700352 kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
353 } else if (a->induction_class == kInvariant) {
354 InductionInfo* new_a = b->op_a;
355 InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
356 if (b->induction_class != kLinear) {
357 DCHECK(b->induction_class == kWrapAround || b->induction_class == kPeriodic);
358 new_a = TransferAddSub(a, new_a, op);
359 } else if (op == kSub) { // Negation required.
360 new_a = TransferNeg(new_a);
361 }
Aart Bik471a2032015-09-04 18:22:11 -0700362 return CreateInduction(b->induction_class, new_a, new_b);
Aart Bike609b7c2015-08-27 13:46:58 -0700363 } else if (b->induction_class == kInvariant) {
364 InductionInfo* new_a = a->op_a;
365 InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
366 if (a->induction_class != kLinear) {
367 DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
368 new_a = TransferAddSub(new_a, b, op);
369 }
Aart Bik471a2032015-09-04 18:22:11 -0700370 return CreateInduction(a->induction_class, new_a, new_b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700371 }
372 }
373 return nullptr;
374}
375
376HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
377 InductionInfo* b) {
Aart Bike609b7c2015-08-27 13:46:58 -0700378 // Transfer over a multiplication: any invariant, linear, wrap-around, or periodic
379 // can be multiplied with an invariant to yield a similar but multiplied result.
380 // Two non-invariant inputs cannot be multiplied, however.
Aart Bik30efb4e2015-07-30 12:14:31 -0700381 if (a != nullptr && b != nullptr) {
382 if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700383 return CreateInvariantOp(kMul, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700384 } else if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700385 return CreateInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
Aart Bike609b7c2015-08-27 13:46:58 -0700386 } else if (b->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700387 return CreateInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
Aart Bike609b7c2015-08-27 13:46:58 -0700388 }
389 }
390 return nullptr;
391}
392
393HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
394 InductionInfo* b,
Aart Bikd14c5952015-09-08 15:25:15 -0700395 Primitive::Type type) {
Aart Bike609b7c2015-08-27 13:46:58 -0700396 // Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
Aart Bik471a2032015-09-04 18:22:11 -0700397 int64_t value = -1;
398 if (a != nullptr && IsIntAndGet(b, &value)) {
Aart Bike609b7c2015-08-27 13:46:58 -0700399 // Obtain the constant needed for the multiplication. This yields an existing instruction
400 // if the constants is already there. Otherwise, this has a side effect on the HIR.
401 // The restriction on the shift factor avoids generating a negative constant
402 // (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
403 // for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
Aart Bikd14c5952015-09-08 15:25:15 -0700404 if ((type == Primitive::kPrimInt && 0 <= value && value < 31) ||
405 (type == Primitive::kPrimLong && 0 <= value && value < 63)) {
406 return TransferMul(a, CreateConstant(1 << value, type));
Aart Bik30efb4e2015-07-30 12:14:31 -0700407 }
408 }
409 return nullptr;
410}
411
412HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
Aart Bike609b7c2015-08-27 13:46:58 -0700413 // Transfer over a unary negation: an invariant, linear, wrap-around, or periodic input
414 // yields a similar but negated induction as result.
Aart Bik30efb4e2015-07-30 12:14:31 -0700415 if (a != nullptr) {
416 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700417 return CreateInvariantOp(kNeg, nullptr, a);
Aart Bik30efb4e2015-07-30 12:14:31 -0700418 }
Aart Bik471a2032015-09-04 18:22:11 -0700419 return CreateInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
Aart Bik30efb4e2015-07-30 12:14:31 -0700420 }
421 return nullptr;
422}
423
Aart Bike609b7c2015-08-27 13:46:58 -0700424HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HLoopInformation* loop,
425 HInstruction* phi,
426 HInstruction* instruction) {
427 // Solve within a cycle over a phi: identical inputs are combined into that input as result.
428 const size_t count = instruction->InputCount();
429 DCHECK_GT(count, 0u);
430 auto ita = cycle_.find(instruction->InputAt(0));
Aart Bik30efb4e2015-07-30 12:14:31 -0700431 if (ita != cycle_.end()) {
432 InductionInfo* a = ita->second;
433 for (size_t i = 1; i < count; i++) {
Aart Bike609b7c2015-08-27 13:46:58 -0700434 auto itb = cycle_.find(instruction->InputAt(i));
435 if (itb == cycle_.end() || !HInductionVarAnalysis::InductionEqual(a, itb->second)) {
Aart Bik30efb4e2015-07-30 12:14:31 -0700436 return nullptr;
437 }
438 }
439 return a;
440 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700441
Aart Bike609b7c2015-08-27 13:46:58 -0700442 // Solve within a cycle over another entry-phi: add invariants into a periodic.
443 if (IsEntryPhi(loop, instruction)) {
444 InductionInfo* a = LookupInfo(loop, instruction->InputAt(0));
445 if (a != nullptr && a->induction_class == kInvariant) {
446 if (instruction->InputAt(1) == phi) {
447 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700448 return CreateInduction(kPeriodic, a, initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700449 }
450 auto it = cycle_.find(instruction->InputAt(1));
451 if (it != cycle_.end()) {
452 InductionInfo* b = it->second;
453 if (b->induction_class == kPeriodic) {
Aart Bik471a2032015-09-04 18:22:11 -0700454 return CreateInduction(kPeriodic, a, b);
Aart Bik30efb4e2015-07-30 12:14:31 -0700455 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700456 }
457 }
458 }
Aart Bike609b7c2015-08-27 13:46:58 -0700459
Aart Bik30efb4e2015-07-30 12:14:31 -0700460 return nullptr;
461}
462
Aart Bike609b7c2015-08-27 13:46:58 -0700463HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
464 HInstruction* phi,
465 HInstruction* instruction,
466 HInstruction* x,
467 HInstruction* y,
468 InductionOp op,
469 bool is_first_call) {
470 // Solve within a cycle over an addition or subtraction: adding or subtracting an
471 // invariant value, seeded from phi, keeps adding to the stride of the induction.
472 InductionInfo* b = LookupInfo(loop, y);
473 if (b != nullptr && b->induction_class == kInvariant) {
474 if (x == phi) {
Aart Bik471a2032015-09-04 18:22:11 -0700475 return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700476 }
477 auto it = cycle_.find(x);
478 if (it != cycle_.end()) {
479 InductionInfo* a = it->second;
480 if (a->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700481 return CreateInvariantOp(op, a, b);
Aart Bike609b7c2015-08-27 13:46:58 -0700482 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700483 }
484 }
Aart Bike609b7c2015-08-27 13:46:58 -0700485
486 // Try some alternatives before failing.
487 if (op == kAdd) {
488 // Try the other way around for an addition if considered for first time.
489 if (is_first_call) {
490 return SolveAddSub(loop, phi, instruction, y, x, op, false);
491 }
492 } else if (op == kSub) {
493 // Solve within a tight cycle for a periodic idiom k = c - k;
494 if (y == phi && instruction == phi->InputAt(1)) {
495 InductionInfo* a = LookupInfo(loop, x);
496 if (a != nullptr && a->induction_class == kInvariant) {
497 InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
Aart Bik471a2032015-09-04 18:22:11 -0700498 return CreateInduction(kPeriodic, CreateInvariantOp(kSub, a, initial), initial);
Aart Bike609b7c2015-08-27 13:46:58 -0700499 }
500 }
501 }
502
Aart Bik30efb4e2015-07-30 12:14:31 -0700503 return nullptr;
504}
505
Aart Bikd14c5952015-09-08 15:25:15 -0700506void HInductionVarAnalysis::VisitControl(HLoopInformation* loop) {
507 HInstruction* control = loop->GetHeader()->GetLastInstruction();
508 if (control->IsIf()) {
509 HIf* ifs = control->AsIf();
510 HBasicBlock* if_true = ifs->IfTrueSuccessor();
511 HBasicBlock* if_false = ifs->IfFalseSuccessor();
512 HInstruction* if_expr = ifs->InputAt(0);
513 // Determine if loop has following structure in header.
514 // loop-header: ....
515 // if (condition) goto X
516 if (if_expr->IsCondition()) {
517 HCondition* condition = if_expr->AsCondition();
518 InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
519 InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
520 Primitive::Type type = condition->InputAt(0)->GetType();
521 // Determine if the loop control uses integral arithmetic and an if-exit (X outside) or an
522 // if-iterate (X inside), always expressed as if-iterate when passing into VisitCondition().
523 if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
524 // Loop control is not 32/64-bit integral.
525 } else if (a == nullptr || b == nullptr) {
526 // Loop control is not a sequence.
527 } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
528 VisitCondition(loop, a, b, type, condition->GetOppositeCondition());
529 } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
530 VisitCondition(loop, a, b, type, condition->GetCondition());
531 }
532 }
533 }
534}
535
536void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
537 InductionInfo* a,
538 InductionInfo* b,
539 Primitive::Type type,
540 IfCondition cmp) {
541 if (a->induction_class == kInvariant && b->induction_class == kLinear) {
542 // Swap conditions (e.g. U > i is same as i < U).
543 switch (cmp) {
544 case kCondLT: VisitCondition(loop, b, a, type, kCondGT); break;
545 case kCondLE: VisitCondition(loop, b, a, type, kCondGE); break;
546 case kCondGT: VisitCondition(loop, b, a, type, kCondLT); break;
547 case kCondGE: VisitCondition(loop, b, a, type, kCondLE); break;
548 default: break;
549 }
550 } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
551 // Normalize a linear loop control with a constant, nonzero stride:
552 // stride > 0, either i < U or i <= U
553 // stride < 0, either i > U or i >= U
554 InductionInfo* stride = a->op_a;
555 InductionInfo* lo_val = a->op_b;
556 InductionInfo* hi_val = b;
Aart Bik22af3be2015-09-10 12:50:58 -0700557 // Analyze the stride thoroughly, since its representation may be compound at this point.
558 InductionVarRange::Value v1 = InductionVarRange::GetMin(stride, nullptr);
559 InductionVarRange::Value v2 = InductionVarRange::GetMax(stride, nullptr);
560 if (v1.a_constant == 0 && v2.a_constant == 0 && v1.b_constant == v2.b_constant) {
561 const int32_t stride_value = v1.b_constant;
562 if ((stride_value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
563 (stride_value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
Aart Bikd14c5952015-09-08 15:25:15 -0700564 bool is_strict = cmp == kCondLT || cmp == kCondGT;
Aart Bik22af3be2015-09-10 12:50:58 -0700565 VisitTripCount(loop, lo_val, hi_val, stride, stride_value, type, is_strict);
Aart Bikd14c5952015-09-08 15:25:15 -0700566 }
567 }
568 }
569}
570
571void HInductionVarAnalysis::VisitTripCount(HLoopInformation* loop,
572 InductionInfo* lo_val,
573 InductionInfo* hi_val,
574 InductionInfo* stride,
575 int32_t stride_value,
576 Primitive::Type type,
577 bool is_strict) {
578 // Any loop of the general form:
579 //
580 // for (i = L; i <= U; i += S) // S > 0
581 // or for (i = L; i >= U; i += S) // S < 0
582 // .. i ..
583 //
584 // can be normalized into:
585 //
586 // for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
587 // .. L + S * n ..
588 //
589 // NOTE: The TC (trip-count) expression is only valid if the top-test path is taken at
590 // least once. Otherwise TC is 0. Also, the expression assumes the loop does not
591 // have any early-exits. Otherwise, TC is an upper bound.
592 //
Aart Bik22af3be2015-09-10 12:50:58 -0700593 bool cancels = is_strict && std::abs(stride_value) == 1; // compensation cancels conversion?
Aart Bikd14c5952015-09-08 15:25:15 -0700594 if (!cancels) {
595 // Convert exclusive integral inequality into inclusive integral inequality,
596 // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
597 if (is_strict) {
598 const InductionOp op = stride_value > 0 ? kSub : kAdd;
599 hi_val = CreateInvariantOp(op, hi_val, CreateConstant(1, type));
600 }
601 // Compensate for stride.
602 hi_val = CreateInvariantOp(kAdd, hi_val, stride);
603 }
604
605 // Assign the trip-count expression to the loop control. Clients that use the information
Aart Bik22af3be2015-09-10 12:50:58 -0700606 // should be aware that due to the top-test assumption, the expression is only valid in the
Aart Bikd14c5952015-09-08 15:25:15 -0700607 // loop-body proper, and not yet in the loop-header. If the loop has any early exits, the
608 // trip-count forms a conservative upper bound on the number of loop iterations.
609 InductionInfo* trip_count =
610 CreateInvariantOp(kDiv, CreateInvariantOp(kSub, hi_val, lo_val), stride);
611 AssignInfo(loop, loop->GetHeader()->GetLastInstruction(), trip_count);
612}
613
Aart Bik30efb4e2015-07-30 12:14:31 -0700614void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
615 HInstruction* instruction,
616 InductionInfo* info) {
Aart Bike609b7c2015-08-27 13:46:58 -0700617 auto it = induction_.find(loop);
618 if (it == induction_.end()) {
619 it = induction_.Put(loop,
620 ArenaSafeMap<HInstruction*, InductionInfo*>(
621 std::less<HInstruction*>(), graph_->GetArena()->Adapter()));
622 }
623 it->second.Put(instruction, info);
Aart Bik30efb4e2015-07-30 12:14:31 -0700624}
625
Aart Bike609b7c2015-08-27 13:46:58 -0700626HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
627 HInstruction* instruction) {
628 auto it = induction_.find(loop);
629 if (it != induction_.end()) {
630 auto loop_it = it->second.find(instruction);
631 if (loop_it != it->second.end()) {
632 return loop_it->second;
633 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700634 }
Aart Bike609b7c2015-08-27 13:46:58 -0700635 if (IsLoopInvariant(loop, instruction)) {
Aart Bik471a2032015-09-04 18:22:11 -0700636 InductionInfo* info = CreateInvariantFetch(instruction);
Aart Bike609b7c2015-08-27 13:46:58 -0700637 AssignInfo(loop, instruction, info);
638 return info;
639 }
640 return nullptr;
Aart Bik30efb4e2015-07-30 12:14:31 -0700641}
642
Aart Bikd14c5952015-09-08 15:25:15 -0700643HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
644 Primitive::Type type) {
645 if (type == Primitive::kPrimInt) {
646 return CreateInvariantFetch(graph_->GetIntConstant(value));
647 }
648 DCHECK_EQ(type, Primitive::kPrimLong);
649 return CreateInvariantFetch(graph_->GetLongConstant(value));
650}
651
Aart Bik471a2032015-09-04 18:22:11 -0700652HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
653 InductionOp op,
654 InductionInfo* a,
655 InductionInfo* b) {
656 // Perform some light-weight simplifications during construction of a new invariant.
657 // This often safes memory and yields a more concise representation of the induction.
658 // More exhaustive simplifications are done by later phases once induction nodes are
659 // translated back into HIR code (e.g. by loop optimizations or BCE).
660 int64_t value = -1;
661 if (IsIntAndGet(a, &value)) {
662 if (value == 0) {
663 // Simplify 0 + b = b, 0 * b = 0.
664 if (op == kAdd) {
665 return b;
666 } else if (op == kMul) {
667 return a;
668 }
Aart Bikd14c5952015-09-08 15:25:15 -0700669 } else if (op == kMul) {
670 // Simplify 1 * b = b, -1 * b = -b
671 if (value == 1) {
672 return b;
673 } else if (value == -1) {
674 op = kNeg;
675 a = nullptr;
676 }
Aart Bik471a2032015-09-04 18:22:11 -0700677 }
678 }
679 if (IsIntAndGet(b, &value)) {
680 if (value == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700681 // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, -0 = 0.
Aart Bik471a2032015-09-04 18:22:11 -0700682 if (op == kAdd || op == kSub) {
683 return a;
684 } else if (op == kMul || op == kNeg) {
685 return b;
686 }
Aart Bikd14c5952015-09-08 15:25:15 -0700687 } else if (op == kMul || op == kDiv) {
688 // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
689 if (value == 1) {
690 return a;
691 } else if (value == -1) {
692 op = kNeg;
693 b = a;
694 a = nullptr;
695 }
Aart Bik471a2032015-09-04 18:22:11 -0700696 }
697 } else if (b->operation == kNeg) {
Aart Bikd14c5952015-09-08 15:25:15 -0700698 // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
699 if (op == kAdd) {
700 op = kSub;
701 b = b->op_b;
702 } else if (op == kSub) {
703 op = kAdd;
704 b = b->op_b;
705 } else if (op == kNeg) {
706 return b->op_b;
Aart Bik471a2032015-09-04 18:22:11 -0700707 }
708 }
709 return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
710}
711
Aart Bik30efb4e2015-07-30 12:14:31 -0700712bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
713 InductionInfo* info2) {
714 // Test structural equality only, without accounting for simplifications.
715 if (info1 != nullptr && info2 != nullptr) {
716 return
717 info1->induction_class == info2->induction_class &&
718 info1->operation == info2->operation &&
719 info1->fetch == info2->fetch &&
720 InductionEqual(info1->op_a, info2->op_a) &&
721 InductionEqual(info1->op_b, info2->op_b);
722 }
723 // Otherwise only two nullptrs are considered equal.
724 return info1 == info2;
725}
726
Aart Bik471a2032015-09-04 18:22:11 -0700727bool HInductionVarAnalysis::IsIntAndGet(InductionInfo* info, int64_t* value) {
728 if (info != nullptr && info->induction_class == kInvariant && info->operation == kFetch) {
729 DCHECK(info->fetch);
730 if (info->fetch->IsIntConstant()) {
731 *value = info->fetch->AsIntConstant()->GetValue();
732 return true;
733 } else if (info->fetch->IsLongConstant()) {
734 *value = info->fetch->AsLongConstant()->GetValue();
735 return true;
736 }
737 }
738 return false;
739}
740
Aart Bik30efb4e2015-07-30 12:14:31 -0700741std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
742 if (info != nullptr) {
743 if (info->induction_class == kInvariant) {
Aart Bik471a2032015-09-04 18:22:11 -0700744 int64_t value = -1;
Aart Bik30efb4e2015-07-30 12:14:31 -0700745 std::string inv = "(";
746 inv += InductionToString(info->op_a);
747 switch (info->operation) {
Aart Bike609b7c2015-08-27 13:46:58 -0700748 case kNop: inv += " @ "; break;
749 case kAdd: inv += " + "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700750 case kSub:
Aart Bike609b7c2015-08-27 13:46:58 -0700751 case kNeg: inv += " - "; break;
752 case kMul: inv += " * "; break;
753 case kDiv: inv += " / "; break;
Aart Bik30efb4e2015-07-30 12:14:31 -0700754 case kFetch:
Aart Bike609b7c2015-08-27 13:46:58 -0700755 DCHECK(info->fetch);
Aart Bik471a2032015-09-04 18:22:11 -0700756 if (IsIntAndGet(info, &value)) {
757 inv += std::to_string(value);
758 } else {
759 inv += std::to_string(info->fetch->GetId()) + ":" + info->fetch->DebugName();
760 }
Aart Bik30efb4e2015-07-30 12:14:31 -0700761 break;
762 }
763 inv += InductionToString(info->op_b);
764 return inv + ")";
765 } else {
Aart Bike609b7c2015-08-27 13:46:58 -0700766 DCHECK(info->operation == kNop);
Aart Bik30efb4e2015-07-30 12:14:31 -0700767 if (info->induction_class == kLinear) {
768 return "(" + InductionToString(info->op_a) + " * i + " +
769 InductionToString(info->op_b) + ")";
770 } else if (info->induction_class == kWrapAround) {
771 return "wrap(" + InductionToString(info->op_a) + ", " +
772 InductionToString(info->op_b) + ")";
773 } else if (info->induction_class == kPeriodic) {
774 return "periodic(" + InductionToString(info->op_a) + ", " +
775 InductionToString(info->op_b) + ")";
776 }
777 }
778 }
779 return "";
780}
781
782} // namespace art