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