blob: 663cbaf2de859c4a02f82be69b722bc409eb07f2 [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 Bik9abf8942016-10-14 09:49:42 -0700165 return GenerateRangeOrLastValue(context,
166 instruction,
167 is_last_value,
168 nullptr,
169 nullptr,
170 nullptr,
171 nullptr,
172 nullptr, // nothing generated yet
173 &stride_value,
174 needs_finite_test,
175 needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700176 && (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 Bik9abf8942016-10-14 09:49:42 -0700190 if (!GenerateRangeOrLastValue(context,
191 instruction,
192 is_last_value,
193 graph,
194 block,
195 lower,
196 upper,
197 nullptr,
198 &stride_value,
199 &b1,
200 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700201 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 Bik9abf8942016-10-14 09:49:42 -0700212 if (!GenerateRangeOrLastValue(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)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700223 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;
Aart Bik9abf8942016-10-14 09:49:42 -0700233 return GenerateRangeOrLastValue(instruction,
234 instruction,
235 is_last_value,
236 nullptr,
237 nullptr,
238 nullptr,
239 nullptr,
240 nullptr, // nothing generated yet
241 &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
Aart Bik9abf8942016-10-14 09:49:42 -0700254 if (!GenerateRangeOrLastValue(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)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700265 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 Bik9abf8942016-10-14 09:49:42 -0700283bool InductionVarRange::IsFinite(HLoopInformation* loop) const {
284 HInductionVarAnalysis::InductionInfo *trip =
285 induction_analysis_->LookupInfo(loop, GetLoopControl(loop));
286 return trip != nullptr && !IsUnsafeTripCount(trip);
287}
288
Aart Bikd14c5952015-09-08 15:25:15 -0700289//
290// Private class methods.
291//
292
Aart Bik97412c922016-02-19 20:14:38 -0800293bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
294 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700295 /*out*/ int64_t* value) const {
Aart Bik97412c922016-02-19 20:14:38 -0800296 if (info != nullptr) {
297 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
298 // any of the three requests (kExact, kAtMost, and KAtLeast).
299 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
300 info->operation == HInductionVarAnalysis::kFetch) {
301 if (IsIntAndGet(info->fetch, value)) {
302 return true;
303 }
304 }
Aart Bik52be7e72016-06-23 11:20:41 -0700305 // Try range analysis on the invariant, but only on proper range to avoid wrap-around anomalies.
306 Value min_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ true);
307 Value max_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ false);
308 if (IsConstantValue(min_val) &&
309 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
310 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
311 *value = max_val.b_constant;
312 return true;
313 } else if (request == kAtLeast) {
314 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800315 return true;
316 }
317 }
Aart Bik97412c922016-02-19 20:14:38 -0800318 }
319 return false;
320}
321
Aart Bik52be7e72016-06-23 11:20:41 -0700322bool InductionVarRange::HasInductionInfo(
323 HInstruction* context,
324 HInstruction* instruction,
325 /*out*/ HLoopInformation** loop,
326 /*out*/ HInductionVarAnalysis::InductionInfo** info,
327 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
Aart Bik009cace2016-09-16 10:15:19 -0700328 HLoopInformation* lp = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
329 if (lp != nullptr) {
330 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(lp, instruction);
Aart Bik52be7e72016-06-23 11:20:41 -0700331 if (i != nullptr) {
Aart Bik009cace2016-09-16 10:15:19 -0700332 *loop = lp;
Aart Bik52be7e72016-06-23 11:20:41 -0700333 *info = i;
Aart Bik009cace2016-09-16 10:15:19 -0700334 *trip = induction_analysis_->LookupInfo(lp, GetLoopControl(lp));
Aart Bik52be7e72016-06-23 11:20:41 -0700335 return true;
336 }
337 }
338 return false;
339}
340
341bool InductionVarRange::IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
342 if (trip != nullptr) {
343 // Both bounds that define a trip-count are well-behaved if they either are not defined
344 // in any loop, or are contained in a proper interval. This allows finding the min/max
345 // of an expression by chasing outward.
346 InductionVarRange range(induction_analysis_);
347 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
348 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
349 int64_t not_used = 0;
350 return (!HasFetchInLoop(lower) || range.IsConstant(lower, kAtLeast, &not_used)) &&
351 (!HasFetchInLoop(upper) || range.IsConstant(upper, kAtLeast, &not_used));
352 }
353 return true;
354}
355
356bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
357 if (info != nullptr) {
358 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
359 info->operation == HInductionVarAnalysis::kFetch) {
360 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
361 }
362 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
363 }
364 return false;
365}
366
Aart Bik16d3a652016-09-09 10:33:50 -0700367bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
368 int64_t* stride_value) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700369 if (info != nullptr) {
370 if (info->induction_class == HInductionVarAnalysis::kLinear) {
Aart Bik16d3a652016-09-09 10:33:50 -0700371 return IsConstant(info->op_a, kExact, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700372 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
Aart Bik16d3a652016-09-09 10:33:50 -0700373 return NeedsTripCount(info->op_b, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700374 }
Aart Bikd14c5952015-09-08 15:25:15 -0700375 }
Aart Bik389b3db2015-10-28 14:23:40 -0700376 return false;
377}
378
Aart Bik7d57d7f2015-12-09 14:39:48 -0800379bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700380 if (trip != nullptr) {
381 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
382 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
383 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
384 }
385 }
386 return false;
387}
388
Aart Bik7d57d7f2015-12-09 14:39:48 -0800389bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700390 if (trip != nullptr) {
391 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
392 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
393 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
394 }
395 }
396 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700397}
398
Aart Bik7d57d7f2015-12-09 14:39:48 -0800399InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
400 HInductionVarAnalysis::InductionInfo* trip,
401 bool in_body,
402 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700403 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800404 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
405 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
406 // with intermediate results that only incorporate single instructions.
407 if (trip != nullptr) {
408 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700409 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800410 int64_t stride_value = 0;
411 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800412 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800413 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800414 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
415 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
416 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700417 trip->induction_class,
418 trip->operation,
419 trip_expr->op_a,
420 trip->op_b,
421 nullptr,
422 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800423 return GetVal(&cancelled_trip, trip, in_body, is_min);
424 }
425 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800426 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800427 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
428 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
429 HInductionVarAnalysis::InductionInfo neg(
430 HInductionVarAnalysis::kInvariant,
431 HInductionVarAnalysis::kNeg,
432 nullptr,
433 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700434 nullptr,
435 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800436 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700437 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800438 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
439 }
440 }
441 }
442 }
443 }
444 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
445 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
446 GetVal(info->op_b, trip, in_body, is_min));
447}
448
Aart Bikd14c5952015-09-08 15:25:15 -0700449InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700450 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700451 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800452 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700453 // Stop chasing the instruction at constant or hint.
Aart Bik97412c922016-02-19 20:14:38 -0800454 int64_t value;
Aart Bik52be7e72016-06-23 11:20:41 -0700455 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800456 return Value(static_cast<int32_t>(value));
Aart Bik52be7e72016-06-23 11:20:41 -0700457 } else if (instruction == chase_hint_) {
458 return Value(instruction, 1, 0);
459 }
460 // Special cases when encountering a single instruction that denotes trip count in the
461 // loop-body: min is 1 and, when chasing constants, max of safe trip-count is max int
462 if (in_body && trip != nullptr && instruction == trip->op_a->fetch) {
463 if (is_min) {
464 return Value(1);
465 } else if (chase_hint_ == nullptr && !IsUnsafeTripCount(trip)) {
466 return Value(std::numeric_limits<int32_t>::max());
467 }
468 }
469 // Chase the instruction a bit deeper into the HIR tree, so that it becomes more likely
470 // range analysis will compare the same instructions as terminal nodes.
471 if (instruction->IsAdd()) {
Aart Bik97412c922016-02-19 20:14:38 -0800472 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
473 return AddValue(Value(static_cast<int32_t>(value)),
474 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
475 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
476 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
477 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700478 }
Aart Bik52be7e72016-06-23 11:20:41 -0700479 } else if (instruction->IsArrayLength()) {
480 // Return extreme values when chasing constants. Otherwise, chase deeper.
481 if (chase_hint_ == nullptr) {
482 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
483 } else if (instruction->InputAt(0)->IsNewArray()) {
484 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
485 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700486 } else if (instruction->IsTypeConversion()) {
487 // Since analysis is 32-bit (or narrower) we allow a widening along the path.
488 if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
489 instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
490 return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
491 }
Aart Bik52be7e72016-06-23 11:20:41 -0700492 }
493 // Chase an invariant fetch that is defined by an outer loop if the trip-count used
494 // so far is well-behaved in both bounds and the next trip-count is safe.
495 // Example:
496 // for (int i = 0; i <= 100; i++) // safe
497 // for (int j = 0; j <= i; j++) // well-behaved
498 // j is in range [0, i ] (if i is chase hint)
499 // or in range [0, 100] (otherwise)
500 HLoopInformation* next_loop = nullptr;
501 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
502 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
503 bool next_in_body = true; // inner loop is always in body of outer loop
504 if (HasInductionInfo(instruction, instruction, &next_loop, &next_info, &next_trip) &&
505 IsWellBehavedTripCount(trip) &&
506 !IsUnsafeTripCount(next_trip)) {
507 return GetVal(next_info, next_trip, next_in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700508 }
509 return Value(instruction, 1, 0);
510}
511
Aart Bikcd26feb2015-09-23 17:50:50 -0700512InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
513 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700514 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800515 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700516 if (info != nullptr) {
517 switch (info->induction_class) {
518 case HInductionVarAnalysis::kInvariant:
519 // Invariants.
520 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700521 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700522 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
523 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700524 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700525 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
526 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700527 case HInductionVarAnalysis::kNeg: // second reversed!
528 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700529 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700530 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700531 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700532 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700533 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bik7dc96932016-10-12 10:01:05 -0700534 case HInductionVarAnalysis::kXor:
535 return GetXor(info->op_a, info->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -0700536 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700537 return GetFetch(info->fetch, trip, in_body, is_min);
538 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700539 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700540 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700541 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700542 }
543 FALLTHROUGH_INTENDED;
544 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700545 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700546 if (is_min) {
547 return Value(0);
548 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700549 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700550 }
551 break;
552 default:
553 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700554 }
555 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700556 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700557 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700558 case HInductionVarAnalysis::kWrapAround:
559 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700560 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
561 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700562 }
563 }
Aart Bikb3365e02015-09-21 14:45:05 -0700564 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700565}
566
567InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
568 HInductionVarAnalysis::InductionInfo* info2,
569 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700570 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800571 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700572 // Constant times range.
573 int64_t value = 0;
574 if (IsConstant(info1, kExact, &value)) {
575 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
576 } else if (IsConstant(info2, kExact, &value)) {
577 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
578 }
579 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700580 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
581 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
582 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
583 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800584 // Positive range vs. positive or negative range.
585 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
586 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
587 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
588 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
589 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700590 }
Aart Bik97412c922016-02-19 20:14:38 -0800591 }
592 // Negative range vs. positive or negative range.
593 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
594 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
595 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
596 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
597 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700598 }
599 }
Aart Bikb3365e02015-09-21 14:45:05 -0700600 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700601}
602
603InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
604 HInductionVarAnalysis::InductionInfo* info2,
605 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700606 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800607 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700608 // Range divided by constant.
609 int64_t value = 0;
610 if (IsConstant(info2, kExact, &value)) {
611 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
612 }
613 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700614 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
615 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
616 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
617 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800618 // Positive range vs. positive or negative range.
619 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
620 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
621 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
622 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
623 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700624 }
Aart Bik97412c922016-02-19 20:14:38 -0800625 }
626 // Negative range vs. positive or negative range.
627 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
628 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
629 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
630 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
631 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700632 }
633 }
Aart Bikb3365e02015-09-21 14:45:05 -0700634 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700635}
636
Aart Bik7dc96932016-10-12 10:01:05 -0700637InductionVarRange::Value InductionVarRange::GetXor(
638 HInductionVarAnalysis::InductionInfo* info1,
639 HInductionVarAnalysis::InductionInfo* info2) const {
640 int64_t v1 = 0;
641 int64_t v2 = 0;
642 // Only accept exact values.
643 if (IsConstant(info1, kExact, &v1) && IsConstant(info2, kExact, &v2)) {
644 int64_t value = v1 ^ v2;
645 if (CanLongValueFitIntoInt(value)) {
646 return Value(static_cast<int32_t>(value));
647 }
648 }
649 return Value();
650}
651
Aart Bik52be7e72016-06-23 11:20:41 -0700652InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
653 int64_t value,
654 HInductionVarAnalysis::InductionInfo* info,
655 HInductionVarAnalysis::InductionInfo* trip,
656 bool in_body,
657 bool is_min) const {
658 if (CanLongValueFitIntoInt(value)) {
659 Value c(static_cast<int32_t>(value));
660 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
661 }
662 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800663}
664
Aart Bik52be7e72016-06-23 11:20:41 -0700665InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
666 int64_t value,
667 HInductionVarAnalysis::InductionInfo* info,
668 HInductionVarAnalysis::InductionInfo* trip,
669 bool in_body,
670 bool is_min) const {
671 if (CanLongValueFitIntoInt(value)) {
672 Value c(static_cast<int32_t>(value));
673 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
674 }
675 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700676}
677
Aart Bik7d57d7f2015-12-09 14:39:48 -0800678InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700679 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700680 const int32_t b = v1.b_constant + v2.b_constant;
681 if (v1.a_constant == 0) {
682 return Value(v2.instruction, v2.a_constant, b);
683 } else if (v2.a_constant == 0) {
684 return Value(v1.instruction, v1.a_constant, b);
685 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
686 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
687 }
688 }
Aart Bikb3365e02015-09-21 14:45:05 -0700689 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700690}
691
Aart Bik7d57d7f2015-12-09 14:39:48 -0800692InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700693 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700694 const int32_t b = v1.b_constant - v2.b_constant;
695 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
696 return Value(v2.instruction, -v2.a_constant, b);
697 } else if (v2.a_constant == 0) {
698 return Value(v1.instruction, v1.a_constant, b);
699 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
700 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
701 }
702 }
Aart Bikb3365e02015-09-21 14:45:05 -0700703 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700704}
705
Aart Bik7d57d7f2015-12-09 14:39:48 -0800706InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700707 if (v1.is_known && v2.is_known) {
708 if (v1.a_constant == 0) {
709 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
710 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
711 }
712 } else if (v2.a_constant == 0) {
713 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
714 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
715 }
Aart Bikd14c5952015-09-08 15:25:15 -0700716 }
717 }
Aart Bikb3365e02015-09-21 14:45:05 -0700718 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700719}
720
Aart Bik7d57d7f2015-12-09 14:39:48 -0800721InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700722 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700723 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
724 return Value(v1.b_constant / v2.b_constant);
725 }
726 }
Aart Bikb3365e02015-09-21 14:45:05 -0700727 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700728}
729
Aart Bik7d57d7f2015-12-09 14:39:48 -0800730InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700731 if (v1.is_known && v2.is_known) {
732 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700733 return Value(v1.instruction, v1.a_constant,
734 is_min ? std::min(v1.b_constant, v2.b_constant)
735 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700736 }
Aart Bikd14c5952015-09-08 15:25:15 -0700737 }
Aart Bikb3365e02015-09-21 14:45:05 -0700738 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700739}
740
Aart Bik9abf8942016-10-14 09:49:42 -0700741bool InductionVarRange::GenerateRangeOrLastValue(HInstruction* context,
742 HInstruction* instruction,
743 bool is_last_value,
744 HGraph* graph,
745 HBasicBlock* block,
746 /*out*/HInstruction** lower,
747 /*out*/HInstruction** upper,
748 /*out*/HInstruction** taken_test,
749 /*out*/int64_t* stride_value,
750 /*out*/bool* needs_finite_test,
751 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700752 HLoopInformation* loop = nullptr;
753 HInductionVarAnalysis::InductionInfo* info = nullptr;
754 HInductionVarAnalysis::InductionInfo* trip = nullptr;
755 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
756 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -0800757 }
758 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
759 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
760 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
761 // code does not use the trip-count explicitly (since there could be an implicit relation
762 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700763 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik16d3a652016-09-09 10:33:50 -0700764 *stride_value = 0;
765 *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -0800766 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -0700767 // Handle last value request.
768 if (is_last_value) {
Aart Bik9abf8942016-10-14 09:49:42 -0700769 if (info->induction_class == HInductionVarAnalysis::kLinear) {
770 if (*stride_value > 0) {
771 lower = nullptr;
772 } else {
773 upper = nullptr;
774 }
775 } else if (info->induction_class == HInductionVarAnalysis::kPeriodic) {
776 DCHECK(!in_body);
777 return GenerateLastValuePeriodic(info, trip, graph, block, lower, needs_taken_test);
Aart Bik16d3a652016-09-09 10:33:50 -0700778 } else {
Aart Bik9abf8942016-10-14 09:49:42 -0700779 return false;
Aart Bik16d3a652016-09-09 10:33:50 -0700780 }
781 }
Aart Bik97412c922016-02-19 20:14:38 -0800782 // Code generation for taken test: generate the code when requested or otherwise analyze
783 // if code generation is feasible when taken test is needed.
784 if (taken_test != nullptr) {
785 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
786 } else if (*needs_taken_test) {
787 if (!GenerateCode(
788 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
789 return false;
790 }
791 }
792 // Code generation for lower and upper.
793 return
794 // Success on lower if invariant (not set), or code can be generated.
795 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
796 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
797 // And success on upper.
798 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700799}
800
Aart Bik9abf8942016-10-14 09:49:42 -0700801bool InductionVarRange::GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info,
802 HInductionVarAnalysis::InductionInfo* trip,
803 HGraph* graph,
804 HBasicBlock* block,
805 /*out*/HInstruction** result,
806 /*out*/bool* needs_taken_test) const {
807 DCHECK(info->induction_class == HInductionVarAnalysis::kPeriodic);
808 // Count period.
809 int32_t period = 1;
810 for (HInductionVarAnalysis::InductionInfo* p = info;
811 p->induction_class == HInductionVarAnalysis::kPeriodic;
812 p = p->op_b, ++period) {}
813 // Handle periodic(x, y) case for restricted types.
814 if (period != 2 ||
815 trip->op_a->type != Primitive::kPrimInt ||
816 (info->type != Primitive::kPrimInt && info->type != Primitive::kPrimBoolean)) {
817 return false; // TODO: easy to generalize
818 }
819 HInstruction* x_instr = nullptr;
820 HInstruction* y_instr = nullptr;
821 HInstruction* trip_expr = nullptr;
822 if (GenerateCode(info->op_a, nullptr, graph, block, graph ? &x_instr : nullptr, false, false) &&
823 GenerateCode(info->op_b, nullptr, graph, block, graph ? &y_instr : nullptr, false, false) &&
824 GenerateCode(trip->op_a, nullptr, graph, block, graph ? &trip_expr : nullptr, false, false)) {
825 // During actual code generation (graph != nullptr),
826 // generate is_even ? x : y select instruction.
827 if (graph != nullptr) {
828 HInstruction* is_even = Insert(block, new (graph->GetArena()) HEqual(
829 Insert(block, new (graph->GetArena()) HAnd(
830 Primitive::kPrimInt, trip_expr, graph->GetIntConstant(1))),
831 graph->GetIntConstant(0), kNoDexPc));
832 *result = Insert(block, new (graph->GetArena()) HSelect(is_even, x_instr, y_instr, kNoDexPc));
833 }
834 // Guard select with taken test if needed.
835 if (*needs_taken_test) {
836 HInstruction* taken_test = nullptr;
837 if (!GenerateCode(
838 trip->op_b, nullptr, graph, block, graph ? &taken_test : nullptr, false, false)) {
839 return false;
840 } else if (graph != nullptr) {
841 *result = Insert(block,
842 new (graph->GetArena()) HSelect(taken_test, *result, x_instr, kNoDexPc));
843 }
844 *needs_taken_test = false; // taken care of
845 }
846 return true;
847 }
848 return false;
849}
850
Aart Bikaec3cce2015-10-14 17:44:55 -0700851bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
852 HInductionVarAnalysis::InductionInfo* trip,
853 HGraph* graph, // when set, code is generated
854 HBasicBlock* block,
855 /*out*/HInstruction** result,
856 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800857 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700858 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -0700859 // If during codegen, the result is not needed (nullptr), simply return success.
860 if (graph != nullptr && result == nullptr) {
861 return true;
862 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700863 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700864 Primitive::Type type = Primitive::kPrimInt;
Aart Bik0d345cf2016-03-16 10:49:38 -0700865 if (info->type != type) {
866 return false;
867 }
868 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700869 HInstruction* opa = nullptr;
870 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700871 switch (info->induction_class) {
872 case HInductionVarAnalysis::kInvariant:
873 // Invariants.
874 switch (info->operation) {
875 case HInductionVarAnalysis::kAdd:
Aart Bik9abf8942016-10-14 09:49:42 -0700876 case HInductionVarAnalysis::kXor:
Aart Bik389b3db2015-10-28 14:23:40 -0700877 case HInductionVarAnalysis::kLT:
878 case HInductionVarAnalysis::kLE:
879 case HInductionVarAnalysis::kGT:
880 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700881 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
882 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
883 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700884 HInstruction* operation = nullptr;
885 switch (info->operation) {
886 case HInductionVarAnalysis::kAdd:
887 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
Aart Bik9abf8942016-10-14 09:49:42 -0700888 case HInductionVarAnalysis::kXor:
889 operation = new (graph->GetArena()) HXor(type, opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -0700890 case HInductionVarAnalysis::kLT:
891 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
892 case HInductionVarAnalysis::kLE:
893 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
894 case HInductionVarAnalysis::kGT:
895 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
896 case HInductionVarAnalysis::kGE:
897 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
898 default:
899 LOG(FATAL) << "unknown operation";
900 }
901 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700902 }
903 return true;
904 }
905 break;
906 case HInductionVarAnalysis::kSub: // second reversed!
907 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
908 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
909 if (graph != nullptr) {
910 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
911 }
912 return true;
913 }
914 break;
915 case HInductionVarAnalysis::kNeg: // reversed!
916 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
917 if (graph != nullptr) {
918 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
919 }
920 return true;
921 }
922 break;
923 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -0700924 if (graph != nullptr) {
925 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -0700926 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700927 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700928 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700929 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700930 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700931 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700932 }
933 FALLTHROUGH_INTENDED;
934 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700935 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700936 if (is_min) {
937 if (graph != nullptr) {
938 *result = graph->GetIntConstant(0);
939 }
940 return true;
941 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700942 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700943 if (graph != nullptr) {
944 *result = Insert(block,
945 new (graph->GetArena())
946 HSub(type, opb, graph->GetIntConstant(1)));
947 }
948 return true;
949 }
950 }
951 break;
952 default:
953 break;
954 }
955 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700956 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -0700957 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
958 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
959 // are harder to guard against. For a last value, requesting min/max based on any
960 // stride yields right value.
Aart Bik97412c922016-02-19 20:14:38 -0800961 int64_t stride_value = 0;
962 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700963 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
964 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
965 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
966 if (graph != nullptr) {
967 HInstruction* oper;
968 if (stride_value == 1) {
969 oper = new (graph->GetArena()) HAdd(type, opa, opb);
970 } else if (stride_value == -1) {
971 oper = new (graph->GetArena()) HSub(type, opb, opa);
972 } else {
Aart Bik009cace2016-09-16 10:15:19 -0700973 HInstruction* mul = new (graph->GetArena()) HMul(
974 type, graph->GetIntConstant(stride_value), opa);
Aart Bik16d3a652016-09-09 10:33:50 -0700975 oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
Aart Bikaec3cce2015-10-14 17:44:55 -0700976 }
Aart Bik16d3a652016-09-09 10:33:50 -0700977 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700978 }
Aart Bik16d3a652016-09-09 10:33:50 -0700979 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700980 }
981 }
982 break;
Aart Bik4a342772015-11-30 10:17:46 -0800983 }
984 case HInductionVarAnalysis::kWrapAround:
985 case HInductionVarAnalysis::kPeriodic: {
986 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
987 // values are easy to test at runtime without complications of arithmetic wrap-around.
988 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800989 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800990 if (graph != nullptr) {
991 *result = graph->GetIntConstant(extreme.b_constant);
992 }
993 return true;
994 }
995 break;
996 }
Aart Bik389b3db2015-10-28 14:23:40 -0700997 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700998 break;
999 }
1000 }
1001 return false;
1002}
1003
Aart Bik16d3a652016-09-09 10:33:50 -07001004void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
1005 HInstruction* fetch,
1006 HInstruction* replacement) {
1007 if (info != nullptr) {
1008 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
1009 info->operation == HInductionVarAnalysis::kFetch &&
1010 info->fetch == fetch) {
1011 info->fetch = replacement;
1012 }
1013 ReplaceInduction(info->op_a, fetch, replacement);
1014 ReplaceInduction(info->op_b, fetch, replacement);
1015 }
1016}
1017
Aart Bikd14c5952015-09-08 15:25:15 -07001018} // namespace art