blob: 18e6f5ca9f143ccddd1e47517cd0e8382a94e956 [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 Bik97412c922016-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 Bik97412c922016-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 Bik0d345cf2016-03-16 10:49:38 -070061 * An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as length + b
Aart Bikb3365e02015-09-21 14:45:05 -070062 * because length >= 0 is true. This makes it more likely the bound is useful to clients.
63 */
64static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) {
Aart Bik97412c922016-02-19 20:14:38 -080065 int64_t value;
66 if (v.is_known &&
Aart Bik0d345cf2016-03-16 10:49:38 -070067 v.a_constant >= 1 &&
Aart Bikb3365e02015-09-21 14:45:05 -070068 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
Aart Bik52be7e72016-06-23 11:20:41 -070076/** Helper method to test for a constant value. */
77static bool IsConstantValue(InductionVarRange::Value v) {
78 return v.is_known && v.a_constant == 0;
79}
80
81/** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
Aart Bik0d345cf2016-03-16 10:49:38 -070082static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, Primitive::Type type) {
83 switch (type) {
84 case Primitive::kPrimShort:
85 case Primitive::kPrimChar:
86 case Primitive::kPrimByte: {
87 // Constants within range only.
88 // TODO: maybe some room for improvement, like allowing widening conversions
89 const int32_t min = Primitive::MinValueOfIntegralType(type);
90 const int32_t max = Primitive::MaxValueOfIntegralType(type);
Aart Bik52be7e72016-06-23 11:20:41 -070091 return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
Aart Bik0d345cf2016-03-16 10:49:38 -070092 ? v
93 : InductionVarRange::Value();
94 }
95 default:
Aart Bik0d345cf2016-03-16 10:49:38 -070096 return v;
97 }
98}
99
Aart Bik389b3db2015-10-28 14:23:40 -0700100/** Helper method to insert an instruction. */
101static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
102 DCHECK(block != nullptr);
103 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -0700104 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -0700105 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -0700106 return instruction;
107}
108
Aart Bikd14c5952015-09-08 15:25:15 -0700109//
110// Public class methods.
111//
112
113InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
Aart Bik52be7e72016-06-23 11:20:41 -0700114 : induction_analysis_(induction_analysis),
115 chase_hint_(nullptr) {
Aart Bikb3365e02015-09-21 14:45:05 -0700116 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700117}
118
Aart Bik1fc3afb2016-02-02 13:26:16 -0800119bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700120 HInstruction* instruction,
Aart Bik52be7e72016-06-23 11:20:41 -0700121 HInstruction* chase_hint,
Aart Bik389b3db2015-10-28 14:23:40 -0700122 /*out*/Value* min_val,
123 /*out*/Value* max_val,
124 /*out*/bool* needs_finite_test) {
Aart Bik52be7e72016-06-23 11:20:41 -0700125 HLoopInformation* loop = nullptr;
126 HInductionVarAnalysis::InductionInfo* info = nullptr;
127 HInductionVarAnalysis::InductionInfo* trip = nullptr;
128 if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
129 return false;
Aart Bik97412c922016-02-19 20:14:38 -0800130 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700131 // Type int or lower (this is not too restrictive since intended clients, like
132 // bounds check elimination, will have truncated higher precision induction
133 // at their use point already).
134 switch (info->type) {
135 case Primitive::kPrimInt:
136 case Primitive::kPrimShort:
137 case Primitive::kPrimChar:
138 case Primitive::kPrimByte:
139 break;
140 default:
141 return false;
142 }
Aart Bik97412c922016-02-19 20:14:38 -0800143 // Find range.
Aart Bik52be7e72016-06-23 11:20:41 -0700144 chase_hint_ = chase_hint;
145 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700146 int64_t stride_value = 0;
Aart Bik97412c922016-02-19 20:14:38 -0800147 *min_val = GetVal(info, trip, in_body, /* is_min */ true);
148 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
Aart Bik16d3a652016-09-09 10:33:50 -0700149 *needs_finite_test = NeedsTripCount(info, &stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800150 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700151}
152
Aart Bik16d3a652016-09-09 10:33:50 -0700153bool InductionVarRange::CanGenerateRange(HInstruction* context,
154 HInstruction* instruction,
155 /*out*/bool* needs_finite_test,
156 /*out*/bool* needs_taken_test) {
157 bool is_last_value = false;
158 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700159 return GenerateCode(context,
160 instruction,
Aart Bik16d3a652016-09-09 10:33:50 -0700161 is_last_value,
162 nullptr,
163 nullptr,
164 nullptr,
165 nullptr,
166 nullptr, // nothing generated yet
167 &stride_value,
Aart Bik389b3db2015-10-28 14:23:40 -0700168 needs_finite_test,
Aart Bik16d3a652016-09-09 10:33:50 -0700169 needs_taken_test)
170 && (stride_value == -1 ||
171 stride_value == 0 ||
172 stride_value == 1); // avoid wrap-around anomalies.
Aart Bikaec3cce2015-10-14 17:44:55 -0700173}
174
Aart Bik16d3a652016-09-09 10:33:50 -0700175void InductionVarRange::GenerateRange(HInstruction* context,
176 HInstruction* instruction,
177 HGraph* graph,
178 HBasicBlock* block,
179 /*out*/HInstruction** lower,
180 /*out*/HInstruction** upper) {
181 bool is_last_value = false;
182 int64_t s = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700183 bool b1, b2; // unused
Aart Bik16d3a652016-09-09 10:33:50 -0700184 if (!GenerateCode(context,
185 instruction,
186 is_last_value,
187 graph,
188 block,
189 lower,
190 upper,
191 nullptr,
192 &s,
193 &b1,
194 &b2)) {
195 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
Aart Bik389b3db2015-10-28 14:23:40 -0700196 }
197}
198
Aart Bik16d3a652016-09-09 10:33:50 -0700199HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context,
200 HGraph* graph,
201 HBasicBlock* block) {
202 HInstruction* taken_test = nullptr;
203 bool is_last_value = false;
204 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700205 bool b1, b2; // unused
Aart Bik16d3a652016-09-09 10:33:50 -0700206 if (!GenerateCode(context,
207 context,
208 is_last_value,
209 graph,
210 block,
211 nullptr,
212 nullptr,
213 &taken_test,
214 &stride_value,
215 &b1,
216 &b2)) {
217 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
218 }
219 return taken_test;
220}
221
222bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
223 bool is_last_value = true;
224 int64_t stride_value = 0;
225 bool needs_finite_test = false;
226 bool needs_taken_test = false;
227 return GenerateCode(instruction,
228 instruction,
229 is_last_value,
230 nullptr,
231 nullptr,
232 nullptr,
233 nullptr,
234 nullptr, // nothing generated yet
235 &stride_value, &needs_finite_test, &needs_taken_test)
236 && !needs_finite_test && !needs_taken_test;
237}
238
239HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
240 HGraph* graph,
241 HBasicBlock* block) {
242 HInstruction* last_value = nullptr;
243 bool is_last_value = true;
244 int64_t stride_value = 0;
245 bool b1, b2; // unused
246 if (!GenerateCode(instruction,
247 instruction,
248 is_last_value,
249 graph,
250 block,
251 &last_value,
252 &last_value,
253 nullptr,
254 &stride_value,
255 &b1,
256 &b2)) {
257 LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
258 }
259 return last_value;
260}
261
262void InductionVarRange::Replace(HInstruction* instruction,
263 HInstruction* fetch,
264 HInstruction* replacement) {
265 for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
266 lp != nullptr;
267 lp = lp->GetPreHeader()->GetLoopInformation()) {
268 ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
Aart Bik389b3db2015-10-28 14:23:40 -0700269 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700270}
271
Aart Bikd14c5952015-09-08 15:25:15 -0700272//
273// Private class methods.
274//
275
Aart Bik97412c922016-02-19 20:14:38 -0800276bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
277 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700278 /*out*/ int64_t* value) const {
Aart Bik97412c922016-02-19 20:14:38 -0800279 if (info != nullptr) {
280 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
281 // any of the three requests (kExact, kAtMost, and KAtLeast).
282 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
283 info->operation == HInductionVarAnalysis::kFetch) {
284 if (IsIntAndGet(info->fetch, value)) {
285 return true;
286 }
287 }
Aart Bik52be7e72016-06-23 11:20:41 -0700288 // Try range analysis on the invariant, but only on proper range to avoid wrap-around anomalies.
289 Value min_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ true);
290 Value max_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ false);
291 if (IsConstantValue(min_val) &&
292 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
293 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
294 *value = max_val.b_constant;
295 return true;
296 } else if (request == kAtLeast) {
297 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800298 return true;
299 }
300 }
Aart Bik97412c922016-02-19 20:14:38 -0800301 }
302 return false;
303}
304
Aart Bik52be7e72016-06-23 11:20:41 -0700305bool InductionVarRange::HasInductionInfo(
306 HInstruction* context,
307 HInstruction* instruction,
308 /*out*/ HLoopInformation** loop,
309 /*out*/ HInductionVarAnalysis::InductionInfo** info,
310 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
311 HLoopInformation* l = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
312 if (l != nullptr) {
313 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(l, instruction);
314 if (i != nullptr) {
315 *loop = l;
316 *info = i;
317 *trip = induction_analysis_->LookupInfo(l, l->GetHeader()->GetLastInstruction());
318 return true;
319 }
320 }
321 return false;
322}
323
324bool InductionVarRange::IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
325 if (trip != nullptr) {
326 // Both bounds that define a trip-count are well-behaved if they either are not defined
327 // in any loop, or are contained in a proper interval. This allows finding the min/max
328 // of an expression by chasing outward.
329 InductionVarRange range(induction_analysis_);
330 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
331 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
332 int64_t not_used = 0;
333 return (!HasFetchInLoop(lower) || range.IsConstant(lower, kAtLeast, &not_used)) &&
334 (!HasFetchInLoop(upper) || range.IsConstant(upper, kAtLeast, &not_used));
335 }
336 return true;
337}
338
339bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
340 if (info != nullptr) {
341 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
342 info->operation == HInductionVarAnalysis::kFetch) {
343 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
344 }
345 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
346 }
347 return false;
348}
349
Aart Bik16d3a652016-09-09 10:33:50 -0700350bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
351 int64_t* stride_value) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700352 if (info != nullptr) {
353 if (info->induction_class == HInductionVarAnalysis::kLinear) {
Aart Bik16d3a652016-09-09 10:33:50 -0700354 return IsConstant(info->op_a, kExact, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700355 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
Aart Bik16d3a652016-09-09 10:33:50 -0700356 return NeedsTripCount(info->op_b, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700357 }
Aart Bikd14c5952015-09-08 15:25:15 -0700358 }
Aart Bik389b3db2015-10-28 14:23:40 -0700359 return false;
360}
361
Aart Bik7d57d7f2015-12-09 14:39:48 -0800362bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700363 if (trip != nullptr) {
364 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
365 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
366 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
367 }
368 }
369 return false;
370}
371
Aart Bik7d57d7f2015-12-09 14:39:48 -0800372bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700373 if (trip != nullptr) {
374 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
375 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
376 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
377 }
378 }
379 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700380}
381
Aart Bik7d57d7f2015-12-09 14:39:48 -0800382InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
383 HInductionVarAnalysis::InductionInfo* trip,
384 bool in_body,
385 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700386 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800387 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
388 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
389 // with intermediate results that only incorporate single instructions.
390 if (trip != nullptr) {
391 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700392 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800393 int64_t stride_value = 0;
394 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800395 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800396 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800397 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
398 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
399 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700400 trip->induction_class,
401 trip->operation,
402 trip_expr->op_a,
403 trip->op_b,
404 nullptr,
405 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800406 return GetVal(&cancelled_trip, trip, in_body, is_min);
407 }
408 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800409 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800410 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
411 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
412 HInductionVarAnalysis::InductionInfo neg(
413 HInductionVarAnalysis::kInvariant,
414 HInductionVarAnalysis::kNeg,
415 nullptr,
416 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700417 nullptr,
418 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800419 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700420 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800421 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
422 }
423 }
424 }
425 }
426 }
427 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
428 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
429 GetVal(info->op_b, trip, in_body, is_min));
430}
431
Aart Bikd14c5952015-09-08 15:25:15 -0700432InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700433 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700434 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800435 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700436 // Stop chasing the instruction at constant or hint.
Aart Bik97412c922016-02-19 20:14:38 -0800437 int64_t value;
Aart Bik52be7e72016-06-23 11:20:41 -0700438 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800439 return Value(static_cast<int32_t>(value));
Aart Bik52be7e72016-06-23 11:20:41 -0700440 } else if (instruction == chase_hint_) {
441 return Value(instruction, 1, 0);
442 }
443 // Special cases when encountering a single instruction that denotes trip count in the
444 // loop-body: min is 1 and, when chasing constants, max of safe trip-count is max int
445 if (in_body && trip != nullptr && instruction == trip->op_a->fetch) {
446 if (is_min) {
447 return Value(1);
448 } else if (chase_hint_ == nullptr && !IsUnsafeTripCount(trip)) {
449 return Value(std::numeric_limits<int32_t>::max());
450 }
451 }
452 // Chase the instruction a bit deeper into the HIR tree, so that it becomes more likely
453 // range analysis will compare the same instructions as terminal nodes.
454 if (instruction->IsAdd()) {
Aart Bik97412c922016-02-19 20:14:38 -0800455 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
456 return AddValue(Value(static_cast<int32_t>(value)),
457 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
458 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
459 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
460 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700461 }
Aart Bik52be7e72016-06-23 11:20:41 -0700462 } else if (instruction->IsArrayLength()) {
463 // Return extreme values when chasing constants. Otherwise, chase deeper.
464 if (chase_hint_ == nullptr) {
465 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
466 } else if (instruction->InputAt(0)->IsNewArray()) {
467 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
468 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700469 } else if (instruction->IsTypeConversion()) {
470 // Since analysis is 32-bit (or narrower) we allow a widening along the path.
471 if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
472 instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
473 return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
474 }
Aart Bik52be7e72016-06-23 11:20:41 -0700475 }
476 // Chase an invariant fetch that is defined by an outer loop if the trip-count used
477 // so far is well-behaved in both bounds and the next trip-count is safe.
478 // Example:
479 // for (int i = 0; i <= 100; i++) // safe
480 // for (int j = 0; j <= i; j++) // well-behaved
481 // j is in range [0, i ] (if i is chase hint)
482 // or in range [0, 100] (otherwise)
483 HLoopInformation* next_loop = nullptr;
484 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
485 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
486 bool next_in_body = true; // inner loop is always in body of outer loop
487 if (HasInductionInfo(instruction, instruction, &next_loop, &next_info, &next_trip) &&
488 IsWellBehavedTripCount(trip) &&
489 !IsUnsafeTripCount(next_trip)) {
490 return GetVal(next_info, next_trip, next_in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700491 }
492 return Value(instruction, 1, 0);
493}
494
Aart Bikcd26feb2015-09-23 17:50:50 -0700495InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
496 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700497 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800498 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700499 if (info != nullptr) {
500 switch (info->induction_class) {
501 case HInductionVarAnalysis::kInvariant:
502 // Invariants.
503 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700504 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700505 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
506 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700507 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700508 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
509 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700510 case HInductionVarAnalysis::kNeg: // second reversed!
511 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700512 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700513 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700514 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700515 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700516 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700517 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700518 return GetFetch(info->fetch, trip, in_body, is_min);
519 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700520 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700521 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700522 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700523 }
524 FALLTHROUGH_INTENDED;
525 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700526 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700527 if (is_min) {
528 return Value(0);
529 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700530 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700531 }
532 break;
533 default:
534 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700535 }
536 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700537 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700538 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700539 case HInductionVarAnalysis::kWrapAround:
540 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700541 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
542 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700543 }
544 }
Aart Bikb3365e02015-09-21 14:45:05 -0700545 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700546}
547
548InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
549 HInductionVarAnalysis::InductionInfo* info2,
550 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700551 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800552 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700553 // Constant times range.
554 int64_t value = 0;
555 if (IsConstant(info1, kExact, &value)) {
556 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
557 } else if (IsConstant(info2, kExact, &value)) {
558 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
559 }
560 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700561 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
562 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
563 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
564 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800565 // Positive range vs. positive or negative range.
566 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
567 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
568 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
569 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
570 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700571 }
Aart Bik97412c922016-02-19 20:14:38 -0800572 }
573 // Negative range vs. positive or negative range.
574 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
575 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
576 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
577 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
578 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700579 }
580 }
Aart Bikb3365e02015-09-21 14:45:05 -0700581 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700582}
583
584InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
585 HInductionVarAnalysis::InductionInfo* info2,
586 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700587 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800588 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700589 // Range divided by constant.
590 int64_t value = 0;
591 if (IsConstant(info2, kExact, &value)) {
592 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
593 }
594 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700595 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
596 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
597 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
598 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800599 // Positive range vs. positive or negative range.
600 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
601 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
602 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
603 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
604 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700605 }
Aart Bik97412c922016-02-19 20:14:38 -0800606 }
607 // Negative range vs. positive or negative range.
608 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
609 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
610 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
611 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
612 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700613 }
614 }
Aart Bikb3365e02015-09-21 14:45:05 -0700615 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700616}
617
Aart Bik52be7e72016-06-23 11:20:41 -0700618InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
619 int64_t value,
620 HInductionVarAnalysis::InductionInfo* info,
621 HInductionVarAnalysis::InductionInfo* trip,
622 bool in_body,
623 bool is_min) const {
624 if (CanLongValueFitIntoInt(value)) {
625 Value c(static_cast<int32_t>(value));
626 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
627 }
628 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800629}
630
Aart Bik52be7e72016-06-23 11:20:41 -0700631InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
632 int64_t value,
633 HInductionVarAnalysis::InductionInfo* info,
634 HInductionVarAnalysis::InductionInfo* trip,
635 bool in_body,
636 bool is_min) const {
637 if (CanLongValueFitIntoInt(value)) {
638 Value c(static_cast<int32_t>(value));
639 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
640 }
641 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700642}
643
Aart Bik7d57d7f2015-12-09 14:39:48 -0800644InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700645 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700646 const int32_t b = v1.b_constant + v2.b_constant;
647 if (v1.a_constant == 0) {
648 return Value(v2.instruction, v2.a_constant, b);
649 } else if (v2.a_constant == 0) {
650 return Value(v1.instruction, v1.a_constant, b);
651 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
652 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
653 }
654 }
Aart Bikb3365e02015-09-21 14:45:05 -0700655 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700656}
657
Aart Bik7d57d7f2015-12-09 14:39:48 -0800658InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700659 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700660 const int32_t b = v1.b_constant - v2.b_constant;
661 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
662 return Value(v2.instruction, -v2.a_constant, b);
663 } else if (v2.a_constant == 0) {
664 return Value(v1.instruction, v1.a_constant, b);
665 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
666 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
667 }
668 }
Aart Bikb3365e02015-09-21 14:45:05 -0700669 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700670}
671
Aart Bik7d57d7f2015-12-09 14:39:48 -0800672InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700673 if (v1.is_known && v2.is_known) {
674 if (v1.a_constant == 0) {
675 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
676 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
677 }
678 } else if (v2.a_constant == 0) {
679 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
680 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
681 }
Aart Bikd14c5952015-09-08 15:25:15 -0700682 }
683 }
Aart Bikb3365e02015-09-21 14:45:05 -0700684 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700685}
686
Aart Bik7d57d7f2015-12-09 14:39:48 -0800687InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700688 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700689 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
690 return Value(v1.b_constant / v2.b_constant);
691 }
692 }
Aart Bikb3365e02015-09-21 14:45:05 -0700693 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700694}
695
Aart Bik7d57d7f2015-12-09 14:39:48 -0800696InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700697 if (v1.is_known && v2.is_known) {
698 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700699 return Value(v1.instruction, v1.a_constant,
700 is_min ? std::min(v1.b_constant, v2.b_constant)
701 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700702 }
Aart Bikd14c5952015-09-08 15:25:15 -0700703 }
Aart Bikb3365e02015-09-21 14:45:05 -0700704 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700705}
706
Aart Bikaec3cce2015-10-14 17:44:55 -0700707bool InductionVarRange::GenerateCode(HInstruction* context,
708 HInstruction* instruction,
Aart Bik16d3a652016-09-09 10:33:50 -0700709 bool is_last_value,
Aart Bikaec3cce2015-10-14 17:44:55 -0700710 HGraph* graph,
711 HBasicBlock* block,
712 /*out*/HInstruction** lower,
713 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700714 /*out*/HInstruction** taken_test,
Aart Bik16d3a652016-09-09 10:33:50 -0700715 /*out*/int64_t* stride_value,
Aart Bik389b3db2015-10-28 14:23:40 -0700716 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800717 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700718 HLoopInformation* loop = nullptr;
719 HInductionVarAnalysis::InductionInfo* info = nullptr;
720 HInductionVarAnalysis::InductionInfo* trip = nullptr;
721 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
722 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -0800723 }
724 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
725 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
726 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
727 // code does not use the trip-count explicitly (since there could be an implicit relation
728 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700729 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700730 *stride_value = 0;
731 *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800732 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -0700733 // Handle last value request.
734 if (is_last_value) {
735 if (info->induction_class != HInductionVarAnalysis::kLinear) {
736 return false;
737 } else if (*stride_value > 0) {
738 lower = nullptr;
739 } else {
740 upper = nullptr;
741 }
742 }
Aart Bik97412c922016-02-19 20:14:38 -0800743 // Code generation for taken test: generate the code when requested or otherwise analyze
744 // if code generation is feasible when taken test is needed.
745 if (taken_test != nullptr) {
746 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
747 } else if (*needs_taken_test) {
748 if (!GenerateCode(
749 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
750 return false;
751 }
752 }
753 // Code generation for lower and upper.
754 return
755 // Success on lower if invariant (not set), or code can be generated.
756 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
757 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
758 // And success on upper.
759 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700760}
761
762bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
763 HInductionVarAnalysis::InductionInfo* trip,
764 HGraph* graph, // when set, code is generated
765 HBasicBlock* block,
766 /*out*/HInstruction** result,
767 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800768 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700769 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -0700770 // If during codegen, the result is not needed (nullptr), simply return success.
771 if (graph != nullptr && result == nullptr) {
772 return true;
773 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700774 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700775 Primitive::Type type = Primitive::kPrimInt;
Aart Bik0d345cf2016-03-16 10:49:38 -0700776 if (info->type != type) {
777 return false;
778 }
779 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700780 HInstruction* opa = nullptr;
781 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700782 switch (info->induction_class) {
783 case HInductionVarAnalysis::kInvariant:
784 // Invariants.
785 switch (info->operation) {
786 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700787 case HInductionVarAnalysis::kLT:
788 case HInductionVarAnalysis::kLE:
789 case HInductionVarAnalysis::kGT:
790 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700791 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
792 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
793 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700794 HInstruction* operation = nullptr;
795 switch (info->operation) {
796 case HInductionVarAnalysis::kAdd:
797 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
798 case HInductionVarAnalysis::kLT:
799 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
800 case HInductionVarAnalysis::kLE:
801 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
802 case HInductionVarAnalysis::kGT:
803 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
804 case HInductionVarAnalysis::kGE:
805 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
806 default:
807 LOG(FATAL) << "unknown operation";
808 }
809 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700810 }
811 return true;
812 }
813 break;
814 case HInductionVarAnalysis::kSub: // second reversed!
815 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
816 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
817 if (graph != nullptr) {
818 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
819 }
820 return true;
821 }
822 break;
823 case HInductionVarAnalysis::kNeg: // reversed!
824 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
825 if (graph != nullptr) {
826 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
827 }
828 return true;
829 }
830 break;
831 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -0700832 if (graph != nullptr) {
833 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -0700834 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700835 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700836 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700837 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700838 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700839 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700840 }
841 FALLTHROUGH_INTENDED;
842 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700843 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700844 if (is_min) {
845 if (graph != nullptr) {
846 *result = graph->GetIntConstant(0);
847 }
848 return true;
849 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700850 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700851 if (graph != nullptr) {
852 *result = Insert(block,
853 new (graph->GetArena())
854 HSub(type, opb, graph->GetIntConstant(1)));
855 }
856 return true;
857 }
858 }
859 break;
860 default:
861 break;
862 }
863 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700864 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -0700865 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
866 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
867 // are harder to guard against. For a last value, requesting min/max based on any
868 // stride yields right value.
Aart Bik97412c922016-02-19 20:14:38 -0800869 int64_t stride_value = 0;
870 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700871 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
872 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
873 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
874 if (graph != nullptr) {
875 HInstruction* oper;
876 if (stride_value == 1) {
877 oper = new (graph->GetArena()) HAdd(type, opa, opb);
878 } else if (stride_value == -1) {
879 oper = new (graph->GetArena()) HSub(type, opb, opa);
880 } else {
881 HInstruction* mul = new (graph->GetArena()) HMul(type, graph->GetIntConstant(stride_value), opa);
882 oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
Aart Bikaec3cce2015-10-14 17:44:55 -0700883 }
Aart Bik16d3a652016-09-09 10:33:50 -0700884 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700885 }
Aart Bik16d3a652016-09-09 10:33:50 -0700886 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700887 }
888 }
889 break;
Aart Bik4a342772015-11-30 10:17:46 -0800890 }
891 case HInductionVarAnalysis::kWrapAround:
892 case HInductionVarAnalysis::kPeriodic: {
893 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
894 // values are easy to test at runtime without complications of arithmetic wrap-around.
895 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800896 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800897 if (graph != nullptr) {
898 *result = graph->GetIntConstant(extreme.b_constant);
899 }
900 return true;
901 }
902 break;
903 }
Aart Bik389b3db2015-10-28 14:23:40 -0700904 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700905 break;
906 }
907 }
908 return false;
909}
910
Aart Bik16d3a652016-09-09 10:33:50 -0700911void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
912 HInstruction* fetch,
913 HInstruction* replacement) {
914 if (info != nullptr) {
915 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
916 info->operation == HInductionVarAnalysis::kFetch &&
917 info->fetch == fetch) {
918 info->fetch = replacement;
919 }
920 ReplaceInduction(info->op_a, fetch, replacement);
921 ReplaceInduction(info->op_b, fetch, replacement);
922 }
923}
924
Aart Bikd14c5952015-09-08 15:25:15 -0700925} // namespace art