• 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_range.h"
18 
19 #include <limits>
20 #include "optimizing/nodes.h"
21 
22 namespace art HIDDEN {
23 
24 /** Returns true if 64-bit constant fits in 32-bit constant. */
CanLongValueFitIntoInt(int64_t c)25 static bool CanLongValueFitIntoInt(int64_t c) {
26   return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
27 }
28 
29 /** Returns true if 32-bit addition can be done safely. */
IsSafeAdd(int32_t c1,int32_t c2)30 static bool IsSafeAdd(int32_t c1, int32_t c2) {
31   return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
32 }
33 
34 /** Returns true if 32-bit subtraction can be done safely. */
IsSafeSub(int32_t c1,int32_t c2)35 static bool IsSafeSub(int32_t c1, int32_t c2) {
36   return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
37 }
38 
39 /** Returns true if 32-bit multiplication can be done safely. */
IsSafeMul(int32_t c1,int32_t c2)40 static bool IsSafeMul(int32_t c1, int32_t c2) {
41   return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
42 }
43 
44 /** Returns true if 32-bit division can be done safely. */
IsSafeDiv(int32_t c1,int32_t c2)45 static bool IsSafeDiv(int32_t c1, int32_t c2) {
46   return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
47 }
48 
49 /** Computes a * b for a,b > 0 (at least until first overflow happens). */
SafeMul(int64_t a,int64_t b,bool * overflow)50 static int64_t SafeMul(int64_t a, int64_t b, /*out*/ bool* overflow) {
51   if (a > 0 && b > 0 && a > (std::numeric_limits<int64_t>::max() / b)) {
52     *overflow = true;
53   }
54   return a * b;
55 }
56 
57 /** Returns b^e for b,e > 0. Sets overflow if arithmetic wrap-around occurred. */
IntPow(int64_t b,int64_t e,bool * overflow)58 static int64_t IntPow(int64_t b, int64_t e, /*out*/ bool* overflow) {
59   DCHECK_LT(0, b);
60   DCHECK_LT(0, e);
61   int64_t pow = 1;
62   while (e) {
63     if (e & 1) {
64       pow = SafeMul(pow, b, overflow);
65     }
66     e >>= 1;
67     if (e) {
68       b = SafeMul(b, b, overflow);
69     }
70   }
71   return pow;
72 }
73 
74 /** Hunts "under the hood" for a suitable instruction at the hint. */
IsMaxAtHint(HInstruction * instruction,HInstruction * hint,HInstruction ** suitable)75 static bool IsMaxAtHint(
76     HInstruction* instruction, HInstruction* hint, /*out*/HInstruction** suitable) {
77   if (instruction->IsMin()) {
78     // For MIN(x, y), return most suitable x or y as maximum.
79     return IsMaxAtHint(instruction->InputAt(0), hint, suitable) ||
80            IsMaxAtHint(instruction->InputAt(1), hint, suitable);
81   } else {
82     *suitable = instruction;
83     return HuntForDeclaration(instruction) == hint;
84   }
85 }
86 
87 /** Post-analysis simplification of a minimum value that makes the bound more useful to clients. */
SimplifyMin(InductionVarRange::Value v)88 static InductionVarRange::Value SimplifyMin(InductionVarRange::Value v) {
89   if (v.is_known && v.a_constant == 1 && v.b_constant <= 0) {
90     // If a == 1,  instruction >= 0 and b <= 0, just return the constant b.
91     // No arithmetic wrap-around can occur.
92     if (IsGEZero(v.instruction)) {
93       return InductionVarRange::Value(v.b_constant);
94     }
95   }
96   return v;
97 }
98 
99 /** Post-analysis simplification of a maximum value that makes the bound more useful to clients. */
SimplifyMax(InductionVarRange::Value v,HInstruction * hint)100 static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v, HInstruction* hint) {
101   if (v.is_known && v.a_constant >= 1) {
102     // An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as
103     // length + b because length >= 0 is true.
104     int64_t value;
105     if (v.instruction->IsDiv() &&
106         v.instruction->InputAt(0)->IsArrayLength() &&
107         IsInt64AndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
108       return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
109     }
110     // If a == 1, the most suitable one suffices as maximum value.
111     HInstruction* suitable = nullptr;
112     if (v.a_constant == 1 && IsMaxAtHint(v.instruction, hint, &suitable)) {
113       return InductionVarRange::Value(suitable, 1, v.b_constant);
114     }
115   }
116   return v;
117 }
118 
119 /** Tests for a constant value. */
IsConstantValue(InductionVarRange::Value v)120 static bool IsConstantValue(InductionVarRange::Value v) {
121   return v.is_known && v.a_constant == 0;
122 }
123 
124 /** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
CorrectForType(InductionVarRange::Value v,DataType::Type type)125 static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, DataType::Type type) {
126   switch (type) {
127     case DataType::Type::kUint8:
128     case DataType::Type::kInt8:
129     case DataType::Type::kUint16:
130     case DataType::Type::kInt16: {
131       // Constants within range only.
132       // TODO: maybe some room for improvement, like allowing widening conversions
133       int32_t min = DataType::MinValueOfIntegralType(type);
134       int32_t max = DataType::MaxValueOfIntegralType(type);
135       return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
136           ? v
137           : InductionVarRange::Value();
138     }
139     default:
140       return v;
141   }
142 }
143 
144 /** Inserts an instruction. */
Insert(HBasicBlock * block,HInstruction * instruction)145 static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
146   DCHECK(block != nullptr);
147   DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
148   DCHECK(instruction != nullptr);
149   block->InsertInstructionBefore(instruction, block->GetLastInstruction());
150   return instruction;
151 }
152 
153 /** Obtains loop's control instruction. */
GetLoopControl(const HLoopInformation * loop)154 static HInstruction* GetLoopControl(const HLoopInformation* loop) {
155   DCHECK(loop != nullptr);
156   return loop->GetHeader()->GetLastInstruction();
157 }
158 
159 /** Determines whether the `context` is in the body of the `loop`. */
IsContextInBody(const HBasicBlock * context,const HLoopInformation * loop)160 static bool IsContextInBody(const HBasicBlock* context, const HLoopInformation* loop) {
161   DCHECK(loop != nullptr);
162   // We're currently classifying trip count only for the exit condition from loop header.
163   // All other blocks in the loop are considered loop body.
164   return context != loop->GetHeader() && loop->Contains(*context);
165 }
166 
167 /** Determines whether to use the full trip count for given `context`, `loop` and `is_min`. */
UseFullTripCount(const HBasicBlock * context,const HLoopInformation * loop,bool is_min)168 bool UseFullTripCount(const HBasicBlock* context, const HLoopInformation* loop, bool is_min) {
169   // We're currently classifying trip count only for the exit condition from loop header.
170   // So, we should call this helper function only if the loop control is an `HIf` with
171   // one edge leaving the loop. The loop header is the only block that's both inside
172   // the loop and not in the loop body.
173   DCHECK(GetLoopControl(loop)->IsIf());
174   DCHECK_NE(loop->Contains(*GetLoopControl(loop)->AsIf()->IfTrueSuccessor()),
175             loop->Contains(*GetLoopControl(loop)->AsIf()->IfFalseSuccessor()));
176   if (loop->Contains(*context)) {
177     // Use the full trip count if determining the maximum and context is not in the loop body.
178     DCHECK_NE(context == loop->GetHeader(), IsContextInBody(context, loop));
179     return !is_min && context == loop->GetHeader();
180   } else {
181     // Trip count after the loop is always the maximum (ignoring `is_min`),
182     // as long as the `context` is dominated by the loop control exit block.
183     // If there are additional exit edges, the value is unknown on those paths.
184     HInstruction* loop_control = GetLoopControl(loop);
185     HBasicBlock* then_block = loop_control->AsIf()->IfTrueSuccessor();
186     HBasicBlock* else_block = loop_control->AsIf()->IfFalseSuccessor();
187     HBasicBlock* loop_exit_block = loop->Contains(*then_block) ? else_block : then_block;
188     return loop_exit_block->Dominates(context);
189   }
190 }
191 
192 //
193 // Public class methods.
194 //
195 
InductionVarRange(HInductionVarAnalysis * induction_analysis)196 InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
197     : induction_analysis_(induction_analysis),
198       chase_hint_(nullptr) {
199   DCHECK(induction_analysis != nullptr);
200 }
201 
GetInductionRange(const HBasicBlock * context,HInstruction * instruction,HInstruction * chase_hint,Value * min_val,Value * max_val,bool * needs_finite_test)202 bool InductionVarRange::GetInductionRange(const HBasicBlock* context,
203                                           HInstruction* instruction,
204                                           HInstruction* chase_hint,
205                                           /*out*/Value* min_val,
206                                           /*out*/Value* max_val,
207                                           /*out*/bool* needs_finite_test) {
208   const HLoopInformation* loop = nullptr;
209   HInductionVarAnalysis::InductionInfo* info = nullptr;
210   HInductionVarAnalysis::InductionInfo* trip = nullptr;
211   if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
212     return false;
213   }
214   // Type int or lower (this is not too restrictive since intended clients, like
215   // bounds check elimination, will have truncated higher precision induction
216   // at their use point already).
217   switch (info->type) {
218     case DataType::Type::kUint8:
219     case DataType::Type::kInt8:
220     case DataType::Type::kUint16:
221     case DataType::Type::kInt16:
222     case DataType::Type::kInt32:
223       break;
224     default:
225       return false;
226   }
227   // Find range.
228   chase_hint_ = chase_hint;
229   int64_t stride_value = 0;
230   *min_val = SimplifyMin(GetVal(context, loop, info, trip, /*is_min=*/ true));
231   *max_val = SimplifyMax(GetVal(context, loop, info, trip, /*is_min=*/ false), chase_hint);
232   *needs_finite_test =
233       NeedsTripCount(context, loop, info, &stride_value) && IsUnsafeTripCount(trip);
234   chase_hint_ = nullptr;
235   // Retry chasing constants for wrap-around (merge sensitive).
236   if (!min_val->is_known && info->induction_class == HInductionVarAnalysis::kWrapAround) {
237     *min_val = SimplifyMin(GetVal(context, loop, info, trip, /*is_min=*/ true));
238   }
239   return true;
240 }
241 
CanGenerateRange(const HBasicBlock * context,HInstruction * instruction,bool * needs_finite_test,bool * needs_taken_test)242 bool InductionVarRange::CanGenerateRange(const HBasicBlock* context,
243                                          HInstruction* instruction,
244                                          /*out*/bool* needs_finite_test,
245                                          /*out*/bool* needs_taken_test) {
246   bool is_last_value = false;
247   int64_t stride_value = 0;
248   return GenerateRangeOrLastValue(context,
249                                   instruction,
250                                   is_last_value,
251                                   nullptr,
252                                   nullptr,
253                                   nullptr,
254                                   nullptr,
255                                   nullptr,  // nothing generated yet
256                                   &stride_value,
257                                   needs_finite_test,
258                                   needs_taken_test) &&
259          (stride_value == -1 ||
260           stride_value == 0 ||
261           stride_value == 1);  // avoid arithmetic wrap-around anomalies.
262 }
263 
GenerateRange(const HBasicBlock * context,HInstruction * instruction,HGraph * graph,HBasicBlock * block,HInstruction ** lower,HInstruction ** upper)264 void InductionVarRange::GenerateRange(const HBasicBlock* context,
265                                       HInstruction* instruction,
266                                       HGraph* graph,
267                                       HBasicBlock* block,
268                                       /*out*/HInstruction** lower,
269                                       /*out*/HInstruction** upper) {
270   bool is_last_value = false;
271   int64_t stride_value = 0;
272   bool b1, b2;  // unused
273   if (!GenerateRangeOrLastValue(context,
274                                 instruction,
275                                 is_last_value,
276                                 graph,
277                                 block,
278                                 lower,
279                                 upper,
280                                 nullptr,
281                                 &stride_value,
282                                 &b1,
283                                 &b2) ||
284       (stride_value != -1 &&
285        stride_value != 0 &&
286        stride_value != 1)) {
287     LOG(FATAL) << "Failed precondition: CanGenerateRange()";
288   }
289 }
290 
GenerateTakenTest(HInstruction * loop_control,HGraph * graph,HBasicBlock * block)291 HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* loop_control,
292                                                    HGraph* graph,
293                                                    HBasicBlock* block) {
294   const HBasicBlock* context = loop_control->GetBlock();
295   HInstruction* taken_test = nullptr;
296   bool is_last_value = false;
297   int64_t stride_value = 0;
298   bool b1, b2;  // unused
299   if (!GenerateRangeOrLastValue(context,
300                                 loop_control,
301                                 is_last_value,
302                                 graph,
303                                 block,
304                                 nullptr,
305                                 nullptr,
306                                 &taken_test,
307                                 &stride_value,
308                                 &b1,
309                                 &b2) ||
310       (stride_value != -1 &&
311        stride_value != 0 &&
312        stride_value != 1)) {
313     LOG(FATAL) << "Failed precondition: CanGenerateRange()";
314   }
315   return taken_test;
316 }
317 
CanGenerateLastValue(HInstruction * instruction)318 bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
319   const HBasicBlock* context = instruction->GetBlock();
320   bool is_last_value = true;
321   int64_t stride_value = 0;
322   bool needs_finite_test = false;
323   bool needs_taken_test = false;
324   return GenerateRangeOrLastValue(context,
325                                   instruction,
326                                   is_last_value,
327                                   nullptr,
328                                   nullptr,
329                                   nullptr,
330                                   nullptr,
331                                   nullptr,  // nothing generated yet
332                                   &stride_value,
333                                   &needs_finite_test,
334                                   &needs_taken_test)
335       && !needs_finite_test && !needs_taken_test;
336 }
337 
GenerateLastValue(HInstruction * instruction,HGraph * graph,HBasicBlock * block)338 HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
339                                                    HGraph* graph,
340                                                    HBasicBlock* block) {
341   const HBasicBlock* context = instruction->GetBlock();
342   HInstruction* last_value = nullptr;
343   bool is_last_value = true;
344   int64_t stride_value = 0;
345   bool needs_finite_test = false;
346   bool needs_taken_test = false;
347   if (!GenerateRangeOrLastValue(context,
348                                 instruction,
349                                 is_last_value,
350                                 graph,
351                                 block,
352                                 &last_value,
353                                 &last_value,
354                                 nullptr,
355                                 &stride_value,
356                                 &needs_finite_test,
357                                 &needs_taken_test) ||
358       needs_finite_test ||
359       needs_taken_test) {
360     LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
361   }
362   return last_value;
363 }
364 
Replace(HInstruction * instruction,HInstruction * fetch,HInstruction * replacement)365 void InductionVarRange::Replace(HInstruction* instruction,
366                                 HInstruction* fetch,
367                                 HInstruction* replacement) {
368   for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation();  // closest enveloping loop
369        lp != nullptr;
370        lp = lp->GetPreHeader()->GetLoopInformation()) {
371     // Update instruction's information.
372     ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
373     // Update loop's trip-count information.
374     ReplaceInduction(induction_analysis_->LookupInfo(lp, GetLoopControl(lp)), fetch, replacement);
375   }
376 }
377 
IsFinite(const HLoopInformation * loop,int64_t * trip_count) const378 bool InductionVarRange::IsFinite(const HLoopInformation* loop, /*out*/ int64_t* trip_count) const {
379   bool is_constant_unused = false;
380   return CheckForFiniteAndConstantProps(loop, &is_constant_unused, trip_count);
381 }
382 
HasKnownTripCount(const HLoopInformation * loop,int64_t * trip_count) const383 bool InductionVarRange::HasKnownTripCount(const HLoopInformation* loop,
384                                           /*out*/ int64_t* trip_count) const {
385   bool is_constant = false;
386   CheckForFiniteAndConstantProps(loop, &is_constant, trip_count);
387   return is_constant;
388 }
389 
IsUnitStride(const HBasicBlock * context,HInstruction * instruction,HGraph * graph,HInstruction ** offset) const390 bool InductionVarRange::IsUnitStride(const HBasicBlock* context,
391                                      HInstruction* instruction,
392                                      HGraph* graph,
393                                      /*out*/ HInstruction** offset) const {
394   const HLoopInformation* loop = nullptr;
395   HInductionVarAnalysis::InductionInfo* info = nullptr;
396   HInductionVarAnalysis::InductionInfo* trip = nullptr;
397   if (HasInductionInfo(context, instruction, &loop, &info, &trip)) {
398     if (info->induction_class == HInductionVarAnalysis::kLinear &&
399         !HInductionVarAnalysis::IsNarrowingLinear(info)) {
400       int64_t stride_value = 0;
401       if (IsConstant(context, loop, info->op_a, kExact, &stride_value) && stride_value == 1) {
402         int64_t off_value = 0;
403         if (IsConstant(context, loop, info->op_b, kExact, &off_value)) {
404           *offset = graph->GetConstant(info->op_b->type, off_value);
405         } else if (info->op_b->operation == HInductionVarAnalysis::kFetch) {
406           *offset = info->op_b->fetch;
407         } else {
408           return false;
409         }
410         return true;
411       }
412     }
413   }
414   return false;
415 }
416 
GenerateTripCount(const HLoopInformation * loop,HGraph * graph,HBasicBlock * block)417 HInstruction* InductionVarRange::GenerateTripCount(const HLoopInformation* loop,
418                                                    HGraph* graph,
419                                                    HBasicBlock* block) {
420   HInstruction* loop_control = GetLoopControl(loop);
421   HInductionVarAnalysis::InductionInfo *trip = induction_analysis_->LookupInfo(loop, loop_control);
422   if (trip != nullptr && !IsUnsafeTripCount(trip)) {
423     const HBasicBlock* context = loop_control->GetBlock();
424     HInstruction* taken_test = nullptr;
425     HInstruction* trip_expr = nullptr;
426     if (IsBodyTripCount(trip)) {
427       if (!GenerateCode(context,
428                         loop,
429                         trip->op_b,
430                         /*trip=*/ nullptr,
431                         graph,
432                         block,
433                         /*is_min=*/ false,
434                         &taken_test)) {
435         return nullptr;
436       }
437     }
438     if (GenerateCode(context,
439                      loop,
440                      trip->op_a,
441                      /*trip=*/ nullptr,
442                      graph,
443                      block,
444                      /*is_min=*/ false,
445                      &trip_expr)) {
446       if (taken_test != nullptr) {
447         HInstruction* zero = graph->GetConstant(trip->type, 0);
448         ArenaAllocator* allocator = graph->GetAllocator();
449         trip_expr = Insert(block, new (allocator) HSelect(taken_test, trip_expr, zero, kNoDexPc));
450       }
451       return trip_expr;
452     }
453   }
454   return nullptr;
455 }
456 
457 //
458 // Private class methods.
459 //
460 
CheckForFiniteAndConstantProps(const HLoopInformation * loop,bool * is_constant,int64_t * trip_count) const461 bool InductionVarRange::CheckForFiniteAndConstantProps(const HLoopInformation* loop,
462                                                        /*out*/ bool* is_constant,
463                                                        /*out*/ int64_t* trip_count) const {
464   HInstruction* loop_control = GetLoopControl(loop);
465   HInductionVarAnalysis::InductionInfo *trip = induction_analysis_->LookupInfo(loop, loop_control);
466   if (trip != nullptr && !IsUnsafeTripCount(trip)) {
467     const HBasicBlock* context = loop_control->GetBlock();
468     *is_constant = IsConstant(context, loop, trip->op_a, kExact, trip_count);
469     return true;
470   }
471   return false;
472 }
473 
IsConstant(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,ConstantRequest request,int64_t * value) const474 bool InductionVarRange::IsConstant(const HBasicBlock* context,
475                                    const HLoopInformation* loop,
476                                    HInductionVarAnalysis::InductionInfo* info,
477                                    ConstantRequest request,
478                                    /*out*/ int64_t* value) const {
479   if (info != nullptr) {
480     // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
481     // any of the three requests (kExact, kAtMost, and KAtLeast).
482     if (info->induction_class == HInductionVarAnalysis::kInvariant &&
483         info->operation == HInductionVarAnalysis::kFetch) {
484       if (IsInt64AndGet(info->fetch, value)) {
485         return true;
486       }
487     }
488     // Try range analysis on the invariant, only accept a proper range
489     // to avoid arithmetic wrap-around anomalies.
490     Value min_val = GetVal(context, loop, info, /*trip=*/ nullptr, /*is_min=*/ true);
491     Value max_val = GetVal(context, loop, info, /*trip=*/ nullptr, /*is_min=*/ false);
492     if (IsConstantValue(min_val) &&
493         IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
494       if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
495         *value = max_val.b_constant;
496         return true;
497       } else if (request == kAtLeast) {
498         *value = min_val.b_constant;
499         return true;
500       }
501     }
502   }
503   return false;
504 }
505 
HasInductionInfo(const HBasicBlock * context,HInstruction * instruction,const HLoopInformation ** loop,HInductionVarAnalysis::InductionInfo ** info,HInductionVarAnalysis::InductionInfo ** trip) const506 bool InductionVarRange::HasInductionInfo(
507     const HBasicBlock* context,
508     HInstruction* instruction,
509     /*out*/ const HLoopInformation** loop,
510     /*out*/ HInductionVarAnalysis::InductionInfo** info,
511     /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
512   DCHECK(context != nullptr);
513   HLoopInformation* lp = context->GetLoopInformation();  // closest enveloping loop
514   if (lp != nullptr) {
515     HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(lp, instruction);
516     if (i != nullptr) {
517       *loop = lp;
518       *info = i;
519       *trip = induction_analysis_->LookupInfo(lp, GetLoopControl(lp));
520       return true;
521     }
522   }
523   return false;
524 }
525 
IsWellBehavedTripCount(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * trip) const526 bool InductionVarRange::IsWellBehavedTripCount(const HBasicBlock* context,
527                                                const HLoopInformation* loop,
528                                                HInductionVarAnalysis::InductionInfo* trip) const {
529   if (trip != nullptr) {
530     // Both bounds that define a trip-count are well-behaved if they either are not defined
531     // in any loop, or are contained in a proper interval. This allows finding the min/max
532     // of an expression by chasing outward.
533     InductionVarRange range(induction_analysis_);
534     HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
535     HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
536     int64_t not_used = 0;
537     return
538         (!HasFetchInLoop(lower) || range.IsConstant(context, loop, lower, kAtLeast, &not_used)) &&
539         (!HasFetchInLoop(upper) || range.IsConstant(context, loop, upper, kAtLeast, &not_used));
540   }
541   return true;
542 }
543 
HasFetchInLoop(HInductionVarAnalysis::InductionInfo * info) const544 bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
545   if (info != nullptr) {
546     if (info->induction_class == HInductionVarAnalysis::kInvariant &&
547         info->operation == HInductionVarAnalysis::kFetch) {
548       return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
549     }
550     return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
551   }
552   return false;
553 }
554 
NeedsTripCount(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,int64_t * stride_value) const555 bool InductionVarRange::NeedsTripCount(const HBasicBlock* context,
556                                        const HLoopInformation* loop,
557                                        HInductionVarAnalysis::InductionInfo* info,
558                                        int64_t* stride_value) const {
559   if (info != nullptr) {
560     if (info->induction_class == HInductionVarAnalysis::kLinear) {
561       return IsConstant(context, loop, info->op_a, kExact, stride_value);
562     } else if (info->induction_class == HInductionVarAnalysis::kPolynomial) {
563       return NeedsTripCount(context, loop, info->op_a, stride_value);
564     } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
565       return NeedsTripCount(context, loop, info->op_b, stride_value);
566     }
567   }
568   return false;
569 }
570 
IsBodyTripCount(HInductionVarAnalysis::InductionInfo * trip) const571 bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
572   if (trip != nullptr) {
573     if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
574       return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
575              trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
576     }
577   }
578   return false;
579 }
580 
IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo * trip) const581 bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
582   if (trip != nullptr) {
583     if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
584       return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
585              trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
586     }
587   }
588   return false;
589 }
590 
GetLinear(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const591 InductionVarRange::Value InductionVarRange::GetLinear(const HBasicBlock* context,
592                                                       const HLoopInformation* loop,
593                                                       HInductionVarAnalysis::InductionInfo* info,
594                                                       HInductionVarAnalysis::InductionInfo* trip,
595                                                       bool is_min) const {
596   DCHECK(info != nullptr);
597   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kLinear);
598   // Detect common situation where an offset inside the trip-count cancels out during range
599   // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
600   // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
601   // with intermediate results that only incorporate single instructions.
602   if (trip != nullptr) {
603     HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
604     if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
605       int64_t stride_value = 0;
606       if (IsConstant(context, loop, info->op_a, kExact, &stride_value)) {
607         if (!is_min && stride_value == 1) {
608           // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
609           if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
610             // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
611             HInductionVarAnalysis::InductionInfo cancelled_trip(
612                 trip->induction_class,
613                 trip->operation,
614                 trip_expr->op_a,
615                 trip->op_b,
616                 nullptr,
617                 trip->type);
618             return GetVal(context, loop, &cancelled_trip, trip, is_min);
619           }
620         } else if (is_min && stride_value == -1) {
621           // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
622           if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
623             // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
624             HInductionVarAnalysis::InductionInfo neg(
625                 HInductionVarAnalysis::kInvariant,
626                 HInductionVarAnalysis::kNeg,
627                 nullptr,
628                 trip_expr->op_b,
629                 nullptr,
630                 trip->type);
631             HInductionVarAnalysis::InductionInfo cancelled_trip(
632                 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
633             return SubValue(Value(0), GetVal(context, loop, &cancelled_trip, trip, !is_min));
634           }
635         }
636       }
637     }
638   }
639   // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
640   return AddValue(GetMul(context, loop, info->op_a, trip, trip, is_min),
641                   GetVal(context, loop, info->op_b, trip, is_min));
642 }
643 
GetPolynomial(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const644 InductionVarRange::Value InductionVarRange::GetPolynomial(
645     const HBasicBlock* context,
646     const HLoopInformation* loop,
647     HInductionVarAnalysis::InductionInfo* info,
648     HInductionVarAnalysis::InductionInfo* trip,
649     bool is_min) const {
650   DCHECK(info != nullptr);
651   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPolynomial);
652   int64_t a = 0;
653   int64_t b = 0;
654   if (IsConstant(context, loop, info->op_a->op_a, kExact, &a) &&
655       CanLongValueFitIntoInt(a) &&
656       a >= 0 &&
657       IsConstant(context, loop, info->op_a->op_b, kExact, &b) &&
658       CanLongValueFitIntoInt(b) &&
659       b >= 0) {
660     // Evaluate bounds on sum_i=0^m-1(a * i + b) + c with a,b >= 0 for
661     // maximum index value m as a * (m * (m-1)) / 2 + b * m + c.
662     // Do not simply return `c` as minimum because the trip count may be non-zero
663     // if the `context` is after the `loop` (and therefore ignoring `is_min`).
664     Value c = GetVal(context, loop, info->op_b, trip, is_min);
665     Value m = GetVal(context, loop, trip, trip, is_min);
666     Value t = DivValue(MulValue(m, SubValue(m, Value(1))), Value(2));
667     Value x = MulValue(Value(a), t);
668     Value y = MulValue(Value(b), m);
669     return AddValue(AddValue(x, y), c);
670   }
671   return Value();
672 }
673 
GetGeometric(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const674 InductionVarRange::Value InductionVarRange::GetGeometric(const HBasicBlock* context,
675                                                          const HLoopInformation* loop,
676                                                          HInductionVarAnalysis::InductionInfo* info,
677                                                          HInductionVarAnalysis::InductionInfo* trip,
678                                                          bool is_min) const {
679   DCHECK(info != nullptr);
680   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kGeometric);
681   int64_t a = 0;
682   int64_t f = 0;
683   if (IsConstant(context, loop, info->op_a, kExact, &a) &&
684       CanLongValueFitIntoInt(a) &&
685       IsInt64AndGet(info->fetch, &f) && f >= 1) {
686     // Conservative bounds on a * f^-i + b with f >= 1 can be computed without
687     // trip count. Other forms would require a much more elaborate evaluation.
688     const bool is_min_a = a >= 0 ? is_min : !is_min;
689     if (info->operation == HInductionVarAnalysis::kDiv) {
690       Value b = GetVal(context, loop, info->op_b, trip, is_min);
691       return is_min_a ? b : AddValue(Value(a), b);
692     }
693   }
694   return Value();
695 }
696 
GetFetch(const HBasicBlock * context,const HLoopInformation * loop,HInstruction * instruction,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const697 InductionVarRange::Value InductionVarRange::GetFetch(const HBasicBlock* context,
698                                                      const HLoopInformation* loop,
699                                                      HInstruction* instruction,
700                                                      HInductionVarAnalysis::InductionInfo* trip,
701                                                      bool is_min) const {
702   // Special case when chasing constants: single instruction that denotes trip count in the
703   // loop-body is minimal 1 and maximal, with safe trip-count, max int,
704   if (chase_hint_ == nullptr &&
705       IsContextInBody(context, loop) &&
706       trip != nullptr &&
707       instruction == trip->op_a->fetch) {
708     if (is_min) {
709       return Value(1);
710     } else if (!instruction->IsConstant() && !IsUnsafeTripCount(trip)) {
711       return Value(std::numeric_limits<int32_t>::max());
712     }
713   }
714   // Unless at a constant or hint, chase the instruction a bit deeper into the HIR tree, so that
715   // it becomes more likely range analysis will compare the same instructions as terminal nodes.
716   int64_t value;
717   if (IsInt64AndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
718     // Proper constant reveals best information.
719     return Value(static_cast<int32_t>(value));
720   } else if (instruction == chase_hint_) {
721     // At hint, fetch is represented by itself.
722     return Value(instruction, 1, 0);
723   } else if (instruction->IsAdd()) {
724     // Incorporate suitable constants in the chased value.
725     if (IsInt64AndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
726       return AddValue(Value(static_cast<int32_t>(value)),
727                       GetFetch(context, loop, instruction->InputAt(1), trip, is_min));
728     } else if (IsInt64AndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
729       return AddValue(GetFetch(context, loop, instruction->InputAt(0), trip, is_min),
730                       Value(static_cast<int32_t>(value)));
731     }
732   } else if (instruction->IsSub()) {
733     // Incorporate suitable constants in the chased value.
734     if (IsInt64AndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
735       return SubValue(Value(static_cast<int32_t>(value)),
736                       GetFetch(context, loop, instruction->InputAt(1), trip, !is_min));
737     } else if (IsInt64AndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
738       return SubValue(GetFetch(context, loop, instruction->InputAt(0), trip, is_min),
739                       Value(static_cast<int32_t>(value)));
740     }
741   } else if (instruction->IsArrayLength()) {
742     // Exploit length properties when chasing constants or chase into a new array declaration.
743     if (chase_hint_ == nullptr) {
744       return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
745     } else if (instruction->InputAt(0)->IsNewArray()) {
746       return GetFetch(
747           context, loop, instruction->InputAt(0)->AsNewArray()->GetLength(), trip, is_min);
748     }
749   } else if (instruction->IsTypeConversion()) {
750     // Since analysis is 32-bit (or narrower), chase beyond widening along the path.
751     // For example, this discovers the length in: for (long i = 0; i < a.length; i++);
752     if (instruction->AsTypeConversion()->GetInputType() == DataType::Type::kInt32 &&
753         instruction->AsTypeConversion()->GetResultType() == DataType::Type::kInt64) {
754       return GetFetch(context, loop, instruction->InputAt(0), trip, is_min);
755     }
756   }
757   // Chase an invariant fetch that is defined by another loop if the trip-count used
758   // so far is well-behaved in both bounds and the next trip-count is safe.
759   // Example:
760   //   for (int i = 0; i <= 100; i++)  // safe
761   //     for (int j = 0; j <= i; j++)  // well-behaved
762   //       j is in range [0, i  ] (if i is chase hint)
763   //         or in range [0, 100] (otherwise)
764   // Example:
765   //   for (i = 0; i < 100; ++i)
766   //     <some-code>
767   //   for (j = 0; j < 10; ++j)
768   //     sum += i;  // The `i` is a "fetch" of a loop Phi from the previous loop.
769   const HLoopInformation* next_loop = nullptr;
770   HInductionVarAnalysis::InductionInfo* next_info = nullptr;
771   HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
772   if (HasInductionInfo(instruction->GetBlock(), instruction, &next_loop, &next_info, &next_trip) &&
773       IsWellBehavedTripCount(context, next_loop, trip) &&
774       !IsUnsafeTripCount(next_trip)) {
775     return GetVal(context, next_loop, next_info, next_trip, is_min);
776   }
777   // Fetch is represented by itself.
778   return Value(instruction, 1, 0);
779 }
780 
GetVal(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const781 InductionVarRange::Value InductionVarRange::GetVal(const HBasicBlock* context,
782                                                    const HLoopInformation* loop,
783                                                    HInductionVarAnalysis::InductionInfo* info,
784                                                    HInductionVarAnalysis::InductionInfo* trip,
785                                                    bool is_min) const {
786   if (info != nullptr) {
787     switch (info->induction_class) {
788       case HInductionVarAnalysis::kInvariant:
789         // Invariants.
790         switch (info->operation) {
791           case HInductionVarAnalysis::kAdd:
792             return AddValue(GetVal(context, loop, info->op_a, trip, is_min),
793                             GetVal(context, loop, info->op_b, trip, is_min));
794           case HInductionVarAnalysis::kSub:  // second reversed!
795             return SubValue(GetVal(context, loop, info->op_a, trip, is_min),
796                             GetVal(context, loop, info->op_b, trip, !is_min));
797           case HInductionVarAnalysis::kNeg:  // second reversed!
798             return SubValue(Value(0),
799                             GetVal(context, loop, info->op_b, trip, !is_min));
800           case HInductionVarAnalysis::kMul:
801             return GetMul(context, loop, info->op_a, info->op_b, trip, is_min);
802           case HInductionVarAnalysis::kDiv:
803             return GetDiv(context, loop, info->op_a, info->op_b, trip, is_min);
804           case HInductionVarAnalysis::kRem:
805             return GetRem(context, loop, info->op_a, info->op_b);
806           case HInductionVarAnalysis::kXor:
807             return GetXor(context, loop, info->op_a, info->op_b);
808           case HInductionVarAnalysis::kFetch:
809             return GetFetch(context, loop, info->fetch, trip, is_min);
810           case HInductionVarAnalysis::kTripCountInLoop:
811           case HInductionVarAnalysis::kTripCountInLoopUnsafe:
812             if (UseFullTripCount(context, loop, is_min)) {
813               // Return the full trip count (do not subtract 1 as we do in loop body).
814               return GetVal(context, loop, info->op_a, trip, /*is_min=*/ false);
815             }
816             FALLTHROUGH_INTENDED;
817           case HInductionVarAnalysis::kTripCountInBody:
818           case HInductionVarAnalysis::kTripCountInBodyUnsafe:
819             if (is_min) {
820               return Value(0);
821             } else if (IsContextInBody(context, loop)) {
822               return SubValue(GetVal(context, loop, info->op_a, trip, is_min), Value(1));
823             }
824             break;
825           default:
826             break;
827         }
828         break;
829       case HInductionVarAnalysis::kLinear:
830         return CorrectForType(GetLinear(context, loop, info, trip, is_min), info->type);
831       case HInductionVarAnalysis::kPolynomial:
832         return GetPolynomial(context, loop, info, trip, is_min);
833       case HInductionVarAnalysis::kGeometric:
834         return GetGeometric(context, loop, info, trip, is_min);
835       case HInductionVarAnalysis::kWrapAround:
836       case HInductionVarAnalysis::kPeriodic:
837         return MergeVal(GetVal(context, loop, info->op_a, trip, is_min),
838                         GetVal(context, loop, info->op_b, trip, is_min),
839                         is_min);
840     }
841   }
842   return Value();
843 }
844 
GetMul(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info1,HInductionVarAnalysis::InductionInfo * info2,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const845 InductionVarRange::Value InductionVarRange::GetMul(const HBasicBlock* context,
846                                                    const HLoopInformation* loop,
847                                                    HInductionVarAnalysis::InductionInfo* info1,
848                                                    HInductionVarAnalysis::InductionInfo* info2,
849                                                    HInductionVarAnalysis::InductionInfo* trip,
850                                                    bool is_min) const {
851   // Constant times range.
852   int64_t value = 0;
853   if (IsConstant(context, loop, info1, kExact, &value)) {
854     return MulRangeAndConstant(context, loop, value, info2, trip, is_min);
855   } else if (IsConstant(context, loop, info2, kExact, &value)) {
856     return MulRangeAndConstant(context, loop, value, info1, trip, is_min);
857   }
858   // Interval ranges.
859   Value v1_min = GetVal(context, loop, info1, trip, /*is_min=*/ true);
860   Value v1_max = GetVal(context, loop, info1, trip, /*is_min=*/ false);
861   Value v2_min = GetVal(context, loop, info2, trip, /*is_min=*/ true);
862   Value v2_max = GetVal(context, loop, info2, trip, /*is_min=*/ false);
863   // Positive range vs. positive or negative range.
864   if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
865     if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
866       return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
867     } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
868       return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
869     }
870   }
871   // Negative range vs. positive or negative range.
872   if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
873     if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
874       return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
875     } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
876       return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
877     }
878   }
879   return Value();
880 }
881 
GetDiv(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info1,HInductionVarAnalysis::InductionInfo * info2,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const882 InductionVarRange::Value InductionVarRange::GetDiv(const HBasicBlock* context,
883                                                    const HLoopInformation* loop,
884                                                    HInductionVarAnalysis::InductionInfo* info1,
885                                                    HInductionVarAnalysis::InductionInfo* info2,
886                                                    HInductionVarAnalysis::InductionInfo* trip,
887                                                    bool is_min) const {
888   // Range divided by constant.
889   int64_t value = 0;
890   if (IsConstant(context, loop, info2, kExact, &value)) {
891     return DivRangeAndConstant(context, loop, value, info1, trip, is_min);
892   }
893   // Interval ranges.
894   Value v1_min = GetVal(context, loop, info1, trip, /*is_min=*/ true);
895   Value v1_max = GetVal(context, loop, info1, trip, /*is_min=*/ false);
896   Value v2_min = GetVal(context, loop, info2, trip, /*is_min=*/ true);
897   Value v2_max = GetVal(context, loop, info2, trip, /*is_min=*/ false);
898   // Positive range vs. positive or negative range.
899   if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
900     if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
901       return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
902     } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
903       return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
904     }
905   }
906   // Negative range vs. positive or negative range.
907   if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
908     if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
909       return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
910     } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
911       return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
912     }
913   }
914   return Value();
915 }
916 
GetRem(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info1,HInductionVarAnalysis::InductionInfo * info2) const917 InductionVarRange::Value InductionVarRange::GetRem(
918     const HBasicBlock* context,
919     const HLoopInformation* loop,
920     HInductionVarAnalysis::InductionInfo* info1,
921     HInductionVarAnalysis::InductionInfo* info2) const {
922   int64_t v1 = 0;
923   int64_t v2 = 0;
924   // Only accept exact values.
925   if (IsConstant(context, loop, info1, kExact, &v1) &&
926       IsConstant(context, loop, info2, kExact, &v2) &&
927       v2 != 0) {
928     int64_t value = v1 % v2;
929     if (CanLongValueFitIntoInt(value)) {
930       return Value(static_cast<int32_t>(value));
931     }
932   }
933   return Value();
934 }
935 
GetXor(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info1,HInductionVarAnalysis::InductionInfo * info2) const936 InductionVarRange::Value InductionVarRange::GetXor(
937     const HBasicBlock* context,
938     const HLoopInformation* loop,
939     HInductionVarAnalysis::InductionInfo* info1,
940     HInductionVarAnalysis::InductionInfo* info2) const {
941   int64_t v1 = 0;
942   int64_t v2 = 0;
943   // Only accept exact values.
944   if (IsConstant(context, loop, info1, kExact, &v1) &&
945       IsConstant(context, loop, info2, kExact, &v2)) {
946     int64_t value = v1 ^ v2;
947     if (CanLongValueFitIntoInt(value)) {
948       return Value(static_cast<int32_t>(value));
949     }
950   }
951   return Value();
952 }
953 
MulRangeAndConstant(const HBasicBlock * context,const HLoopInformation * loop,int64_t value,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const954 InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
955     const HBasicBlock* context,
956     const HLoopInformation* loop,
957     int64_t value,
958     HInductionVarAnalysis::InductionInfo* info,
959     HInductionVarAnalysis::InductionInfo* trip,
960     bool is_min) const {
961   if (CanLongValueFitIntoInt(value)) {
962     Value c(static_cast<int32_t>(value));
963     return MulValue(GetVal(context, loop, info, trip, is_min == value >= 0), c);
964   }
965   return Value();
966 }
967 
DivRangeAndConstant(const HBasicBlock * context,const HLoopInformation * loop,int64_t value,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,bool is_min) const968 InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
969     const HBasicBlock* context,
970     const HLoopInformation* loop,
971     int64_t value,
972     HInductionVarAnalysis::InductionInfo* info,
973     HInductionVarAnalysis::InductionInfo* trip,
974     bool is_min) const {
975   if (CanLongValueFitIntoInt(value)) {
976     Value c(static_cast<int32_t>(value));
977     return DivValue(GetVal(context, loop, info, trip, is_min == value >= 0), c);
978   }
979   return Value();
980 }
981 
AddValue(Value v1,Value v2) const982 InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
983   if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
984     int32_t b = v1.b_constant + v2.b_constant;
985     if (v1.a_constant == 0) {
986       return Value(v2.instruction, v2.a_constant, b);
987     } else if (v2.a_constant == 0) {
988       return Value(v1.instruction, v1.a_constant, b);
989     } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
990       return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
991     }
992   }
993   return Value();
994 }
995 
SubValue(Value v1,Value v2) const996 InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
997   if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
998     int32_t b = v1.b_constant - v2.b_constant;
999     if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
1000       return Value(v2.instruction, -v2.a_constant, b);
1001     } else if (v2.a_constant == 0) {
1002       return Value(v1.instruction, v1.a_constant, b);
1003     } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
1004       return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
1005     }
1006   }
1007   return Value();
1008 }
1009 
MulValue(Value v1,Value v2) const1010 InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
1011   if (v1.is_known && v2.is_known) {
1012     if (v1.a_constant == 0) {
1013       if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
1014         return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
1015       }
1016     } else if (v2.a_constant == 0) {
1017       if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
1018         return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
1019       }
1020     }
1021   }
1022   return Value();
1023 }
1024 
DivValue(Value v1,Value v2) const1025 InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
1026   if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
1027     if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
1028       return Value(v1.b_constant / v2.b_constant);
1029     }
1030   }
1031   return Value();
1032 }
1033 
MergeVal(Value v1,Value v2,bool is_min) const1034 InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
1035   if (v1.is_known && v2.is_known) {
1036     if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
1037       return Value(v1.instruction, v1.a_constant,
1038                    is_min ? std::min(v1.b_constant, v2.b_constant)
1039                           : std::max(v1.b_constant, v2.b_constant));
1040     }
1041   }
1042   return Value();
1043 }
1044 
GenerateRangeOrLastValue(const HBasicBlock * context,HInstruction * instruction,bool is_last_value,HGraph * graph,HBasicBlock * block,HInstruction ** lower,HInstruction ** upper,HInstruction ** taken_test,int64_t * stride_value,bool * needs_finite_test,bool * needs_taken_test) const1045 bool InductionVarRange::GenerateRangeOrLastValue(const HBasicBlock* context,
1046                                                  HInstruction* instruction,
1047                                                  bool is_last_value,
1048                                                  HGraph* graph,
1049                                                  HBasicBlock* block,
1050                                                  /*out*/HInstruction** lower,
1051                                                  /*out*/HInstruction** upper,
1052                                                  /*out*/HInstruction** taken_test,
1053                                                  /*out*/int64_t* stride_value,
1054                                                  /*out*/bool* needs_finite_test,
1055                                                  /*out*/bool* needs_taken_test) const {
1056   const HLoopInformation* loop = nullptr;
1057   HInductionVarAnalysis::InductionInfo* info = nullptr;
1058   HInductionVarAnalysis::InductionInfo* trip = nullptr;
1059   if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
1060     return false;  // codegen needs all information, including tripcount
1061   }
1062   // Determine what tests are needed. A finite test is needed if the evaluation code uses the
1063   // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
1064   // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
1065   // code does not use the trip-count explicitly (since there could be an implicit relation
1066   // between e.g. an invariant subscript and a not-taken condition).
1067   *stride_value = 0;
1068   *needs_finite_test = NeedsTripCount(context, loop, info, stride_value) && IsUnsafeTripCount(trip);
1069   *needs_taken_test = IsBodyTripCount(trip);
1070   // Handle last value request.
1071   if (is_last_value) {
1072     DCHECK(!IsContextInBody(context, loop));
1073     switch (info->induction_class) {
1074       case HInductionVarAnalysis::kLinear:
1075         if (*stride_value > 0) {
1076           lower = nullptr;
1077           return GenerateLastValueLinear(
1078               context, loop, info, trip, graph, block, /*is_min=*/false, upper, needs_taken_test);
1079         } else {
1080           upper = nullptr;
1081           return GenerateLastValueLinear(
1082               context, loop, info, trip, graph, block, /*is_min=*/true, lower, needs_taken_test);
1083         }
1084       case HInductionVarAnalysis::kPolynomial:
1085         return GenerateLastValuePolynomial(context, loop, info, trip, graph, block, lower);
1086       case HInductionVarAnalysis::kGeometric:
1087         return GenerateLastValueGeometric(context, loop, info, trip, graph, block, lower);
1088       case HInductionVarAnalysis::kWrapAround:
1089         return GenerateLastValueWrapAround(context, loop, info, trip, graph, block, lower);
1090       case HInductionVarAnalysis::kPeriodic:
1091         return GenerateLastValuePeriodic(
1092             context, loop, info, trip, graph, block, lower, needs_taken_test);
1093       default:
1094         return false;
1095     }
1096   }
1097   // Code generation for taken test: generate the code when requested or otherwise analyze
1098   // if code generation is feasible when taken test is needed.
1099   if (taken_test != nullptr) {
1100     return GenerateCode(context,
1101                         loop,
1102                         trip->op_b,
1103                         /*trip=*/ nullptr,
1104                         graph,
1105                         block,
1106                         /*is_min=*/ false,
1107                         taken_test);
1108   } else if (*needs_taken_test) {
1109     if (!GenerateCode(context,
1110                       loop,
1111                       trip->op_b,
1112                       /*trip=*/ nullptr,
1113                       /*graph=*/ nullptr,
1114                       /*block=*/ nullptr,
1115                       /*is_min=*/ false,
1116                       /*result=*/ nullptr)) {
1117       return false;
1118     }
1119   }
1120   // Code generation for lower and upper.
1121   return
1122       // Success on lower if invariant (not set), or code can be generated.
1123       ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
1124           GenerateCode(context, loop, info, trip, graph, block, /*is_min=*/ true, lower)) &&
1125       // And success on upper.
1126       GenerateCode(context, loop, info, trip, graph, block, /*is_min=*/ false, upper);
1127 }
1128 
GenerateLastValueLinear(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,bool is_min,HInstruction ** result,bool * needs_taken_test) const1129 bool InductionVarRange::GenerateLastValueLinear(const HBasicBlock* context,
1130                                                 const HLoopInformation* loop,
1131                                                 HInductionVarAnalysis::InductionInfo* info,
1132                                                 HInductionVarAnalysis::InductionInfo* trip,
1133                                                 HGraph* graph,
1134                                                 HBasicBlock* block,
1135                                                 bool is_min,
1136                                                 /*out*/ HInstruction** result,
1137                                                 /*inout*/ bool* needs_taken_test) const {
1138   DataType::Type type = info->type;
1139   // Avoid any narrowing linear induction or any type mismatch between the linear induction and the
1140   // trip count expression.
1141   if (HInductionVarAnalysis::IsNarrowingLinear(info) || trip->type != type) {
1142     return false;
1143   }
1144 
1145   // Stride value must be a known constant that fits into int32. The stride will be the `i` in `a *
1146   // i + b`.
1147   int64_t stride_value = 0;
1148   if (!IsConstant(context, loop, info->op_a, kExact, &stride_value) ||
1149       !CanLongValueFitIntoInt(stride_value)) {
1150     return false;
1151   }
1152 
1153   // We require the calculation of `a` to not overflow.
1154   const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
1155   HInstruction* opa;
1156   HInstruction* opb;
1157   if (!GenerateCode(context,
1158                     loop,
1159                     trip,
1160                     trip,
1161                     graph,
1162                     block,
1163                     is_min_a,
1164                     &opa,
1165                     /*allow_potential_overflow=*/false) ||
1166       !GenerateCode(context, loop, info->op_b, trip, graph, block, is_min, &opb)) {
1167     return false;
1168   }
1169 
1170   if (graph != nullptr) {
1171     ArenaAllocator* allocator = graph->GetAllocator();
1172     HInstruction* oper;
1173     // Emit instructions for `a * i + b`. These are fine to overflow as they would have overflown
1174     // also if we had kept the loop.
1175     if (stride_value == 1) {
1176       oper = new (allocator) HAdd(type, opa, opb);
1177     } else if (stride_value == -1) {
1178       oper = new (graph->GetAllocator()) HSub(type, opb, opa);
1179     } else {
1180       HInstruction* mul = new (allocator) HMul(type, graph->GetConstant(type, stride_value), opa);
1181       oper = new (allocator) HAdd(type, Insert(block, mul), opb);
1182     }
1183     *result = Insert(block, oper);
1184   }
1185 
1186   if (*needs_taken_test) {
1187     if (TryGenerateTakenTest(context, loop, trip->op_b, graph, block, result, opb)) {
1188       *needs_taken_test = false;  // taken care of
1189     } else {
1190       return false;
1191     }
1192   }
1193 
1194   return true;
1195 }
1196 
GenerateLastValuePolynomial(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,HInstruction ** result) const1197 bool InductionVarRange::GenerateLastValuePolynomial(const HBasicBlock* context,
1198                                                     const HLoopInformation* loop,
1199                                                     HInductionVarAnalysis::InductionInfo* info,
1200                                                     HInductionVarAnalysis::InductionInfo* trip,
1201                                                     HGraph* graph,
1202                                                     HBasicBlock* block,
1203                                                     /*out*/HInstruction** result) const {
1204   DCHECK(info != nullptr);
1205   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPolynomial);
1206   // Detect known coefficients and trip count (always taken).
1207   int64_t a = 0;
1208   int64_t b = 0;
1209   int64_t m = 0;
1210   if (IsConstant(context, loop, info->op_a->op_a, kExact, &a) &&
1211       IsConstant(context, loop, info->op_a->op_b, kExact, &b) &&
1212       IsConstant(context, loop, trip->op_a, kExact, &m) &&
1213       m >= 1) {
1214     // Evaluate bounds on sum_i=0^m-1(a * i + b) + c for known
1215     // maximum index value m as a * (m * (m-1)) / 2 + b * m + c.
1216     HInstruction* c = nullptr;
1217     if (GenerateCode(context,
1218                      loop,
1219                      info->op_b,
1220                      /*trip=*/ nullptr,
1221                      graph,
1222                      block,
1223                      /*is_min=*/ false,
1224                      graph ? &c : nullptr)) {
1225       if (graph != nullptr) {
1226         DataType::Type type = info->type;
1227         int64_t sum = a * ((m * (m - 1)) / 2) + b * m;
1228         if (type != DataType::Type::kInt64) {
1229           sum = static_cast<int32_t>(sum);  // okay to truncate
1230         }
1231         *result =
1232             Insert(block, new (graph->GetAllocator()) HAdd(type, graph->GetConstant(type, sum), c));
1233       }
1234       return true;
1235     }
1236   }
1237   return false;
1238 }
1239 
GenerateLastValueGeometric(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,HInstruction ** result) const1240 bool InductionVarRange::GenerateLastValueGeometric(const HBasicBlock* context,
1241                                                    const HLoopInformation* loop,
1242                                                    HInductionVarAnalysis::InductionInfo* info,
1243                                                    HInductionVarAnalysis::InductionInfo* trip,
1244                                                    HGraph* graph,
1245                                                    HBasicBlock* block,
1246                                                    /*out*/HInstruction** result) const {
1247   DCHECK(info != nullptr);
1248   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kGeometric);
1249   // Detect known base and trip count (always taken).
1250   int64_t f = 0;
1251   int64_t m = 0;
1252   if (IsInt64AndGet(info->fetch, &f) &&
1253       f >= 1 &&
1254       IsConstant(context, loop, trip->op_a, kExact, &m) &&
1255       m >= 1) {
1256     HInstruction* opa = nullptr;
1257     HInstruction* opb = nullptr;
1258     if (GenerateCode(
1259             context, loop, info->op_a, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, &opa) &&
1260         GenerateCode(
1261             context, loop, info->op_b, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, &opb)) {
1262       if (graph != nullptr) {
1263         DataType::Type type = info->type;
1264         // Compute f ^ m for known maximum index value m.
1265         bool overflow = false;
1266         int64_t fpow = IntPow(f, m, &overflow);
1267         if (info->operation == HInductionVarAnalysis::kDiv) {
1268           // For division, any overflow truncates to zero.
1269           if (overflow || (type != DataType::Type::kInt64 && !CanLongValueFitIntoInt(fpow))) {
1270             fpow = 0;
1271           }
1272         } else if (type != DataType::Type::kInt64) {
1273           // For multiplication, okay to truncate to required precision.
1274           DCHECK(info->operation == HInductionVarAnalysis::kMul);
1275           fpow = static_cast<int32_t>(fpow);
1276         }
1277         // Generate code.
1278         if (fpow == 0) {
1279           // Special case: repeated mul/div always yields zero.
1280           *result = graph->GetConstant(type, 0);
1281         } else {
1282           // Last value: a * f ^ m + b or a * f ^ -m + b.
1283           HInstruction* e = nullptr;
1284           ArenaAllocator* allocator = graph->GetAllocator();
1285           if (info->operation == HInductionVarAnalysis::kMul) {
1286             e = new (allocator) HMul(type, opa, graph->GetConstant(type, fpow));
1287           } else {
1288             e = new (allocator) HDiv(type, opa, graph->GetConstant(type, fpow), kNoDexPc);
1289           }
1290           *result = Insert(block, new (allocator) HAdd(type, Insert(block, e), opb));
1291         }
1292       }
1293       return true;
1294     }
1295   }
1296   return false;
1297 }
1298 
GenerateLastValueWrapAround(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,HInstruction ** result) const1299 bool InductionVarRange::GenerateLastValueWrapAround(const HBasicBlock* context,
1300                                                     const HLoopInformation* loop,
1301                                                     HInductionVarAnalysis::InductionInfo* info,
1302                                                     HInductionVarAnalysis::InductionInfo* trip,
1303                                                     HGraph* graph,
1304                                                     HBasicBlock* block,
1305                                                     /*out*/HInstruction** result) const {
1306   DCHECK(info != nullptr);
1307   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kWrapAround);
1308   // Count depth.
1309   int32_t depth = 0;
1310   for (; info->induction_class == HInductionVarAnalysis::kWrapAround;
1311        info = info->op_b, ++depth) {}
1312   // Handle wrap(x, wrap(.., y)) if trip count reaches an invariant at end.
1313   // TODO: generalize, but be careful to adjust the terminal.
1314   int64_t m = 0;
1315   if (info->induction_class == HInductionVarAnalysis::kInvariant &&
1316       IsConstant(context, loop, trip->op_a, kExact, &m) &&
1317       m >= depth) {
1318     return GenerateCode(
1319         context, loop, info, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, result);
1320   }
1321   return false;
1322 }
1323 
GenerateLastValuePeriodic(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,HInstruction ** result,bool * needs_taken_test) const1324 bool InductionVarRange::GenerateLastValuePeriodic(const HBasicBlock* context,
1325                                                   const HLoopInformation* loop,
1326                                                   HInductionVarAnalysis::InductionInfo* info,
1327                                                   HInductionVarAnalysis::InductionInfo* trip,
1328                                                   HGraph* graph,
1329                                                   HBasicBlock* block,
1330                                                   /*out*/ HInstruction** result,
1331                                                   /*inout*/ bool* needs_taken_test) const {
1332   DCHECK(info != nullptr);
1333   DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPeriodic);
1334   // Count period and detect all-invariants.
1335   int64_t period = 1;
1336   bool all_invariants = true;
1337   HInductionVarAnalysis::InductionInfo* p = info;
1338   for (; p->induction_class == HInductionVarAnalysis::kPeriodic; p = p->op_b, ++period) {
1339     DCHECK_EQ(p->op_a->induction_class, HInductionVarAnalysis::kInvariant);
1340     if (p->op_a->operation != HInductionVarAnalysis::kFetch) {
1341       all_invariants = false;
1342     }
1343   }
1344   DCHECK_EQ(p->induction_class, HInductionVarAnalysis::kInvariant);
1345   if (p->operation != HInductionVarAnalysis::kFetch) {
1346     all_invariants = false;
1347   }
1348   // Don't rely on FP arithmetic to be precise, unless the full period
1349   // consist of pre-computed expressions only.
1350   if (info->type == DataType::Type::kFloat32 || info->type == DataType::Type::kFloat64) {
1351     if (!all_invariants) {
1352       return false;
1353     }
1354   }
1355   // Handle any periodic(x, periodic(.., y)) for known maximum index value m.
1356   int64_t m = 0;
1357   if (IsConstant(context, loop, trip->op_a, kExact, &m) && m >= 1) {
1358     int64_t li = m % period;
1359     for (int64_t i = 0; i < li; info = info->op_b, i++) {}
1360     if (info->induction_class == HInductionVarAnalysis::kPeriodic) {
1361       info = info->op_a;
1362     }
1363     return GenerateCode(
1364         context, loop, info, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, result);
1365   }
1366   // Handle periodic(x, y) using even/odd-select on trip count. Enter trip count expression
1367   // directly to obtain the maximum index value t even if taken test is needed.
1368   HInstruction* x = nullptr;
1369   HInstruction* y = nullptr;
1370   HInstruction* t = nullptr;
1371 
1372   // Overflows when the stride is equal to `1` are fine since the periodicity is
1373   // `2` and the lowest bit is the same. Similar with `-1`.
1374   auto allow_potential_overflow = [&]() {
1375     int64_t stride_value = 0;
1376     return IsConstant(context, loop, trip->op_a->op_b, kExact, &stride_value) &&
1377            (stride_value == 1 || stride_value == -1);
1378   };
1379 
1380   if (period == 2 &&
1381       GenerateCode(context,
1382                    loop,
1383                    info->op_a,
1384                    /*trip=*/ nullptr,
1385                    graph,
1386                    block,
1387                    /*is_min=*/ false,
1388                    graph ? &x : nullptr) &&
1389       GenerateCode(context,
1390                    loop,
1391                    info->op_b,
1392                    /*trip=*/ nullptr,
1393                    graph,
1394                    block,
1395                    /*is_min=*/ false,
1396                    graph ? &y : nullptr) &&
1397       GenerateCode(context,
1398                    loop,
1399                    trip->op_a,
1400                    /*trip=*/ nullptr,
1401                    graph,
1402                    block,
1403                    /*is_min=*/ false,
1404                    graph ? &t : nullptr,
1405                    allow_potential_overflow())) {
1406     // During actual code generation (graph != nullptr), generate is_even ? x : y.
1407     if (graph != nullptr) {
1408       DataType::Type type = trip->type;
1409       ArenaAllocator* allocator = graph->GetAllocator();
1410       HInstruction* msk =
1411           Insert(block, new (allocator) HAnd(type, t, graph->GetConstant(type, 1)));
1412       HInstruction* is_even =
1413           Insert(block, new (allocator) HEqual(msk, graph->GetConstant(type, 0), kNoDexPc));
1414       *result = Insert(block, new (graph->GetAllocator()) HSelect(is_even, x, y, kNoDexPc));
1415     }
1416 
1417     if (*needs_taken_test) {
1418       if (TryGenerateTakenTest(context, loop, trip->op_b, graph, block, result, x)) {
1419         *needs_taken_test = false;  // taken care of
1420       } else {
1421         return false;
1422       }
1423     }
1424     return true;
1425   }
1426   return false;
1427 }
1428 
GenerateCode(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HInductionVarAnalysis::InductionInfo * trip,HGraph * graph,HBasicBlock * block,bool is_min,HInstruction ** result,bool allow_potential_overflow) const1429 bool InductionVarRange::GenerateCode(const HBasicBlock* context,
1430                                      const HLoopInformation* loop,
1431                                      HInductionVarAnalysis::InductionInfo* info,
1432                                      HInductionVarAnalysis::InductionInfo* trip,
1433                                      HGraph* graph,  // when set, code is generated
1434                                      HBasicBlock* block,
1435                                      bool is_min,
1436                                      /*out*/ HInstruction** result,
1437                                      bool allow_potential_overflow) const {
1438   if (info != nullptr) {
1439     // If during codegen, the result is not needed (nullptr), simply return success.
1440     if (graph != nullptr && result == nullptr) {
1441       return true;
1442     }
1443     // Handle current operation.
1444     DataType::Type type = info->type;
1445     HInstruction* opa = nullptr;
1446     HInstruction* opb = nullptr;
1447     switch (info->induction_class) {
1448       case HInductionVarAnalysis::kInvariant:
1449         // Invariants (note that since invariants only have other invariants as
1450         // sub expressions, viz. no induction, there is no need to adjust is_min).
1451         switch (info->operation) {
1452           case HInductionVarAnalysis::kAdd:
1453           case HInductionVarAnalysis::kSub:
1454           case HInductionVarAnalysis::kMul:
1455           case HInductionVarAnalysis::kDiv:
1456           case HInductionVarAnalysis::kRem:
1457           case HInductionVarAnalysis::kXor:
1458           case HInductionVarAnalysis::kLT:
1459           case HInductionVarAnalysis::kLE:
1460           case HInductionVarAnalysis::kGT:
1461           case HInductionVarAnalysis::kGE:
1462             if (GenerateCode(context,
1463                              loop,
1464                              info->op_a,
1465                              trip,
1466                              graph,
1467                              block,
1468                              is_min,
1469                              &opa,
1470                              allow_potential_overflow) &&
1471                 GenerateCode(context,
1472                              loop,
1473                              info->op_b,
1474                              trip,
1475                              graph,
1476                              block,
1477                              is_min,
1478                              &opb,
1479                              allow_potential_overflow)) {
1480               // Check for potentially invalid operations.
1481               if (!allow_potential_overflow) {
1482                 switch (info->operation) {
1483                   case HInductionVarAnalysis::kAdd:
1484                     return TryGenerateAddWithoutOverflow(
1485                         context, loop, info, graph, opa, opb, result);
1486                   case HInductionVarAnalysis::kSub:
1487                     return TryGenerateSubWithoutOverflow(context, loop, info, graph, opa, result);
1488                   default:
1489                     // The rest of the operations are not relevant in the cases where
1490                     // `allow_potential_overflow` is false. Fall through to the allowed overflow
1491                     // case.
1492                     break;
1493                 }
1494               }
1495 
1496               // Overflows here are accepted.
1497               if (graph != nullptr) {
1498                 HInstruction* operation = nullptr;
1499                 switch (info->operation) {
1500                   case HInductionVarAnalysis::kAdd:
1501                     operation = new (graph->GetAllocator()) HAdd(type, opa, opb); break;
1502                   case HInductionVarAnalysis::kSub:
1503                     operation = new (graph->GetAllocator()) HSub(type, opa, opb); break;
1504                   case HInductionVarAnalysis::kMul:
1505                     operation = new (graph->GetAllocator()) HMul(type, opa, opb, kNoDexPc); break;
1506                   case HInductionVarAnalysis::kDiv:
1507                     operation = new (graph->GetAllocator()) HDiv(type, opa, opb, kNoDexPc); break;
1508                   case HInductionVarAnalysis::kRem:
1509                     operation = new (graph->GetAllocator()) HRem(type, opa, opb, kNoDexPc); break;
1510                   case HInductionVarAnalysis::kXor:
1511                     operation = new (graph->GetAllocator()) HXor(type, opa, opb); break;
1512                   case HInductionVarAnalysis::kLT:
1513                     operation = new (graph->GetAllocator()) HLessThan(opa, opb); break;
1514                   case HInductionVarAnalysis::kLE:
1515                     operation = new (graph->GetAllocator()) HLessThanOrEqual(opa, opb); break;
1516                   case HInductionVarAnalysis::kGT:
1517                     operation = new (graph->GetAllocator()) HGreaterThan(opa, opb); break;
1518                   case HInductionVarAnalysis::kGE:
1519                     operation = new (graph->GetAllocator()) HGreaterThanOrEqual(opa, opb); break;
1520                   default:
1521                     LOG(FATAL) << "unknown operation";
1522                 }
1523                 *result = Insert(block, operation);
1524               }
1525               return true;
1526             }
1527             break;
1528           case HInductionVarAnalysis::kNeg:
1529             if (GenerateCode(context,
1530                              loop,
1531                              info->op_b,
1532                              trip,
1533                              graph,
1534                              block,
1535                              !is_min,
1536                              &opb,
1537                              allow_potential_overflow)) {
1538               if (graph != nullptr) {
1539                 *result = Insert(block, new (graph->GetAllocator()) HNeg(type, opb));
1540               }
1541               return true;
1542             }
1543             break;
1544           case HInductionVarAnalysis::kFetch:
1545             if (graph != nullptr) {
1546               *result = info->fetch;  // already in HIR
1547             }
1548             return true;
1549           case HInductionVarAnalysis::kTripCountInLoop:
1550           case HInductionVarAnalysis::kTripCountInLoopUnsafe:
1551             if (UseFullTripCount(context, loop, is_min)) {
1552               // Generate the full trip count (do not subtract 1 as we do in loop body).
1553               return GenerateCode(context,
1554                                   loop,
1555                                   info->op_a,
1556                                   trip,
1557                                   graph,
1558                                   block,
1559                                   /*is_min=*/false,
1560                                   result,
1561                                   allow_potential_overflow);
1562             }
1563             FALLTHROUGH_INTENDED;
1564           case HInductionVarAnalysis::kTripCountInBody:
1565           case HInductionVarAnalysis::kTripCountInBodyUnsafe:
1566             if (is_min) {
1567               if (graph != nullptr) {
1568                 *result = graph->GetConstant(type, 0);
1569               }
1570               return true;
1571             } else if (IsContextInBody(context, loop) ||
1572                        (context == loop->GetHeader() && !allow_potential_overflow)) {
1573               if (GenerateCode(context,
1574                                loop,
1575                                info->op_a,
1576                                trip,
1577                                graph,
1578                                block,
1579                                is_min,
1580                                &opb,
1581                                allow_potential_overflow)) {
1582                 if (graph != nullptr) {
1583                   if (IsContextInBody(context, loop)) {
1584                     ArenaAllocator* allocator = graph->GetAllocator();
1585                     *result =
1586                         Insert(block, new (allocator) HSub(type, opb, graph->GetConstant(type, 1)));
1587                   } else {
1588                     // We want to generate the full trip count since we want the last value. This
1589                     // will be combined with an `is_taken` test so we don't want to subtract one.
1590                     DCHECK(context == loop->GetHeader());
1591                     // TODO(solanes): Remove the !allow_potential_overflow restriction and allow
1592                     // other parts e.g. BCE to take advantage of this.
1593                     DCHECK(!allow_potential_overflow);
1594                     *result = opb;
1595                   }
1596                 }
1597                 return true;
1598               }
1599             }
1600             break;
1601           case HInductionVarAnalysis::kNop:
1602             LOG(FATAL) << "unexpected invariant nop";
1603         }  // switch invariant operation
1604         break;
1605       case HInductionVarAnalysis::kLinear: {
1606         // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
1607         // be restricted to a unit stride to avoid arithmetic wrap-around situations that
1608         // are harder to guard against. For a last value, requesting min/max based on any
1609         // known stride yields right value. Always avoid any narrowing linear induction or
1610         // any type mismatch between the linear induction and the trip count expression.
1611         // TODO: careful runtime type conversions could generalize this latter restriction.
1612         if (!HInductionVarAnalysis::IsNarrowingLinear(info) && trip->type == type) {
1613           int64_t stride_value = 0;
1614           if (IsConstant(context, loop, info->op_a, kExact, &stride_value) &&
1615               CanLongValueFitIntoInt(stride_value)) {
1616             const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
1617             if (GenerateCode(context,
1618                              loop,
1619                              trip,
1620                              trip,
1621                              graph,
1622                              block,
1623                              is_min_a,
1624                              &opa,
1625                              allow_potential_overflow) &&
1626                 GenerateCode(context,
1627                              loop,
1628                              info->op_b,
1629                              trip,
1630                              graph,
1631                              block,
1632                              is_min,
1633                              &opb,
1634                              allow_potential_overflow)) {
1635               if (graph != nullptr) {
1636                 ArenaAllocator* allocator = graph->GetAllocator();
1637                 HInstruction* oper;
1638                 if (stride_value == 1) {
1639                   oper = new (allocator) HAdd(type, opa, opb);
1640                 } else if (stride_value == -1) {
1641                   oper = new (graph->GetAllocator()) HSub(type, opb, opa);
1642                 } else {
1643                   HInstruction* mul =
1644                       new (allocator) HMul(type, graph->GetConstant(type, stride_value), opa);
1645                   oper = new (allocator) HAdd(type, Insert(block, mul), opb);
1646                 }
1647                 *result = Insert(block, oper);
1648               }
1649               return true;
1650             }
1651           }
1652         }
1653         break;
1654       }
1655       case HInductionVarAnalysis::kPolynomial:
1656       case HInductionVarAnalysis::kGeometric:
1657         break;
1658       case HInductionVarAnalysis::kWrapAround:
1659       case HInductionVarAnalysis::kPeriodic: {
1660         // Wrap-around and periodic inductions are restricted to constants only, so that extreme
1661         // values are easy to test at runtime without complications of arithmetic wrap-around.
1662         Value extreme = GetVal(context, loop, info, trip, is_min);
1663         if (IsConstantValue(extreme)) {
1664           if (graph != nullptr) {
1665             *result = graph->GetConstant(type, extreme.b_constant);
1666           }
1667           return true;
1668         }
1669         break;
1670       }
1671     }  // switch induction class
1672   }
1673   return false;
1674 }
1675 
TryGenerateAddWithoutOverflow(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HGraph * graph,HInstruction * opa,HInstruction * opb,HInstruction ** result) const1676 bool InductionVarRange::TryGenerateAddWithoutOverflow(const HBasicBlock* context,
1677                                                       const HLoopInformation* loop,
1678                                                       HInductionVarAnalysis::InductionInfo* info,
1679                                                       HGraph* graph,
1680                                                       /*in*/ HInstruction* opa,
1681                                                       /*in*/ HInstruction* opb,
1682                                                       /*out*/ HInstruction** result) const {
1683   // Calculate `a + b` making sure we can't overflow.
1684   int64_t val_a;
1685   const bool a_is_const = IsConstant(context, loop, info->op_a, kExact, &val_a);
1686   int64_t val_b;
1687   const bool b_is_const = IsConstant(context, loop, info->op_b, kExact, &val_b);
1688   if (a_is_const && b_is_const) {
1689     // Calculate `a + b` and use that. Note that even when the values are known,
1690     // their addition can still overflow.
1691     Value add_val = AddValue(Value(val_a), Value(val_b));
1692     if (add_val.is_known) {
1693       DCHECK(IsConstantValue(add_val));
1694       // Known value not overflowing.
1695       if (graph != nullptr) {
1696         *result = graph->GetConstant(info->type, add_val.b_constant);
1697       }
1698       return true;
1699     }
1700   }
1701 
1702   // When `a` is `0`, we can just use `b`.
1703   if (a_is_const && val_a == 0) {
1704     if (graph != nullptr) {
1705       *result = opb;
1706     }
1707     return true;
1708   }
1709 
1710   if (b_is_const && val_b == 0) {
1711     if (graph != nullptr) {
1712       *result = opa;
1713     }
1714     return true;
1715   }
1716 
1717   // Couldn't safely calculate the addition.
1718   return false;
1719 }
1720 
TryGenerateSubWithoutOverflow(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HGraph * graph,HInstruction * opa,HInstruction ** result) const1721 bool InductionVarRange::TryGenerateSubWithoutOverflow(const HBasicBlock* context,
1722                                                       const HLoopInformation* loop,
1723                                                       HInductionVarAnalysis::InductionInfo* info,
1724                                                       HGraph* graph,
1725                                                       /*in*/ HInstruction* opa,
1726                                                       /*out*/ HInstruction** result) const {
1727   // Calculate `a - b` making sure we can't overflow.
1728   int64_t val_b;
1729   if (!IsConstant(context, loop, info->op_b, kExact, &val_b)) {
1730     // If b is unknown, a - b can potentially overflow for any value of a since b
1731     // can be Integer.MIN_VALUE.
1732     return false;
1733   }
1734 
1735   int64_t val_a;
1736   if (IsConstant(context, loop, info->op_a, kExact, &val_a)) {
1737     // Calculate `a - b` and use that. Note that even when the values are known,
1738     // their subtraction can still overflow.
1739     Value sub_val = SubValue(Value(val_a), Value(val_b));
1740     if (sub_val.is_known) {
1741       DCHECK(IsConstantValue(sub_val));
1742       // Known value not overflowing.
1743       if (graph != nullptr) {
1744         *result = graph->GetConstant(info->type, sub_val.b_constant);
1745       }
1746       return true;
1747     }
1748   }
1749 
1750   // When `b` is `0`, we can just use `a`.
1751   if (val_b == 0) {
1752     if (graph != nullptr) {
1753       *result = opa;
1754     }
1755     return true;
1756   }
1757 
1758   // Couldn't safely calculate the subtraction.
1759   return false;
1760 }
1761 
TryGenerateTakenTest(const HBasicBlock * context,const HLoopInformation * loop,HInductionVarAnalysis::InductionInfo * info,HGraph * graph,HBasicBlock * block,HInstruction ** result,HInstruction * not_taken_result) const1762 bool InductionVarRange::TryGenerateTakenTest(const HBasicBlock* context,
1763                                              const HLoopInformation* loop,
1764                                              HInductionVarAnalysis::InductionInfo* info,
1765                                              HGraph* graph,
1766                                              HBasicBlock* block,
1767                                              /*inout*/ HInstruction** result,
1768                                              /*inout*/ HInstruction* not_taken_result) const {
1769   HInstruction* is_taken = nullptr;
1770   if (GenerateCode(context,
1771                    loop,
1772                    info,
1773                    /*trip=*/nullptr,
1774                    graph,
1775                    block,
1776                    /*is_min=*/false,
1777                    graph != nullptr ? &is_taken : nullptr)) {
1778     if (graph != nullptr) {
1779       ArenaAllocator* allocator = graph->GetAllocator();
1780       *result =
1781           Insert(block, new (allocator) HSelect(is_taken, *result, not_taken_result, kNoDexPc));
1782     }
1783     return true;
1784   } else {
1785     return false;
1786   }
1787 }
1788 
ReplaceInduction(HInductionVarAnalysis::InductionInfo * info,HInstruction * fetch,HInstruction * replacement)1789 void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
1790                                          HInstruction* fetch,
1791                                          HInstruction* replacement) {
1792   if (info != nullptr) {
1793     if (info->induction_class == HInductionVarAnalysis::kInvariant &&
1794         info->operation == HInductionVarAnalysis::kFetch &&
1795         info->fetch == fetch) {
1796       info->fetch = replacement;
1797     }
1798     ReplaceInduction(info->op_a, fetch, replacement);
1799     ReplaceInduction(info->op_b, fetch, replacement);
1800   }
1801 }
1802 
1803 }  // namespace art
1804