1 /*
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 #include "induction_var_range.h"
19 
20 namespace art {
21 
22 /**
23  * Since graph traversal may enter a SCC at any position, an initial representation may be rotated,
24  * along dependences, viz. any of (a, b, c, d), (d, a, b, c)  (c, d, a, b), (b, c, d, a) assuming
25  * a chain of dependences (mutual independent items may occur in arbitrary order). For proper
26  * classification, the lexicographically first loop-phi is rotated to the front.
27  */
RotateEntryPhiFirst(HLoopInformation * loop,ArenaVector<HInstruction * > * scc,ArenaVector<HInstruction * > * new_scc)28 static void RotateEntryPhiFirst(HLoopInformation* loop,
29                                 ArenaVector<HInstruction*>* scc,
30                                 ArenaVector<HInstruction*>* new_scc) {
31   // Find very first loop-phi.
32   const HInstructionList& phis = loop->GetHeader()->GetPhis();
33   HInstruction* phi = nullptr;
34   size_t phi_pos = -1;
35   const size_t size = scc->size();
36   for (size_t i = 0; i < size; i++) {
37     HInstruction* other = (*scc)[i];
38     if (other->IsLoopHeaderPhi() && (phi == nullptr || phis.FoundBefore(other, phi))) {
39       phi = other;
40       phi_pos = i;
41     }
42   }
43 
44   // If found, bring that loop-phi to front.
45   if (phi != nullptr) {
46     new_scc->clear();
47     for (size_t i = 0; i < size; i++) {
48       new_scc->push_back((*scc)[phi_pos]);
49       if (++phi_pos >= size) phi_pos = 0;
50     }
51     DCHECK_EQ(size, new_scc->size());
52     scc->swap(*new_scc);
53   }
54 }
55 
56 /**
57  * Returns true if the from/to types denote a narrowing, integral conversion (precision loss).
58  */
IsNarrowingIntegralConversion(DataType::Type from,DataType::Type to)59 static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to) {
60   switch (from) {
61     case DataType::Type::kInt64:
62       return to == DataType::Type::kUint8 ||
63              to == DataType::Type::kInt8 ||
64              to == DataType::Type::kUint16 ||
65              to == DataType::Type::kInt16 ||
66              to == DataType::Type::kInt32;
67     case DataType::Type::kInt32:
68       return to == DataType::Type::kUint8 ||
69              to == DataType::Type::kInt8 ||
70              to == DataType::Type::kUint16 ||
71              to == DataType::Type::kInt16;
72     case DataType::Type::kUint16:
73     case DataType::Type::kInt16:
74       return to == DataType::Type::kUint8 || to == DataType::Type::kInt8;
75     default:
76       return false;
77   }
78 }
79 
80 /**
81  * Returns result of implicit widening type conversion done in HIR.
82  */
ImplicitConversion(DataType::Type type)83 static DataType::Type ImplicitConversion(DataType::Type type) {
84   switch (type) {
85     case DataType::Type::kBool:
86     case DataType::Type::kUint8:
87     case DataType::Type::kInt8:
88     case DataType::Type::kUint16:
89     case DataType::Type::kInt16:
90       return DataType::Type::kInt32;
91     default:
92       return type;
93   }
94 }
95 
96 /**
97  * Returns true if loop is guarded by "a cmp b" on entry.
98  */
IsGuardedBy(HLoopInformation * loop,IfCondition cmp,HInstruction * a,HInstruction * b)99 static bool IsGuardedBy(HLoopInformation* loop,
100                         IfCondition cmp,
101                         HInstruction* a,
102                         HInstruction* b) {
103   // Chase back through straightline code to the first potential
104   // block that has a control dependence.
105   // guard:   if (x) bypass
106   //              |
107   // entry: straightline code
108   //              |
109   //           preheader
110   //              |
111   //            header
112   HBasicBlock* guard = loop->GetPreHeader();
113   HBasicBlock* entry = loop->GetHeader();
114   while (guard->GetPredecessors().size() == 1 &&
115          guard->GetSuccessors().size() == 1) {
116     entry = guard;
117     guard = guard->GetSinglePredecessor();
118   }
119   // Find guard.
120   HInstruction* control = guard->GetLastInstruction();
121   if (!control->IsIf()) {
122     return false;
123   }
124   HIf* ifs = control->AsIf();
125   HInstruction* if_expr = ifs->InputAt(0);
126   if (if_expr->IsCondition()) {
127     IfCondition other_cmp = ifs->IfTrueSuccessor() == entry
128         ? if_expr->AsCondition()->GetCondition()
129         : if_expr->AsCondition()->GetOppositeCondition();
130     if (if_expr->InputAt(0) == a && if_expr->InputAt(1) == b) {
131       return cmp == other_cmp;
132     } else if (if_expr->InputAt(1) == a && if_expr->InputAt(0) == b) {
133       switch (cmp) {
134         case kCondLT: return other_cmp == kCondGT;
135         case kCondLE: return other_cmp == kCondGE;
136         case kCondGT: return other_cmp == kCondLT;
137         case kCondGE: return other_cmp == kCondLE;
138         default: LOG(FATAL) << "unexpected cmp: " << cmp;
139       }
140     }
141   }
142   return false;
143 }
144 
145 /* Finds first loop header phi use. */
FindFirstLoopHeaderPhiUse(HLoopInformation * loop,HInstruction * instruction)146 HInstruction* FindFirstLoopHeaderPhiUse(HLoopInformation* loop, HInstruction* instruction) {
147   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
148     if (use.GetUser()->GetBlock() == loop->GetHeader() &&
149         use.GetUser()->IsPhi() &&
150         use.GetUser()->InputAt(1) == instruction) {
151       return use.GetUser();
152     }
153   }
154   return nullptr;
155 }
156 
157 /**
158  * Relinks the Phi structure after break-loop rewriting.
159  */
FixOutsideUse(HLoopInformation * loop,HInstruction * instruction,HInstruction * replacement,bool rewrite)160 bool FixOutsideUse(HLoopInformation* loop,
161                    HInstruction* instruction,
162                    HInstruction* replacement,
163                    bool rewrite) {
164   // Deal with regular uses.
165   const HUseList<HInstruction*>& uses = instruction->GetUses();
166   for (auto it = uses.begin(), end = uses.end(); it != end; ) {
167     HInstruction* user = it->GetUser();
168     size_t index = it->GetIndex();
169     ++it;  // increment prior to potential removal
170     if (user->GetBlock()->GetLoopInformation() != loop) {
171       if (replacement == nullptr) {
172         return false;
173       } else if (rewrite) {
174         user->ReplaceInput(replacement, index);
175       }
176     }
177   }
178   // Deal with environment uses.
179   const HUseList<HEnvironment*>& env_uses = instruction->GetEnvUses();
180   for (auto it = env_uses.begin(), end = env_uses.end(); it != end;) {
181     HEnvironment* user = it->GetUser();
182     size_t index = it->GetIndex();
183     ++it;  // increment prior to potential removal
184     if (user->GetHolder()->GetBlock()->GetLoopInformation() != loop) {
185       if (replacement == nullptr) {
186         return false;
187       } else if (rewrite) {
188         user->RemoveAsUserOfInput(index);
189         user->SetRawEnvAt(index, replacement);
190         replacement->AddEnvUseAt(user, index);
191       }
192     }
193   }
194   return true;
195 }
196 
197 /**
198  * Test and rewrite the loop body of a break-loop. Returns true on success.
199  */
RewriteBreakLoopBody(HLoopInformation * loop,HBasicBlock * body,HInstruction * cond,HInstruction * index,HInstruction * upper,bool rewrite)200 bool RewriteBreakLoopBody(HLoopInformation* loop,
201                           HBasicBlock* body,
202                           HInstruction* cond,
203                           HInstruction* index,
204                           HInstruction* upper,
205                           bool rewrite) {
206   // Deal with Phis. Outside use prohibited, except for index (which gets exit value).
207   for (HInstructionIterator it(loop->GetHeader()->GetPhis()); !it.Done(); it.Advance()) {
208     HInstruction* exit_value = it.Current() == index ? upper : nullptr;
209     if (!FixOutsideUse(loop, it.Current(), exit_value, rewrite)) {
210       return false;
211     }
212   }
213   // Deal with other statements in header.
214   for (HInstruction* m = cond->GetPrevious(), *p = nullptr; m && !m->IsSuspendCheck(); m = p) {
215     p = m->GetPrevious();
216     if (rewrite) {
217       m->MoveBefore(body->GetFirstInstruction(), false);
218     }
219     if (!FixOutsideUse(loop, m, FindFirstLoopHeaderPhiUse(loop, m), rewrite)) {
220       return false;
221     }
222   }
223   return true;
224 }
225 
226 //
227 // Class methods.
228 //
229 
HInductionVarAnalysis(HGraph * graph,const char * name)230 HInductionVarAnalysis::HInductionVarAnalysis(HGraph* graph, const char* name)
231     : HOptimization(graph, name),
232       global_depth_(0),
233       stack_(graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
234       map_(std::less<HInstruction*>(),
235            graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
236       scc_(graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
237       cycle_(std::less<HInstruction*>(),
238              graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
239       type_(DataType::Type::kVoid),
240       induction_(std::less<HLoopInformation*>(),
241                  graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)),
242       cycles_(std::less<HPhi*>(),
243               graph->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)) {
244 }
245 
Run()246 void HInductionVarAnalysis::Run() {
247   // Detects sequence variables (generalized induction variables) during an outer to inner
248   // traversal of all loops using Gerlek's algorithm. The order is important to enable
249   // range analysis on outer loop while visiting inner loops.
250   for (HBasicBlock* graph_block : graph_->GetReversePostOrder()) {
251     // Don't analyze irreducible loops.
252     if (graph_block->IsLoopHeader() && !graph_block->GetLoopInformation()->IsIrreducible()) {
253       VisitLoop(graph_block->GetLoopInformation());
254     }
255   }
256 }
257 
VisitLoop(HLoopInformation * loop)258 void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
259   // Find strongly connected components (SSCs) in the SSA graph of this loop using Tarjan's
260   // algorithm. Due to the descendant-first nature, classification happens "on-demand".
261   global_depth_ = 0;
262   DCHECK(stack_.empty());
263   map_.clear();
264 
265   for (HBlocksInLoopIterator it_loop(*loop); !it_loop.Done(); it_loop.Advance()) {
266     HBasicBlock* loop_block = it_loop.Current();
267     DCHECK(loop_block->IsInLoop());
268     if (loop_block->GetLoopInformation() != loop) {
269       continue;  // Inner loops visited later.
270     }
271     // Visit phi-operations and instructions.
272     for (HInstructionIterator it(loop_block->GetPhis()); !it.Done(); it.Advance()) {
273       HInstruction* instruction = it.Current();
274       if (!IsVisitedNode(instruction)) {
275         VisitNode(loop, instruction);
276       }
277     }
278     for (HInstructionIterator it(loop_block->GetInstructions()); !it.Done(); it.Advance()) {
279       HInstruction* instruction = it.Current();
280       if (!IsVisitedNode(instruction)) {
281         VisitNode(loop, instruction);
282       }
283     }
284   }
285 
286   DCHECK(stack_.empty());
287   map_.clear();
288 
289   // Determine the loop's trip-count.
290   VisitControl(loop);
291 }
292 
VisitNode(HLoopInformation * loop,HInstruction * instruction)293 void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
294   const uint32_t d1 = ++global_depth_;
295   map_.Put(instruction, NodeInfo(d1));
296   stack_.push_back(instruction);
297 
298   // Visit all descendants.
299   uint32_t low = d1;
300   for (HInstruction* input : instruction->GetInputs()) {
301     low = std::min(low, VisitDescendant(loop, input));
302   }
303 
304   // Lower or found SCC?
305   if (low < d1) {
306     map_.find(instruction)->second.depth = low;
307   } else {
308     scc_.clear();
309     cycle_.clear();
310 
311     // Pop the stack to build the SCC for classification.
312     while (!stack_.empty()) {
313       HInstruction* x = stack_.back();
314       scc_.push_back(x);
315       stack_.pop_back();
316       map_.find(x)->second.done = true;
317       if (x == instruction) {
318         break;
319       }
320     }
321 
322     // Type of induction.
323     type_ = scc_[0]->GetType();
324 
325     // Classify the SCC.
326     if (scc_.size() == 1 && !scc_[0]->IsLoopHeaderPhi()) {
327       ClassifyTrivial(loop, scc_[0]);
328     } else {
329       ClassifyNonTrivial(loop);
330     }
331 
332     scc_.clear();
333     cycle_.clear();
334   }
335 }
336 
VisitDescendant(HLoopInformation * loop,HInstruction * instruction)337 uint32_t HInductionVarAnalysis::VisitDescendant(HLoopInformation* loop, HInstruction* instruction) {
338   // If the definition is either outside the loop (loop invariant entry value)
339   // or assigned in inner loop (inner exit value), the traversal stops.
340   HLoopInformation* otherLoop = instruction->GetBlock()->GetLoopInformation();
341   if (otherLoop != loop) {
342     return global_depth_;
343   }
344 
345   // Inspect descendant node.
346   if (!IsVisitedNode(instruction)) {
347     VisitNode(loop, instruction);
348     return map_.find(instruction)->second.depth;
349   } else {
350     auto it = map_.find(instruction);
351     return it->second.done ? global_depth_ : it->second.depth;
352   }
353 }
354 
ClassifyTrivial(HLoopInformation * loop,HInstruction * instruction)355 void HInductionVarAnalysis::ClassifyTrivial(HLoopInformation* loop, HInstruction* instruction) {
356   InductionInfo* info = nullptr;
357   if (instruction->IsPhi()) {
358     info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 0);
359   } else if (instruction->IsAdd()) {
360     info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
361                           LookupInfo(loop, instruction->InputAt(1)), kAdd);
362   } else if (instruction->IsSub()) {
363     info = TransferAddSub(LookupInfo(loop, instruction->InputAt(0)),
364                           LookupInfo(loop, instruction->InputAt(1)), kSub);
365   } else if (instruction->IsNeg()) {
366     info = TransferNeg(LookupInfo(loop, instruction->InputAt(0)));
367   } else if (instruction->IsMul()) {
368     info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
369                        LookupInfo(loop, instruction->InputAt(1)));
370   } else if (instruction->IsShl()) {
371     HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
372     if (mulc != nullptr) {
373       info = TransferMul(LookupInfo(loop, instruction->InputAt(0)),
374                          LookupInfo(loop, mulc));
375     }
376   } else if (instruction->IsSelect()) {
377     info = TransferPhi(loop, instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);
378   } else if (instruction->IsTypeConversion()) {
379     info = TransferConversion(LookupInfo(loop, instruction->InputAt(0)),
380                               instruction->AsTypeConversion()->GetInputType(),
381                               instruction->AsTypeConversion()->GetResultType());
382   } else if (instruction->IsBoundsCheck()) {
383     info = LookupInfo(loop, instruction->InputAt(0));  // Pass-through.
384   }
385 
386   // Successfully classified?
387   if (info != nullptr) {
388     AssignInfo(loop, instruction, info);
389   }
390 }
391 
ClassifyNonTrivial(HLoopInformation * loop)392 void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
393   const size_t size = scc_.size();
394   DCHECK_GE(size, 1u);
395 
396   // Rotate proper loop-phi to front.
397   if (size > 1) {
398     ArenaVector<HInstruction*> other(
399         graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis));
400     RotateEntryPhiFirst(loop, &scc_, &other);
401   }
402 
403   // Analyze from loop-phi onwards.
404   HInstruction* phi = scc_[0];
405   if (!phi->IsLoopHeaderPhi()) {
406     return;
407   }
408 
409   // External link should be loop invariant.
410   InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
411   if (initial == nullptr || initial->induction_class != kInvariant) {
412     return;
413   }
414 
415   // Store interesting cycle in each loop phi.
416   for (size_t i = 0; i < size; i++) {
417     if (scc_[i]->IsLoopHeaderPhi()) {
418       AssignCycle(scc_[i]->AsPhi());
419     }
420   }
421 
422   // Singleton is wrap-around induction if all internal links have the same meaning.
423   if (size == 1) {
424     InductionInfo* update = TransferPhi(loop, phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
425     if (update != nullptr) {
426       AssignInfo(loop, phi, CreateInduction(kWrapAround,
427                                             kNop,
428                                             initial,
429                                             update,
430                                             /*fetch*/ nullptr,
431                                             type_));
432     }
433     return;
434   }
435 
436   // Inspect remainder of the cycle that resides in scc_. The cycle_ mapping assigns
437   // temporary meaning to its nodes, seeded from the phi instruction and back.
438   for (size_t i = 1; i < size; i++) {
439     HInstruction* instruction = scc_[i];
440     InductionInfo* update = nullptr;
441     if (instruction->IsPhi()) {
442       update = SolvePhiAllInputs(loop, phi, instruction);
443     } else if (instruction->IsAdd()) {
444       update = SolveAddSub(
445           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kAdd, true);
446     } else if (instruction->IsSub()) {
447       update = SolveAddSub(
448           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kSub, true);
449     } else if (instruction->IsMul()) {
450       update = SolveOp(
451           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kMul);
452     } else if (instruction->IsDiv()) {
453       update = SolveOp(
454           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kDiv);
455     } else if (instruction->IsRem()) {
456       update = SolveOp(
457           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kRem);
458     } else if (instruction->IsShl()) {
459       HInstruction* mulc = GetShiftConstant(loop, instruction, /*initial*/ nullptr);
460       if (mulc != nullptr) {
461         update = SolveOp(loop, phi, instruction, instruction->InputAt(0), mulc, kMul);
462       }
463     } else if (instruction->IsShr() || instruction->IsUShr()) {
464       HInstruction* divc = GetShiftConstant(loop, instruction, initial);
465       if (divc != nullptr) {
466         update = SolveOp(loop, phi, instruction, instruction->InputAt(0), divc, kDiv);
467       }
468     } else if (instruction->IsXor()) {
469       update = SolveOp(
470           loop, phi, instruction, instruction->InputAt(0), instruction->InputAt(1), kXor);
471     } else if (instruction->IsEqual()) {
472       update = SolveTest(loop, phi, instruction, 0);
473     } else if (instruction->IsNotEqual()) {
474       update = SolveTest(loop, phi, instruction, 1);
475     } else if (instruction->IsSelect()) {
476       update = SolvePhi(instruction, /*input_index*/ 0, /*adjust_input_size*/ 1);  // acts like Phi
477     } else if (instruction->IsTypeConversion()) {
478       update = SolveConversion(loop, phi, instruction->AsTypeConversion());
479     }
480     if (update == nullptr) {
481       return;
482     }
483     cycle_.Put(instruction, update);
484   }
485 
486   // Success if all internal links received the same temporary meaning.
487   InductionInfo* induction = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
488   if (induction != nullptr) {
489     switch (induction->induction_class) {
490       case kInvariant:
491         // Construct combined stride of the linear induction.
492         induction = CreateInduction(kLinear, kNop, induction, initial, /*fetch*/ nullptr, type_);
493         FALLTHROUGH_INTENDED;
494       case kPolynomial:
495       case kGeometric:
496       case kWrapAround:
497         // Classify first phi and then the rest of the cycle "on-demand".
498         // Statements are scanned in order.
499         AssignInfo(loop, phi, induction);
500         for (size_t i = 1; i < size; i++) {
501           ClassifyTrivial(loop, scc_[i]);
502         }
503         break;
504       case kPeriodic:
505         // Classify all elements in the cycle with the found periodic induction while
506         // rotating each first element to the end. Lastly, phi is classified.
507         // Statements are scanned in reverse order.
508         for (size_t i = size - 1; i >= 1; i--) {
509           AssignInfo(loop, scc_[i], induction);
510           induction = RotatePeriodicInduction(induction->op_b, induction->op_a);
511         }
512         AssignInfo(loop, phi, induction);
513         break;
514       default:
515         break;
516     }
517   }
518 }
519 
RotatePeriodicInduction(InductionInfo * induction,InductionInfo * last)520 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduction(
521     InductionInfo* induction,
522     InductionInfo* last) {
523   // Rotates a periodic induction of the form
524   //   (a, b, c, d, e)
525   // into
526   //   (b, c, d, e, a)
527   // in preparation of assigning this to the previous variable in the sequence.
528   if (induction->induction_class == kInvariant) {
529     return CreateInduction(kPeriodic,
530                            kNop,
531                            induction,
532                            last,
533                            /*fetch*/ nullptr,
534                            type_);
535   }
536   return CreateInduction(kPeriodic,
537                          kNop,
538                          induction->op_a,
539                          RotatePeriodicInduction(induction->op_b, last),
540                          /*fetch*/ nullptr,
541                          type_);
542 }
543 
TransferPhi(HLoopInformation * loop,HInstruction * phi,size_t input_index,size_t adjust_input_size)544 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(HLoopInformation* loop,
545                                                                          HInstruction* phi,
546                                                                          size_t input_index,
547                                                                          size_t adjust_input_size) {
548   // Match all phi inputs from input_index onwards exactly.
549   HInputsRef inputs = phi->GetInputs();
550   DCHECK_LT(input_index, inputs.size());
551   InductionInfo* a = LookupInfo(loop, inputs[input_index]);
552   for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
553     InductionInfo* b = LookupInfo(loop, inputs[i]);
554     if (!InductionEqual(a, b)) {
555       return nullptr;
556     }
557   }
558   return a;
559 }
560 
TransferAddSub(InductionInfo * a,InductionInfo * b,InductionOp op)561 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(InductionInfo* a,
562                                                                             InductionInfo* b,
563                                                                             InductionOp op) {
564   // Transfer over an addition or subtraction: any invariant, linear, polynomial, geometric,
565   // wrap-around, or periodic can be combined with an invariant to yield a similar result.
566   // Two linear or two polynomial inputs can be combined too. Other combinations fail.
567   if (a != nullptr && b != nullptr) {
568     if (IsNarrowingLinear(a) || IsNarrowingLinear(b)) {
569       return nullptr;  // no transfer
570     } else if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
571       return CreateInvariantOp(op, a, b);  // direct invariant
572     } else if ((a->induction_class == kLinear && b->induction_class == kLinear) ||
573                (a->induction_class == kPolynomial && b->induction_class == kPolynomial)) {
574       // Rule induc(a, b) + induc(a', b') -> induc(a + a', b + b').
575       InductionInfo* new_a = TransferAddSub(a->op_a, b->op_a, op);
576       InductionInfo* new_b = TransferAddSub(a->op_b, b->op_b, op);
577       if (new_a != nullptr && new_b != nullptr)  {
578         return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
579       }
580     } else if (a->induction_class == kInvariant) {
581       // Rule a + induc(a', b') -> induc(a', a + b') or induc(a + a', a + b').
582       InductionInfo* new_a = b->op_a;
583       InductionInfo* new_b = TransferAddSub(a, b->op_b, op);
584       if (b->induction_class == kWrapAround || b->induction_class == kPeriodic) {
585         new_a = TransferAddSub(a, new_a, op);
586       } else if (op == kSub) {  // Negation required.
587         new_a = TransferNeg(new_a);
588       }
589       if (new_a != nullptr && new_b != nullptr)  {
590         return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type_);
591       }
592     } else if (b->induction_class == kInvariant) {
593       // Rule induc(a, b) + b' -> induc(a, b + b') or induc(a + b', b + b').
594       InductionInfo* new_a = a->op_a;
595       InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
596       if (a->induction_class == kWrapAround || a->induction_class == kPeriodic) {
597         new_a = TransferAddSub(new_a, b, op);
598       }
599       if (new_a != nullptr && new_b != nullptr)  {
600         return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
601       }
602     }
603   }
604   return nullptr;
605 }
606 
TransferNeg(InductionInfo * a)607 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(InductionInfo* a) {
608   // Transfer over a unary negation: an invariant, linear, polynomial, geometric (mul),
609   // wrap-around, or periodic input yields a similar but negated induction as result.
610   if (a != nullptr) {
611     if (IsNarrowingLinear(a)) {
612       return nullptr;  // no transfer
613     } else if (a->induction_class == kInvariant) {
614       return CreateInvariantOp(kNeg, nullptr, a);  // direct invariant
615     } else if (a->induction_class != kGeometric || a->operation == kMul) {
616       // Rule - induc(a, b) -> induc(-a, -b).
617       InductionInfo* new_a = TransferNeg(a->op_a);
618       InductionInfo* new_b = TransferNeg(a->op_b);
619       if (new_a != nullptr && new_b != nullptr) {
620         return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
621       }
622     }
623   }
624   return nullptr;
625 }
626 
TransferMul(InductionInfo * a,InductionInfo * b)627 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(InductionInfo* a,
628                                                                          InductionInfo* b) {
629   // Transfer over a multiplication: any invariant, linear, polynomial, geometric (mul),
630   // wrap-around, or periodic can be multiplied with an invariant to yield a similar
631   // but multiplied result. Two non-invariant inputs cannot be multiplied, however.
632   if (a != nullptr && b != nullptr) {
633     if (IsNarrowingLinear(a) || IsNarrowingLinear(b)) {
634       return nullptr;  // no transfer
635     } else if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
636       return CreateInvariantOp(kMul, a, b);  // direct invariant
637     } else if (a->induction_class == kInvariant && (b->induction_class != kGeometric ||
638                                                     b->operation == kMul)) {
639       // Rule a * induc(a', b') -> induc(a * a', b * b').
640       InductionInfo* new_a = TransferMul(a, b->op_a);
641       InductionInfo* new_b = TransferMul(a, b->op_b);
642       if (new_a != nullptr && new_b != nullptr) {
643         return CreateInduction(b->induction_class, b->operation, new_a, new_b, b->fetch, type_);
644       }
645     } else if (b->induction_class == kInvariant && (a->induction_class != kGeometric ||
646                                                     a->operation == kMul)) {
647       // Rule induc(a, b) * b' -> induc(a * b', b * b').
648       InductionInfo* new_a = TransferMul(a->op_a, b);
649       InductionInfo* new_b = TransferMul(a->op_b, b);
650       if (new_a != nullptr && new_b != nullptr) {
651         return CreateInduction(a->induction_class, a->operation, new_a, new_b, a->fetch, type_);
652       }
653     }
654   }
655   return nullptr;
656 }
657 
TransferConversion(InductionInfo * a,DataType::Type from,DataType::Type to)658 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferConversion(
659     InductionInfo* a,
660     DataType::Type from,
661     DataType::Type to) {
662   if (a != nullptr) {
663     // Allow narrowing conversion on linear induction in certain cases:
664     // induction is already at narrow type, or can be made narrower.
665     if (IsNarrowingIntegralConversion(from, to) &&
666         a->induction_class == kLinear &&
667         (a->type == to || IsNarrowingIntegralConversion(a->type, to))) {
668       return CreateInduction(kLinear, kNop, a->op_a, a->op_b, a->fetch, to);
669     }
670   }
671   return nullptr;
672 }
673 
SolvePhi(HInstruction * phi,size_t input_index,size_t adjust_input_size)674 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HInstruction* phi,
675                                                                       size_t input_index,
676                                                                       size_t adjust_input_size) {
677   // Match all phi inputs from input_index onwards exactly.
678   HInputsRef inputs = phi->GetInputs();
679   DCHECK_LT(input_index, inputs.size());
680   auto ita = cycle_.find(inputs[input_index]);
681   if (ita != cycle_.end()) {
682     for (size_t i = input_index + 1, n = inputs.size() - adjust_input_size; i < n; i++) {
683       auto itb = cycle_.find(inputs[i]);
684       if (itb == cycle_.end() ||
685           !HInductionVarAnalysis::InductionEqual(ita->second, itb->second)) {
686         return nullptr;
687       }
688     }
689     return ita->second;
690   }
691   return nullptr;
692 }
693 
SolvePhiAllInputs(HLoopInformation * loop,HInstruction * entry_phi,HInstruction * phi)694 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhiAllInputs(
695     HLoopInformation* loop,
696     HInstruction* entry_phi,
697     HInstruction* phi) {
698   // Match all phi inputs.
699   InductionInfo* match = SolvePhi(phi, /*input_index*/ 0, /*adjust_input_size*/ 0);
700   if (match != nullptr) {
701     return match;
702   }
703 
704   // Otherwise, try to solve for a periodic seeded from phi onward.
705   // Only tight multi-statement cycles are considered in order to
706   // simplify rotating the periodic during the final classification.
707   if (phi->IsLoopHeaderPhi() && phi->InputCount() == 2) {
708     InductionInfo* a = LookupInfo(loop, phi->InputAt(0));
709     if (a != nullptr && a->induction_class == kInvariant) {
710       if (phi->InputAt(1) == entry_phi) {
711         InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
712         return CreateInduction(kPeriodic, kNop, a, initial, /*fetch*/ nullptr, type_);
713       }
714       InductionInfo* b = SolvePhi(phi, /*input_index*/ 1, /*adjust_input_size*/ 0);
715       if (b != nullptr && b->induction_class == kPeriodic) {
716         return CreateInduction(kPeriodic, kNop, a, b, /*fetch*/ nullptr, type_);
717       }
718     }
719   }
720   return nullptr;
721 }
722 
SolveAddSub(HLoopInformation * loop,HInstruction * entry_phi,HInstruction * instruction,HInstruction * x,HInstruction * y,InductionOp op,bool is_first_call)723 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopInformation* loop,
724                                                                          HInstruction* entry_phi,
725                                                                          HInstruction* instruction,
726                                                                          HInstruction* x,
727                                                                          HInstruction* y,
728                                                                          InductionOp op,
729                                                                          bool is_first_call) {
730   // Solve within a cycle over an addition or subtraction.
731   InductionInfo* b = LookupInfo(loop, y);
732   if (b != nullptr) {
733     if (b->induction_class == kInvariant) {
734       // Adding or subtracting an invariant value, seeded from phi,
735       // keeps adding to the stride of the linear induction.
736       if (x == entry_phi) {
737         return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
738       }
739       auto it = cycle_.find(x);
740       if (it != cycle_.end()) {
741         InductionInfo* a = it->second;
742         if (a->induction_class == kInvariant) {
743           return CreateInvariantOp(op, a, b);
744         }
745       }
746     } else if (b->induction_class == kLinear && b->type == type_) {
747       // Solve within a tight cycle that adds a term that is already classified as a linear
748       // induction for a polynomial induction k = k + i (represented as sum over linear terms).
749       if (x == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
750         InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
751         InductionInfo* new_a = op == kAdd ? b : TransferNeg(b);
752         if (new_a != nullptr) {
753           return CreateInduction(kPolynomial, kNop, new_a, initial, /*fetch*/ nullptr, type_);
754         }
755       }
756     }
757   }
758 
759   // Try some alternatives before failing.
760   if (op == kAdd) {
761     // Try the other way around for an addition if considered for first time.
762     if (is_first_call) {
763       return SolveAddSub(loop, entry_phi, instruction, y, x, op, false);
764     }
765   } else if (op == kSub) {
766     // Solve within a tight cycle that is formed by exactly two instructions,
767     // one phi and one update, for a periodic idiom of the form k = c - k.
768     if (y == entry_phi && entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
769       InductionInfo* a = LookupInfo(loop, x);
770       if (a != nullptr && a->induction_class == kInvariant) {
771         InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
772         return CreateInduction(kPeriodic,
773                                kNop,
774                                CreateInvariantOp(kSub, a, initial),
775                                initial,
776                                /*fetch*/ nullptr,
777                                type_);
778       }
779     }
780   }
781   return nullptr;
782 }
783 
SolveOp(HLoopInformation * loop,HInstruction * entry_phi,HInstruction * instruction,HInstruction * x,HInstruction * y,InductionOp op)784 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveOp(HLoopInformation* loop,
785                                                                       HInstruction* entry_phi,
786                                                                       HInstruction* instruction,
787                                                                       HInstruction* x,
788                                                                       HInstruction* y,
789                                                                       InductionOp op) {
790   // Solve within a tight cycle for a binary operation k = k op c or, for some op, k = c op k.
791   if (entry_phi->InputCount() == 2 && instruction == entry_phi->InputAt(1)) {
792     InductionInfo* c = nullptr;
793     InductionInfo* b = LookupInfo(loop, y);
794     if (b != nullptr && b->induction_class == kInvariant && entry_phi == x) {
795       c = b;
796     } else if (op != kDiv && op != kRem) {
797       InductionInfo* a = LookupInfo(loop, x);
798       if (a != nullptr && a->induction_class == kInvariant && entry_phi == y) {
799         c = a;
800       }
801     }
802     // Found suitable operand left or right?
803     if (c != nullptr) {
804       InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
805       switch (op) {
806         case kMul:
807         case kDiv:
808           // Restrict base of geometric induction to direct fetch.
809           if (c->operation == kFetch) {
810             return CreateInduction(kGeometric,
811                                    op,
812                                    initial,
813                                    CreateConstant(0, type_),
814                                    c->fetch,
815                                    type_);
816           }
817           break;
818         case kRem:
819           // Idiomatic MOD wrap-around induction.
820           return CreateInduction(kWrapAround,
821                                  kNop,
822                                  initial,
823                                  CreateInvariantOp(kRem, initial, c),
824                                  /*fetch*/ nullptr,
825                                  type_);
826         case kXor:
827           // Idiomatic XOR periodic induction.
828           return CreateInduction(kPeriodic,
829                                  kNop,
830                                  CreateInvariantOp(kXor, initial, c),
831                                  initial,
832                                  /*fetch*/ nullptr,
833                                  type_);
834         default:
835           LOG(FATAL) << op;
836           UNREACHABLE();
837       }
838     }
839   }
840   return nullptr;
841 }
842 
SolveTest(HLoopInformation * loop,HInstruction * entry_phi,HInstruction * instruction,int64_t opposite_value)843 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveTest(HLoopInformation* loop,
844                                                                        HInstruction* entry_phi,
845                                                                        HInstruction* instruction,
846                                                                        int64_t opposite_value) {
847   // Detect hidden XOR construction in x = (x == false) or x = (x != true).
848   int64_t value = -1;
849   HInstruction* x = instruction->InputAt(0);
850   HInstruction* y = instruction->InputAt(1);
851   if (IsExact(LookupInfo(loop, x), &value) && value == opposite_value) {
852     return SolveOp(loop, entry_phi, instruction, graph_->GetIntConstant(1), y, kXor);
853   } else if (IsExact(LookupInfo(loop, y), &value) && value == opposite_value) {
854     return SolveOp(loop, entry_phi, instruction, x, graph_->GetIntConstant(1), kXor);
855   }
856   return nullptr;
857 }
858 
SolveConversion(HLoopInformation * loop,HInstruction * entry_phi,HTypeConversion * conversion)859 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveConversion(
860     HLoopInformation* loop,
861     HInstruction* entry_phi,
862     HTypeConversion* conversion) {
863   DataType::Type from = conversion->GetInputType();
864   DataType::Type to = conversion->GetResultType();
865   // A narrowing conversion is allowed as *last* operation of the cycle of a linear induction
866   // with an initial value that fits the type, provided that the narrowest encountered type is
867   // recorded with the induction to account for the precision loss. The narrower induction does
868   // *not* transfer to any wider operations, however, since these may yield out-of-type values
869   if (entry_phi->InputCount() == 2 && conversion == entry_phi->InputAt(1)) {
870     int64_t min = DataType::MinValueOfIntegralType(to);
871     int64_t max = DataType::MaxValueOfIntegralType(to);
872     int64_t value = 0;
873     InductionInfo* initial = LookupInfo(loop, entry_phi->InputAt(0));
874     if (IsNarrowingIntegralConversion(from, to) &&
875         IsAtLeast(initial, &value) && value >= min &&
876         IsAtMost(initial, &value)  && value <= max) {
877       auto it = cycle_.find(conversion->GetInput());
878       if (it != cycle_.end() && it->second->induction_class == kInvariant) {
879         type_ = to;
880         return it->second;
881       }
882     }
883   }
884   return nullptr;
885 }
886 
887 //
888 // Loop trip count analysis methods.
889 //
890 
VisitControl(HLoopInformation * loop)891 void HInductionVarAnalysis::VisitControl(HLoopInformation* loop) {
892   HInstruction* control = loop->GetHeader()->GetLastInstruction();
893   if (control->IsIf()) {
894     HIf* ifs = control->AsIf();
895     HBasicBlock* if_true = ifs->IfTrueSuccessor();
896     HBasicBlock* if_false = ifs->IfFalseSuccessor();
897     HInstruction* if_expr = ifs->InputAt(0);
898     // Determine if loop has following structure in header.
899     // loop-header: ....
900     //              if (condition) goto X
901     if (if_expr->IsCondition()) {
902       HCondition* condition = if_expr->AsCondition();
903       InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
904       InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
905       DataType::Type type = ImplicitConversion(condition->InputAt(0)->GetType());
906       // Determine if the loop control uses a known sequence on an if-exit (X outside) or on
907       // an if-iterate (X inside), expressed as if-iterate when passed into VisitCondition().
908       if (a == nullptr || b == nullptr) {
909         return;  // Loop control is not a sequence.
910       } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
911         VisitCondition(loop, if_false, a, b, type, condition->GetOppositeCondition());
912       } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
913         VisitCondition(loop, if_true, a, b, type, condition->GetCondition());
914       }
915     }
916   }
917 }
918 
VisitCondition(HLoopInformation * loop,HBasicBlock * body,InductionInfo * a,InductionInfo * b,DataType::Type type,IfCondition cmp)919 void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
920                                            HBasicBlock* body,
921                                            InductionInfo* a,
922                                            InductionInfo* b,
923                                            DataType::Type type,
924                                            IfCondition cmp) {
925   if (a->induction_class == kInvariant && b->induction_class == kLinear) {
926     // Swap condition if induction is at right-hand-side (e.g. U > i is same as i < U).
927     switch (cmp) {
928       case kCondLT: VisitCondition(loop, body, b, a, type, kCondGT); break;
929       case kCondLE: VisitCondition(loop, body, b, a, type, kCondGE); break;
930       case kCondGT: VisitCondition(loop, body, b, a, type, kCondLT); break;
931       case kCondGE: VisitCondition(loop, body, b, a, type, kCondLE); break;
932       case kCondNE: VisitCondition(loop, body, b, a, type, kCondNE); break;
933       default: break;
934     }
935   } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
936     // Analyze condition with induction at left-hand-side (e.g. i < U).
937     InductionInfo* lower_expr = a->op_b;
938     InductionInfo* upper_expr = b;
939     InductionInfo* stride_expr = a->op_a;
940     // Test for constant stride and integral condition.
941     int64_t stride_value = 0;
942     if (!IsExact(stride_expr, &stride_value)) {
943       return;  // unknown stride
944     } else if (type != DataType::Type::kInt32 && type != DataType::Type::kInt64) {
945       return;  // not integral
946     }
947     // Since loops with a i != U condition will not be normalized by the method below, first
948     // try to rewrite a break-loop with terminating condition i != U into an equivalent loop
949     // with non-strict end condition i <= U or i >= U if such a rewriting is possible and safe.
950     if (cmp == kCondNE && RewriteBreakLoop(loop, body, stride_value, type)) {
951       cmp = stride_value > 0 ? kCondLE : kCondGE;
952     }
953     // If this rewriting failed, try to rewrite condition i != U into strict end condition i < U
954     // or i > U if this end condition is reached exactly (tested by verifying if the loop has a
955     // unit stride and the non-strict condition would be always taken).
956     if (cmp == kCondNE && ((stride_value == +1 && IsTaken(lower_expr, upper_expr, kCondLE)) ||
957                            (stride_value == -1 && IsTaken(lower_expr, upper_expr, kCondGE)))) {
958       cmp = stride_value > 0 ? kCondLT : kCondGT;
959     }
960     // A mismatch between the type of condition and the induction is only allowed if the,
961     // necessarily narrower, induction range fits the narrower control.
962     if (type != a->type &&
963         !FitsNarrowerControl(lower_expr, upper_expr, stride_value, a->type, cmp)) {
964       return;  // mismatched type
965     }
966     // Normalize a linear loop control with a nonzero stride:
967     //   stride > 0, either i < U or i <= U
968     //   stride < 0, either i > U or i >= U
969     if ((stride_value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
970         (stride_value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
971       VisitTripCount(loop, lower_expr, upper_expr, stride_expr, stride_value, type, cmp);
972     }
973   }
974 }
975 
VisitTripCount(HLoopInformation * loop,InductionInfo * lower_expr,InductionInfo * upper_expr,InductionInfo * stride_expr,int64_t stride_value,DataType::Type type,IfCondition cmp)976 void HInductionVarAnalysis::VisitTripCount(HLoopInformation* loop,
977                                            InductionInfo* lower_expr,
978                                            InductionInfo* upper_expr,
979                                            InductionInfo* stride_expr,
980                                            int64_t stride_value,
981                                            DataType::Type type,
982                                            IfCondition cmp) {
983   // Any loop of the general form:
984   //
985   //    for (i = L; i <= U; i += S) // S > 0
986   // or for (i = L; i >= U; i += S) // S < 0
987   //      .. i ..
988   //
989   // can be normalized into:
990   //
991   //    for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
992   //      .. L + S * n ..
993   //
994   // taking the following into consideration:
995   //
996   // (1) Using the same precision, the TC (trip-count) expression should be interpreted as
997   //     an unsigned entity, for example, as in the following loop that uses the full range:
998   //     for (int i = INT_MIN; i < INT_MAX; i++) // TC = UINT_MAX
999   // (2) The TC is only valid if the loop is taken, otherwise TC = 0, as in:
1000   //     for (int i = 12; i < U; i++) // TC = 0 when U <= 12
1001   //     If this cannot be determined at compile-time, the TC is only valid within the
1002   //     loop-body proper, not the loop-header unless enforced with an explicit taken-test.
1003   // (3) The TC is only valid if the loop is finite, otherwise TC has no value, as in:
1004   //     for (int i = 0; i <= U; i++) // TC = Inf when U = INT_MAX
1005   //     If this cannot be determined at compile-time, the TC is only valid when enforced
1006   //     with an explicit finite-test.
1007   // (4) For loops which early-exits, the TC forms an upper bound, as in:
1008   //     for (int i = 0; i < 10 && ....; i++) // TC <= 10
1009   InductionInfo* trip_count = upper_expr;
1010   const bool is_taken = IsTaken(lower_expr, upper_expr, cmp);
1011   const bool is_finite = IsFinite(upper_expr, stride_value, type, cmp);
1012   const bool cancels = (cmp == kCondLT || cmp == kCondGT) && std::abs(stride_value) == 1;
1013   if (!cancels) {
1014     // Convert exclusive integral inequality into inclusive integral inequality,
1015     // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
1016     if (cmp == kCondLT) {
1017       trip_count = CreateInvariantOp(kSub, trip_count, CreateConstant(1, type));
1018     } else if (cmp == kCondGT) {
1019       trip_count = CreateInvariantOp(kAdd, trip_count, CreateConstant(1, type));
1020     }
1021     // Compensate for stride.
1022     trip_count = CreateInvariantOp(kAdd, trip_count, stride_expr);
1023   }
1024   trip_count = CreateInvariantOp(
1025       kDiv, CreateInvariantOp(kSub, trip_count, lower_expr), stride_expr);
1026   // Assign the trip-count expression to the loop control. Clients that use the information
1027   // should be aware that the expression is only valid under the conditions listed above.
1028   InductionOp tcKind = kTripCountInBodyUnsafe;  // needs both tests
1029   if (is_taken && is_finite) {
1030     tcKind = kTripCountInLoop;  // needs neither test
1031   } else if (is_finite) {
1032     tcKind = kTripCountInBody;  // needs taken-test
1033   } else if (is_taken) {
1034     tcKind = kTripCountInLoopUnsafe;  // needs finite-test
1035   }
1036   InductionOp op = kNop;
1037   switch (cmp) {
1038     case kCondLT: op = kLT; break;
1039     case kCondLE: op = kLE; break;
1040     case kCondGT: op = kGT; break;
1041     case kCondGE: op = kGE; break;
1042     default:      LOG(FATAL) << "CONDITION UNREACHABLE";
1043   }
1044   // Associate trip count with control instruction, rather than the condition (even
1045   // though it's its use) since former provides a convenient use-free placeholder.
1046   HInstruction* control = loop->GetHeader()->GetLastInstruction();
1047   InductionInfo* taken_test = CreateInvariantOp(op, lower_expr, upper_expr);
1048   DCHECK(control->IsIf());
1049   AssignInfo(loop, control, CreateTripCount(tcKind, trip_count, taken_test, type));
1050 }
1051 
IsTaken(InductionInfo * lower_expr,InductionInfo * upper_expr,IfCondition cmp)1052 bool HInductionVarAnalysis::IsTaken(InductionInfo* lower_expr,
1053                                     InductionInfo* upper_expr,
1054                                     IfCondition cmp) {
1055   int64_t lower_value;
1056   int64_t upper_value;
1057   switch (cmp) {
1058     case kCondLT:
1059       return IsAtMost(lower_expr, &lower_value)
1060           && IsAtLeast(upper_expr, &upper_value)
1061           && lower_value < upper_value;
1062     case kCondLE:
1063       return IsAtMost(lower_expr, &lower_value)
1064           && IsAtLeast(upper_expr, &upper_value)
1065           && lower_value <= upper_value;
1066     case kCondGT:
1067       return IsAtLeast(lower_expr, &lower_value)
1068           && IsAtMost(upper_expr, &upper_value)
1069           && lower_value > upper_value;
1070     case kCondGE:
1071       return IsAtLeast(lower_expr, &lower_value)
1072           && IsAtMost(upper_expr, &upper_value)
1073           && lower_value >= upper_value;
1074     default:
1075       LOG(FATAL) << "CONDITION UNREACHABLE";
1076   }
1077   return false;  // not certain, may be untaken
1078 }
1079 
IsFinite(InductionInfo * upper_expr,int64_t stride_value,DataType::Type type,IfCondition cmp)1080 bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr,
1081                                      int64_t stride_value,
1082                                      DataType::Type type,
1083                                      IfCondition cmp) {
1084   int64_t min = DataType::MinValueOfIntegralType(type);
1085   int64_t max = DataType::MaxValueOfIntegralType(type);
1086   // Some rules under which it is certain at compile-time that the loop is finite.
1087   int64_t value;
1088   switch (cmp) {
1089     case kCondLT:
1090       return stride_value == 1 ||
1091           (IsAtMost(upper_expr, &value) && value <= (max - stride_value + 1));
1092     case kCondLE:
1093       return (IsAtMost(upper_expr, &value) && value <= (max - stride_value));
1094     case kCondGT:
1095       return stride_value == -1 ||
1096           (IsAtLeast(upper_expr, &value) && value >= (min - stride_value - 1));
1097     case kCondGE:
1098       return (IsAtLeast(upper_expr, &value) && value >= (min - stride_value));
1099     default:
1100       LOG(FATAL) << "CONDITION UNREACHABLE";
1101   }
1102   return false;  // not certain, may be infinite
1103 }
1104 
FitsNarrowerControl(InductionInfo * lower_expr,InductionInfo * upper_expr,int64_t stride_value,DataType::Type type,IfCondition cmp)1105 bool HInductionVarAnalysis::FitsNarrowerControl(InductionInfo* lower_expr,
1106                                                 InductionInfo* upper_expr,
1107                                                 int64_t stride_value,
1108                                                 DataType::Type type,
1109                                                 IfCondition cmp) {
1110   int64_t min = DataType::MinValueOfIntegralType(type);
1111   int64_t max = DataType::MaxValueOfIntegralType(type);
1112   // Inclusive test need one extra.
1113   if (stride_value != 1 && stride_value != -1) {
1114     return false;  // non-unit stride
1115   } else if (cmp == kCondLE) {
1116     max--;
1117   } else if (cmp == kCondGE) {
1118     min++;
1119   }
1120   // Do both bounds fit the range?
1121   int64_t value = 0;
1122   return IsAtLeast(lower_expr, &value) && value >= min &&
1123          IsAtMost(lower_expr, &value)  && value <= max &&
1124          IsAtLeast(upper_expr, &value) && value >= min &&
1125          IsAtMost(upper_expr, &value)  && value <= max;
1126 }
1127 
RewriteBreakLoop(HLoopInformation * loop,HBasicBlock * body,int64_t stride_value,DataType::Type type)1128 bool HInductionVarAnalysis::RewriteBreakLoop(HLoopInformation* loop,
1129                                              HBasicBlock* body,
1130                                              int64_t stride_value,
1131                                              DataType::Type type) {
1132   // Only accept unit stride.
1133   if (std::abs(stride_value) != 1) {
1134     return false;
1135   }
1136   // Simple terminating i != U condition, used nowhere else.
1137   HIf* ifs = loop->GetHeader()->GetLastInstruction()->AsIf();
1138   HInstruction* cond = ifs->InputAt(0);
1139   if (ifs->GetPrevious() != cond || !cond->HasOnlyOneNonEnvironmentUse()) {
1140     return false;
1141   }
1142   int c = LookupInfo(loop, cond->InputAt(0))->induction_class == kLinear ? 0 : 1;
1143   HInstruction* index = cond->InputAt(c);
1144   HInstruction* upper = cond->InputAt(1 - c);
1145   // Safe to rewrite into i <= U?
1146   IfCondition cmp = stride_value > 0 ? kCondLE : kCondGE;
1147   if (!index->IsPhi() || !IsFinite(LookupInfo(loop, upper), stride_value, type, cmp)) {
1148     return false;
1149   }
1150   // Body consists of update to index i only, used nowhere else.
1151   if (body->GetSuccessors().size() != 1 ||
1152       body->GetSingleSuccessor() != loop->GetHeader() ||
1153       !body->GetPhis().IsEmpty() ||
1154       body->GetInstructions().IsEmpty() ||
1155       body->GetFirstInstruction() != index->InputAt(1) ||
1156       !body->GetFirstInstruction()->HasOnlyOneNonEnvironmentUse() ||
1157       !body->GetFirstInstruction()->GetNext()->IsGoto()) {
1158     return false;
1159   }
1160   // Always taken or guarded by enclosing condition.
1161   if (!IsTaken(LookupInfo(loop, index)->op_b, LookupInfo(loop, upper), cmp) &&
1162       !IsGuardedBy(loop, cmp, index->InputAt(0), upper)) {
1163     return false;
1164   }
1165   // Test if break-loop body can be written, and do so on success.
1166   if (RewriteBreakLoopBody(loop, body, cond, index, upper, /*rewrite*/ false)) {
1167     RewriteBreakLoopBody(loop, body, cond, index, upper, /*rewrite*/ true);
1168   } else {
1169     return false;
1170   }
1171   // Rewrite condition in HIR.
1172   if (ifs->IfTrueSuccessor() != body) {
1173     cmp = (cmp == kCondLE) ? kCondGT : kCondLT;
1174   }
1175   HInstruction* rep = nullptr;
1176   switch (cmp) {
1177     case kCondLT: rep = new (graph_->GetAllocator()) HLessThan(index, upper); break;
1178     case kCondGT: rep = new (graph_->GetAllocator()) HGreaterThan(index, upper); break;
1179     case kCondLE: rep = new (graph_->GetAllocator()) HLessThanOrEqual(index, upper); break;
1180     case kCondGE: rep = new (graph_->GetAllocator()) HGreaterThanOrEqual(index, upper); break;
1181     default: LOG(FATAL) << cmp; UNREACHABLE();
1182   }
1183   loop->GetHeader()->ReplaceAndRemoveInstructionWith(cond, rep);
1184   return true;
1185 }
1186 
1187 //
1188 // Helper methods.
1189 //
1190 
AssignInfo(HLoopInformation * loop,HInstruction * instruction,InductionInfo * info)1191 void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
1192                                        HInstruction* instruction,
1193                                        InductionInfo* info) {
1194   auto it = induction_.find(loop);
1195   if (it == induction_.end()) {
1196     it = induction_.Put(loop,
1197                         ArenaSafeMap<HInstruction*, InductionInfo*>(
1198                             std::less<HInstruction*>(),
1199                             graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)));
1200   }
1201   it->second.Put(instruction, info);
1202 }
1203 
LookupInfo(HLoopInformation * loop,HInstruction * instruction)1204 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInformation* loop,
1205                                                                         HInstruction* instruction) {
1206   auto it = induction_.find(loop);
1207   if (it != induction_.end()) {
1208     auto loop_it = it->second.find(instruction);
1209     if (loop_it != it->second.end()) {
1210       return loop_it->second;
1211     }
1212   }
1213   if (loop->IsDefinedOutOfTheLoop(instruction)) {
1214     InductionInfo* info = CreateInvariantFetch(instruction);
1215     AssignInfo(loop, instruction, info);
1216     return info;
1217   }
1218   return nullptr;
1219 }
1220 
CreateConstant(int64_t value,DataType::Type type)1221 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
1222                                                                             DataType::Type type) {
1223   HInstruction* constant;
1224   switch (type) {
1225     case DataType::Type::kFloat64: constant = graph_->GetDoubleConstant(value); break;
1226     case DataType::Type::kFloat32: constant = graph_->GetFloatConstant(value);  break;
1227     case DataType::Type::kInt64:   constant = graph_->GetLongConstant(value);   break;
1228     default:                       constant = graph_->GetIntConstant(value);    break;
1229   }
1230   return CreateInvariantFetch(constant);
1231 }
1232 
CreateSimplifiedInvariant(InductionOp op,InductionInfo * a,InductionInfo * b)1233 HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
1234     InductionOp op,
1235     InductionInfo* a,
1236     InductionInfo* b) {
1237   // Perform some light-weight simplifications during construction of a new invariant.
1238   // This often safes memory and yields a more concise representation of the induction.
1239   // More exhaustive simplifications are done by later phases once induction nodes are
1240   // translated back into HIR code (e.g. by loop optimizations or BCE).
1241   int64_t value = -1;
1242   if (IsExact(a, &value)) {
1243     if (value == 0) {
1244       // Simplify 0 + b = b, 0 ^ b = b, 0 * b = 0.
1245       if (op == kAdd || op == kXor) {
1246         return b;
1247       } else if (op == kMul) {
1248         return a;
1249       }
1250     } else if (op == kMul) {
1251       // Simplify 1 * b = b, -1 * b = -b
1252       if (value == 1) {
1253         return b;
1254       } else if (value == -1) {
1255         return CreateSimplifiedInvariant(kNeg, nullptr, b);
1256       }
1257     }
1258   }
1259   if (IsExact(b, &value)) {
1260     if (value == 0) {
1261       // Simplify a + 0 = a, a - 0 = a, a ^ 0 = a, a * 0 = 0, -0 = 0.
1262       if (op == kAdd || op == kSub || op == kXor) {
1263         return a;
1264       } else if (op == kMul || op == kNeg) {
1265         return b;
1266       }
1267     } else if (op == kMul || op == kDiv) {
1268       // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
1269       if (value == 1) {
1270         return a;
1271       } else if (value == -1) {
1272         return CreateSimplifiedInvariant(kNeg, nullptr, a);
1273       }
1274     }
1275   } else if (b->operation == kNeg) {
1276     // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
1277     if (op == kAdd) {
1278       return CreateSimplifiedInvariant(kSub, a, b->op_b);
1279     } else if (op == kSub) {
1280       return CreateSimplifiedInvariant(kAdd, a, b->op_b);
1281     } else if (op == kNeg) {
1282       return b->op_b;
1283     }
1284   } else if (b->operation == kSub) {
1285     // Simplify - (a - b) = b - a.
1286     if (op == kNeg) {
1287       return CreateSimplifiedInvariant(kSub, b->op_b, b->op_a);
1288     }
1289   }
1290   return new (graph_->GetAllocator()) InductionInfo(
1291       kInvariant, op, a, b, nullptr, ImplicitConversion(b->type));
1292 }
1293 
GetShiftConstant(HLoopInformation * loop,HInstruction * instruction,InductionInfo * initial)1294 HInstruction* HInductionVarAnalysis::GetShiftConstant(HLoopInformation* loop,
1295                                                       HInstruction* instruction,
1296                                                       InductionInfo* initial) {
1297   DCHECK(instruction->IsShl() || instruction->IsShr() || instruction->IsUShr());
1298   // Shift-rights are only the same as division for non-negative initial inputs.
1299   // Otherwise we would round incorrectly.
1300   if (initial != nullptr) {
1301     int64_t value = -1;
1302     if (!IsAtLeast(initial, &value) || value < 0) {
1303       return nullptr;
1304     }
1305   }
1306   // Obtain the constant needed to treat shift as equivalent multiplication or division.
1307   // This yields an existing instruction if the constant is already there. Otherwise, this
1308   // has a side effect on the HIR. The restriction on the shift factor avoids generating a
1309   // negative constant (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that
1310   // generalization for shift factors outside [0,32) and [0,64) ranges is done earlier.
1311   InductionInfo* b = LookupInfo(loop, instruction->InputAt(1));
1312   int64_t value = -1;
1313   if (IsExact(b, &value)) {
1314     DataType::Type type = instruction->InputAt(0)->GetType();
1315     if (type == DataType::Type::kInt32 && 0 <= value && value < 31) {
1316       return graph_->GetIntConstant(1 << value);
1317     }
1318     if (type == DataType::Type::kInt64 && 0 <= value && value < 63) {
1319       return graph_->GetLongConstant(1L << value);
1320     }
1321   }
1322   return nullptr;
1323 }
1324 
AssignCycle(HPhi * phi)1325 void HInductionVarAnalysis::AssignCycle(HPhi* phi) {
1326   ArenaSet<HInstruction*>* set = &cycles_.Put(phi, ArenaSet<HInstruction*>(
1327       graph_->GetAllocator()->Adapter(kArenaAllocInductionVarAnalysis)))->second;
1328   for (HInstruction* i : scc_) {
1329     set->insert(i);
1330   }
1331 }
1332 
LookupCycle(HPhi * phi)1333 ArenaSet<HInstruction*>* HInductionVarAnalysis::LookupCycle(HPhi* phi) {
1334   auto it = cycles_.find(phi);
1335   if (it != cycles_.end()) {
1336     return &it->second;
1337   }
1338   return nullptr;
1339 }
1340 
IsExact(InductionInfo * info,int64_t * value)1341 bool HInductionVarAnalysis::IsExact(InductionInfo* info, int64_t* value) {
1342   return InductionVarRange(this).IsConstant(info, InductionVarRange::kExact, value);
1343 }
1344 
IsAtMost(InductionInfo * info,int64_t * value)1345 bool HInductionVarAnalysis::IsAtMost(InductionInfo* info, int64_t* value) {
1346   return InductionVarRange(this).IsConstant(info, InductionVarRange::kAtMost, value);
1347 }
1348 
IsAtLeast(InductionInfo * info,int64_t * value)1349 bool HInductionVarAnalysis::IsAtLeast(InductionInfo* info, int64_t* value) {
1350   return InductionVarRange(this).IsConstant(info, InductionVarRange::kAtLeast, value);
1351 }
1352 
IsNarrowingLinear(InductionInfo * info)1353 bool HInductionVarAnalysis::IsNarrowingLinear(InductionInfo* info) {
1354   return info != nullptr &&
1355       info->induction_class == kLinear &&
1356       (info->type == DataType::Type::kUint8 ||
1357        info->type == DataType::Type::kInt8 ||
1358        info->type == DataType::Type::kUint16 ||
1359        info->type == DataType::Type::kInt16 ||
1360        (info->type == DataType::Type::kInt32 && (info->op_a->type == DataType::Type::kInt64 ||
1361                                                  info->op_b->type == DataType::Type::kInt64)));
1362 }
1363 
InductionEqual(InductionInfo * info1,InductionInfo * info2)1364 bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
1365                                            InductionInfo* info2) {
1366   // Test structural equality only, without accounting for simplifications.
1367   if (info1 != nullptr && info2 != nullptr) {
1368     return
1369         info1->induction_class == info2->induction_class &&
1370         info1->operation       == info2->operation       &&
1371         info1->fetch           == info2->fetch           &&
1372         info1->type            == info2->type            &&
1373         InductionEqual(info1->op_a, info2->op_a)         &&
1374         InductionEqual(info1->op_b, info2->op_b);
1375   }
1376   // Otherwise only two nullptrs are considered equal.
1377   return info1 == info2;
1378 }
1379 
FetchToString(HInstruction * fetch)1380 std::string HInductionVarAnalysis::FetchToString(HInstruction* fetch) {
1381   DCHECK(fetch != nullptr);
1382   if (fetch->IsIntConstant()) {
1383     return std::to_string(fetch->AsIntConstant()->GetValue());
1384   } else if (fetch->IsLongConstant()) {
1385     return std::to_string(fetch->AsLongConstant()->GetValue());
1386   }
1387   return std::to_string(fetch->GetId()) + ":" + fetch->DebugName();
1388 }
1389 
InductionToString(InductionInfo * info)1390 std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
1391   if (info != nullptr) {
1392     if (info->induction_class == kInvariant) {
1393       std::string inv = "(";
1394       inv += InductionToString(info->op_a);
1395       switch (info->operation) {
1396         case kNop:   inv += " @ ";  break;
1397         case kAdd:   inv += " + ";  break;
1398         case kSub:
1399         case kNeg:   inv += " - ";  break;
1400         case kMul:   inv += " * ";  break;
1401         case kDiv:   inv += " / ";  break;
1402         case kRem:   inv += " % ";  break;
1403         case kXor:   inv += " ^ ";  break;
1404         case kLT:    inv += " < ";  break;
1405         case kLE:    inv += " <= "; break;
1406         case kGT:    inv += " > ";  break;
1407         case kGE:    inv += " >= "; break;
1408         case kFetch: inv += FetchToString(info->fetch); break;
1409         case kTripCountInLoop:       inv += " (TC-loop) ";        break;
1410         case kTripCountInBody:       inv += " (TC-body) ";        break;
1411         case kTripCountInLoopUnsafe: inv += " (TC-loop-unsafe) "; break;
1412         case kTripCountInBodyUnsafe: inv += " (TC-body-unsafe) "; break;
1413       }
1414       inv += InductionToString(info->op_b);
1415       inv += ")";
1416       return inv;
1417     } else {
1418       if (info->induction_class == kLinear) {
1419         DCHECK(info->operation == kNop);
1420         return "(" + InductionToString(info->op_a) + " * i + " +
1421                      InductionToString(info->op_b) + "):" +
1422                      DataType::PrettyDescriptor(info->type);
1423       } else if (info->induction_class == kPolynomial) {
1424         DCHECK(info->operation == kNop);
1425         return "poly(sum_lt(" + InductionToString(info->op_a) + ") + " +
1426                                 InductionToString(info->op_b) + "):" +
1427                                 DataType::PrettyDescriptor(info->type);
1428       } else if (info->induction_class == kGeometric) {
1429         DCHECK(info->operation == kMul || info->operation == kDiv);
1430         DCHECK(info->fetch != nullptr);
1431         return "geo(" + InductionToString(info->op_a) + " * " +
1432                         FetchToString(info->fetch) +
1433                         (info->operation == kMul ? " ^ i + " : " ^ -i + ") +
1434                         InductionToString(info->op_b) + "):" +
1435                         DataType::PrettyDescriptor(info->type);
1436       } else if (info->induction_class == kWrapAround) {
1437         DCHECK(info->operation == kNop);
1438         return "wrap(" + InductionToString(info->op_a) + ", " +
1439                          InductionToString(info->op_b) + "):" +
1440                          DataType::PrettyDescriptor(info->type);
1441       } else if (info->induction_class == kPeriodic) {
1442         DCHECK(info->operation == kNop);
1443         return "periodic(" + InductionToString(info->op_a) + ", " +
1444                              InductionToString(info->op_b) + "):" +
1445                              DataType::PrettyDescriptor(info->type);
1446       }
1447     }
1448   }
1449   return "";
1450 }
1451 
1452 }  // namespace art
1453