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