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