blob: 235793d8d2b7e08416acece1b0aa6f1bf7b42ddc [file] [log] [blame]
Aart Bikd14c5952015-09-08 15:25:15 -07001/*
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
Aart Bikd14c5952015-09-08 15:25:15 -070017#include "induction_var_range.h"
18
Aart Bikcd26feb2015-09-23 17:50:50 -070019#include <limits>
20
Aart Bikd14c5952015-09-08 15:25:15 -070021namespace art {
22
Aart Bikb3365e02015-09-21 14:45:05 -070023/** Returns true if 64-bit constant fits in 32-bit constant. */
24static bool CanLongValueFitIntoInt(int64_t c) {
Aart Bikcd26feb2015-09-23 17:50:50 -070025 return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
Aart Bikd14c5952015-09-08 15:25:15 -070026}
27
Aart Bikb3365e02015-09-21 14:45:05 -070028/** Returns true if 32-bit addition can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070029static bool IsSafeAdd(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070030 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070031}
32
Aart Bikb3365e02015-09-21 14:45:05 -070033/** Returns true if 32-bit subtraction can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070034static bool IsSafeSub(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070035 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070036}
37
Aart Bikb3365e02015-09-21 14:45:05 -070038/** Returns true if 32-bit multiplication can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070039static bool IsSafeMul(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070040 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070041}
42
Aart Bikb3365e02015-09-21 14:45:05 -070043/** Returns true if 32-bit division can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070044static bool IsSafeDiv(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070045 return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070046}
47
Aart Bik97412c92016-02-19 20:14:38 -080048/** Returns true for 32/64-bit constant instruction. */
49static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
Aart Bikd14c5952015-09-08 15:25:15 -070050 if (instruction->IsIntConstant()) {
Aart Bikb3365e02015-09-21 14:45:05 -070051 *value = instruction->AsIntConstant()->GetValue();
52 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070053 } else if (instruction->IsLongConstant()) {
Aart Bik97412c92016-02-19 20:14:38 -080054 *value = instruction->AsLongConstant()->GetValue();
55 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070056 }
57 return false;
58}
59
Aart Bikb3365e02015-09-21 14:45:05 -070060/**
Aart Bik40fbf742016-10-31 11:02:50 -070061 * Detects an instruction that is >= 0. As long as the value is carried by
62 * a single instruction, arithmetic wrap-around cannot occur.
Aart Bikb3365e02015-09-21 14:45:05 -070063 */
Aart Bik40fbf742016-10-31 11:02:50 -070064static bool IsGEZero(HInstruction* instruction) {
65 DCHECK(instruction != nullptr);
66 if (instruction->IsArrayLength()) {
67 return true;
68 } else if (instruction->IsInvokeStaticOrDirect()) {
69 switch (instruction->AsInvoke()->GetIntrinsic()) {
70 case Intrinsics::kMathMinIntInt:
71 case Intrinsics::kMathMinLongLong:
72 // Instruction MIN(>=0, >=0) is >= 0.
73 return IsGEZero(instruction->InputAt(0)) &&
74 IsGEZero(instruction->InputAt(1));
75 case Intrinsics::kMathAbsInt:
76 case Intrinsics::kMathAbsLong:
77 // Instruction ABS(x) is >= 0.
78 return true;
79 default:
80 break;
81 }
82 }
83 int64_t value = -1;
84 return IsIntAndGet(instruction, &value) && value >= 0;
85}
86
87/** Hunts "under the hood" for a suitable instruction at the hint. */
88static bool IsMaxAtHint(
89 HInstruction* instruction, HInstruction* hint, /*out*/HInstruction** suitable) {
90 if (instruction->IsInvokeStaticOrDirect()) {
91 switch (instruction->AsInvoke()->GetIntrinsic()) {
92 case Intrinsics::kMathMinIntInt:
93 case Intrinsics::kMathMinLongLong:
94 // For MIN(x, y), return most suitable x or y as maximum.
95 return IsMaxAtHint(instruction->InputAt(0), hint, suitable) ||
96 IsMaxAtHint(instruction->InputAt(1), hint, suitable);
97 default:
98 break;
99 }
100 } else {
101 *suitable = instruction;
102 while (instruction->IsArrayLength() ||
103 instruction->IsNullCheck() ||
104 instruction->IsNewArray()) {
105 instruction = instruction->InputAt(0);
106 }
107 return instruction == hint;
108 }
109 return false;
110}
111
112/** Post-analysis simplification of a minimum value that makes the bound more useful to clients. */
113static InductionVarRange::Value SimplifyMin(InductionVarRange::Value v) {
114 if (v.is_known && v.a_constant == 1 && v.b_constant <= 0) {
115 // If a == 1, instruction >= 0 and b <= 0, just return the constant b.
116 // No arithmetic wrap-around can occur.
117 if (IsGEZero(v.instruction)) {
118 return InductionVarRange::Value(v.b_constant);
119 }
Aart Bikb3365e02015-09-21 14:45:05 -0700120 }
121 return v;
122}
123
Aart Bik40fbf742016-10-31 11:02:50 -0700124/** Post-analysis simplification of a maximum value that makes the bound more useful to clients. */
125static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v, HInstruction* hint) {
126 if (v.is_known && v.a_constant >= 1) {
127 // An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as
128 // length + b because length >= 0 is true.
129 int64_t value;
130 if (v.instruction->IsDiv() &&
131 v.instruction->InputAt(0)->IsArrayLength() &&
132 IsIntAndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
133 return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
134 }
135 // If a == 1, the most suitable one suffices as maximum value.
136 HInstruction* suitable = nullptr;
137 if (v.a_constant == 1 && IsMaxAtHint(v.instruction, hint, &suitable)) {
138 return InductionVarRange::Value(suitable, 1, v.b_constant);
139 }
140 }
141 return v;
142}
143
144/** Tests for a constant value. */
Aart Bik52be7e72016-06-23 11:20:41 -0700145static bool IsConstantValue(InductionVarRange::Value v) {
146 return v.is_known && v.a_constant == 0;
147}
148
149/** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
Aart Bik0d345cf2016-03-16 10:49:38 -0700150static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, Primitive::Type type) {
151 switch (type) {
152 case Primitive::kPrimShort:
153 case Primitive::kPrimChar:
154 case Primitive::kPrimByte: {
155 // Constants within range only.
156 // TODO: maybe some room for improvement, like allowing widening conversions
157 const int32_t min = Primitive::MinValueOfIntegralType(type);
158 const int32_t max = Primitive::MaxValueOfIntegralType(type);
Aart Bik52be7e72016-06-23 11:20:41 -0700159 return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
Aart Bik0d345cf2016-03-16 10:49:38 -0700160 ? v
161 : InductionVarRange::Value();
162 }
163 default:
Aart Bik0d345cf2016-03-16 10:49:38 -0700164 return v;
165 }
166}
167
Aart Bik40fbf742016-10-31 11:02:50 -0700168/** Inserts an instruction. */
Aart Bik389b3db2015-10-28 14:23:40 -0700169static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
170 DCHECK(block != nullptr);
171 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -0700172 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -0700173 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -0700174 return instruction;
175}
176
Aart Bik40fbf742016-10-31 11:02:50 -0700177/** Obtains loop's control instruction. */
Aart Bik009cace2016-09-16 10:15:19 -0700178static HInstruction* GetLoopControl(HLoopInformation* loop) {
179 DCHECK(loop != nullptr);
180 return loop->GetHeader()->GetLastInstruction();
181}
182
Aart Bikd14c5952015-09-08 15:25:15 -0700183//
184// Public class methods.
185//
186
187InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
Aart Bik52be7e72016-06-23 11:20:41 -0700188 : induction_analysis_(induction_analysis),
189 chase_hint_(nullptr) {
Aart Bikb3365e02015-09-21 14:45:05 -0700190 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700191}
192
Aart Bik1fc3afb2016-02-02 13:26:16 -0800193bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700194 HInstruction* instruction,
Aart Bik52be7e72016-06-23 11:20:41 -0700195 HInstruction* chase_hint,
Aart Bik389b3db2015-10-28 14:23:40 -0700196 /*out*/Value* min_val,
197 /*out*/Value* max_val,
198 /*out*/bool* needs_finite_test) {
Aart Bik52be7e72016-06-23 11:20:41 -0700199 HLoopInformation* loop = nullptr;
200 HInductionVarAnalysis::InductionInfo* info = nullptr;
201 HInductionVarAnalysis::InductionInfo* trip = nullptr;
202 if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
203 return false;
Aart Bik97412c92016-02-19 20:14:38 -0800204 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700205 // Type int or lower (this is not too restrictive since intended clients, like
206 // bounds check elimination, will have truncated higher precision induction
207 // at their use point already).
208 switch (info->type) {
209 case Primitive::kPrimInt:
210 case Primitive::kPrimShort:
211 case Primitive::kPrimChar:
212 case Primitive::kPrimByte:
213 break;
214 default:
215 return false;
216 }
Aart Bik97412c92016-02-19 20:14:38 -0800217 // Find range.
Aart Bik52be7e72016-06-23 11:20:41 -0700218 chase_hint_ = chase_hint;
219 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700220 int64_t stride_value = 0;
Aart Bik40fbf742016-10-31 11:02:50 -0700221 *min_val = SimplifyMin(GetVal(info, trip, in_body, /* is_min */ true));
222 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false), chase_hint);
Aart Bik16d3a652016-09-09 10:33:50 -0700223 *needs_finite_test = NeedsTripCount(info, &stride_value) && IsUnsafeTripCount(trip);
Aart Bik40fbf742016-10-31 11:02:50 -0700224 chase_hint_ = nullptr;
225 // Retry chasing constants for wrap-around (merge sensitive).
226 if (!min_val->is_known && info->induction_class == HInductionVarAnalysis::kWrapAround) {
227 *min_val = SimplifyMin(GetVal(info, trip, in_body, /* is_min */ true));
228 }
Aart Bik97412c92016-02-19 20:14:38 -0800229 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700230}
231
Aart Bik16d3a652016-09-09 10:33:50 -0700232bool InductionVarRange::CanGenerateRange(HInstruction* context,
233 HInstruction* instruction,
234 /*out*/bool* needs_finite_test,
235 /*out*/bool* needs_taken_test) {
236 bool is_last_value = false;
237 int64_t stride_value = 0;
Aart Bik9abf8942016-10-14 09:49:42 -0700238 return GenerateRangeOrLastValue(context,
239 instruction,
240 is_last_value,
241 nullptr,
242 nullptr,
243 nullptr,
244 nullptr,
245 nullptr, // nothing generated yet
246 &stride_value,
247 needs_finite_test,
248 needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700249 && (stride_value == -1 ||
250 stride_value == 0 ||
Aart Bik40fbf742016-10-31 11:02:50 -0700251 stride_value == 1); // avoid arithmetic wrap-around anomalies.
Aart Bikaec3cce2015-10-14 17:44:55 -0700252}
253
Aart Bik16d3a652016-09-09 10:33:50 -0700254void InductionVarRange::GenerateRange(HInstruction* context,
255 HInstruction* instruction,
256 HGraph* graph,
257 HBasicBlock* block,
258 /*out*/HInstruction** lower,
259 /*out*/HInstruction** upper) {
260 bool is_last_value = false;
Aart Bik009cace2016-09-16 10:15:19 -0700261 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700262 bool b1, b2; // unused
Aart Bik9abf8942016-10-14 09:49:42 -0700263 if (!GenerateRangeOrLastValue(context,
264 instruction,
265 is_last_value,
266 graph,
267 block,
268 lower,
269 upper,
270 nullptr,
271 &stride_value,
272 &b1,
273 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700274 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
Aart Bik389b3db2015-10-28 14:23:40 -0700275 }
276}
277
Aart Bik16d3a652016-09-09 10:33:50 -0700278HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context,
279 HGraph* graph,
280 HBasicBlock* block) {
281 HInstruction* taken_test = nullptr;
282 bool is_last_value = false;
283 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700284 bool b1, b2; // unused
Aart Bik9abf8942016-10-14 09:49:42 -0700285 if (!GenerateRangeOrLastValue(context,
286 context,
287 is_last_value,
288 graph,
289 block,
290 nullptr,
291 nullptr,
292 &taken_test,
293 &stride_value,
294 &b1,
295 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700296 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
297 }
298 return taken_test;
299}
300
301bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
302 bool is_last_value = true;
303 int64_t stride_value = 0;
304 bool needs_finite_test = false;
305 bool needs_taken_test = false;
Aart Bik9abf8942016-10-14 09:49:42 -0700306 return GenerateRangeOrLastValue(instruction,
307 instruction,
308 is_last_value,
309 nullptr,
310 nullptr,
311 nullptr,
312 nullptr,
313 nullptr, // nothing generated yet
314 &stride_value,
315 &needs_finite_test,
316 &needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700317 && !needs_finite_test && !needs_taken_test;
318}
319
320HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
321 HGraph* graph,
322 HBasicBlock* block) {
323 HInstruction* last_value = nullptr;
324 bool is_last_value = true;
325 int64_t stride_value = 0;
326 bool b1, b2; // unused
Aart Bik9abf8942016-10-14 09:49:42 -0700327 if (!GenerateRangeOrLastValue(instruction,
328 instruction,
329 is_last_value,
330 graph,
331 block,
332 &last_value,
333 &last_value,
334 nullptr,
335 &stride_value,
336 &b1,
337 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700338 LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
339 }
340 return last_value;
341}
342
343void InductionVarRange::Replace(HInstruction* instruction,
344 HInstruction* fetch,
345 HInstruction* replacement) {
346 for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
347 lp != nullptr;
348 lp = lp->GetPreHeader()->GetLoopInformation()) {
Aart Bik009cace2016-09-16 10:15:19 -0700349 // Update instruction's information.
Aart Bik16d3a652016-09-09 10:33:50 -0700350 ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
Aart Bik009cace2016-09-16 10:15:19 -0700351 // Update loop's trip-count information.
352 ReplaceInduction(induction_analysis_->LookupInfo(lp, GetLoopControl(lp)), fetch, replacement);
Aart Bik389b3db2015-10-28 14:23:40 -0700353 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700354}
355
Aart Bik9abf8942016-10-14 09:49:42 -0700356bool InductionVarRange::IsFinite(HLoopInformation* loop) const {
357 HInductionVarAnalysis::InductionInfo *trip =
358 induction_analysis_->LookupInfo(loop, GetLoopControl(loop));
359 return trip != nullptr && !IsUnsafeTripCount(trip);
360}
361
Aart Bikd14c5952015-09-08 15:25:15 -0700362//
363// Private class methods.
364//
365
Aart Bik97412c92016-02-19 20:14:38 -0800366bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
367 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700368 /*out*/ int64_t* value) const {
Aart Bik97412c92016-02-19 20:14:38 -0800369 if (info != nullptr) {
370 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
371 // any of the three requests (kExact, kAtMost, and KAtLeast).
372 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
373 info->operation == HInductionVarAnalysis::kFetch) {
374 if (IsIntAndGet(info->fetch, value)) {
375 return true;
376 }
377 }
Aart Bik40fbf742016-10-31 11:02:50 -0700378 // Try range analysis on the invariant, only accept a proper range
379 // to avoid arithmetic wrap-around anomalies.
Aart Bik52be7e72016-06-23 11:20:41 -0700380 Value min_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ true);
381 Value max_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ false);
382 if (IsConstantValue(min_val) &&
383 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
384 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
385 *value = max_val.b_constant;
386 return true;
387 } else if (request == kAtLeast) {
388 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800389 return true;
390 }
391 }
Aart Bik97412c92016-02-19 20:14:38 -0800392 }
393 return false;
394}
395
Aart Bik52be7e72016-06-23 11:20:41 -0700396bool InductionVarRange::HasInductionInfo(
397 HInstruction* context,
398 HInstruction* instruction,
399 /*out*/ HLoopInformation** loop,
400 /*out*/ HInductionVarAnalysis::InductionInfo** info,
401 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
Aart Bik009cace2016-09-16 10:15:19 -0700402 HLoopInformation* lp = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
403 if (lp != nullptr) {
404 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(lp, instruction);
Aart Bik52be7e72016-06-23 11:20:41 -0700405 if (i != nullptr) {
Aart Bik009cace2016-09-16 10:15:19 -0700406 *loop = lp;
Aart Bik52be7e72016-06-23 11:20:41 -0700407 *info = i;
Aart Bik009cace2016-09-16 10:15:19 -0700408 *trip = induction_analysis_->LookupInfo(lp, GetLoopControl(lp));
Aart Bik52be7e72016-06-23 11:20:41 -0700409 return true;
410 }
411 }
412 return false;
413}
414
415bool InductionVarRange::IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
416 if (trip != nullptr) {
417 // Both bounds that define a trip-count are well-behaved if they either are not defined
418 // in any loop, or are contained in a proper interval. This allows finding the min/max
419 // of an expression by chasing outward.
420 InductionVarRange range(induction_analysis_);
421 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
422 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
423 int64_t not_used = 0;
424 return (!HasFetchInLoop(lower) || range.IsConstant(lower, kAtLeast, &not_used)) &&
425 (!HasFetchInLoop(upper) || range.IsConstant(upper, kAtLeast, &not_used));
426 }
427 return true;
428}
429
430bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
431 if (info != nullptr) {
432 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
433 info->operation == HInductionVarAnalysis::kFetch) {
434 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
435 }
436 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
437 }
438 return false;
439}
440
Aart Bik16d3a652016-09-09 10:33:50 -0700441bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
442 int64_t* stride_value) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700443 if (info != nullptr) {
444 if (info->induction_class == HInductionVarAnalysis::kLinear) {
Aart Bik16d3a652016-09-09 10:33:50 -0700445 return IsConstant(info->op_a, kExact, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700446 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
Aart Bik16d3a652016-09-09 10:33:50 -0700447 return NeedsTripCount(info->op_b, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700448 }
Aart Bikd14c5952015-09-08 15:25:15 -0700449 }
Aart Bik389b3db2015-10-28 14:23:40 -0700450 return false;
451}
452
Aart Bik7d57d7f2015-12-09 14:39:48 -0800453bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700454 if (trip != nullptr) {
455 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
456 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
457 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
458 }
459 }
460 return false;
461}
462
Aart Bik7d57d7f2015-12-09 14:39:48 -0800463bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700464 if (trip != nullptr) {
465 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
466 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
467 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
468 }
469 }
470 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700471}
472
Aart Bik7d57d7f2015-12-09 14:39:48 -0800473InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
474 HInductionVarAnalysis::InductionInfo* trip,
475 bool in_body,
476 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700477 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800478 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
479 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
480 // with intermediate results that only incorporate single instructions.
481 if (trip != nullptr) {
482 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700483 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c92016-02-19 20:14:38 -0800484 int64_t stride_value = 0;
485 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800486 if (!is_min && stride_value == 1) {
Aart Bik97412c92016-02-19 20:14:38 -0800487 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800488 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
489 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
490 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700491 trip->induction_class,
492 trip->operation,
493 trip_expr->op_a,
494 trip->op_b,
495 nullptr,
496 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800497 return GetVal(&cancelled_trip, trip, in_body, is_min);
498 }
499 } else if (is_min && stride_value == -1) {
Aart Bik97412c92016-02-19 20:14:38 -0800500 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800501 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
502 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
503 HInductionVarAnalysis::InductionInfo neg(
504 HInductionVarAnalysis::kInvariant,
505 HInductionVarAnalysis::kNeg,
506 nullptr,
507 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700508 nullptr,
509 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800510 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700511 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800512 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
513 }
514 }
515 }
516 }
517 }
518 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
519 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
520 GetVal(info->op_b, trip, in_body, is_min));
521}
522
Aart Bikd14c5952015-09-08 15:25:15 -0700523InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700524 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700525 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800526 bool is_min) const {
Aart Bik40fbf742016-10-31 11:02:50 -0700527 // Special case when chasing constants: single instruction that denotes trip count in the
528 // loop-body is minimal 1 and maximal, with safe trip-count, max int,
529 if (chase_hint_ == nullptr && in_body && trip != nullptr && instruction == trip->op_a->fetch) {
Aart Bik52be7e72016-06-23 11:20:41 -0700530 if (is_min) {
531 return Value(1);
Aart Bik40fbf742016-10-31 11:02:50 -0700532 } else if (!IsUnsafeTripCount(trip)) {
Aart Bik52be7e72016-06-23 11:20:41 -0700533 return Value(std::numeric_limits<int32_t>::max());
534 }
535 }
Aart Bik40fbf742016-10-31 11:02:50 -0700536 // Unless at a constant or hint, chase the instruction a bit deeper into the HIR tree, so that
537 // it becomes more likely range analysis will compare the same instructions as terminal nodes.
538 int64_t value;
539 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
540 // Proper constant reveals best information.
541 return Value(static_cast<int32_t>(value));
542 } else if (instruction == chase_hint_) {
543 // At hint, fetch is represented by itself.
544 return Value(instruction, 1, 0);
545 } else if (instruction->IsAdd()) {
546 // Incorporate suitable constants in the chased value.
Aart Bik97412c92016-02-19 20:14:38 -0800547 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
548 return AddValue(Value(static_cast<int32_t>(value)),
549 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
550 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
551 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
552 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700553 }
Aart Bik52be7e72016-06-23 11:20:41 -0700554 } else if (instruction->IsArrayLength()) {
Aart Bik40fbf742016-10-31 11:02:50 -0700555 // Exploit length properties when chasing constants or chase into a new array declaration.
Aart Bik52be7e72016-06-23 11:20:41 -0700556 if (chase_hint_ == nullptr) {
557 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
558 } else if (instruction->InputAt(0)->IsNewArray()) {
559 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
560 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700561 } else if (instruction->IsTypeConversion()) {
Aart Bik40fbf742016-10-31 11:02:50 -0700562 // Since analysis is 32-bit (or narrower), chase beyond widening along the path.
Aart Bik0d345cf2016-03-16 10:49:38 -0700563 if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
564 instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
565 return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
566 }
Aart Bik52be7e72016-06-23 11:20:41 -0700567 }
568 // Chase an invariant fetch that is defined by an outer loop if the trip-count used
569 // so far is well-behaved in both bounds and the next trip-count is safe.
570 // Example:
571 // for (int i = 0; i <= 100; i++) // safe
572 // for (int j = 0; j <= i; j++) // well-behaved
573 // j is in range [0, i ] (if i is chase hint)
574 // or in range [0, 100] (otherwise)
575 HLoopInformation* next_loop = nullptr;
576 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
577 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
578 bool next_in_body = true; // inner loop is always in body of outer loop
579 if (HasInductionInfo(instruction, instruction, &next_loop, &next_info, &next_trip) &&
580 IsWellBehavedTripCount(trip) &&
581 !IsUnsafeTripCount(next_trip)) {
582 return GetVal(next_info, next_trip, next_in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700583 }
Aart Bik40fbf742016-10-31 11:02:50 -0700584 // Fetch is represented by itself.
Aart Bikd14c5952015-09-08 15:25:15 -0700585 return Value(instruction, 1, 0);
586}
587
Aart Bikcd26feb2015-09-23 17:50:50 -0700588InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
589 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700590 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800591 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700592 if (info != nullptr) {
593 switch (info->induction_class) {
594 case HInductionVarAnalysis::kInvariant:
595 // Invariants.
596 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700597 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700598 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
599 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700600 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700601 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
602 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700603 case HInductionVarAnalysis::kNeg: // second reversed!
604 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700605 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700606 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700607 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700608 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700609 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bik7dc96932016-10-12 10:01:05 -0700610 case HInductionVarAnalysis::kXor:
611 return GetXor(info->op_a, info->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -0700612 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700613 return GetFetch(info->fetch, trip, in_body, is_min);
614 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700615 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700616 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700617 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700618 }
619 FALLTHROUGH_INTENDED;
620 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700621 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700622 if (is_min) {
623 return Value(0);
624 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700625 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700626 }
627 break;
628 default:
629 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700630 }
631 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700632 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700633 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700634 case HInductionVarAnalysis::kWrapAround:
635 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700636 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
637 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700638 }
639 }
Aart Bikb3365e02015-09-21 14:45:05 -0700640 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700641}
642
643InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
644 HInductionVarAnalysis::InductionInfo* info2,
645 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700646 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800647 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700648 // Constant times range.
649 int64_t value = 0;
650 if (IsConstant(info1, kExact, &value)) {
651 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
652 } else if (IsConstant(info2, kExact, &value)) {
653 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
654 }
655 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700656 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
657 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
658 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
659 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c92016-02-19 20:14:38 -0800660 // Positive range vs. positive or negative range.
661 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
662 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
663 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
664 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
665 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700666 }
Aart Bik97412c92016-02-19 20:14:38 -0800667 }
668 // Negative range vs. positive or negative range.
669 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
670 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
671 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
672 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
673 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700674 }
675 }
Aart Bikb3365e02015-09-21 14:45:05 -0700676 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700677}
678
679InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
680 HInductionVarAnalysis::InductionInfo* info2,
681 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700682 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800683 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700684 // Range divided by constant.
685 int64_t value = 0;
686 if (IsConstant(info2, kExact, &value)) {
687 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
688 }
689 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700690 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
691 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
692 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
693 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c92016-02-19 20:14:38 -0800694 // Positive range vs. positive or negative range.
695 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
696 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
697 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
698 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
699 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700700 }
Aart Bik97412c92016-02-19 20:14:38 -0800701 }
702 // Negative range vs. positive or negative range.
703 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
704 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
705 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
706 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
707 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700708 }
709 }
Aart Bikb3365e02015-09-21 14:45:05 -0700710 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700711}
712
Aart Bik7dc96932016-10-12 10:01:05 -0700713InductionVarRange::Value InductionVarRange::GetXor(
714 HInductionVarAnalysis::InductionInfo* info1,
715 HInductionVarAnalysis::InductionInfo* info2) const {
716 int64_t v1 = 0;
717 int64_t v2 = 0;
718 // Only accept exact values.
719 if (IsConstant(info1, kExact, &v1) && IsConstant(info2, kExact, &v2)) {
720 int64_t value = v1 ^ v2;
721 if (CanLongValueFitIntoInt(value)) {
722 return Value(static_cast<int32_t>(value));
723 }
724 }
725 return Value();
726}
727
Aart Bik52be7e72016-06-23 11:20:41 -0700728InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
729 int64_t value,
730 HInductionVarAnalysis::InductionInfo* info,
731 HInductionVarAnalysis::InductionInfo* trip,
732 bool in_body,
733 bool is_min) const {
734 if (CanLongValueFitIntoInt(value)) {
735 Value c(static_cast<int32_t>(value));
736 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
737 }
738 return Value();
Aart Bik97412c92016-02-19 20:14:38 -0800739}
740
Aart Bik52be7e72016-06-23 11:20:41 -0700741InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
742 int64_t value,
743 HInductionVarAnalysis::InductionInfo* info,
744 HInductionVarAnalysis::InductionInfo* trip,
745 bool in_body,
746 bool is_min) const {
747 if (CanLongValueFitIntoInt(value)) {
748 Value c(static_cast<int32_t>(value));
749 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
750 }
751 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700752}
753
Aart Bik7d57d7f2015-12-09 14:39:48 -0800754InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700755 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700756 const int32_t b = v1.b_constant + v2.b_constant;
757 if (v1.a_constant == 0) {
758 return Value(v2.instruction, v2.a_constant, b);
759 } else if (v2.a_constant == 0) {
760 return Value(v1.instruction, v1.a_constant, b);
761 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
762 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
763 }
764 }
Aart Bikb3365e02015-09-21 14:45:05 -0700765 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700766}
767
Aart Bik7d57d7f2015-12-09 14:39:48 -0800768InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700769 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700770 const int32_t b = v1.b_constant - v2.b_constant;
771 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
772 return Value(v2.instruction, -v2.a_constant, b);
773 } else if (v2.a_constant == 0) {
774 return Value(v1.instruction, v1.a_constant, b);
775 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
776 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
777 }
778 }
Aart Bikb3365e02015-09-21 14:45:05 -0700779 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700780}
781
Aart Bik7d57d7f2015-12-09 14:39:48 -0800782InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700783 if (v1.is_known && v2.is_known) {
784 if (v1.a_constant == 0) {
785 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
786 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
787 }
788 } else if (v2.a_constant == 0) {
789 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
790 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
791 }
Aart Bikd14c5952015-09-08 15:25:15 -0700792 }
793 }
Aart Bikb3365e02015-09-21 14:45:05 -0700794 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700795}
796
Aart Bik7d57d7f2015-12-09 14:39:48 -0800797InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700798 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700799 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
800 return Value(v1.b_constant / v2.b_constant);
801 }
802 }
Aart Bikb3365e02015-09-21 14:45:05 -0700803 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700804}
805
Aart Bik7d57d7f2015-12-09 14:39:48 -0800806InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700807 if (v1.is_known && v2.is_known) {
808 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700809 return Value(v1.instruction, v1.a_constant,
810 is_min ? std::min(v1.b_constant, v2.b_constant)
811 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700812 }
Aart Bikd14c5952015-09-08 15:25:15 -0700813 }
Aart Bikb3365e02015-09-21 14:45:05 -0700814 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700815}
816
Aart Bik9abf8942016-10-14 09:49:42 -0700817bool InductionVarRange::GenerateRangeOrLastValue(HInstruction* context,
818 HInstruction* instruction,
819 bool is_last_value,
820 HGraph* graph,
821 HBasicBlock* block,
822 /*out*/HInstruction** lower,
823 /*out*/HInstruction** upper,
824 /*out*/HInstruction** taken_test,
825 /*out*/int64_t* stride_value,
826 /*out*/bool* needs_finite_test,
827 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700828 HLoopInformation* loop = nullptr;
829 HInductionVarAnalysis::InductionInfo* info = nullptr;
830 HInductionVarAnalysis::InductionInfo* trip = nullptr;
831 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
832 return false; // codegen needs all information, including tripcount
Aart Bik97412c92016-02-19 20:14:38 -0800833 }
834 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
835 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
836 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
837 // code does not use the trip-count explicitly (since there could be an implicit relation
838 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700839 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700840 *stride_value = 0;
841 *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c92016-02-19 20:14:38 -0800842 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -0700843 // Handle last value request.
844 if (is_last_value) {
Aart Bik9abf8942016-10-14 09:49:42 -0700845 if (info->induction_class == HInductionVarAnalysis::kLinear) {
846 if (*stride_value > 0) {
847 lower = nullptr;
848 } else {
849 upper = nullptr;
850 }
851 } else if (info->induction_class == HInductionVarAnalysis::kPeriodic) {
852 DCHECK(!in_body);
853 return GenerateLastValuePeriodic(info, trip, graph, block, lower, needs_taken_test);
Aart Bik16d3a652016-09-09 10:33:50 -0700854 } else {
Aart Bik9abf8942016-10-14 09:49:42 -0700855 return false;
Aart Bik16d3a652016-09-09 10:33:50 -0700856 }
857 }
Aart Bik97412c92016-02-19 20:14:38 -0800858 // Code generation for taken test: generate the code when requested or otherwise analyze
859 // if code generation is feasible when taken test is needed.
860 if (taken_test != nullptr) {
861 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
862 } else if (*needs_taken_test) {
863 if (!GenerateCode(
864 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
865 return false;
866 }
867 }
868 // Code generation for lower and upper.
869 return
870 // Success on lower if invariant (not set), or code can be generated.
871 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
872 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
873 // And success on upper.
874 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700875}
876
Aart Bik9abf8942016-10-14 09:49:42 -0700877bool InductionVarRange::GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info,
878 HInductionVarAnalysis::InductionInfo* trip,
879 HGraph* graph,
880 HBasicBlock* block,
881 /*out*/HInstruction** result,
882 /*out*/bool* needs_taken_test) const {
883 DCHECK(info->induction_class == HInductionVarAnalysis::kPeriodic);
884 // Count period.
885 int32_t period = 1;
886 for (HInductionVarAnalysis::InductionInfo* p = info;
887 p->induction_class == HInductionVarAnalysis::kPeriodic;
888 p = p->op_b, ++period) {}
889 // Handle periodic(x, y) case for restricted types.
890 if (period != 2 ||
891 trip->op_a->type != Primitive::kPrimInt ||
892 (info->type != Primitive::kPrimInt && info->type != Primitive::kPrimBoolean)) {
893 return false; // TODO: easy to generalize
894 }
895 HInstruction* x_instr = nullptr;
896 HInstruction* y_instr = nullptr;
897 HInstruction* trip_expr = nullptr;
898 if (GenerateCode(info->op_a, nullptr, graph, block, graph ? &x_instr : nullptr, false, false) &&
899 GenerateCode(info->op_b, nullptr, graph, block, graph ? &y_instr : nullptr, false, false) &&
900 GenerateCode(trip->op_a, nullptr, graph, block, graph ? &trip_expr : nullptr, false, false)) {
901 // During actual code generation (graph != nullptr),
902 // generate is_even ? x : y select instruction.
903 if (graph != nullptr) {
904 HInstruction* is_even = Insert(block, new (graph->GetArena()) HEqual(
905 Insert(block, new (graph->GetArena()) HAnd(
906 Primitive::kPrimInt, trip_expr, graph->GetIntConstant(1))),
907 graph->GetIntConstant(0), kNoDexPc));
908 *result = Insert(block, new (graph->GetArena()) HSelect(is_even, x_instr, y_instr, kNoDexPc));
909 }
910 // Guard select with taken test if needed.
911 if (*needs_taken_test) {
912 HInstruction* taken_test = nullptr;
913 if (!GenerateCode(
914 trip->op_b, nullptr, graph, block, graph ? &taken_test : nullptr, false, false)) {
915 return false;
916 } else if (graph != nullptr) {
917 *result = Insert(block,
918 new (graph->GetArena()) HSelect(taken_test, *result, x_instr, kNoDexPc));
919 }
920 *needs_taken_test = false; // taken care of
921 }
922 return true;
923 }
924 return false;
925}
926
Aart Bikaec3cce2015-10-14 17:44:55 -0700927bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
928 HInductionVarAnalysis::InductionInfo* trip,
929 HGraph* graph, // when set, code is generated
930 HBasicBlock* block,
931 /*out*/HInstruction** result,
932 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800933 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700934 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -0700935 // If during codegen, the result is not needed (nullptr), simply return success.
936 if (graph != nullptr && result == nullptr) {
937 return true;
938 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700939 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700940 Primitive::Type type = Primitive::kPrimInt;
Aart Bik639cc8c2016-10-18 13:03:31 -0700941 if (info->type != Primitive::kPrimInt && info->type != Primitive::kPrimBoolean) {
Aart Bik0d345cf2016-03-16 10:49:38 -0700942 return false;
943 }
944 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700945 HInstruction* opa = nullptr;
946 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700947 switch (info->induction_class) {
948 case HInductionVarAnalysis::kInvariant:
Aart Bik40fbf742016-10-31 11:02:50 -0700949 // Invariants (note that even though is_min does not impact code generation for
950 // invariants, some effort is made to keep this parameter consistent).
Aart Bikaec3cce2015-10-14 17:44:55 -0700951 switch (info->operation) {
952 case HInductionVarAnalysis::kAdd:
Aart Bik40fbf742016-10-31 11:02:50 -0700953 case HInductionVarAnalysis::kXor: // no proper is_min for second arg
Aart Bik389b3db2015-10-28 14:23:40 -0700954 case HInductionVarAnalysis::kLT:
955 case HInductionVarAnalysis::kLE:
956 case HInductionVarAnalysis::kGT:
957 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700958 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
959 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
960 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700961 HInstruction* operation = nullptr;
962 switch (info->operation) {
963 case HInductionVarAnalysis::kAdd:
964 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
Aart Bik9abf8942016-10-14 09:49:42 -0700965 case HInductionVarAnalysis::kXor:
966 operation = new (graph->GetArena()) HXor(type, opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -0700967 case HInductionVarAnalysis::kLT:
968 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
969 case HInductionVarAnalysis::kLE:
970 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
971 case HInductionVarAnalysis::kGT:
972 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
973 case HInductionVarAnalysis::kGE:
974 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
975 default:
976 LOG(FATAL) << "unknown operation";
977 }
978 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700979 }
980 return true;
981 }
982 break;
983 case HInductionVarAnalysis::kSub: // second reversed!
984 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
985 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
986 if (graph != nullptr) {
987 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
988 }
989 return true;
990 }
991 break;
992 case HInductionVarAnalysis::kNeg: // reversed!
993 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
994 if (graph != nullptr) {
995 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
996 }
997 return true;
998 }
999 break;
1000 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -07001001 if (graph != nullptr) {
1002 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -07001003 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001004 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -07001005 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -07001006 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -07001007 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -07001008 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -07001009 }
1010 FALLTHROUGH_INTENDED;
1011 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -07001012 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -07001013 if (is_min) {
1014 if (graph != nullptr) {
1015 *result = graph->GetIntConstant(0);
1016 }
1017 return true;
1018 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -07001019 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -07001020 if (graph != nullptr) {
1021 *result = Insert(block,
1022 new (graph->GetArena())
1023 HSub(type, opb, graph->GetIntConstant(1)));
1024 }
1025 return true;
1026 }
1027 }
1028 break;
1029 default:
1030 break;
1031 }
1032 break;
Aart Bik389b3db2015-10-28 14:23:40 -07001033 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -07001034 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
1035 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
1036 // are harder to guard against. For a last value, requesting min/max based on any
1037 // stride yields right value.
Aart Bik97412c92016-02-19 20:14:38 -08001038 int64_t stride_value = 0;
1039 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik16d3a652016-09-09 10:33:50 -07001040 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
1041 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
1042 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
1043 if (graph != nullptr) {
1044 HInstruction* oper;
1045 if (stride_value == 1) {
1046 oper = new (graph->GetArena()) HAdd(type, opa, opb);
1047 } else if (stride_value == -1) {
1048 oper = new (graph->GetArena()) HSub(type, opb, opa);
1049 } else {
Aart Bik009cace2016-09-16 10:15:19 -07001050 HInstruction* mul = new (graph->GetArena()) HMul(
1051 type, graph->GetIntConstant(stride_value), opa);
Aart Bik16d3a652016-09-09 10:33:50 -07001052 oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
Aart Bikaec3cce2015-10-14 17:44:55 -07001053 }
Aart Bik16d3a652016-09-09 10:33:50 -07001054 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -07001055 }
Aart Bik16d3a652016-09-09 10:33:50 -07001056 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -07001057 }
1058 }
1059 break;
Aart Bik4a342772015-11-30 10:17:46 -08001060 }
1061 case HInductionVarAnalysis::kWrapAround:
1062 case HInductionVarAnalysis::kPeriodic: {
1063 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
1064 // values are easy to test at runtime without complications of arithmetic wrap-around.
1065 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c92016-02-19 20:14:38 -08001066 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -08001067 if (graph != nullptr) {
1068 *result = graph->GetIntConstant(extreme.b_constant);
1069 }
1070 return true;
1071 }
1072 break;
1073 }
Aart Bik389b3db2015-10-28 14:23:40 -07001074 default:
Aart Bikaec3cce2015-10-14 17:44:55 -07001075 break;
1076 }
1077 }
1078 return false;
1079}
1080
Aart Bik16d3a652016-09-09 10:33:50 -07001081void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
1082 HInstruction* fetch,
1083 HInstruction* replacement) {
1084 if (info != nullptr) {
1085 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
1086 info->operation == HInductionVarAnalysis::kFetch &&
1087 info->fetch == fetch) {
1088 info->fetch = replacement;
1089 }
1090 ReplaceInduction(info->op_a, fetch, replacement);
1091 ReplaceInduction(info->op_b, fetch, replacement);
1092 }
1093}
1094
Aart Bikd14c5952015-09-08 15:25:15 -07001095} // namespace art