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