blob: 140c7f0c40951b2957d67df9dc40ed6b576a1414 [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 Bik7dc96932016-10-12 10:01:05 -0700528 case HInductionVarAnalysis::kXor:
529 return GetXor(info->op_a, info->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -0700530 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700531 return GetFetch(info->fetch, trip, in_body, is_min);
532 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700533 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700534 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700535 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700536 }
537 FALLTHROUGH_INTENDED;
538 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700539 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700540 if (is_min) {
541 return Value(0);
542 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700543 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700544 }
545 break;
546 default:
547 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700548 }
549 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700550 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700551 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700552 case HInductionVarAnalysis::kWrapAround:
553 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700554 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
555 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700556 }
557 }
Aart Bikb3365e02015-09-21 14:45:05 -0700558 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700559}
560
561InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
562 HInductionVarAnalysis::InductionInfo* info2,
563 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700564 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800565 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700566 // Constant times range.
567 int64_t value = 0;
568 if (IsConstant(info1, kExact, &value)) {
569 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
570 } else if (IsConstant(info2, kExact, &value)) {
571 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
572 }
573 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700574 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
575 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
576 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
577 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800578 // Positive range vs. positive or negative range.
579 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
580 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
581 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
582 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
583 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700584 }
Aart Bik97412c922016-02-19 20:14:38 -0800585 }
586 // Negative range vs. positive or negative range.
587 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
588 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
589 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
590 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
591 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700592 }
593 }
Aart Bikb3365e02015-09-21 14:45:05 -0700594 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700595}
596
597InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
598 HInductionVarAnalysis::InductionInfo* info2,
599 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700600 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800601 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700602 // Range divided by constant.
603 int64_t value = 0;
604 if (IsConstant(info2, kExact, &value)) {
605 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
606 }
607 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700608 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
609 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
610 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
611 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800612 // Positive range vs. positive or negative range.
613 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
614 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
615 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
616 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
617 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700618 }
Aart Bik97412c922016-02-19 20:14:38 -0800619 }
620 // Negative range vs. positive or negative range.
621 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
622 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
623 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
624 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
625 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700626 }
627 }
Aart Bikb3365e02015-09-21 14:45:05 -0700628 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700629}
630
Aart Bik7dc96932016-10-12 10:01:05 -0700631InductionVarRange::Value InductionVarRange::GetXor(
632 HInductionVarAnalysis::InductionInfo* info1,
633 HInductionVarAnalysis::InductionInfo* info2) const {
634 int64_t v1 = 0;
635 int64_t v2 = 0;
636 // Only accept exact values.
637 if (IsConstant(info1, kExact, &v1) && IsConstant(info2, kExact, &v2)) {
638 int64_t value = v1 ^ v2;
639 if (CanLongValueFitIntoInt(value)) {
640 return Value(static_cast<int32_t>(value));
641 }
642 }
643 return Value();
644}
645
Aart Bik52be7e72016-06-23 11:20:41 -0700646InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
647 int64_t value,
648 HInductionVarAnalysis::InductionInfo* info,
649 HInductionVarAnalysis::InductionInfo* trip,
650 bool in_body,
651 bool is_min) const {
652 if (CanLongValueFitIntoInt(value)) {
653 Value c(static_cast<int32_t>(value));
654 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
655 }
656 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800657}
658
Aart Bik52be7e72016-06-23 11:20:41 -0700659InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
660 int64_t value,
661 HInductionVarAnalysis::InductionInfo* info,
662 HInductionVarAnalysis::InductionInfo* trip,
663 bool in_body,
664 bool is_min) const {
665 if (CanLongValueFitIntoInt(value)) {
666 Value c(static_cast<int32_t>(value));
667 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
668 }
669 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700670}
671
Aart Bik7d57d7f2015-12-09 14:39:48 -0800672InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700673 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700674 const int32_t b = v1.b_constant + v2.b_constant;
675 if (v1.a_constant == 0) {
676 return Value(v2.instruction, v2.a_constant, b);
677 } else if (v2.a_constant == 0) {
678 return Value(v1.instruction, v1.a_constant, b);
679 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
680 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
681 }
682 }
Aart Bikb3365e02015-09-21 14:45:05 -0700683 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700684}
685
Aart Bik7d57d7f2015-12-09 14:39:48 -0800686InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700687 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700688 const int32_t b = v1.b_constant - v2.b_constant;
689 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
690 return Value(v2.instruction, -v2.a_constant, b);
691 } else if (v2.a_constant == 0) {
692 return Value(v1.instruction, v1.a_constant, b);
693 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
694 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
695 }
696 }
Aart Bikb3365e02015-09-21 14:45:05 -0700697 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700698}
699
Aart Bik7d57d7f2015-12-09 14:39:48 -0800700InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700701 if (v1.is_known && v2.is_known) {
702 if (v1.a_constant == 0) {
703 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
704 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
705 }
706 } else if (v2.a_constant == 0) {
707 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
708 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
709 }
Aart Bikd14c5952015-09-08 15:25:15 -0700710 }
711 }
Aart Bikb3365e02015-09-21 14:45:05 -0700712 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700713}
714
Aart Bik7d57d7f2015-12-09 14:39:48 -0800715InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700716 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700717 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
718 return Value(v1.b_constant / v2.b_constant);
719 }
720 }
Aart Bikb3365e02015-09-21 14:45:05 -0700721 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700722}
723
Aart Bik7d57d7f2015-12-09 14:39:48 -0800724InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700725 if (v1.is_known && v2.is_known) {
726 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700727 return Value(v1.instruction, v1.a_constant,
728 is_min ? std::min(v1.b_constant, v2.b_constant)
729 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700730 }
Aart Bikd14c5952015-09-08 15:25:15 -0700731 }
Aart Bikb3365e02015-09-21 14:45:05 -0700732 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700733}
734
Aart Bikaec3cce2015-10-14 17:44:55 -0700735bool InductionVarRange::GenerateCode(HInstruction* context,
736 HInstruction* instruction,
Aart Bik16d3a652016-09-09 10:33:50 -0700737 bool is_last_value,
Aart Bikaec3cce2015-10-14 17:44:55 -0700738 HGraph* graph,
739 HBasicBlock* block,
740 /*out*/HInstruction** lower,
741 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700742 /*out*/HInstruction** taken_test,
Aart Bik16d3a652016-09-09 10:33:50 -0700743 /*out*/int64_t* stride_value,
Aart Bik389b3db2015-10-28 14:23:40 -0700744 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800745 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700746 HLoopInformation* loop = nullptr;
747 HInductionVarAnalysis::InductionInfo* info = nullptr;
748 HInductionVarAnalysis::InductionInfo* trip = nullptr;
749 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
750 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -0800751 }
752 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
753 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
754 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
755 // code does not use the trip-count explicitly (since there could be an implicit relation
756 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700757 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700758 *stride_value = 0;
759 *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800760 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -0700761 // Handle last value request.
762 if (is_last_value) {
763 if (info->induction_class != HInductionVarAnalysis::kLinear) {
764 return false;
765 } else if (*stride_value > 0) {
766 lower = nullptr;
767 } else {
768 upper = nullptr;
769 }
770 }
Aart Bik97412c922016-02-19 20:14:38 -0800771 // Code generation for taken test: generate the code when requested or otherwise analyze
772 // if code generation is feasible when taken test is needed.
773 if (taken_test != nullptr) {
774 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
775 } else if (*needs_taken_test) {
776 if (!GenerateCode(
777 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
778 return false;
779 }
780 }
781 // Code generation for lower and upper.
782 return
783 // Success on lower if invariant (not set), or code can be generated.
784 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
785 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
786 // And success on upper.
787 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700788}
789
790bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
791 HInductionVarAnalysis::InductionInfo* trip,
792 HGraph* graph, // when set, code is generated
793 HBasicBlock* block,
794 /*out*/HInstruction** result,
795 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800796 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700797 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -0700798 // If during codegen, the result is not needed (nullptr), simply return success.
799 if (graph != nullptr && result == nullptr) {
800 return true;
801 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700802 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700803 Primitive::Type type = Primitive::kPrimInt;
Aart Bik0d345cf2016-03-16 10:49:38 -0700804 if (info->type != type) {
805 return false;
806 }
807 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700808 HInstruction* opa = nullptr;
809 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700810 switch (info->induction_class) {
811 case HInductionVarAnalysis::kInvariant:
812 // Invariants.
813 switch (info->operation) {
814 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700815 case HInductionVarAnalysis::kLT:
816 case HInductionVarAnalysis::kLE:
817 case HInductionVarAnalysis::kGT:
818 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700819 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
820 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
821 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700822 HInstruction* operation = nullptr;
823 switch (info->operation) {
824 case HInductionVarAnalysis::kAdd:
825 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
826 case HInductionVarAnalysis::kLT:
827 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
828 case HInductionVarAnalysis::kLE:
829 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
830 case HInductionVarAnalysis::kGT:
831 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
832 case HInductionVarAnalysis::kGE:
833 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
834 default:
835 LOG(FATAL) << "unknown operation";
836 }
837 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700838 }
839 return true;
840 }
841 break;
842 case HInductionVarAnalysis::kSub: // second reversed!
843 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
844 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
845 if (graph != nullptr) {
846 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
847 }
848 return true;
849 }
850 break;
851 case HInductionVarAnalysis::kNeg: // reversed!
852 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
853 if (graph != nullptr) {
854 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
855 }
856 return true;
857 }
858 break;
859 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -0700860 if (graph != nullptr) {
861 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -0700862 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700863 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700864 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700865 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700866 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700867 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700868 }
869 FALLTHROUGH_INTENDED;
870 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700871 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700872 if (is_min) {
873 if (graph != nullptr) {
874 *result = graph->GetIntConstant(0);
875 }
876 return true;
877 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700878 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700879 if (graph != nullptr) {
880 *result = Insert(block,
881 new (graph->GetArena())
882 HSub(type, opb, graph->GetIntConstant(1)));
883 }
884 return true;
885 }
886 }
887 break;
888 default:
889 break;
890 }
891 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700892 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -0700893 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
894 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
895 // are harder to guard against. For a last value, requesting min/max based on any
896 // stride yields right value.
Aart Bik97412c922016-02-19 20:14:38 -0800897 int64_t stride_value = 0;
898 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700899 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
900 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
901 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
902 if (graph != nullptr) {
903 HInstruction* oper;
904 if (stride_value == 1) {
905 oper = new (graph->GetArena()) HAdd(type, opa, opb);
906 } else if (stride_value == -1) {
907 oper = new (graph->GetArena()) HSub(type, opb, opa);
908 } else {
Aart Bik009cace2016-09-16 10:15:19 -0700909 HInstruction* mul = new (graph->GetArena()) HMul(
910 type, graph->GetIntConstant(stride_value), opa);
Aart Bik16d3a652016-09-09 10:33:50 -0700911 oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
Aart Bikaec3cce2015-10-14 17:44:55 -0700912 }
Aart Bik16d3a652016-09-09 10:33:50 -0700913 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700914 }
Aart Bik16d3a652016-09-09 10:33:50 -0700915 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700916 }
917 }
918 break;
Aart Bik4a342772015-11-30 10:17:46 -0800919 }
920 case HInductionVarAnalysis::kWrapAround:
921 case HInductionVarAnalysis::kPeriodic: {
922 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
923 // values are easy to test at runtime without complications of arithmetic wrap-around.
924 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800925 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800926 if (graph != nullptr) {
927 *result = graph->GetIntConstant(extreme.b_constant);
928 }
929 return true;
930 }
931 break;
932 }
Aart Bik389b3db2015-10-28 14:23:40 -0700933 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700934 break;
935 }
936 }
937 return false;
938}
939
Aart Bik16d3a652016-09-09 10:33:50 -0700940void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
941 HInstruction* fetch,
942 HInstruction* replacement) {
943 if (info != nullptr) {
944 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
945 info->operation == HInductionVarAnalysis::kFetch &&
946 info->fetch == fetch) {
947 info->fetch = replacement;
948 }
949 ReplaceInduction(info->op_a, fetch, replacement);
950 ReplaceInduction(info->op_b, fetch, replacement);
951 }
952}
953
Aart Bikd14c5952015-09-08 15:25:15 -0700954} // namespace art