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