blob: cd8b7c7960c82e8ef144533c1dc6d37e06e29a99 [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 Bik009cace2016-09-16 10:15:19 -0700109/** Helper method to obtain loop's control instruction. */
110static HInstruction* GetLoopControl(HLoopInformation* loop) {
111 DCHECK(loop != nullptr);
112 return loop->GetHeader()->GetLastInstruction();
113}
114
Aart Bikd14c5952015-09-08 15:25:15 -0700115//
116// Public class methods.
117//
118
119InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
Aart Bik52be7e72016-06-23 11:20:41 -0700120 : induction_analysis_(induction_analysis),
121 chase_hint_(nullptr) {
Aart Bikb3365e02015-09-21 14:45:05 -0700122 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700123}
124
Aart Bik1fc3afb2016-02-02 13:26:16 -0800125bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700126 HInstruction* instruction,
Aart Bik52be7e72016-06-23 11:20:41 -0700127 HInstruction* chase_hint,
Aart Bik389b3db2015-10-28 14:23:40 -0700128 /*out*/Value* min_val,
129 /*out*/Value* max_val,
130 /*out*/bool* needs_finite_test) {
Aart Bik52be7e72016-06-23 11:20:41 -0700131 HLoopInformation* loop = nullptr;
132 HInductionVarAnalysis::InductionInfo* info = nullptr;
133 HInductionVarAnalysis::InductionInfo* trip = nullptr;
134 if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
135 return false;
Aart Bik97412c922016-02-19 20:14:38 -0800136 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700137 // Type int or lower (this is not too restrictive since intended clients, like
138 // bounds check elimination, will have truncated higher precision induction
139 // at their use point already).
140 switch (info->type) {
141 case Primitive::kPrimInt:
142 case Primitive::kPrimShort:
143 case Primitive::kPrimChar:
144 case Primitive::kPrimByte:
145 break;
146 default:
147 return false;
148 }
Aart Bik97412c922016-02-19 20:14:38 -0800149 // Find range.
Aart Bik52be7e72016-06-23 11:20:41 -0700150 chase_hint_ = chase_hint;
151 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700152 int64_t stride_value = 0;
Aart Bik97412c922016-02-19 20:14:38 -0800153 *min_val = GetVal(info, trip, in_body, /* is_min */ true);
154 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
Aart Bik16d3a652016-09-09 10:33:50 -0700155 *needs_finite_test = NeedsTripCount(info, &stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800156 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700157}
158
Aart Bik16d3a652016-09-09 10:33:50 -0700159bool InductionVarRange::CanGenerateRange(HInstruction* context,
160 HInstruction* instruction,
161 /*out*/bool* needs_finite_test,
162 /*out*/bool* needs_taken_test) {
163 bool is_last_value = false;
164 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700165 return GenerateCode(context,
166 instruction,
Aart Bik16d3a652016-09-09 10:33:50 -0700167 is_last_value,
168 nullptr,
169 nullptr,
170 nullptr,
171 nullptr,
172 nullptr, // nothing generated yet
173 &stride_value,
Aart Bik389b3db2015-10-28 14:23:40 -0700174 needs_finite_test,
Aart Bik16d3a652016-09-09 10:33:50 -0700175 needs_taken_test)
176 && (stride_value == -1 ||
177 stride_value == 0 ||
178 stride_value == 1); // avoid wrap-around anomalies.
Aart Bikaec3cce2015-10-14 17:44:55 -0700179}
180
Aart Bik16d3a652016-09-09 10:33:50 -0700181void InductionVarRange::GenerateRange(HInstruction* context,
182 HInstruction* instruction,
183 HGraph* graph,
184 HBasicBlock* block,
185 /*out*/HInstruction** lower,
186 /*out*/HInstruction** upper) {
187 bool is_last_value = false;
Aart Bik009cace2016-09-16 10:15:19 -0700188 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700189 bool b1, b2; // unused
Aart Bik16d3a652016-09-09 10:33:50 -0700190 if (!GenerateCode(context,
191 instruction,
192 is_last_value,
193 graph,
194 block,
195 lower,
196 upper,
197 nullptr,
Aart Bik009cace2016-09-16 10:15:19 -0700198 &stride_value,
Aart Bik16d3a652016-09-09 10:33:50 -0700199 &b1,
200 &b2)) {
201 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
Aart Bik389b3db2015-10-28 14:23:40 -0700202 }
203}
204
Aart Bik16d3a652016-09-09 10:33:50 -0700205HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context,
206 HGraph* graph,
207 HBasicBlock* block) {
208 HInstruction* taken_test = nullptr;
209 bool is_last_value = false;
210 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700211 bool b1, b2; // unused
Aart Bik16d3a652016-09-09 10:33:50 -0700212 if (!GenerateCode(context,
213 context,
214 is_last_value,
215 graph,
216 block,
217 nullptr,
218 nullptr,
219 &taken_test,
220 &stride_value,
221 &b1,
222 &b2)) {
223 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
224 }
225 return taken_test;
226}
227
228bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
229 bool is_last_value = true;
230 int64_t stride_value = 0;
231 bool needs_finite_test = false;
232 bool needs_taken_test = false;
233 return GenerateCode(instruction,
234 instruction,
235 is_last_value,
236 nullptr,
237 nullptr,
238 nullptr,
239 nullptr,
240 nullptr, // nothing generated yet
Aart Bik009cace2016-09-16 10:15:19 -0700241 &stride_value,
242 &needs_finite_test,
243 &needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700244 && !needs_finite_test && !needs_taken_test;
245}
246
247HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
248 HGraph* graph,
249 HBasicBlock* block) {
250 HInstruction* last_value = nullptr;
251 bool is_last_value = true;
252 int64_t stride_value = 0;
253 bool b1, b2; // unused
254 if (!GenerateCode(instruction,
255 instruction,
256 is_last_value,
257 graph,
258 block,
259 &last_value,
260 &last_value,
261 nullptr,
262 &stride_value,
263 &b1,
264 &b2)) {
265 LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
266 }
267 return last_value;
268}
269
270void InductionVarRange::Replace(HInstruction* instruction,
271 HInstruction* fetch,
272 HInstruction* replacement) {
273 for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
274 lp != nullptr;
275 lp = lp->GetPreHeader()->GetLoopInformation()) {
Aart Bik009cace2016-09-16 10:15:19 -0700276 // Update instruction's information.
Aart Bik16d3a652016-09-09 10:33:50 -0700277 ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
Aart Bik009cace2016-09-16 10:15:19 -0700278 // Update loop's trip-count information.
279 ReplaceInduction(induction_analysis_->LookupInfo(lp, GetLoopControl(lp)), fetch, replacement);
Aart Bik389b3db2015-10-28 14:23:40 -0700280 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700281}
282
Aart Bikd14c5952015-09-08 15:25:15 -0700283//
284// Private class methods.
285//
286
Aart Bik97412c922016-02-19 20:14:38 -0800287bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
288 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700289 /*out*/ int64_t* value) const {
Aart Bik97412c922016-02-19 20:14:38 -0800290 if (info != nullptr) {
291 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
292 // any of the three requests (kExact, kAtMost, and KAtLeast).
293 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
294 info->operation == HInductionVarAnalysis::kFetch) {
295 if (IsIntAndGet(info->fetch, value)) {
296 return true;
297 }
298 }
Aart Bik52be7e72016-06-23 11:20:41 -0700299 // Try range analysis on the invariant, but only on proper range to avoid wrap-around anomalies.
300 Value min_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ true);
301 Value max_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ false);
302 if (IsConstantValue(min_val) &&
303 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
304 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
305 *value = max_val.b_constant;
306 return true;
307 } else if (request == kAtLeast) {
308 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800309 return true;
310 }
311 }
Aart Bik97412c922016-02-19 20:14:38 -0800312 }
313 return false;
314}
315
Aart Bik52be7e72016-06-23 11:20:41 -0700316bool InductionVarRange::HasInductionInfo(
317 HInstruction* context,
318 HInstruction* instruction,
319 /*out*/ HLoopInformation** loop,
320 /*out*/ HInductionVarAnalysis::InductionInfo** info,
321 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
Aart Bik009cace2016-09-16 10:15:19 -0700322 HLoopInformation* lp = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
323 if (lp != nullptr) {
324 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(lp, instruction);
Aart Bik52be7e72016-06-23 11:20:41 -0700325 if (i != nullptr) {
Aart Bik009cace2016-09-16 10:15:19 -0700326 *loop = lp;
Aart Bik52be7e72016-06-23 11:20:41 -0700327 *info = i;
Aart Bik009cace2016-09-16 10:15:19 -0700328 *trip = induction_analysis_->LookupInfo(lp, GetLoopControl(lp));
Aart Bik52be7e72016-06-23 11:20:41 -0700329 return true;
330 }
331 }
332 return false;
333}
334
335bool InductionVarRange::IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
336 if (trip != nullptr) {
337 // Both bounds that define a trip-count are well-behaved if they either are not defined
338 // in any loop, or are contained in a proper interval. This allows finding the min/max
339 // of an expression by chasing outward.
340 InductionVarRange range(induction_analysis_);
341 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
342 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
343 int64_t not_used = 0;
344 return (!HasFetchInLoop(lower) || range.IsConstant(lower, kAtLeast, &not_used)) &&
345 (!HasFetchInLoop(upper) || range.IsConstant(upper, kAtLeast, &not_used));
346 }
347 return true;
348}
349
350bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
351 if (info != nullptr) {
352 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
353 info->operation == HInductionVarAnalysis::kFetch) {
354 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
355 }
356 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
357 }
358 return false;
359}
360
Aart Bik16d3a652016-09-09 10:33:50 -0700361bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
362 int64_t* stride_value) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700363 if (info != nullptr) {
364 if (info->induction_class == HInductionVarAnalysis::kLinear) {
Aart Bik16d3a652016-09-09 10:33:50 -0700365 return IsConstant(info->op_a, kExact, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700366 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
Aart Bik16d3a652016-09-09 10:33:50 -0700367 return NeedsTripCount(info->op_b, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700368 }
Aart Bikd14c5952015-09-08 15:25:15 -0700369 }
Aart Bik389b3db2015-10-28 14:23:40 -0700370 return false;
371}
372
Aart Bik7d57d7f2015-12-09 14:39:48 -0800373bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700374 if (trip != nullptr) {
375 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
376 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
377 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
378 }
379 }
380 return false;
381}
382
Aart Bik7d57d7f2015-12-09 14:39:48 -0800383bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700384 if (trip != nullptr) {
385 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
386 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
387 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
388 }
389 }
390 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700391}
392
Aart Bik7d57d7f2015-12-09 14:39:48 -0800393InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
394 HInductionVarAnalysis::InductionInfo* trip,
395 bool in_body,
396 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700397 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800398 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
399 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
400 // with intermediate results that only incorporate single instructions.
401 if (trip != nullptr) {
402 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700403 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800404 int64_t stride_value = 0;
405 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800406 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800407 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800408 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
409 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
410 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700411 trip->induction_class,
412 trip->operation,
413 trip_expr->op_a,
414 trip->op_b,
415 nullptr,
416 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800417 return GetVal(&cancelled_trip, trip, in_body, is_min);
418 }
419 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800420 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800421 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
422 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
423 HInductionVarAnalysis::InductionInfo neg(
424 HInductionVarAnalysis::kInvariant,
425 HInductionVarAnalysis::kNeg,
426 nullptr,
427 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700428 nullptr,
429 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800430 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700431 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800432 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
433 }
434 }
435 }
436 }
437 }
438 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
439 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
440 GetVal(info->op_b, trip, in_body, is_min));
441}
442
Aart Bikd14c5952015-09-08 15:25:15 -0700443InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700444 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700445 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800446 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700447 // Stop chasing the instruction at constant or hint.
Aart Bik97412c922016-02-19 20:14:38 -0800448 int64_t value;
Aart Bik52be7e72016-06-23 11:20:41 -0700449 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800450 return Value(static_cast<int32_t>(value));
Aart Bik52be7e72016-06-23 11:20:41 -0700451 } else if (instruction == chase_hint_) {
452 return Value(instruction, 1, 0);
453 }
454 // Special cases when encountering a single instruction that denotes trip count in the
455 // loop-body: min is 1 and, when chasing constants, max of safe trip-count is max int
456 if (in_body && trip != nullptr && instruction == trip->op_a->fetch) {
457 if (is_min) {
458 return Value(1);
459 } else if (chase_hint_ == nullptr && !IsUnsafeTripCount(trip)) {
460 return Value(std::numeric_limits<int32_t>::max());
461 }
462 }
463 // Chase the instruction a bit deeper into the HIR tree, so that it becomes more likely
464 // range analysis will compare the same instructions as terminal nodes.
465 if (instruction->IsAdd()) {
Aart Bik97412c922016-02-19 20:14:38 -0800466 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
467 return AddValue(Value(static_cast<int32_t>(value)),
468 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
469 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
470 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
471 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700472 }
Aart Bik52be7e72016-06-23 11:20:41 -0700473 } else if (instruction->IsArrayLength()) {
474 // Return extreme values when chasing constants. Otherwise, chase deeper.
475 if (chase_hint_ == nullptr) {
476 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
477 } else if (instruction->InputAt(0)->IsNewArray()) {
478 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
479 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700480 } else if (instruction->IsTypeConversion()) {
481 // Since analysis is 32-bit (or narrower) we allow a widening along the path.
482 if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
483 instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
484 return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
485 }
Aart Bik52be7e72016-06-23 11:20:41 -0700486 }
487 // Chase an invariant fetch that is defined by an outer loop if the trip-count used
488 // so far is well-behaved in both bounds and the next trip-count is safe.
489 // Example:
490 // for (int i = 0; i <= 100; i++) // safe
491 // for (int j = 0; j <= i; j++) // well-behaved
492 // j is in range [0, i ] (if i is chase hint)
493 // or in range [0, 100] (otherwise)
494 HLoopInformation* next_loop = nullptr;
495 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
496 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
497 bool next_in_body = true; // inner loop is always in body of outer loop
498 if (HasInductionInfo(instruction, instruction, &next_loop, &next_info, &next_trip) &&
499 IsWellBehavedTripCount(trip) &&
500 !IsUnsafeTripCount(next_trip)) {
501 return GetVal(next_info, next_trip, next_in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700502 }
503 return Value(instruction, 1, 0);
504}
505
Aart Bikcd26feb2015-09-23 17:50:50 -0700506InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
507 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700508 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800509 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700510 if (info != nullptr) {
511 switch (info->induction_class) {
512 case HInductionVarAnalysis::kInvariant:
513 // Invariants.
514 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700515 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700516 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
517 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700518 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700519 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
520 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700521 case HInductionVarAnalysis::kNeg: // second reversed!
522 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700523 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700524 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700525 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700526 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700527 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700528 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700529 return GetFetch(info->fetch, trip, in_body, is_min);
530 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700531 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700532 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700533 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700534 }
535 FALLTHROUGH_INTENDED;
536 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700537 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700538 if (is_min) {
539 return Value(0);
540 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700541 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700542 }
543 break;
544 default:
545 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700546 }
547 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700548 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700549 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700550 case HInductionVarAnalysis::kWrapAround:
551 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700552 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
553 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700554 }
555 }
Aart Bikb3365e02015-09-21 14:45:05 -0700556 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700557}
558
559InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
560 HInductionVarAnalysis::InductionInfo* info2,
561 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700562 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800563 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700564 // Constant times range.
565 int64_t value = 0;
566 if (IsConstant(info1, kExact, &value)) {
567 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
568 } else if (IsConstant(info2, kExact, &value)) {
569 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
570 }
571 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700572 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
573 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
574 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
575 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800576 // Positive range vs. positive or negative range.
577 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
578 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
579 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
580 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
581 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700582 }
Aart Bik97412c922016-02-19 20:14:38 -0800583 }
584 // Negative range vs. positive or negative range.
585 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
586 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
587 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
588 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
589 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700590 }
591 }
Aart Bikb3365e02015-09-21 14:45:05 -0700592 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700593}
594
595InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
596 HInductionVarAnalysis::InductionInfo* info2,
597 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700598 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800599 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700600 // Range divided by constant.
601 int64_t value = 0;
602 if (IsConstant(info2, kExact, &value)) {
603 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
604 }
605 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700606 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
607 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
608 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
609 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800610 // Positive range vs. positive or negative range.
611 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
612 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
613 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
614 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
615 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700616 }
Aart Bik97412c922016-02-19 20:14:38 -0800617 }
618 // Negative range vs. positive or negative range.
619 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
620 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
621 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
622 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
623 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700624 }
625 }
Aart Bikb3365e02015-09-21 14:45:05 -0700626 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700627}
628
Aart Bik52be7e72016-06-23 11:20:41 -0700629InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
630 int64_t value,
631 HInductionVarAnalysis::InductionInfo* info,
632 HInductionVarAnalysis::InductionInfo* trip,
633 bool in_body,
634 bool is_min) const {
635 if (CanLongValueFitIntoInt(value)) {
636 Value c(static_cast<int32_t>(value));
637 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
638 }
639 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800640}
641
Aart Bik52be7e72016-06-23 11:20:41 -0700642InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
643 int64_t value,
644 HInductionVarAnalysis::InductionInfo* info,
645 HInductionVarAnalysis::InductionInfo* trip,
646 bool in_body,
647 bool is_min) const {
648 if (CanLongValueFitIntoInt(value)) {
649 Value c(static_cast<int32_t>(value));
650 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
651 }
652 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700653}
654
Aart Bik7d57d7f2015-12-09 14:39:48 -0800655InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700656 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700657 const int32_t b = v1.b_constant + v2.b_constant;
658 if (v1.a_constant == 0) {
659 return Value(v2.instruction, v2.a_constant, b);
660 } else if (v2.a_constant == 0) {
661 return Value(v1.instruction, v1.a_constant, b);
662 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
663 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
664 }
665 }
Aart Bikb3365e02015-09-21 14:45:05 -0700666 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700667}
668
Aart Bik7d57d7f2015-12-09 14:39:48 -0800669InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700670 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700671 const int32_t b = v1.b_constant - v2.b_constant;
672 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
673 return Value(v2.instruction, -v2.a_constant, b);
674 } else if (v2.a_constant == 0) {
675 return Value(v1.instruction, v1.a_constant, b);
676 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
677 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
678 }
679 }
Aart Bikb3365e02015-09-21 14:45:05 -0700680 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700681}
682
Aart Bik7d57d7f2015-12-09 14:39:48 -0800683InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700684 if (v1.is_known && v2.is_known) {
685 if (v1.a_constant == 0) {
686 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
687 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
688 }
689 } else if (v2.a_constant == 0) {
690 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
691 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
692 }
Aart Bikd14c5952015-09-08 15:25:15 -0700693 }
694 }
Aart Bikb3365e02015-09-21 14:45:05 -0700695 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700696}
697
Aart Bik7d57d7f2015-12-09 14:39:48 -0800698InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700699 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700700 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
701 return Value(v1.b_constant / v2.b_constant);
702 }
703 }
Aart Bikb3365e02015-09-21 14:45:05 -0700704 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700705}
706
Aart Bik7d57d7f2015-12-09 14:39:48 -0800707InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700708 if (v1.is_known && v2.is_known) {
709 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700710 return Value(v1.instruction, v1.a_constant,
711 is_min ? std::min(v1.b_constant, v2.b_constant)
712 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700713 }
Aart Bikd14c5952015-09-08 15:25:15 -0700714 }
Aart Bikb3365e02015-09-21 14:45:05 -0700715 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700716}
717
Aart Bikaec3cce2015-10-14 17:44:55 -0700718bool InductionVarRange::GenerateCode(HInstruction* context,
719 HInstruction* instruction,
Aart Bik16d3a652016-09-09 10:33:50 -0700720 bool is_last_value,
Aart Bikaec3cce2015-10-14 17:44:55 -0700721 HGraph* graph,
722 HBasicBlock* block,
723 /*out*/HInstruction** lower,
724 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700725 /*out*/HInstruction** taken_test,
Aart Bik16d3a652016-09-09 10:33:50 -0700726 /*out*/int64_t* stride_value,
Aart Bik389b3db2015-10-28 14:23:40 -0700727 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800728 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700729 HLoopInformation* loop = nullptr;
730 HInductionVarAnalysis::InductionInfo* info = nullptr;
731 HInductionVarAnalysis::InductionInfo* trip = nullptr;
732 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
733 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -0800734 }
735 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
736 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
737 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
738 // code does not use the trip-count explicitly (since there could be an implicit relation
739 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700740 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700741 *stride_value = 0;
742 *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800743 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -0700744 // Handle last value request.
745 if (is_last_value) {
746 if (info->induction_class != HInductionVarAnalysis::kLinear) {
747 return false;
748 } else if (*stride_value > 0) {
749 lower = nullptr;
750 } else {
751 upper = nullptr;
752 }
753 }
Aart Bik97412c922016-02-19 20:14:38 -0800754 // Code generation for taken test: generate the code when requested or otherwise analyze
755 // if code generation is feasible when taken test is needed.
756 if (taken_test != nullptr) {
757 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
758 } else if (*needs_taken_test) {
759 if (!GenerateCode(
760 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
761 return false;
762 }
763 }
764 // Code generation for lower and upper.
765 return
766 // Success on lower if invariant (not set), or code can be generated.
767 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
768 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
769 // And success on upper.
770 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700771}
772
773bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
774 HInductionVarAnalysis::InductionInfo* trip,
775 HGraph* graph, // when set, code is generated
776 HBasicBlock* block,
777 /*out*/HInstruction** result,
778 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800779 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700780 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -0700781 // If during codegen, the result is not needed (nullptr), simply return success.
782 if (graph != nullptr && result == nullptr) {
783 return true;
784 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700785 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700786 Primitive::Type type = Primitive::kPrimInt;
Aart Bik0d345cf2016-03-16 10:49:38 -0700787 if (info->type != type) {
788 return false;
789 }
790 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700791 HInstruction* opa = nullptr;
792 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700793 switch (info->induction_class) {
794 case HInductionVarAnalysis::kInvariant:
795 // Invariants.
796 switch (info->operation) {
797 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700798 case HInductionVarAnalysis::kLT:
799 case HInductionVarAnalysis::kLE:
800 case HInductionVarAnalysis::kGT:
801 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700802 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
803 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
804 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700805 HInstruction* operation = nullptr;
806 switch (info->operation) {
807 case HInductionVarAnalysis::kAdd:
808 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
809 case HInductionVarAnalysis::kLT:
810 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
811 case HInductionVarAnalysis::kLE:
812 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
813 case HInductionVarAnalysis::kGT:
814 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
815 case HInductionVarAnalysis::kGE:
816 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
817 default:
818 LOG(FATAL) << "unknown operation";
819 }
820 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700821 }
822 return true;
823 }
824 break;
825 case HInductionVarAnalysis::kSub: // second reversed!
826 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
827 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
828 if (graph != nullptr) {
829 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
830 }
831 return true;
832 }
833 break;
834 case HInductionVarAnalysis::kNeg: // reversed!
835 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
836 if (graph != nullptr) {
837 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
838 }
839 return true;
840 }
841 break;
842 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -0700843 if (graph != nullptr) {
844 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -0700845 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700846 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700847 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700848 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700849 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700850 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700851 }
852 FALLTHROUGH_INTENDED;
853 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700854 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700855 if (is_min) {
856 if (graph != nullptr) {
857 *result = graph->GetIntConstant(0);
858 }
859 return true;
860 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700861 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700862 if (graph != nullptr) {
863 *result = Insert(block,
864 new (graph->GetArena())
865 HSub(type, opb, graph->GetIntConstant(1)));
866 }
867 return true;
868 }
869 }
870 break;
871 default:
872 break;
873 }
874 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700875 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -0700876 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
877 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
878 // are harder to guard against. For a last value, requesting min/max based on any
879 // stride yields right value.
Aart Bik97412c922016-02-19 20:14:38 -0800880 int64_t stride_value = 0;
881 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700882 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
883 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
884 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
885 if (graph != nullptr) {
886 HInstruction* oper;
887 if (stride_value == 1) {
888 oper = new (graph->GetArena()) HAdd(type, opa, opb);
889 } else if (stride_value == -1) {
890 oper = new (graph->GetArena()) HSub(type, opb, opa);
891 } else {
Aart Bik009cace2016-09-16 10:15:19 -0700892 HInstruction* mul = new (graph->GetArena()) HMul(
893 type, graph->GetIntConstant(stride_value), opa);
Aart Bik16d3a652016-09-09 10:33:50 -0700894 oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
Aart Bikaec3cce2015-10-14 17:44:55 -0700895 }
Aart Bik16d3a652016-09-09 10:33:50 -0700896 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700897 }
Aart Bik16d3a652016-09-09 10:33:50 -0700898 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700899 }
900 }
901 break;
Aart Bik4a342772015-11-30 10:17:46 -0800902 }
903 case HInductionVarAnalysis::kWrapAround:
904 case HInductionVarAnalysis::kPeriodic: {
905 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
906 // values are easy to test at runtime without complications of arithmetic wrap-around.
907 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800908 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800909 if (graph != nullptr) {
910 *result = graph->GetIntConstant(extreme.b_constant);
911 }
912 return true;
913 }
914 break;
915 }
Aart Bik389b3db2015-10-28 14:23:40 -0700916 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700917 break;
918 }
919 }
920 return false;
921}
922
Aart Bik16d3a652016-09-09 10:33:50 -0700923void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
924 HInstruction* fetch,
925 HInstruction* replacement) {
926 if (info != nullptr) {
927 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
928 info->operation == HInductionVarAnalysis::kFetch &&
929 info->fetch == fetch) {
930 info->fetch = replacement;
931 }
932 ReplaceInduction(info->op_a, fetch, replacement);
933 ReplaceInduction(info->op_b, fetch, replacement);
934 }
935}
936
Aart Bikd14c5952015-09-08 15:25:15 -0700937} // namespace art