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
21namespace art {
22
23/** Returns true if 64-bit constant fits in 32-bit constant. */
24static bool CanLongValueFitIntoInt(int64_t c) {
25  return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
26}
27
28/** Returns true if 32-bit addition can be done safely. */
29static bool IsSafeAdd(int32_t c1, int32_t c2) {
30  return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
31}
32
33/** Returns true if 32-bit subtraction can be done safely. */
34static bool IsSafeSub(int32_t c1, int32_t c2) {
35  return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
36}
37
38/** Returns true if 32-bit multiplication can be done safely. */
39static bool IsSafeMul(int32_t c1, int32_t c2) {
40  return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
41}
42
43/** Returns true if 32-bit division can be done safely. */
44static bool IsSafeDiv(int32_t c1, int32_t c2) {
45  return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
46}
47
48/** Returns true for 32/64-bit constant instruction. */
49static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
50  if (instruction->IsIntConstant()) {
51    *value = instruction->AsIntConstant()->GetValue();
52    return true;
53  } else if (instruction->IsLongConstant()) {
54    *value = instruction->AsLongConstant()->GetValue();
55    return true;
56  }
57  return false;
58}
59
60/**
61 * An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as length + b
62 * because length >= 0 is true. This makes it more likely the bound is useful to clients.
63 */
64static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) {
65  int64_t value;
66  if (v.is_known &&
67      v.a_constant >= 1 &&
68      v.instruction->IsDiv() &&
69      v.instruction->InputAt(0)->IsArrayLength() &&
70      IsIntAndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
71    return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
72  }
73  return v;
74}
75
76/**
77 * Corrects a value for type to account for arithmetic wrap-around in lower precision.
78 */
79static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, Primitive::Type type) {
80  switch (type) {
81    case Primitive::kPrimShort:
82    case Primitive::kPrimChar:
83    case Primitive::kPrimByte: {
84      // Constants within range only.
85      // TODO: maybe some room for improvement, like allowing widening conversions
86      const int32_t min = Primitive::MinValueOfIntegralType(type);
87      const int32_t max = Primitive::MaxValueOfIntegralType(type);
88      return (v.is_known && v.a_constant == 0 && min <= v.b_constant && v.b_constant <= max)
89          ? v
90          : InductionVarRange::Value();
91    }
92    default:
93      // At int or higher.
94      return v;
95  }
96}
97
98/** Helper method to test for a constant value. */
99static bool IsConstantValue(InductionVarRange::Value v) {
100  return v.is_known && v.a_constant == 0;
101}
102
103/** Helper method to test for same constant value. */
104static bool IsSameConstantValue(InductionVarRange::Value v1, InductionVarRange::Value v2) {
105  return IsConstantValue(v1) && IsConstantValue(v2) && v1.b_constant == v2.b_constant;
106}
107
108/** Helper method to insert an instruction. */
109static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
110  DCHECK(block != nullptr);
111  DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
112  DCHECK(instruction != nullptr);
113  block->InsertInstructionBefore(instruction, block->GetLastInstruction());
114  return instruction;
115}
116
117//
118// Public class methods.
119//
120
121InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
122    : induction_analysis_(induction_analysis) {
123  DCHECK(induction_analysis != nullptr);
124}
125
126bool InductionVarRange::GetInductionRange(HInstruction* context,
127                                          HInstruction* instruction,
128                                          /*out*/Value* min_val,
129                                          /*out*/Value* max_val,
130                                          /*out*/bool* needs_finite_test) {
131  HLoopInformation* loop = context->GetBlock()->GetLoopInformation();  // closest enveloping loop
132  if (loop == nullptr) {
133    return false;  // no loop
134  }
135  HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
136  if (info == nullptr) {
137    return false;  // no induction information
138  }
139  // Type int or lower (this is not too restrictive since intended clients, like
140  // bounds check elimination, will have truncated higher precision induction
141  // at their use point already).
142  switch (info->type) {
143    case Primitive::kPrimInt:
144    case Primitive::kPrimShort:
145    case Primitive::kPrimChar:
146    case Primitive::kPrimByte:
147      break;
148    default:
149      return false;
150  }
151  // Set up loop information.
152  HBasicBlock* header = loop->GetHeader();
153  bool in_body = context->GetBlock() != header;
154  HInductionVarAnalysis::InductionInfo* trip =
155      induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
156  // Find range.
157  *min_val = GetVal(info, trip, in_body, /* is_min */ true);
158  *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
159  *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
160  return true;
161}
162
163bool InductionVarRange::RefineOuter(/*in-out*/ Value* min_val,
164                                    /*in-out*/ Value* max_val) const {
165  if (min_val->instruction != nullptr || max_val->instruction != nullptr) {
166    Value v1_min = RefineOuter(*min_val, /* is_min */ true);
167    Value v2_max = RefineOuter(*max_val, /* is_min */ false);
168    // The refined range is safe if both sides refine the same instruction. Otherwise, since two
169    // different ranges are combined, the new refined range is safe to pass back to the client if
170    // the extremes of the computed ranges ensure no arithmetic wrap-around anomalies occur.
171    if (min_val->instruction != max_val->instruction) {
172      Value v1_max = RefineOuter(*min_val, /* is_min */ false);
173      Value v2_min = RefineOuter(*max_val, /* is_min */ true);
174      if (!IsConstantValue(v1_max) ||
175          !IsConstantValue(v2_min) ||
176          v1_max.b_constant > v2_min.b_constant) {
177        return false;
178      }
179    }
180    // Did something change?
181    if (v1_min.instruction != min_val->instruction || v2_max.instruction != max_val->instruction) {
182      *min_val = v1_min;
183      *max_val = v2_max;
184      return true;
185    }
186  }
187  return false;
188}
189
190bool InductionVarRange::CanGenerateCode(HInstruction* context,
191                                        HInstruction* instruction,
192                                        /*out*/bool* needs_finite_test,
193                                        /*out*/bool* needs_taken_test) {
194  return GenerateCode(context,
195                      instruction,
196                      nullptr, nullptr, nullptr, nullptr, nullptr,  // nothing generated yet
197                      needs_finite_test,
198                      needs_taken_test);
199}
200
201void InductionVarRange::GenerateRangeCode(HInstruction* context,
202                                          HInstruction* instruction,
203                                          HGraph* graph,
204                                          HBasicBlock* block,
205                                          /*out*/HInstruction** lower,
206                                          /*out*/HInstruction** upper) {
207  bool b1, b2;  // unused
208  if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
209    LOG(FATAL) << "Failed precondition: GenerateCode()";
210  }
211}
212
213void InductionVarRange::GenerateTakenTest(HInstruction* context,
214                                          HGraph* graph,
215                                          HBasicBlock* block,
216                                          /*out*/HInstruction** taken_test) {
217  bool b1, b2;  // unused
218  if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
219    LOG(FATAL) << "Failed precondition: GenerateCode()";
220  }
221}
222
223//
224// Private class methods.
225//
226
227bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
228                                   ConstantRequest request,
229                                   /*out*/ int64_t *value) const {
230  if (info != nullptr) {
231    // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
232    // any of the three requests (kExact, kAtMost, and KAtLeast).
233    if (info->induction_class == HInductionVarAnalysis::kInvariant &&
234        info->operation == HInductionVarAnalysis::kFetch) {
235      if (IsIntAndGet(info->fetch, value)) {
236        return true;
237      }
238    }
239    // Try range analysis while traversing outward on loops.
240    bool in_body = true;  // no known trip count
241    Value v_min = GetVal(info, nullptr, in_body, /* is_min */ true);
242    Value v_max = GetVal(info, nullptr, in_body, /* is_min */ false);
243    do {
244      // Make sure *both* extremes are known to avoid arithmetic wrap-around anomalies.
245      if (IsConstantValue(v_min) && IsConstantValue(v_max) && v_min.b_constant <= v_max.b_constant) {
246        if ((request == kExact && v_min.b_constant == v_max.b_constant) || request == kAtMost) {
247          *value = v_max.b_constant;
248          return true;
249        } else if (request == kAtLeast) {
250          *value = v_min.b_constant;
251          return true;
252        }
253      }
254    } while (RefineOuter(&v_min, &v_max));
255    // Exploit array length + c >= c, with c <= 0 to avoid arithmetic wrap-around anomalies
256    // (e.g. array length == maxint and c == 1 would yield minint).
257    if (request == kAtLeast) {
258      if (v_min.a_constant == 1 && v_min.b_constant <= 0 && v_min.instruction->IsArrayLength()) {
259        *value = v_min.b_constant;
260        return true;
261      }
262    }
263  }
264  return false;
265}
266
267bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
268  if (info != nullptr) {
269    if (info->induction_class == HInductionVarAnalysis::kLinear) {
270      return true;
271    } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
272      return NeedsTripCount(info->op_b);
273    }
274  }
275  return false;
276}
277
278bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
279  if (trip != nullptr) {
280    if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
281      return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
282             trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
283    }
284  }
285  return false;
286}
287
288bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
289  if (trip != nullptr) {
290    if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
291      return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
292             trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
293    }
294  }
295  return false;
296}
297
298InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
299                                                      HInductionVarAnalysis::InductionInfo* trip,
300                                                      bool in_body,
301                                                      bool is_min) const {
302  // Detect common situation where an offset inside the trip count cancels out during range
303  // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
304  // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
305  // with intermediate results that only incorporate single instructions.
306  if (trip != nullptr) {
307    HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
308    if (trip_expr->operation == HInductionVarAnalysis::kSub) {
309      int64_t stride_value = 0;
310      if (IsConstant(info->op_a, kExact, &stride_value)) {
311        if (!is_min && stride_value == 1) {
312          // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
313          if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
314            // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
315            HInductionVarAnalysis::InductionInfo cancelled_trip(
316                trip->induction_class,
317                trip->operation,
318                trip_expr->op_a,
319                trip->op_b,
320                nullptr,
321                trip->type);
322            return GetVal(&cancelled_trip, trip, in_body, is_min);
323          }
324        } else if (is_min && stride_value == -1) {
325          // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
326          if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
327            // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
328            HInductionVarAnalysis::InductionInfo neg(
329                HInductionVarAnalysis::kInvariant,
330                HInductionVarAnalysis::kNeg,
331                nullptr,
332                trip_expr->op_b,
333                nullptr,
334                trip->type);
335            HInductionVarAnalysis::InductionInfo cancelled_trip(
336                trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
337            return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
338          }
339        }
340      }
341    }
342  }
343  // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
344  return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
345                  GetVal(info->op_b, trip, in_body, is_min));
346}
347
348InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
349                                                     HInductionVarAnalysis::InductionInfo* trip,
350                                                     bool in_body,
351                                                     bool is_min) const {
352  // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
353  // more likely range analysis will compare the same instructions as terminal nodes.
354  int64_t value;
355  if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value))  {
356    return Value(static_cast<int32_t>(value));
357  } else if (instruction->IsAdd()) {
358    if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
359      return AddValue(Value(static_cast<int32_t>(value)),
360                      GetFetch(instruction->InputAt(1), trip, in_body, is_min));
361    } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
362      return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
363                      Value(static_cast<int32_t>(value)));
364    }
365  } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
366    return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
367  } else if (instruction->IsTypeConversion()) {
368    // Since analysis is 32-bit (or narrower) we allow a widening along the path.
369    if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
370        instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
371      return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
372    }
373  } else if (is_min) {
374    // Special case for finding minimum: minimum of trip-count in loop-body is 1.
375    if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
376      return Value(1);
377    }
378  }
379  return Value(instruction, 1, 0);
380}
381
382InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
383                                                   HInductionVarAnalysis::InductionInfo* trip,
384                                                   bool in_body,
385                                                   bool is_min) const {
386  if (info != nullptr) {
387    switch (info->induction_class) {
388      case HInductionVarAnalysis::kInvariant:
389        // Invariants.
390        switch (info->operation) {
391          case HInductionVarAnalysis::kAdd:
392            return AddValue(GetVal(info->op_a, trip, in_body, is_min),
393                            GetVal(info->op_b, trip, in_body, is_min));
394          case HInductionVarAnalysis::kSub:  // second reversed!
395            return SubValue(GetVal(info->op_a, trip, in_body, is_min),
396                            GetVal(info->op_b, trip, in_body, !is_min));
397          case HInductionVarAnalysis::kNeg:  // second reversed!
398            return SubValue(Value(0),
399                            GetVal(info->op_b, trip, in_body, !is_min));
400          case HInductionVarAnalysis::kMul:
401            return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
402          case HInductionVarAnalysis::kDiv:
403            return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
404          case HInductionVarAnalysis::kFetch:
405            return GetFetch(info->fetch, trip, in_body, is_min);
406          case HInductionVarAnalysis::kTripCountInLoop:
407          case HInductionVarAnalysis::kTripCountInLoopUnsafe:
408            if (!in_body && !is_min) {  // one extra!
409              return GetVal(info->op_a, trip, in_body, is_min);
410            }
411            FALLTHROUGH_INTENDED;
412          case HInductionVarAnalysis::kTripCountInBody:
413          case HInductionVarAnalysis::kTripCountInBodyUnsafe:
414            if (is_min) {
415              return Value(0);
416            } else if (in_body) {
417              return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
418            }
419            break;
420          default:
421            break;
422        }
423        break;
424      case HInductionVarAnalysis::kLinear: {
425        return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
426      }
427      case HInductionVarAnalysis::kWrapAround:
428      case HInductionVarAnalysis::kPeriodic:
429        return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
430                        GetVal(info->op_b, trip, in_body, is_min), is_min);
431    }
432  }
433  return Value();
434}
435
436InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
437                                                   HInductionVarAnalysis::InductionInfo* info2,
438                                                   HInductionVarAnalysis::InductionInfo* trip,
439                                                   bool in_body,
440                                                   bool is_min) const {
441  Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
442  Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
443  Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
444  Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
445  // Try to refine first operand.
446  if (!IsConstantValue(v1_min) && !IsConstantValue(v1_max)) {
447    RefineOuter(&v1_min, &v1_max);
448  }
449  // Constant times range.
450  if (IsSameConstantValue(v1_min, v1_max)) {
451    return MulRangeAndConstant(v2_min, v2_max, v1_min, is_min);
452  } else if (IsSameConstantValue(v2_min, v2_max)) {
453    return MulRangeAndConstant(v1_min, v1_max, v2_min, is_min);
454  }
455  // Positive range vs. positive or negative range.
456  if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
457    if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
458      return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
459    } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
460      return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
461    }
462  }
463  // Negative range vs. positive or negative range.
464  if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
465    if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
466      return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
467    } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
468      return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
469    }
470  }
471  return Value();
472}
473
474InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
475                                                   HInductionVarAnalysis::InductionInfo* info2,
476                                                   HInductionVarAnalysis::InductionInfo* trip,
477                                                   bool in_body,
478                                                   bool is_min) const {
479  Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
480  Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
481  Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
482  Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
483  // Range divided by constant.
484  if (IsSameConstantValue(v2_min, v2_max)) {
485    return DivRangeAndConstant(v1_min, v1_max, v2_min, is_min);
486  }
487  // Positive range vs. positive or negative range.
488  if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
489    if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
490      return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
491    } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
492      return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
493    }
494  }
495  // Negative range vs. positive or negative range.
496  if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
497    if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
498      return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
499    } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
500      return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
501    }
502  }
503  return Value();
504}
505
506InductionVarRange::Value InductionVarRange::MulRangeAndConstant(Value v_min,
507                                                                Value v_max,
508                                                                Value c,
509                                                                bool is_min) const {
510  return is_min == (c.b_constant >= 0) ? MulValue(v_min, c) : MulValue(v_max, c);
511}
512
513InductionVarRange::Value InductionVarRange::DivRangeAndConstant(Value v_min,
514                                                                Value v_max,
515                                                                Value c,
516                                                                bool is_min) const {
517  return is_min == (c.b_constant >= 0) ? DivValue(v_min, c) : DivValue(v_max, c);
518}
519
520InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
521  if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
522    const int32_t b = v1.b_constant + v2.b_constant;
523    if (v1.a_constant == 0) {
524      return Value(v2.instruction, v2.a_constant, b);
525    } else if (v2.a_constant == 0) {
526      return Value(v1.instruction, v1.a_constant, b);
527    } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
528      return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
529    }
530  }
531  return Value();
532}
533
534InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
535  if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
536    const int32_t b = v1.b_constant - v2.b_constant;
537    if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
538      return Value(v2.instruction, -v2.a_constant, b);
539    } else if (v2.a_constant == 0) {
540      return Value(v1.instruction, v1.a_constant, b);
541    } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
542      return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
543    }
544  }
545  return Value();
546}
547
548InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
549  if (v1.is_known && v2.is_known) {
550    if (v1.a_constant == 0) {
551      if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
552        return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
553      }
554    } else if (v2.a_constant == 0) {
555      if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
556        return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
557      }
558    }
559  }
560  return Value();
561}
562
563InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
564  if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
565    if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
566      return Value(v1.b_constant / v2.b_constant);
567    }
568  }
569  return Value();
570}
571
572InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
573  if (v1.is_known && v2.is_known) {
574    if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
575      return Value(v1.instruction, v1.a_constant,
576                   is_min ? std::min(v1.b_constant, v2.b_constant)
577                          : std::max(v1.b_constant, v2.b_constant));
578    }
579  }
580  return Value();
581}
582
583InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) const {
584  if (v.instruction == nullptr) {
585    return v;  // nothing to refine
586  }
587  HLoopInformation* loop =
588      v.instruction->GetBlock()->GetLoopInformation();  // closest enveloping loop
589  if (loop == nullptr) {
590    return v;  // no loop
591  }
592  HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, v.instruction);
593  if (info == nullptr) {
594    return v;  // no induction information
595  }
596  // Set up loop information.
597  HBasicBlock* header = loop->GetHeader();
598  bool in_body = true;  // inner always in more outer
599  HInductionVarAnalysis::InductionInfo* trip =
600      induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
601  // Try to refine "a x instruction + b" with outer loop range information on instruction.
602  return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)), Value(v.b_constant));
603}
604
605bool InductionVarRange::GenerateCode(HInstruction* context,
606                                     HInstruction* instruction,
607                                     HGraph* graph,
608                                     HBasicBlock* block,
609                                     /*out*/HInstruction** lower,
610                                     /*out*/HInstruction** upper,
611                                     /*out*/HInstruction** taken_test,
612                                     /*out*/bool* needs_finite_test,
613                                     /*out*/bool* needs_taken_test) const {
614  HLoopInformation* loop = context->GetBlock()->GetLoopInformation();  // closest enveloping loop
615  if (loop == nullptr) {
616    return false;  // no loop
617  }
618  HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
619  if (info == nullptr) {
620    return false;  // no induction information
621  }
622  // Set up loop information.
623  HBasicBlock* header = loop->GetHeader();
624  bool in_body = context->GetBlock() != header;
625  HInductionVarAnalysis::InductionInfo* trip =
626      induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
627  if (trip == nullptr) {
628    return false;  // codegen relies on trip count
629  }
630  // Determine what tests are needed. A finite test is needed if the evaluation code uses the
631  // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
632  // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
633  // code does not use the trip-count explicitly (since there could be an implicit relation
634  // between e.g. an invariant subscript and a not-taken condition).
635  *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
636  *needs_taken_test = IsBodyTripCount(trip);
637  // Code generation for taken test: generate the code when requested or otherwise analyze
638  // if code generation is feasible when taken test is needed.
639  if (taken_test != nullptr) {
640    return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
641  } else if (*needs_taken_test) {
642    if (!GenerateCode(
643        trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
644      return false;
645    }
646  }
647  // Code generation for lower and upper.
648  return
649      // Success on lower if invariant (not set), or code can be generated.
650      ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
651          GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
652      // And success on upper.
653      GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
654}
655
656bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
657                                     HInductionVarAnalysis::InductionInfo* trip,
658                                     HGraph* graph,  // when set, code is generated
659                                     HBasicBlock* block,
660                                     /*out*/HInstruction** result,
661                                     bool in_body,
662                                     bool is_min) const {
663  if (info != nullptr) {
664    // Verify type safety.
665    Primitive::Type type = Primitive::kPrimInt;
666    if (info->type != type) {
667      return false;
668    }
669    // Handle current operation.
670    HInstruction* opa = nullptr;
671    HInstruction* opb = nullptr;
672    switch (info->induction_class) {
673      case HInductionVarAnalysis::kInvariant:
674        // Invariants.
675        switch (info->operation) {
676          case HInductionVarAnalysis::kAdd:
677          case HInductionVarAnalysis::kLT:
678          case HInductionVarAnalysis::kLE:
679          case HInductionVarAnalysis::kGT:
680          case HInductionVarAnalysis::kGE:
681            if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
682                GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
683              if (graph != nullptr) {
684                HInstruction* operation = nullptr;
685                switch (info->operation) {
686                  case HInductionVarAnalysis::kAdd:
687                    operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
688                  case HInductionVarAnalysis::kLT:
689                    operation = new (graph->GetArena()) HLessThan(opa, opb); break;
690                  case HInductionVarAnalysis::kLE:
691                    operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
692                  case HInductionVarAnalysis::kGT:
693                    operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
694                  case HInductionVarAnalysis::kGE:
695                    operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
696                  default:
697                    LOG(FATAL) << "unknown operation";
698                }
699                *result = Insert(block, operation);
700              }
701              return true;
702            }
703            break;
704          case HInductionVarAnalysis::kSub:  // second reversed!
705            if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
706                GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
707              if (graph != nullptr) {
708                *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
709              }
710              return true;
711            }
712            break;
713          case HInductionVarAnalysis::kNeg:  // reversed!
714            if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
715              if (graph != nullptr) {
716                *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
717              }
718              return true;
719            }
720            break;
721          case HInductionVarAnalysis::kFetch:
722            if (graph != nullptr) {
723              *result = info->fetch;  // already in HIR
724            }
725            return true;
726          case HInductionVarAnalysis::kTripCountInLoop:
727          case HInductionVarAnalysis::kTripCountInLoopUnsafe:
728            if (!in_body && !is_min) {  // one extra!
729              return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
730            }
731            FALLTHROUGH_INTENDED;
732          case HInductionVarAnalysis::kTripCountInBody:
733          case HInductionVarAnalysis::kTripCountInBodyUnsafe:
734            if (is_min) {
735              if (graph != nullptr) {
736                *result = graph->GetIntConstant(0);
737              }
738              return true;
739            } else if (in_body) {
740              if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
741                if (graph != nullptr) {
742                  *result = Insert(block,
743                                   new (graph->GetArena())
744                                       HSub(type, opb, graph->GetIntConstant(1)));
745                }
746                return true;
747              }
748            }
749            break;
750          default:
751            break;
752        }
753        break;
754      case HInductionVarAnalysis::kLinear: {
755        // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
756        // to avoid arithmetic wrap-around situations that are hard to guard against.
757        int64_t stride_value = 0;
758        if (IsConstant(info->op_a, kExact, &stride_value)) {
759          if (stride_value == 1 || stride_value == -1) {
760            const bool is_min_a = stride_value == 1 ? is_min : !is_min;
761            if (GenerateCode(trip,       trip, graph, block, &opa, in_body, is_min_a) &&
762                GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
763              if (graph != nullptr) {
764                HInstruction* oper;
765                if (stride_value == 1) {
766                  oper = new (graph->GetArena()) HAdd(type, opa, opb);
767                } else {
768                  oper = new (graph->GetArena()) HSub(type, opb, opa);
769                }
770                *result = Insert(block, oper);
771              }
772              return true;
773            }
774          }
775        }
776        break;
777      }
778      case HInductionVarAnalysis::kWrapAround:
779      case HInductionVarAnalysis::kPeriodic: {
780        // Wrap-around and periodic inductions are restricted to constants only, so that extreme
781        // values are easy to test at runtime without complications of arithmetic wrap-around.
782        Value extreme = GetVal(info, trip, in_body, is_min);
783        if (IsConstantValue(extreme)) {
784          if (graph != nullptr) {
785            *result = graph->GetIntConstant(extreme.b_constant);
786          }
787          return true;
788        }
789        break;
790      }
791      default:
792        break;
793    }
794  }
795  return false;
796}
797
798}  // namespace art
799