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