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