blob: 5e587e081004f8c243818a06675074cefceb6162 [file] [log] [blame]
Aart Bikd14c5952015-09-08 15:25:15 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Aart Bikd14c5952015-09-08 15:25:15 -070017#include "induction_var_range.h"
18
Aart Bikcd26feb2015-09-23 17:50:50 -070019#include <limits>
20
Aart Bikd14c5952015-09-08 15:25:15 -070021namespace art {
22
Aart Bikb3365e02015-09-21 14:45:05 -070023/** Returns true if 64-bit constant fits in 32-bit constant. */
24static bool CanLongValueFitIntoInt(int64_t c) {
Aart Bikcd26feb2015-09-23 17:50:50 -070025 return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
Aart Bikd14c5952015-09-08 15:25:15 -070026}
27
Aart Bikb3365e02015-09-21 14:45:05 -070028/** Returns true if 32-bit addition can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070029static bool IsSafeAdd(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070030 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070031}
32
Aart Bikb3365e02015-09-21 14:45:05 -070033/** Returns true if 32-bit subtraction can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070034static bool IsSafeSub(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070035 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070036}
37
Aart Bikb3365e02015-09-21 14:45:05 -070038/** Returns true if 32-bit multiplication can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070039static bool IsSafeMul(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070040 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070041}
42
Aart Bikb3365e02015-09-21 14:45:05 -070043/** Returns true if 32-bit division can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070044static bool IsSafeDiv(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070045 return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070046}
47
Aart Bik97412c922016-02-19 20:14:38 -080048/** Returns true for 32/64-bit constant instruction. */
49static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
Aart Bikd14c5952015-09-08 15:25:15 -070050 if (instruction->IsIntConstant()) {
Aart Bikb3365e02015-09-21 14:45:05 -070051 *value = instruction->AsIntConstant()->GetValue();
52 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070053 } else if (instruction->IsLongConstant()) {
Aart Bik97412c922016-02-19 20:14:38 -080054 *value = instruction->AsLongConstant()->GetValue();
55 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070056 }
57 return false;
58}
59
Aart Bikb3365e02015-09-21 14:45:05 -070060/**
Aart Bik0d345cf2016-03-16 10:49:38 -070061 * An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as length + b
Aart Bikb3365e02015-09-21 14:45:05 -070062 * because length >= 0 is true. This makes it more likely the bound is useful to clients.
63 */
64static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) {
Aart Bik97412c922016-02-19 20:14:38 -080065 int64_t value;
66 if (v.is_known &&
Aart Bik0d345cf2016-03-16 10:49:38 -070067 v.a_constant >= 1 &&
Aart Bikb3365e02015-09-21 14:45:05 -070068 v.instruction->IsDiv() &&
69 v.instruction->InputAt(0)->IsArrayLength() &&
70 IsIntAndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
71 return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
72 }
73 return v;
74}
75
Aart Bik52be7e72016-06-23 11:20:41 -070076/** Helper method to test for a constant value. */
77static bool IsConstantValue(InductionVarRange::Value v) {
78 return v.is_known && v.a_constant == 0;
79}
80
81/** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
Aart Bik0d345cf2016-03-16 10:49:38 -070082static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, Primitive::Type type) {
83 switch (type) {
84 case Primitive::kPrimShort:
85 case Primitive::kPrimChar:
86 case Primitive::kPrimByte: {
87 // Constants within range only.
88 // TODO: maybe some room for improvement, like allowing widening conversions
89 const int32_t min = Primitive::MinValueOfIntegralType(type);
90 const int32_t max = Primitive::MaxValueOfIntegralType(type);
Aart Bik52be7e72016-06-23 11:20:41 -070091 return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
Aart Bik0d345cf2016-03-16 10:49:38 -070092 ? v
93 : InductionVarRange::Value();
94 }
95 default:
Aart Bik0d345cf2016-03-16 10:49:38 -070096 return v;
97 }
98}
99
Aart Bik389b3db2015-10-28 14:23:40 -0700100/** Helper method to insert an instruction. */
101static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
102 DCHECK(block != nullptr);
103 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -0700104 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -0700105 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -0700106 return instruction;
107}
108
Aart Bikd14c5952015-09-08 15:25:15 -0700109//
110// Public class methods.
111//
112
113InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
Aart Bik52be7e72016-06-23 11:20:41 -0700114 : induction_analysis_(induction_analysis),
115 chase_hint_(nullptr) {
Aart Bikb3365e02015-09-21 14:45:05 -0700116 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700117}
118
Aart Bik1fc3afb2016-02-02 13:26:16 -0800119bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700120 HInstruction* instruction,
Aart Bik52be7e72016-06-23 11:20:41 -0700121 HInstruction* chase_hint,
Aart Bik389b3db2015-10-28 14:23:40 -0700122 /*out*/Value* min_val,
123 /*out*/Value* max_val,
124 /*out*/bool* needs_finite_test) {
Aart Bik52be7e72016-06-23 11:20:41 -0700125 HLoopInformation* loop = nullptr;
126 HInductionVarAnalysis::InductionInfo* info = nullptr;
127 HInductionVarAnalysis::InductionInfo* trip = nullptr;
128 if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
129 return false;
Aart Bik97412c922016-02-19 20:14:38 -0800130 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700131 // Type int or lower (this is not too restrictive since intended clients, like
132 // bounds check elimination, will have truncated higher precision induction
133 // at their use point already).
134 switch (info->type) {
135 case Primitive::kPrimInt:
136 case Primitive::kPrimShort:
137 case Primitive::kPrimChar:
138 case Primitive::kPrimByte:
139 break;
140 default:
141 return false;
142 }
Aart Bik97412c922016-02-19 20:14:38 -0800143 // Find range.
Aart Bik52be7e72016-06-23 11:20:41 -0700144 chase_hint_ = chase_hint;
145 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik97412c922016-02-19 20:14:38 -0800146 *min_val = GetVal(info, trip, in_body, /* is_min */ true);
147 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
148 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
149 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700150}
151
Aart Bikaec3cce2015-10-14 17:44:55 -0700152bool InductionVarRange::CanGenerateCode(HInstruction* context,
153 HInstruction* instruction,
Aart Bik389b3db2015-10-28 14:23:40 -0700154 /*out*/bool* needs_finite_test,
155 /*out*/bool* needs_taken_test) {
156 return GenerateCode(context,
157 instruction,
158 nullptr, nullptr, nullptr, nullptr, nullptr, // nothing generated yet
159 needs_finite_test,
160 needs_taken_test);
Aart Bikaec3cce2015-10-14 17:44:55 -0700161}
162
Aart Bik389b3db2015-10-28 14:23:40 -0700163void InductionVarRange::GenerateRangeCode(HInstruction* context,
164 HInstruction* instruction,
165 HGraph* graph,
166 HBasicBlock* block,
167 /*out*/HInstruction** lower,
168 /*out*/HInstruction** upper) {
169 bool b1, b2; // unused
170 if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
171 LOG(FATAL) << "Failed precondition: GenerateCode()";
172 }
173}
174
175void InductionVarRange::GenerateTakenTest(HInstruction* context,
176 HGraph* graph,
177 HBasicBlock* block,
178 /*out*/HInstruction** taken_test) {
179 bool b1, b2; // unused
180 if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
181 LOG(FATAL) << "Failed precondition: GenerateCode()";
182 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700183}
184
Aart Bikd14c5952015-09-08 15:25:15 -0700185//
186// Private class methods.
187//
188
Aart Bik97412c922016-02-19 20:14:38 -0800189bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
190 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700191 /*out*/ int64_t* value) const {
Aart Bik97412c922016-02-19 20:14:38 -0800192 if (info != nullptr) {
193 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
194 // any of the three requests (kExact, kAtMost, and KAtLeast).
195 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
196 info->operation == HInductionVarAnalysis::kFetch) {
197 if (IsIntAndGet(info->fetch, value)) {
198 return true;
199 }
200 }
Aart Bik52be7e72016-06-23 11:20:41 -0700201 // Try range analysis on the invariant, but only on proper range to avoid wrap-around anomalies.
202 Value min_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ true);
203 Value max_val = GetVal(info, nullptr, /* in_body */ true, /* is_min */ false);
204 if (IsConstantValue(min_val) &&
205 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
206 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
207 *value = max_val.b_constant;
208 return true;
209 } else if (request == kAtLeast) {
210 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800211 return true;
212 }
213 }
Aart Bik97412c922016-02-19 20:14:38 -0800214 }
215 return false;
216}
217
Aart Bik52be7e72016-06-23 11:20:41 -0700218bool InductionVarRange::HasInductionInfo(
219 HInstruction* context,
220 HInstruction* instruction,
221 /*out*/ HLoopInformation** loop,
222 /*out*/ HInductionVarAnalysis::InductionInfo** info,
223 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
224 HLoopInformation* l = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
225 if (l != nullptr) {
226 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(l, instruction);
227 if (i != nullptr) {
228 *loop = l;
229 *info = i;
230 *trip = induction_analysis_->LookupInfo(l, l->GetHeader()->GetLastInstruction());
231 return true;
232 }
233 }
234 return false;
235}
236
237bool InductionVarRange::IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
238 if (trip != nullptr) {
239 // Both bounds that define a trip-count are well-behaved if they either are not defined
240 // in any loop, or are contained in a proper interval. This allows finding the min/max
241 // of an expression by chasing outward.
242 InductionVarRange range(induction_analysis_);
243 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
244 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
245 int64_t not_used = 0;
246 return (!HasFetchInLoop(lower) || range.IsConstant(lower, kAtLeast, &not_used)) &&
247 (!HasFetchInLoop(upper) || range.IsConstant(upper, kAtLeast, &not_used));
248 }
249 return true;
250}
251
252bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
253 if (info != nullptr) {
254 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
255 info->operation == HInductionVarAnalysis::kFetch) {
256 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
257 }
258 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
259 }
260 return false;
261}
262
Aart Bik7d57d7f2015-12-09 14:39:48 -0800263bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700264 if (info != nullptr) {
265 if (info->induction_class == HInductionVarAnalysis::kLinear) {
266 return true;
267 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
268 return NeedsTripCount(info->op_b);
269 }
Aart Bikd14c5952015-09-08 15:25:15 -0700270 }
Aart Bik389b3db2015-10-28 14:23:40 -0700271 return false;
272}
273
Aart Bik7d57d7f2015-12-09 14:39:48 -0800274bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700275 if (trip != nullptr) {
276 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
277 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
278 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
279 }
280 }
281 return false;
282}
283
Aart Bik7d57d7f2015-12-09 14:39:48 -0800284bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700285 if (trip != nullptr) {
286 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
287 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
288 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
289 }
290 }
291 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700292}
293
Aart Bik7d57d7f2015-12-09 14:39:48 -0800294InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
295 HInductionVarAnalysis::InductionInfo* trip,
296 bool in_body,
297 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700298 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800299 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
300 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
301 // with intermediate results that only incorporate single instructions.
302 if (trip != nullptr) {
303 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700304 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800305 int64_t stride_value = 0;
306 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800307 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800308 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800309 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
310 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
311 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700312 trip->induction_class,
313 trip->operation,
314 trip_expr->op_a,
315 trip->op_b,
316 nullptr,
317 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800318 return GetVal(&cancelled_trip, trip, in_body, is_min);
319 }
320 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800321 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800322 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
323 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
324 HInductionVarAnalysis::InductionInfo neg(
325 HInductionVarAnalysis::kInvariant,
326 HInductionVarAnalysis::kNeg,
327 nullptr,
328 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700329 nullptr,
330 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800331 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700332 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800333 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
334 }
335 }
336 }
337 }
338 }
339 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
340 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
341 GetVal(info->op_b, trip, in_body, is_min));
342}
343
Aart Bikd14c5952015-09-08 15:25:15 -0700344InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700345 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700346 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800347 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700348 // Stop chasing the instruction at constant or hint.
Aart Bik97412c922016-02-19 20:14:38 -0800349 int64_t value;
Aart Bik52be7e72016-06-23 11:20:41 -0700350 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800351 return Value(static_cast<int32_t>(value));
Aart Bik52be7e72016-06-23 11:20:41 -0700352 } else if (instruction == chase_hint_) {
353 return Value(instruction, 1, 0);
354 }
355 // Special cases when encountering a single instruction that denotes trip count in the
356 // loop-body: min is 1 and, when chasing constants, max of safe trip-count is max int
357 if (in_body && trip != nullptr && instruction == trip->op_a->fetch) {
358 if (is_min) {
359 return Value(1);
360 } else if (chase_hint_ == nullptr && !IsUnsafeTripCount(trip)) {
361 return Value(std::numeric_limits<int32_t>::max());
362 }
363 }
364 // Chase the instruction a bit deeper into the HIR tree, so that it becomes more likely
365 // range analysis will compare the same instructions as terminal nodes.
366 if (instruction->IsAdd()) {
Aart Bik97412c922016-02-19 20:14:38 -0800367 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
368 return AddValue(Value(static_cast<int32_t>(value)),
369 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
370 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
371 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
372 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700373 }
Aart Bik52be7e72016-06-23 11:20:41 -0700374 } else if (instruction->IsArrayLength()) {
375 // Return extreme values when chasing constants. Otherwise, chase deeper.
376 if (chase_hint_ == nullptr) {
377 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
378 } else if (instruction->InputAt(0)->IsNewArray()) {
379 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
380 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700381 } else if (instruction->IsTypeConversion()) {
382 // Since analysis is 32-bit (or narrower) we allow a widening along the path.
383 if (instruction->AsTypeConversion()->GetInputType() == Primitive::kPrimInt &&
384 instruction->AsTypeConversion()->GetResultType() == Primitive::kPrimLong) {
385 return GetFetch(instruction->InputAt(0), trip, in_body, is_min);
386 }
Aart Bik52be7e72016-06-23 11:20:41 -0700387 }
388 // Chase an invariant fetch that is defined by an outer loop if the trip-count used
389 // so far is well-behaved in both bounds and the next trip-count is safe.
390 // Example:
391 // for (int i = 0; i <= 100; i++) // safe
392 // for (int j = 0; j <= i; j++) // well-behaved
393 // j is in range [0, i ] (if i is chase hint)
394 // or in range [0, 100] (otherwise)
395 HLoopInformation* next_loop = nullptr;
396 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
397 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
398 bool next_in_body = true; // inner loop is always in body of outer loop
399 if (HasInductionInfo(instruction, instruction, &next_loop, &next_info, &next_trip) &&
400 IsWellBehavedTripCount(trip) &&
401 !IsUnsafeTripCount(next_trip)) {
402 return GetVal(next_info, next_trip, next_in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700403 }
404 return Value(instruction, 1, 0);
405}
406
Aart Bikcd26feb2015-09-23 17:50:50 -0700407InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
408 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700409 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800410 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700411 if (info != nullptr) {
412 switch (info->induction_class) {
413 case HInductionVarAnalysis::kInvariant:
414 // Invariants.
415 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700416 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700417 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
418 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700419 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700420 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
421 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700422 case HInductionVarAnalysis::kNeg: // second reversed!
423 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700424 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700425 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700426 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700427 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700428 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700429 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700430 return GetFetch(info->fetch, trip, in_body, is_min);
431 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700432 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700433 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700434 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700435 }
436 FALLTHROUGH_INTENDED;
437 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700438 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700439 if (is_min) {
440 return Value(0);
441 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700442 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700443 }
444 break;
445 default:
446 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700447 }
448 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700449 case HInductionVarAnalysis::kLinear:
Aart Bik0d345cf2016-03-16 10:49:38 -0700450 return CorrectForType(GetLinear(info, trip, in_body, is_min), info->type);
Aart Bikd14c5952015-09-08 15:25:15 -0700451 case HInductionVarAnalysis::kWrapAround:
452 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700453 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
454 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700455 }
456 }
Aart Bikb3365e02015-09-21 14:45:05 -0700457 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700458}
459
460InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
461 HInductionVarAnalysis::InductionInfo* info2,
462 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700463 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800464 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700465 // Constant times range.
466 int64_t value = 0;
467 if (IsConstant(info1, kExact, &value)) {
468 return MulRangeAndConstant(value, info2, trip, in_body, is_min);
469 } else if (IsConstant(info2, kExact, &value)) {
470 return MulRangeAndConstant(value, info1, trip, in_body, is_min);
471 }
472 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700473 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
474 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
475 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
476 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800477 // Positive range vs. positive or negative range.
478 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
479 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
480 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
481 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
482 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700483 }
Aart Bik97412c922016-02-19 20:14:38 -0800484 }
485 // Negative range vs. positive or negative range.
486 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
487 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
488 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
489 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
490 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700491 }
492 }
Aart Bikb3365e02015-09-21 14:45:05 -0700493 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700494}
495
496InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
497 HInductionVarAnalysis::InductionInfo* info2,
498 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700499 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800500 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700501 // Range divided by constant.
502 int64_t value = 0;
503 if (IsConstant(info2, kExact, &value)) {
504 return DivRangeAndConstant(value, info1, trip, in_body, is_min);
505 }
506 // Interval ranges.
Aart Bik9401f532015-09-28 16:25:56 -0700507 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
508 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
509 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
510 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800511 // Positive range vs. positive or negative range.
512 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
513 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
514 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
515 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
516 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700517 }
Aart Bik97412c922016-02-19 20:14:38 -0800518 }
519 // Negative range vs. positive or negative range.
520 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
521 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
522 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
523 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
524 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700525 }
526 }
Aart Bikb3365e02015-09-21 14:45:05 -0700527 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700528}
529
Aart Bik52be7e72016-06-23 11:20:41 -0700530InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
531 int64_t value,
532 HInductionVarAnalysis::InductionInfo* info,
533 HInductionVarAnalysis::InductionInfo* trip,
534 bool in_body,
535 bool is_min) const {
536 if (CanLongValueFitIntoInt(value)) {
537 Value c(static_cast<int32_t>(value));
538 return MulValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
539 }
540 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800541}
542
Aart Bik52be7e72016-06-23 11:20:41 -0700543InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
544 int64_t value,
545 HInductionVarAnalysis::InductionInfo* info,
546 HInductionVarAnalysis::InductionInfo* trip,
547 bool in_body,
548 bool is_min) const {
549 if (CanLongValueFitIntoInt(value)) {
550 Value c(static_cast<int32_t>(value));
551 return DivValue(GetVal(info, trip, in_body, is_min == value >= 0), c);
552 }
553 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700554}
555
Aart Bik7d57d7f2015-12-09 14:39:48 -0800556InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700557 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700558 const int32_t b = v1.b_constant + v2.b_constant;
559 if (v1.a_constant == 0) {
560 return Value(v2.instruction, v2.a_constant, b);
561 } else if (v2.a_constant == 0) {
562 return Value(v1.instruction, v1.a_constant, b);
563 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
564 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
565 }
566 }
Aart Bikb3365e02015-09-21 14:45:05 -0700567 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700568}
569
Aart Bik7d57d7f2015-12-09 14:39:48 -0800570InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700571 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700572 const int32_t b = v1.b_constant - v2.b_constant;
573 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
574 return Value(v2.instruction, -v2.a_constant, b);
575 } else if (v2.a_constant == 0) {
576 return Value(v1.instruction, v1.a_constant, b);
577 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
578 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
579 }
580 }
Aart Bikb3365e02015-09-21 14:45:05 -0700581 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700582}
583
Aart Bik7d57d7f2015-12-09 14:39:48 -0800584InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700585 if (v1.is_known && v2.is_known) {
586 if (v1.a_constant == 0) {
587 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
588 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
589 }
590 } else if (v2.a_constant == 0) {
591 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
592 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
593 }
Aart Bikd14c5952015-09-08 15:25:15 -0700594 }
595 }
Aart Bikb3365e02015-09-21 14:45:05 -0700596 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700597}
598
Aart Bik7d57d7f2015-12-09 14:39:48 -0800599InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700600 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700601 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
602 return Value(v1.b_constant / v2.b_constant);
603 }
604 }
Aart Bikb3365e02015-09-21 14:45:05 -0700605 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700606}
607
Aart Bik7d57d7f2015-12-09 14:39:48 -0800608InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700609 if (v1.is_known && v2.is_known) {
610 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700611 return Value(v1.instruction, v1.a_constant,
612 is_min ? std::min(v1.b_constant, v2.b_constant)
613 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700614 }
Aart Bikd14c5952015-09-08 15:25:15 -0700615 }
Aart Bikb3365e02015-09-21 14:45:05 -0700616 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700617}
618
Aart Bikaec3cce2015-10-14 17:44:55 -0700619bool InductionVarRange::GenerateCode(HInstruction* context,
620 HInstruction* instruction,
621 HGraph* graph,
622 HBasicBlock* block,
623 /*out*/HInstruction** lower,
624 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700625 /*out*/HInstruction** taken_test,
626 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800627 /*out*/bool* needs_taken_test) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700628 HLoopInformation* loop = nullptr;
629 HInductionVarAnalysis::InductionInfo* info = nullptr;
630 HInductionVarAnalysis::InductionInfo* trip = nullptr;
631 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
632 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -0800633 }
634 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
635 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
636 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
637 // code does not use the trip-count explicitly (since there could be an implicit relation
638 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik52be7e72016-06-23 11:20:41 -0700639 bool in_body = context->GetBlock() != loop->GetHeader();
Aart Bik97412c922016-02-19 20:14:38 -0800640 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
641 *needs_taken_test = IsBodyTripCount(trip);
642 // Code generation for taken test: generate the code when requested or otherwise analyze
643 // if code generation is feasible when taken test is needed.
644 if (taken_test != nullptr) {
645 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
646 } else if (*needs_taken_test) {
647 if (!GenerateCode(
648 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
649 return false;
650 }
651 }
652 // Code generation for lower and upper.
653 return
654 // Success on lower if invariant (not set), or code can be generated.
655 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
656 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
657 // And success on upper.
658 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700659}
660
661bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
662 HInductionVarAnalysis::InductionInfo* trip,
663 HGraph* graph, // when set, code is generated
664 HBasicBlock* block,
665 /*out*/HInstruction** result,
666 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800667 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700668 if (info != nullptr) {
Aart Bik0d345cf2016-03-16 10:49:38 -0700669 // Verify type safety.
Aart Bikaec3cce2015-10-14 17:44:55 -0700670 Primitive::Type type = Primitive::kPrimInt;
Aart Bik0d345cf2016-03-16 10:49:38 -0700671 if (info->type != type) {
672 return false;
673 }
674 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700675 HInstruction* opa = nullptr;
676 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700677 switch (info->induction_class) {
678 case HInductionVarAnalysis::kInvariant:
679 // Invariants.
680 switch (info->operation) {
681 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700682 case HInductionVarAnalysis::kLT:
683 case HInductionVarAnalysis::kLE:
684 case HInductionVarAnalysis::kGT:
685 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700686 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
687 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
688 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700689 HInstruction* operation = nullptr;
690 switch (info->operation) {
691 case HInductionVarAnalysis::kAdd:
692 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
693 case HInductionVarAnalysis::kLT:
694 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
695 case HInductionVarAnalysis::kLE:
696 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
697 case HInductionVarAnalysis::kGT:
698 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
699 case HInductionVarAnalysis::kGE:
700 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
701 default:
702 LOG(FATAL) << "unknown operation";
703 }
704 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700705 }
706 return true;
707 }
708 break;
709 case HInductionVarAnalysis::kSub: // second reversed!
710 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
711 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
712 if (graph != nullptr) {
713 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
714 }
715 return true;
716 }
717 break;
718 case HInductionVarAnalysis::kNeg: // reversed!
719 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
720 if (graph != nullptr) {
721 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
722 }
723 return true;
724 }
725 break;
726 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -0700727 if (graph != nullptr) {
728 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -0700729 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700730 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700731 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700732 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700733 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700734 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700735 }
736 FALLTHROUGH_INTENDED;
737 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700738 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700739 if (is_min) {
740 if (graph != nullptr) {
741 *result = graph->GetIntConstant(0);
742 }
743 return true;
744 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700745 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700746 if (graph != nullptr) {
747 *result = Insert(block,
748 new (graph->GetArena())
749 HSub(type, opb, graph->GetIntConstant(1)));
750 }
751 return true;
752 }
753 }
754 break;
755 default:
756 break;
757 }
758 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700759 case HInductionVarAnalysis::kLinear: {
Aart Bik4a342772015-11-30 10:17:46 -0800760 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
761 // to avoid arithmetic wrap-around situations that are hard to guard against.
Aart Bik97412c922016-02-19 20:14:38 -0800762 int64_t stride_value = 0;
763 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik4a342772015-11-30 10:17:46 -0800764 if (stride_value == 1 || stride_value == -1) {
765 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
766 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
767 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
768 if (graph != nullptr) {
769 HInstruction* oper;
770 if (stride_value == 1) {
771 oper = new (graph->GetArena()) HAdd(type, opa, opb);
772 } else {
773 oper = new (graph->GetArena()) HSub(type, opb, opa);
Aart Bik389b3db2015-10-28 14:23:40 -0700774 }
Aart Bik4a342772015-11-30 10:17:46 -0800775 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700776 }
Aart Bik4a342772015-11-30 10:17:46 -0800777 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700778 }
779 }
780 }
781 break;
Aart Bik4a342772015-11-30 10:17:46 -0800782 }
783 case HInductionVarAnalysis::kWrapAround:
784 case HInductionVarAnalysis::kPeriodic: {
785 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
786 // values are easy to test at runtime without complications of arithmetic wrap-around.
787 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800788 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800789 if (graph != nullptr) {
790 *result = graph->GetIntConstant(extreme.b_constant);
791 }
792 return true;
793 }
794 break;
795 }
Aart Bik389b3db2015-10-28 14:23:40 -0700796 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700797 break;
798 }
799 }
800 return false;
801}
802
Aart Bikd14c5952015-09-08 15:25:15 -0700803} // namespace art