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