blob: 9b78699eadf993e625aca5dc560e317cc2976002 [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>
Santiago Aboy Solanes4f18b942022-07-21 10:31:21 +010020#include "optimizing/nodes.h"
Aart Bikcd26feb2015-09-23 17:50:50 -070021
VladimĂ­r Marko434d9682022-11-04 14:04:17 +000022namespace art HIDDEN {
Aart Bikd14c5952015-09-08 15:25:15 -070023
Aart Bikb3365e02015-09-21 14:45:05 -070024/** Returns true if 64-bit constant fits in 32-bit constant. */
25static bool CanLongValueFitIntoInt(int64_t c) {
Aart Bikcd26feb2015-09-23 17:50:50 -070026 return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
Aart Bikd14c5952015-09-08 15:25:15 -070027}
28
Aart Bikb3365e02015-09-21 14:45:05 -070029/** Returns true if 32-bit addition can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070030static bool IsSafeAdd(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070031 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070032}
33
Aart Bikb3365e02015-09-21 14:45:05 -070034/** Returns true if 32-bit subtraction can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070035static bool IsSafeSub(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070036 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070037}
38
Aart Bikb3365e02015-09-21 14:45:05 -070039/** Returns true if 32-bit multiplication can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070040static bool IsSafeMul(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070041 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070042}
43
Aart Bikb3365e02015-09-21 14:45:05 -070044/** Returns true if 32-bit division can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070045static bool IsSafeDiv(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070046 return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070047}
48
Aart Bikb603a5c2017-03-06 18:29:39 -080049/** Computes a * b for a,b > 0 (at least until first overflow happens). */
50static int64_t SafeMul(int64_t a, int64_t b, /*out*/ bool* overflow) {
51 if (a > 0 && b > 0 && a > (std::numeric_limits<int64_t>::max() / b)) {
52 *overflow = true;
53 }
54 return a * b;
55}
56
57/** Returns b^e for b,e > 0. Sets overflow if arithmetic wrap-around occurred. */
Aart Bikd3ba6262017-01-30 14:37:12 -080058static int64_t IntPow(int64_t b, int64_t e, /*out*/ bool* overflow) {
Aart Bikb603a5c2017-03-06 18:29:39 -080059 DCHECK_LT(0, b);
60 DCHECK_LT(0, e);
Aart Bikc071a012016-12-01 10:22:31 -080061 int64_t pow = 1;
62 while (e) {
63 if (e & 1) {
Aart Bikb603a5c2017-03-06 18:29:39 -080064 pow = SafeMul(pow, b, overflow);
Aart Bikc071a012016-12-01 10:22:31 -080065 }
66 e >>= 1;
Aart Bikb603a5c2017-03-06 18:29:39 -080067 if (e) {
68 b = SafeMul(b, b, overflow);
69 }
Aart Bikc071a012016-12-01 10:22:31 -080070 }
71 return pow;
72}
73
Aart Bik40fbf742016-10-31 11:02:50 -070074/** Hunts "under the hood" for a suitable instruction at the hint. */
75static bool IsMaxAtHint(
76 HInstruction* instruction, HInstruction* hint, /*out*/HInstruction** suitable) {
Aart Bik1f8d51b2018-02-15 10:42:37 -080077 if (instruction->IsMin()) {
78 // For MIN(x, y), return most suitable x or y as maximum.
79 return IsMaxAtHint(instruction->InputAt(0), hint, suitable) ||
80 IsMaxAtHint(instruction->InputAt(1), hint, suitable);
Aart Bik40fbf742016-10-31 11:02:50 -070081 } else {
82 *suitable = instruction;
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +000083 return HuntForDeclaration(instruction) == hint;
Aart Bik40fbf742016-10-31 11:02:50 -070084 }
Aart Bik40fbf742016-10-31 11:02:50 -070085}
86
87/** Post-analysis simplification of a minimum value that makes the bound more useful to clients. */
88static InductionVarRange::Value SimplifyMin(InductionVarRange::Value v) {
89 if (v.is_known && v.a_constant == 1 && v.b_constant <= 0) {
90 // If a == 1, instruction >= 0 and b <= 0, just return the constant b.
91 // No arithmetic wrap-around can occur.
92 if (IsGEZero(v.instruction)) {
93 return InductionVarRange::Value(v.b_constant);
94 }
Aart Bikb3365e02015-09-21 14:45:05 -070095 }
96 return v;
97}
98
Aart Bik40fbf742016-10-31 11:02:50 -070099/** Post-analysis simplification of a maximum value that makes the bound more useful to clients. */
100static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v, HInstruction* hint) {
101 if (v.is_known && v.a_constant >= 1) {
102 // An upper bound a * (length / a) + b, where a >= 1, can be conservatively rewritten as
103 // length + b because length >= 0 is true.
104 int64_t value;
105 if (v.instruction->IsDiv() &&
106 v.instruction->InputAt(0)->IsArrayLength() &&
Aart Bikf3e61ee2017-04-12 17:09:20 -0700107 IsInt64AndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
Aart Bik40fbf742016-10-31 11:02:50 -0700108 return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
109 }
110 // If a == 1, the most suitable one suffices as maximum value.
111 HInstruction* suitable = nullptr;
112 if (v.a_constant == 1 && IsMaxAtHint(v.instruction, hint, &suitable)) {
113 return InductionVarRange::Value(suitable, 1, v.b_constant);
114 }
115 }
116 return v;
117}
118
119/** Tests for a constant value. */
Aart Bik52be7e72016-06-23 11:20:41 -0700120static bool IsConstantValue(InductionVarRange::Value v) {
121 return v.is_known && v.a_constant == 0;
122}
123
124/** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100125static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, DataType::Type type) {
Aart Bik0d345cf2016-03-16 10:49:38 -0700126 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +0100127 case DataType::Type::kUint8:
128 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100129 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +0100130 case DataType::Type::kInt16: {
Aart Bik0d345cf2016-03-16 10:49:38 -0700131 // Constants within range only.
132 // TODO: maybe some room for improvement, like allowing widening conversions
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100133 int32_t min = DataType::MinValueOfIntegralType(type);
134 int32_t max = DataType::MaxValueOfIntegralType(type);
Aart Bik52be7e72016-06-23 11:20:41 -0700135 return (IsConstantValue(v) && min <= v.b_constant && v.b_constant <= max)
Aart Bik0d345cf2016-03-16 10:49:38 -0700136 ? v
137 : InductionVarRange::Value();
138 }
139 default:
Aart Bik0d345cf2016-03-16 10:49:38 -0700140 return v;
141 }
142}
143
Aart Bik40fbf742016-10-31 11:02:50 -0700144/** Inserts an instruction. */
Aart Bik389b3db2015-10-28 14:23:40 -0700145static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
146 DCHECK(block != nullptr);
147 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -0700148 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -0700149 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -0700150 return instruction;
151}
152
Aart Bik40fbf742016-10-31 11:02:50 -0700153/** Obtains loop's control instruction. */
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000154static HInstruction* GetLoopControl(const HLoopInformation* loop) {
Aart Bik009cace2016-09-16 10:15:19 -0700155 DCHECK(loop != nullptr);
156 return loop->GetHeader()->GetLastInstruction();
157}
158
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000159/** Determines whether the `context` is in the body of the `loop`. */
160static bool IsContextInBody(const HBasicBlock* context, const HLoopInformation* loop) {
161 DCHECK(loop != nullptr);
162 // We're currently classifying trip count only for the exit condition from loop header.
163 // All other blocks in the loop are considered loop body.
164 return context != loop->GetHeader() && loop->Contains(*context);
165}
166
167/** Determines whether to use the full trip count for given `context`, `loop` and `is_min`. */
168bool UseFullTripCount(const HBasicBlock* context, const HLoopInformation* loop, bool is_min) {
169 // We're currently classifying trip count only for the exit condition from loop header.
170 // So, we should call this helper function only if the loop control is an `HIf` with
171 // one edge leaving the loop. The loop header is the only block that's both inside
172 // the loop and not in the loop body.
173 DCHECK(GetLoopControl(loop)->IsIf());
174 DCHECK_NE(loop->Contains(*GetLoopControl(loop)->AsIf()->IfTrueSuccessor()),
175 loop->Contains(*GetLoopControl(loop)->AsIf()->IfFalseSuccessor()));
176 if (loop->Contains(*context)) {
177 // Use the full trip count if determining the maximum and context is not in the loop body.
178 DCHECK_NE(context == loop->GetHeader(), IsContextInBody(context, loop));
179 return !is_min && context == loop->GetHeader();
180 } else {
181 // Trip count after the loop is always the maximum (ignoring `is_min`),
182 // as long as the `context` is dominated by the loop control exit block.
183 // If there are additional exit edges, the value is unknown on those paths.
184 HInstruction* loop_control = GetLoopControl(loop);
185 HBasicBlock* then_block = loop_control->AsIf()->IfTrueSuccessor();
186 HBasicBlock* else_block = loop_control->AsIf()->IfFalseSuccessor();
187 HBasicBlock* loop_exit_block = loop->Contains(*then_block) ? else_block : then_block;
188 return loop_exit_block->Dominates(context);
189 }
190}
191
Aart Bikd14c5952015-09-08 15:25:15 -0700192//
193// Public class methods.
194//
195
196InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
Aart Bik52be7e72016-06-23 11:20:41 -0700197 : induction_analysis_(induction_analysis),
198 chase_hint_(nullptr) {
Aart Bikb3365e02015-09-21 14:45:05 -0700199 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700200}
201
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000202bool InductionVarRange::GetInductionRange(const HBasicBlock* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700203 HInstruction* instruction,
Aart Bik52be7e72016-06-23 11:20:41 -0700204 HInstruction* chase_hint,
Aart Bik389b3db2015-10-28 14:23:40 -0700205 /*out*/Value* min_val,
206 /*out*/Value* max_val,
207 /*out*/bool* needs_finite_test) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000208 const HLoopInformation* loop = nullptr;
Aart Bik52be7e72016-06-23 11:20:41 -0700209 HInductionVarAnalysis::InductionInfo* info = nullptr;
210 HInductionVarAnalysis::InductionInfo* trip = nullptr;
211 if (!HasInductionInfo(context, instruction, &loop, &info, &trip)) {
212 return false;
Aart Bik97412c922016-02-19 20:14:38 -0800213 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700214 // Type int or lower (this is not too restrictive since intended clients, like
215 // bounds check elimination, will have truncated higher precision induction
216 // at their use point already).
217 switch (info->type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +0100218 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100219 case DataType::Type::kInt8:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +0100220 case DataType::Type::kUint16:
221 case DataType::Type::kInt16:
222 case DataType::Type::kInt32:
Aart Bik0d345cf2016-03-16 10:49:38 -0700223 break;
224 default:
225 return false;
226 }
Aart Bik97412c922016-02-19 20:14:38 -0800227 // Find range.
Aart Bik52be7e72016-06-23 11:20:41 -0700228 chase_hint_ = chase_hint;
Aart Bik16d3a652016-09-09 10:33:50 -0700229 int64_t stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000230 *min_val = SimplifyMin(GetVal(context, loop, info, trip, /*is_min=*/ true));
231 *max_val = SimplifyMax(GetVal(context, loop, info, trip, /*is_min=*/ false), chase_hint);
232 *needs_finite_test =
233 NeedsTripCount(context, loop, info, &stride_value) && IsUnsafeTripCount(trip);
Aart Bik40fbf742016-10-31 11:02:50 -0700234 chase_hint_ = nullptr;
235 // Retry chasing constants for wrap-around (merge sensitive).
236 if (!min_val->is_known && info->induction_class == HInductionVarAnalysis::kWrapAround) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000237 *min_val = SimplifyMin(GetVal(context, loop, info, trip, /*is_min=*/ true));
Aart Bik40fbf742016-10-31 11:02:50 -0700238 }
Aart Bik97412c922016-02-19 20:14:38 -0800239 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700240}
241
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000242bool InductionVarRange::CanGenerateRange(const HBasicBlock* context,
Aart Bik16d3a652016-09-09 10:33:50 -0700243 HInstruction* instruction,
244 /*out*/bool* needs_finite_test,
245 /*out*/bool* needs_taken_test) {
246 bool is_last_value = false;
247 int64_t stride_value = 0;
Aart Bik9abf8942016-10-14 09:49:42 -0700248 return GenerateRangeOrLastValue(context,
249 instruction,
250 is_last_value,
251 nullptr,
252 nullptr,
253 nullptr,
254 nullptr,
255 nullptr, // nothing generated yet
256 &stride_value,
257 needs_finite_test,
258 needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700259 && (stride_value == -1 ||
260 stride_value == 0 ||
Aart Bik40fbf742016-10-31 11:02:50 -0700261 stride_value == 1); // avoid arithmetic wrap-around anomalies.
Aart Bikaec3cce2015-10-14 17:44:55 -0700262}
263
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000264void InductionVarRange::GenerateRange(const HBasicBlock* context,
Aart Bik16d3a652016-09-09 10:33:50 -0700265 HInstruction* instruction,
266 HGraph* graph,
267 HBasicBlock* block,
268 /*out*/HInstruction** lower,
269 /*out*/HInstruction** upper) {
270 bool is_last_value = false;
Aart Bik009cace2016-09-16 10:15:19 -0700271 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700272 bool b1, b2; // unused
Aart Bik9abf8942016-10-14 09:49:42 -0700273 if (!GenerateRangeOrLastValue(context,
274 instruction,
275 is_last_value,
276 graph,
277 block,
278 lower,
279 upper,
280 nullptr,
281 &stride_value,
282 &b1,
283 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700284 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
Aart Bik389b3db2015-10-28 14:23:40 -0700285 }
286}
287
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000288HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* loop_control,
Aart Bik16d3a652016-09-09 10:33:50 -0700289 HGraph* graph,
290 HBasicBlock* block) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000291 const HBasicBlock* context = loop_control->GetBlock();
Aart Bik16d3a652016-09-09 10:33:50 -0700292 HInstruction* taken_test = nullptr;
293 bool is_last_value = false;
294 int64_t stride_value = 0;
Aart Bik389b3db2015-10-28 14:23:40 -0700295 bool b1, b2; // unused
Aart Bik9abf8942016-10-14 09:49:42 -0700296 if (!GenerateRangeOrLastValue(context,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000297 loop_control,
Aart Bik9abf8942016-10-14 09:49:42 -0700298 is_last_value,
299 graph,
300 block,
301 nullptr,
302 nullptr,
303 &taken_test,
304 &stride_value,
305 &b1,
306 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700307 LOG(FATAL) << "Failed precondition: CanGenerateRange()";
308 }
309 return taken_test;
310}
311
312bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000313 const HBasicBlock* context = instruction->GetBlock();
Aart Bik16d3a652016-09-09 10:33:50 -0700314 bool is_last_value = true;
315 int64_t stride_value = 0;
316 bool needs_finite_test = false;
317 bool needs_taken_test = false;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000318 return GenerateRangeOrLastValue(context,
Aart Bik9abf8942016-10-14 09:49:42 -0700319 instruction,
320 is_last_value,
321 nullptr,
322 nullptr,
323 nullptr,
324 nullptr,
325 nullptr, // nothing generated yet
326 &stride_value,
327 &needs_finite_test,
328 &needs_taken_test)
Aart Bik16d3a652016-09-09 10:33:50 -0700329 && !needs_finite_test && !needs_taken_test;
330}
331
332HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
333 HGraph* graph,
334 HBasicBlock* block) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000335 const HBasicBlock* context = instruction->GetBlock();
Aart Bik16d3a652016-09-09 10:33:50 -0700336 HInstruction* last_value = nullptr;
337 bool is_last_value = true;
338 int64_t stride_value = 0;
339 bool b1, b2; // unused
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000340 if (!GenerateRangeOrLastValue(context,
Aart Bik9abf8942016-10-14 09:49:42 -0700341 instruction,
342 is_last_value,
343 graph,
344 block,
345 &last_value,
346 &last_value,
347 nullptr,
348 &stride_value,
349 &b1,
350 &b2)) {
Aart Bik16d3a652016-09-09 10:33:50 -0700351 LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
352 }
353 return last_value;
354}
355
356void InductionVarRange::Replace(HInstruction* instruction,
357 HInstruction* fetch,
358 HInstruction* replacement) {
359 for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
360 lp != nullptr;
361 lp = lp->GetPreHeader()->GetLoopInformation()) {
Aart Bik009cace2016-09-16 10:15:19 -0700362 // Update instruction's information.
Aart Bik16d3a652016-09-09 10:33:50 -0700363 ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
Aart Bik009cace2016-09-16 10:15:19 -0700364 // Update loop's trip-count information.
365 ReplaceInduction(induction_analysis_->LookupInfo(lp, GetLoopControl(lp)), fetch, replacement);
Aart Bik389b3db2015-10-28 14:23:40 -0700366 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700367}
368
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000369bool InductionVarRange::IsFinite(const HLoopInformation* loop, /*out*/ int64_t* trip_count) const {
Artem Serov121f2032017-10-23 19:19:06 +0100370 bool is_constant_unused = false;
371 return CheckForFiniteAndConstantProps(loop, &is_constant_unused, trip_count);
372}
373
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000374bool InductionVarRange::HasKnownTripCount(const HLoopInformation* loop,
Artem Serov121f2032017-10-23 19:19:06 +0100375 /*out*/ int64_t* trip_count) const {
376 bool is_constant = false;
377 CheckForFiniteAndConstantProps(loop, &is_constant, trip_count);
378 return is_constant;
Aart Bik9abf8942016-10-14 09:49:42 -0700379}
380
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000381bool InductionVarRange::IsUnitStride(const HBasicBlock* context,
Aart Bikfa762962017-04-07 11:33:37 -0700382 HInstruction* instruction,
Aart Bik37dc4df2017-06-28 14:08:00 -0700383 HGraph* graph,
Aart Bik8e02e3e2017-02-28 14:41:55 -0800384 /*out*/ HInstruction** offset) const {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000385 const HLoopInformation* loop = nullptr;
Aart Bik8e02e3e2017-02-28 14:41:55 -0800386 HInductionVarAnalysis::InductionInfo* info = nullptr;
387 HInductionVarAnalysis::InductionInfo* trip = nullptr;
Aart Bikfa762962017-04-07 11:33:37 -0700388 if (HasInductionInfo(context, instruction, &loop, &info, &trip)) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800389 if (info->induction_class == HInductionVarAnalysis::kLinear &&
Aart Bik7adb6882017-03-07 13:28:51 -0800390 !HInductionVarAnalysis::IsNarrowingLinear(info)) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800391 int64_t stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000392 if (IsConstant(context, loop, info->op_a, kExact, &stride_value) && stride_value == 1) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800393 int64_t off_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000394 if (IsConstant(context, loop, info->op_b, kExact, &off_value)) {
Aart Bik37dc4df2017-06-28 14:08:00 -0700395 *offset = graph->GetConstant(info->op_b->type, off_value);
396 } else if (info->op_b->operation == HInductionVarAnalysis::kFetch) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800397 *offset = info->op_b->fetch;
Aart Bik37dc4df2017-06-28 14:08:00 -0700398 } else {
399 return false;
Aart Bik8e02e3e2017-02-28 14:41:55 -0800400 }
401 return true;
402 }
403 }
404 }
405 return false;
406}
407
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000408HInstruction* InductionVarRange::GenerateTripCount(const HLoopInformation* loop,
Aart Bik8e02e3e2017-02-28 14:41:55 -0800409 HGraph* graph,
410 HBasicBlock* block) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000411 HInstruction* loop_control = GetLoopControl(loop);
412 HInductionVarAnalysis::InductionInfo *trip = induction_analysis_->LookupInfo(loop, loop_control);
Aart Bik8e02e3e2017-02-28 14:41:55 -0800413 if (trip != nullptr && !IsUnsafeTripCount(trip)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000414 const HBasicBlock* context = loop_control->GetBlock();
Aart Bik8e02e3e2017-02-28 14:41:55 -0800415 HInstruction* taken_test = nullptr;
416 HInstruction* trip_expr = nullptr;
417 if (IsBodyTripCount(trip)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000418 if (!GenerateCode(context,
419 loop,
420 trip->op_b,
421 /*trip=*/ nullptr,
422 graph,
423 block,
424 /*is_min=*/ false,
425 &taken_test)) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800426 return nullptr;
427 }
428 }
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000429 if (GenerateCode(context,
430 loop,
431 trip->op_a,
432 /*trip=*/ nullptr,
433 graph,
434 block,
435 /*is_min=*/ false,
436 &trip_expr)) {
Aart Bik8e02e3e2017-02-28 14:41:55 -0800437 if (taken_test != nullptr) {
438 HInstruction* zero = graph->GetConstant(trip->type, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100439 ArenaAllocator* allocator = graph->GetAllocator();
440 trip_expr = Insert(block, new (allocator) HSelect(taken_test, trip_expr, zero, kNoDexPc));
Aart Bik8e02e3e2017-02-28 14:41:55 -0800441 }
442 return trip_expr;
443 }
444 }
445 return nullptr;
446}
447
Aart Bikd14c5952015-09-08 15:25:15 -0700448//
449// Private class methods.
450//
451
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000452bool InductionVarRange::CheckForFiniteAndConstantProps(const HLoopInformation* loop,
Artem Serov121f2032017-10-23 19:19:06 +0100453 /*out*/ bool* is_constant,
454 /*out*/ int64_t* trip_count) const {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000455 HInstruction* loop_control = GetLoopControl(loop);
456 HInductionVarAnalysis::InductionInfo *trip = induction_analysis_->LookupInfo(loop, loop_control);
Artem Serov121f2032017-10-23 19:19:06 +0100457 if (trip != nullptr && !IsUnsafeTripCount(trip)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000458 const HBasicBlock* context = loop_control->GetBlock();
459 *is_constant = IsConstant(context, loop, trip->op_a, kExact, trip_count);
Artem Serov121f2032017-10-23 19:19:06 +0100460 return true;
461 }
462 return false;
463}
464
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000465bool InductionVarRange::IsConstant(const HBasicBlock* context,
466 const HLoopInformation* loop,
467 HInductionVarAnalysis::InductionInfo* info,
Aart Bik97412c922016-02-19 20:14:38 -0800468 ConstantRequest request,
Aart Bik52be7e72016-06-23 11:20:41 -0700469 /*out*/ int64_t* value) const {
Aart Bik97412c922016-02-19 20:14:38 -0800470 if (info != nullptr) {
471 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
472 // any of the three requests (kExact, kAtMost, and KAtLeast).
473 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
474 info->operation == HInductionVarAnalysis::kFetch) {
Aart Bikf3e61ee2017-04-12 17:09:20 -0700475 if (IsInt64AndGet(info->fetch, value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800476 return true;
477 }
478 }
Aart Bik40fbf742016-10-31 11:02:50 -0700479 // Try range analysis on the invariant, only accept a proper range
480 // to avoid arithmetic wrap-around anomalies.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000481 Value min_val = GetVal(context, loop, info, /*trip=*/ nullptr, /*is_min=*/ true);
482 Value max_val = GetVal(context, loop, info, /*trip=*/ nullptr, /*is_min=*/ false);
Aart Bik52be7e72016-06-23 11:20:41 -0700483 if (IsConstantValue(min_val) &&
484 IsConstantValue(max_val) && min_val.b_constant <= max_val.b_constant) {
485 if ((request == kExact && min_val.b_constant == max_val.b_constant) || request == kAtMost) {
486 *value = max_val.b_constant;
487 return true;
488 } else if (request == kAtLeast) {
489 *value = min_val.b_constant;
Aart Bik358af832016-02-24 14:17:53 -0800490 return true;
491 }
492 }
Aart Bik97412c922016-02-19 20:14:38 -0800493 }
494 return false;
495}
496
Aart Bik52be7e72016-06-23 11:20:41 -0700497bool InductionVarRange::HasInductionInfo(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000498 const HBasicBlock* context,
Aart Bik52be7e72016-06-23 11:20:41 -0700499 HInstruction* instruction,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000500 /*out*/ const HLoopInformation** loop,
Aart Bik52be7e72016-06-23 11:20:41 -0700501 /*out*/ HInductionVarAnalysis::InductionInfo** info,
502 /*out*/ HInductionVarAnalysis::InductionInfo** trip) const {
Aart Bikc071a012016-12-01 10:22:31 -0800503 DCHECK(context != nullptr);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000504 HLoopInformation* lp = context->GetLoopInformation(); // closest enveloping loop
Aart Bik009cace2016-09-16 10:15:19 -0700505 if (lp != nullptr) {
506 HInductionVarAnalysis::InductionInfo* i = induction_analysis_->LookupInfo(lp, instruction);
Aart Bik52be7e72016-06-23 11:20:41 -0700507 if (i != nullptr) {
Aart Bik009cace2016-09-16 10:15:19 -0700508 *loop = lp;
Aart Bik52be7e72016-06-23 11:20:41 -0700509 *info = i;
Aart Bik009cace2016-09-16 10:15:19 -0700510 *trip = induction_analysis_->LookupInfo(lp, GetLoopControl(lp));
Aart Bik52be7e72016-06-23 11:20:41 -0700511 return true;
512 }
513 }
514 return false;
515}
516
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000517bool InductionVarRange::IsWellBehavedTripCount(const HBasicBlock* context,
518 const HLoopInformation* loop,
519 HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700520 if (trip != nullptr) {
521 // Both bounds that define a trip-count are well-behaved if they either are not defined
522 // in any loop, or are contained in a proper interval. This allows finding the min/max
523 // of an expression by chasing outward.
524 InductionVarRange range(induction_analysis_);
525 HInductionVarAnalysis::InductionInfo* lower = trip->op_b->op_a;
526 HInductionVarAnalysis::InductionInfo* upper = trip->op_b->op_b;
527 int64_t not_used = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000528 return
529 (!HasFetchInLoop(lower) || range.IsConstant(context, loop, lower, kAtLeast, &not_used)) &&
530 (!HasFetchInLoop(upper) || range.IsConstant(context, loop, upper, kAtLeast, &not_used));
Aart Bik52be7e72016-06-23 11:20:41 -0700531 }
532 return true;
533}
534
535bool InductionVarRange::HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const {
536 if (info != nullptr) {
537 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
538 info->operation == HInductionVarAnalysis::kFetch) {
539 return info->fetch->GetBlock()->GetLoopInformation() != nullptr;
540 }
541 return HasFetchInLoop(info->op_a) || HasFetchInLoop(info->op_b);
542 }
543 return false;
544}
545
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000546bool InductionVarRange::NeedsTripCount(const HBasicBlock* context,
547 const HLoopInformation* loop,
548 HInductionVarAnalysis::InductionInfo* info,
Aart Bik16d3a652016-09-09 10:33:50 -0700549 int64_t* stride_value) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700550 if (info != nullptr) {
551 if (info->induction_class == HInductionVarAnalysis::kLinear) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000552 return IsConstant(context, loop, info->op_a, kExact, stride_value);
Aart Bikdf7822e2016-12-06 10:05:30 -0800553 } else if (info->induction_class == HInductionVarAnalysis::kPolynomial) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000554 return NeedsTripCount(context, loop, info->op_a, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700555 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000556 return NeedsTripCount(context, loop, info->op_b, stride_value);
Aart Bik389b3db2015-10-28 14:23:40 -0700557 }
Aart Bikd14c5952015-09-08 15:25:15 -0700558 }
Aart Bik389b3db2015-10-28 14:23:40 -0700559 return false;
560}
561
Aart Bik7d57d7f2015-12-09 14:39:48 -0800562bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700563 if (trip != nullptr) {
564 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
565 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
566 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
567 }
568 }
569 return false;
570}
571
Aart Bik7d57d7f2015-12-09 14:39:48 -0800572bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700573 if (trip != nullptr) {
574 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
575 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
576 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
577 }
578 }
579 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700580}
581
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000582InductionVarRange::Value InductionVarRange::GetLinear(const HBasicBlock* context,
583 const HLoopInformation* loop,
584 HInductionVarAnalysis::InductionInfo* info,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800585 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800586 bool is_min) const {
Aart Bikc071a012016-12-01 10:22:31 -0800587 DCHECK(info != nullptr);
Aart Bikdf7822e2016-12-06 10:05:30 -0800588 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kLinear);
Aart Bik52be7e72016-06-23 11:20:41 -0700589 // Detect common situation where an offset inside the trip-count cancels out during range
Aart Bik7d57d7f2015-12-09 14:39:48 -0800590 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
591 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
592 // with intermediate results that only incorporate single instructions.
593 if (trip != nullptr) {
594 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
Aart Bik52be7e72016-06-23 11:20:41 -0700595 if (trip_expr->type == info->type && trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800596 int64_t stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000597 if (IsConstant(context, loop, info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800598 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800599 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800600 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
601 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
602 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700603 trip->induction_class,
604 trip->operation,
605 trip_expr->op_a,
606 trip->op_b,
607 nullptr,
608 trip->type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000609 return GetVal(context, loop, &cancelled_trip, trip, is_min);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800610 }
611 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800612 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800613 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
614 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
615 HInductionVarAnalysis::InductionInfo neg(
616 HInductionVarAnalysis::kInvariant,
617 HInductionVarAnalysis::kNeg,
618 nullptr,
619 trip_expr->op_b,
Aart Bik0d345cf2016-03-16 10:49:38 -0700620 nullptr,
621 trip->type);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800622 HInductionVarAnalysis::InductionInfo cancelled_trip(
Aart Bik0d345cf2016-03-16 10:49:38 -0700623 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr, trip->type);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000624 return SubValue(Value(0), GetVal(context, loop, &cancelled_trip, trip, !is_min));
Aart Bik7d57d7f2015-12-09 14:39:48 -0800625 }
626 }
627 }
628 }
629 }
630 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000631 return AddValue(GetMul(context, loop, info->op_a, trip, trip, is_min),
632 GetVal(context, loop, info->op_b, trip, is_min));
Aart Bik7d57d7f2015-12-09 14:39:48 -0800633}
634
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000635InductionVarRange::Value InductionVarRange::GetPolynomial(
636 const HBasicBlock* context,
637 const HLoopInformation* loop,
638 HInductionVarAnalysis::InductionInfo* info,
639 HInductionVarAnalysis::InductionInfo* trip,
640 bool is_min) const {
Aart Bikdf7822e2016-12-06 10:05:30 -0800641 DCHECK(info != nullptr);
642 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPolynomial);
643 int64_t a = 0;
644 int64_t b = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000645 if (IsConstant(context, loop, info->op_a->op_a, kExact, &a) &&
646 CanLongValueFitIntoInt(a) &&
647 a >= 0 &&
648 IsConstant(context, loop, info->op_a->op_b, kExact, &b) &&
649 CanLongValueFitIntoInt(b) &&
650 b >= 0) {
Aart Bike6bd0272016-12-16 13:57:52 -0800651 // Evaluate bounds on sum_i=0^m-1(a * i + b) + c with a,b >= 0 for
Aart Bikdf7822e2016-12-06 10:05:30 -0800652 // maximum index value m as a * (m * (m-1)) / 2 + b * m + c.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000653 // Do not simply return `c` as minimum because the trip count may be non-zero
654 // if the `context` is after the `loop` (and therefore ignoring `is_min`).
655 Value c = GetVal(context, loop, info->op_b, trip, is_min);
656 Value m = GetVal(context, loop, trip, trip, is_min);
657 Value t = DivValue(MulValue(m, SubValue(m, Value(1))), Value(2));
658 Value x = MulValue(Value(a), t);
659 Value y = MulValue(Value(b), m);
660 return AddValue(AddValue(x, y), c);
Aart Bikdf7822e2016-12-06 10:05:30 -0800661 }
662 return Value();
663}
664
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000665InductionVarRange::Value InductionVarRange::GetGeometric(const HBasicBlock* context,
666 const HLoopInformation* loop,
667 HInductionVarAnalysis::InductionInfo* info,
Aart Bikc071a012016-12-01 10:22:31 -0800668 HInductionVarAnalysis::InductionInfo* trip,
Aart Bikc071a012016-12-01 10:22:31 -0800669 bool is_min) const {
670 DCHECK(info != nullptr);
Aart Bikdf7822e2016-12-06 10:05:30 -0800671 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kGeometric);
Aart Bikc071a012016-12-01 10:22:31 -0800672 int64_t a = 0;
673 int64_t f = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000674 if (IsConstant(context, loop, info->op_a, kExact, &a) &&
Aart Bikc071a012016-12-01 10:22:31 -0800675 CanLongValueFitIntoInt(a) &&
Aart Bikf3e61ee2017-04-12 17:09:20 -0700676 IsInt64AndGet(info->fetch, &f) && f >= 1) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800677 // Conservative bounds on a * f^-i + b with f >= 1 can be computed without
678 // trip count. Other forms would require a much more elaborate evaluation.
Aart Bikc071a012016-12-01 10:22:31 -0800679 const bool is_min_a = a >= 0 ? is_min : !is_min;
680 if (info->operation == HInductionVarAnalysis::kDiv) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000681 Value b = GetVal(context, loop, info->op_b, trip, is_min);
Aart Bikdf7822e2016-12-06 10:05:30 -0800682 return is_min_a ? b : AddValue(Value(a), b);
Aart Bikc071a012016-12-01 10:22:31 -0800683 }
684 }
685 return Value();
686}
687
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000688InductionVarRange::Value InductionVarRange::GetFetch(const HBasicBlock* context,
689 const HLoopInformation* loop,
690 HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700691 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800692 bool is_min) const {
Aart Bik40fbf742016-10-31 11:02:50 -0700693 // Special case when chasing constants: single instruction that denotes trip count in the
694 // loop-body is minimal 1 and maximal, with safe trip-count, max int,
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000695 if (chase_hint_ == nullptr &&
696 IsContextInBody(context, loop) &&
697 trip != nullptr &&
698 instruction == trip->op_a->fetch) {
Aart Bik52be7e72016-06-23 11:20:41 -0700699 if (is_min) {
700 return Value(1);
Aart Bikdf7822e2016-12-06 10:05:30 -0800701 } else if (!instruction->IsConstant() && !IsUnsafeTripCount(trip)) {
Aart Bik52be7e72016-06-23 11:20:41 -0700702 return Value(std::numeric_limits<int32_t>::max());
703 }
704 }
Aart Bik40fbf742016-10-31 11:02:50 -0700705 // Unless at a constant or hint, chase the instruction a bit deeper into the HIR tree, so that
706 // it becomes more likely range analysis will compare the same instructions as terminal nodes.
707 int64_t value;
Aart Bikf3e61ee2017-04-12 17:09:20 -0700708 if (IsInt64AndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
Aart Bik40fbf742016-10-31 11:02:50 -0700709 // Proper constant reveals best information.
710 return Value(static_cast<int32_t>(value));
711 } else if (instruction == chase_hint_) {
712 // At hint, fetch is represented by itself.
713 return Value(instruction, 1, 0);
714 } else if (instruction->IsAdd()) {
715 // Incorporate suitable constants in the chased value.
Aart Bikf3e61ee2017-04-12 17:09:20 -0700716 if (IsInt64AndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
Aart Bik97412c922016-02-19 20:14:38 -0800717 return AddValue(Value(static_cast<int32_t>(value)),
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000718 GetFetch(context, loop, instruction->InputAt(1), trip, is_min));
Aart Bikf3e61ee2017-04-12 17:09:20 -0700719 } else if (IsInt64AndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000720 return AddValue(GetFetch(context, loop, instruction->InputAt(0), trip, is_min),
Aart Bik97412c922016-02-19 20:14:38 -0800721 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700722 }
Aart Bik8e9090b2017-09-08 16:46:50 -0700723 } else if (instruction->IsSub()) {
724 // Incorporate suitable constants in the chased value.
725 if (IsInt64AndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
726 return SubValue(Value(static_cast<int32_t>(value)),
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000727 GetFetch(context, loop, instruction->InputAt(1), trip, !is_min));
Aart Bik8e9090b2017-09-08 16:46:50 -0700728 } else if (IsInt64AndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000729 return SubValue(GetFetch(context, loop, instruction->InputAt(0), trip, is_min),
Aart Bik8e9090b2017-09-08 16:46:50 -0700730 Value(static_cast<int32_t>(value)));
731 }
Aart Bik52be7e72016-06-23 11:20:41 -0700732 } else if (instruction->IsArrayLength()) {
Aart Bik40fbf742016-10-31 11:02:50 -0700733 // Exploit length properties when chasing constants or chase into a new array declaration.
Aart Bik52be7e72016-06-23 11:20:41 -0700734 if (chase_hint_ == nullptr) {
735 return is_min ? Value(0) : Value(std::numeric_limits<int32_t>::max());
736 } else if (instruction->InputAt(0)->IsNewArray()) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000737 return GetFetch(
738 context, loop, instruction->InputAt(0)->AsNewArray()->GetLength(), trip, is_min);
Aart Bik52be7e72016-06-23 11:20:41 -0700739 }
Aart Bik0d345cf2016-03-16 10:49:38 -0700740 } else if (instruction->IsTypeConversion()) {
Aart Bik40fbf742016-10-31 11:02:50 -0700741 // Since analysis is 32-bit (or narrower), chase beyond widening along the path.
Aart Bike6bd0272016-12-16 13:57:52 -0800742 // For example, this discovers the length in: for (long i = 0; i < a.length; i++);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100743 if (instruction->AsTypeConversion()->GetInputType() == DataType::Type::kInt32 &&
744 instruction->AsTypeConversion()->GetResultType() == DataType::Type::kInt64) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000745 return GetFetch(context, loop, instruction->InputAt(0), trip, is_min);
Aart Bik0d345cf2016-03-16 10:49:38 -0700746 }
Aart Bik52be7e72016-06-23 11:20:41 -0700747 }
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000748 // Chase an invariant fetch that is defined by another loop if the trip-count used
Aart Bik52be7e72016-06-23 11:20:41 -0700749 // so far is well-behaved in both bounds and the next trip-count is safe.
750 // Example:
751 // for (int i = 0; i <= 100; i++) // safe
752 // for (int j = 0; j <= i; j++) // well-behaved
753 // j is in range [0, i ] (if i is chase hint)
754 // or in range [0, 100] (otherwise)
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000755 // Example:
756 // for (i = 0; i < 100; ++i)
757 // <some-code>
758 // for (j = 0; j < 10; ++j)
759 // sum += i; // The `i` is a "fetch" of a loop Phi from the previous loop.
760 const HLoopInformation* next_loop = nullptr;
Aart Bik52be7e72016-06-23 11:20:41 -0700761 HInductionVarAnalysis::InductionInfo* next_info = nullptr;
762 HInductionVarAnalysis::InductionInfo* next_trip = nullptr;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000763 if (HasInductionInfo(instruction->GetBlock(), instruction, &next_loop, &next_info, &next_trip) &&
764 IsWellBehavedTripCount(context, next_loop, trip) &&
Aart Bik52be7e72016-06-23 11:20:41 -0700765 !IsUnsafeTripCount(next_trip)) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000766 return GetVal(context, next_loop, next_info, next_trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700767 }
Aart Bik40fbf742016-10-31 11:02:50 -0700768 // Fetch is represented by itself.
Aart Bikd14c5952015-09-08 15:25:15 -0700769 return Value(instruction, 1, 0);
770}
771
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000772InductionVarRange::Value InductionVarRange::GetVal(const HBasicBlock* context,
773 const HLoopInformation* loop,
774 HInductionVarAnalysis::InductionInfo* info,
Aart Bikcd26feb2015-09-23 17:50:50 -0700775 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800776 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700777 if (info != nullptr) {
778 switch (info->induction_class) {
779 case HInductionVarAnalysis::kInvariant:
780 // Invariants.
781 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700782 case HInductionVarAnalysis::kAdd:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000783 return AddValue(GetVal(context, loop, info->op_a, trip, is_min),
784 GetVal(context, loop, info->op_b, trip, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700785 case HInductionVarAnalysis::kSub: // second reversed!
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000786 return SubValue(GetVal(context, loop, info->op_a, trip, is_min),
787 GetVal(context, loop, info->op_b, trip, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700788 case HInductionVarAnalysis::kNeg: // second reversed!
789 return SubValue(Value(0),
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000790 GetVal(context, loop, info->op_b, trip, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700791 case HInductionVarAnalysis::kMul:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000792 return GetMul(context, loop, info->op_a, info->op_b, trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700793 case HInductionVarAnalysis::kDiv:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000794 return GetDiv(context, loop, info->op_a, info->op_b, trip, is_min);
Aart Bikdf7822e2016-12-06 10:05:30 -0800795 case HInductionVarAnalysis::kRem:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000796 return GetRem(context, loop, info->op_a, info->op_b);
Aart Bik7dc96932016-10-12 10:01:05 -0700797 case HInductionVarAnalysis::kXor:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000798 return GetXor(context, loop, info->op_a, info->op_b);
Aart Bikd14c5952015-09-08 15:25:15 -0700799 case HInductionVarAnalysis::kFetch:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000800 return GetFetch(context, loop, info->fetch, trip, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700801 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700802 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000803 if (UseFullTripCount(context, loop, is_min)) {
804 // Return the full trip count (do not subtract 1 as we do in loop body).
805 return GetVal(context, loop, info->op_a, trip, /*is_min=*/ false);
Aart Bik9401f532015-09-28 16:25:56 -0700806 }
807 FALLTHROUGH_INTENDED;
808 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700809 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700810 if (is_min) {
811 return Value(0);
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000812 } else if (IsContextInBody(context, loop)) {
813 return SubValue(GetVal(context, loop, info->op_a, trip, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700814 }
815 break;
816 default:
817 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700818 }
819 break;
Aart Bik52be7e72016-06-23 11:20:41 -0700820 case HInductionVarAnalysis::kLinear:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000821 return CorrectForType(GetLinear(context, loop, info, trip, is_min), info->type);
Aart Bikc071a012016-12-01 10:22:31 -0800822 case HInductionVarAnalysis::kPolynomial:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000823 return GetPolynomial(context, loop, info, trip, is_min);
Aart Bikc071a012016-12-01 10:22:31 -0800824 case HInductionVarAnalysis::kGeometric:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000825 return GetGeometric(context, loop, info, trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700826 case HInductionVarAnalysis::kWrapAround:
827 case HInductionVarAnalysis::kPeriodic:
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000828 return MergeVal(GetVal(context, loop, info->op_a, trip, is_min),
829 GetVal(context, loop, info->op_b, trip, is_min),
830 is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700831 }
832 }
Aart Bikb3365e02015-09-21 14:45:05 -0700833 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700834}
835
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000836InductionVarRange::Value InductionVarRange::GetMul(const HBasicBlock* context,
837 const HLoopInformation* loop,
838 HInductionVarAnalysis::InductionInfo* info1,
Aart Bikd14c5952015-09-08 15:25:15 -0700839 HInductionVarAnalysis::InductionInfo* info2,
840 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800841 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700842 // Constant times range.
843 int64_t value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000844 if (IsConstant(context, loop, info1, kExact, &value)) {
845 return MulRangeAndConstant(context, loop, value, info2, trip, is_min);
846 } else if (IsConstant(context, loop, info2, kExact, &value)) {
847 return MulRangeAndConstant(context, loop, value, info1, trip, is_min);
Aart Bik52be7e72016-06-23 11:20:41 -0700848 }
849 // Interval ranges.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000850 Value v1_min = GetVal(context, loop, info1, trip, /*is_min=*/ true);
851 Value v1_max = GetVal(context, loop, info1, trip, /*is_min=*/ false);
852 Value v2_min = GetVal(context, loop, info2, trip, /*is_min=*/ true);
853 Value v2_max = GetVal(context, loop, info2, trip, /*is_min=*/ false);
Aart Bik97412c922016-02-19 20:14:38 -0800854 // Positive range vs. positive or negative range.
855 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
856 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
857 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
858 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
859 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700860 }
Aart Bik97412c922016-02-19 20:14:38 -0800861 }
862 // Negative range vs. positive or negative range.
863 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
864 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
865 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
866 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
867 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700868 }
869 }
Aart Bikb3365e02015-09-21 14:45:05 -0700870 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700871}
872
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000873InductionVarRange::Value InductionVarRange::GetDiv(const HBasicBlock* context,
874 const HLoopInformation* loop,
875 HInductionVarAnalysis::InductionInfo* info1,
Aart Bikd14c5952015-09-08 15:25:15 -0700876 HInductionVarAnalysis::InductionInfo* info2,
877 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800878 bool is_min) const {
Aart Bik52be7e72016-06-23 11:20:41 -0700879 // Range divided by constant.
880 int64_t value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000881 if (IsConstant(context, loop, info2, kExact, &value)) {
882 return DivRangeAndConstant(context, loop, value, info1, trip, is_min);
Aart Bik52be7e72016-06-23 11:20:41 -0700883 }
884 // Interval ranges.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000885 Value v1_min = GetVal(context, loop, info1, trip, /*is_min=*/ true);
886 Value v1_max = GetVal(context, loop, info1, trip, /*is_min=*/ false);
887 Value v2_min = GetVal(context, loop, info2, trip, /*is_min=*/ true);
888 Value v2_max = GetVal(context, loop, info2, trip, /*is_min=*/ false);
Aart Bik97412c922016-02-19 20:14:38 -0800889 // Positive range vs. positive or negative range.
890 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
891 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
892 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
893 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
894 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700895 }
Aart Bik97412c922016-02-19 20:14:38 -0800896 }
897 // Negative range vs. positive or negative range.
898 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
899 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
900 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
901 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
902 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700903 }
904 }
Aart Bikb3365e02015-09-21 14:45:05 -0700905 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700906}
907
Aart Bikdf7822e2016-12-06 10:05:30 -0800908InductionVarRange::Value InductionVarRange::GetRem(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000909 const HBasicBlock* context,
910 const HLoopInformation* loop,
Aart Bikdf7822e2016-12-06 10:05:30 -0800911 HInductionVarAnalysis::InductionInfo* info1,
912 HInductionVarAnalysis::InductionInfo* info2) const {
913 int64_t v1 = 0;
914 int64_t v2 = 0;
915 // Only accept exact values.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000916 if (IsConstant(context, loop, info1, kExact, &v1) &&
917 IsConstant(context, loop, info2, kExact, &v2) &&
918 v2 != 0) {
Aart Bikdf7822e2016-12-06 10:05:30 -0800919 int64_t value = v1 % v2;
920 if (CanLongValueFitIntoInt(value)) {
921 return Value(static_cast<int32_t>(value));
922 }
923 }
924 return Value();
925}
926
Aart Bik7dc96932016-10-12 10:01:05 -0700927InductionVarRange::Value InductionVarRange::GetXor(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000928 const HBasicBlock* context,
929 const HLoopInformation* loop,
Aart Bik7dc96932016-10-12 10:01:05 -0700930 HInductionVarAnalysis::InductionInfo* info1,
931 HInductionVarAnalysis::InductionInfo* info2) const {
932 int64_t v1 = 0;
933 int64_t v2 = 0;
934 // Only accept exact values.
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000935 if (IsConstant(context, loop, info1, kExact, &v1) &&
936 IsConstant(context, loop, info2, kExact, &v2)) {
Aart Bik7dc96932016-10-12 10:01:05 -0700937 int64_t value = v1 ^ v2;
938 if (CanLongValueFitIntoInt(value)) {
939 return Value(static_cast<int32_t>(value));
940 }
941 }
942 return Value();
943}
944
Aart Bik52be7e72016-06-23 11:20:41 -0700945InductionVarRange::Value InductionVarRange::MulRangeAndConstant(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000946 const HBasicBlock* context,
947 const HLoopInformation* loop,
Aart Bik52be7e72016-06-23 11:20:41 -0700948 int64_t value,
949 HInductionVarAnalysis::InductionInfo* info,
950 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik52be7e72016-06-23 11:20:41 -0700951 bool is_min) const {
952 if (CanLongValueFitIntoInt(value)) {
953 Value c(static_cast<int32_t>(value));
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000954 return MulValue(GetVal(context, loop, info, trip, is_min == value >= 0), c);
Aart Bik52be7e72016-06-23 11:20:41 -0700955 }
956 return Value();
Aart Bik97412c922016-02-19 20:14:38 -0800957}
958
Aart Bik52be7e72016-06-23 11:20:41 -0700959InductionVarRange::Value InductionVarRange::DivRangeAndConstant(
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000960 const HBasicBlock* context,
961 const HLoopInformation* loop,
Aart Bik52be7e72016-06-23 11:20:41 -0700962 int64_t value,
963 HInductionVarAnalysis::InductionInfo* info,
964 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik52be7e72016-06-23 11:20:41 -0700965 bool is_min) const {
966 if (CanLongValueFitIntoInt(value)) {
967 Value c(static_cast<int32_t>(value));
Vladimir Marko8d100ba2022-03-04 10:13:10 +0000968 return DivValue(GetVal(context, loop, info, trip, is_min == value >= 0), c);
Aart Bik52be7e72016-06-23 11:20:41 -0700969 }
970 return Value();
Aart Bik9401f532015-09-28 16:25:56 -0700971}
972
Aart Bik7d57d7f2015-12-09 14:39:48 -0800973InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700974 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bike6bd0272016-12-16 13:57:52 -0800975 int32_t b = v1.b_constant + v2.b_constant;
Aart Bikd14c5952015-09-08 15:25:15 -0700976 if (v1.a_constant == 0) {
977 return Value(v2.instruction, v2.a_constant, b);
978 } else if (v2.a_constant == 0) {
979 return Value(v1.instruction, v1.a_constant, b);
980 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
981 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
982 }
983 }
Aart Bikb3365e02015-09-21 14:45:05 -0700984 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700985}
986
Aart Bik7d57d7f2015-12-09 14:39:48 -0800987InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700988 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bike6bd0272016-12-16 13:57:52 -0800989 int32_t b = v1.b_constant - v2.b_constant;
Aart Bikd14c5952015-09-08 15:25:15 -0700990 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
991 return Value(v2.instruction, -v2.a_constant, b);
992 } else if (v2.a_constant == 0) {
993 return Value(v1.instruction, v1.a_constant, b);
994 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
995 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
996 }
997 }
Aart Bikb3365e02015-09-21 14:45:05 -0700998 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700999}
1000
Aart Bik7d57d7f2015-12-09 14:39:48 -08001001InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -07001002 if (v1.is_known && v2.is_known) {
1003 if (v1.a_constant == 0) {
1004 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
1005 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
1006 }
1007 } else if (v2.a_constant == 0) {
1008 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
1009 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
1010 }
Aart Bikd14c5952015-09-08 15:25:15 -07001011 }
1012 }
Aart Bikb3365e02015-09-21 14:45:05 -07001013 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -07001014}
1015
Aart Bik7d57d7f2015-12-09 14:39:48 -08001016InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -07001017 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -07001018 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
1019 return Value(v1.b_constant / v2.b_constant);
1020 }
1021 }
Aart Bikb3365e02015-09-21 14:45:05 -07001022 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -07001023}
1024
Aart Bik7d57d7f2015-12-09 14:39:48 -08001025InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -07001026 if (v1.is_known && v2.is_known) {
1027 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -07001028 return Value(v1.instruction, v1.a_constant,
1029 is_min ? std::min(v1.b_constant, v2.b_constant)
1030 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -07001031 }
Aart Bikd14c5952015-09-08 15:25:15 -07001032 }
Aart Bikb3365e02015-09-21 14:45:05 -07001033 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -07001034}
1035
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001036bool InductionVarRange::GenerateRangeOrLastValue(const HBasicBlock* context,
Aart Bik9abf8942016-10-14 09:49:42 -07001037 HInstruction* instruction,
1038 bool is_last_value,
1039 HGraph* graph,
1040 HBasicBlock* block,
1041 /*out*/HInstruction** lower,
1042 /*out*/HInstruction** upper,
1043 /*out*/HInstruction** taken_test,
1044 /*out*/int64_t* stride_value,
1045 /*out*/bool* needs_finite_test,
1046 /*out*/bool* needs_taken_test) const {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001047 const HLoopInformation* loop = nullptr;
Aart Bik52be7e72016-06-23 11:20:41 -07001048 HInductionVarAnalysis::InductionInfo* info = nullptr;
1049 HInductionVarAnalysis::InductionInfo* trip = nullptr;
1050 if (!HasInductionInfo(context, instruction, &loop, &info, &trip) || trip == nullptr) {
1051 return false; // codegen needs all information, including tripcount
Aart Bik97412c922016-02-19 20:14:38 -08001052 }
1053 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
1054 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
1055 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
1056 // code does not use the trip-count explicitly (since there could be an implicit relation
1057 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik16d3a652016-09-09 10:33:50 -07001058 *stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001059 *needs_finite_test = NeedsTripCount(context, loop, info, stride_value) && IsUnsafeTripCount(trip);
Aart Bik97412c922016-02-19 20:14:38 -08001060 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik16d3a652016-09-09 10:33:50 -07001061 // Handle last value request.
1062 if (is_last_value) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001063 DCHECK(!IsContextInBody(context, loop));
Aart Bikc071a012016-12-01 10:22:31 -08001064 switch (info->induction_class) {
1065 case HInductionVarAnalysis::kLinear:
1066 if (*stride_value > 0) {
1067 lower = nullptr;
Santiago Aboy Solanes4f18b942022-07-21 10:31:21 +01001068 return GenerateLastValueLinear(
1069 context, loop, info, trip, graph, block, /*is_min=*/false, upper);
Aart Bikc071a012016-12-01 10:22:31 -08001070 } else {
1071 upper = nullptr;
Santiago Aboy Solanes4f18b942022-07-21 10:31:21 +01001072 return GenerateLastValueLinear(
1073 context, loop, info, trip, graph, block, /*is_min=*/true, lower);
Aart Bikc071a012016-12-01 10:22:31 -08001074 }
Aart Bikdf7822e2016-12-06 10:05:30 -08001075 case HInductionVarAnalysis::kPolynomial:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001076 return GenerateLastValuePolynomial(context, loop, info, trip, graph, block, lower);
Aart Bikc071a012016-12-01 10:22:31 -08001077 case HInductionVarAnalysis::kGeometric:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001078 return GenerateLastValueGeometric(context, loop, info, trip, graph, block, lower);
Aart Bikdf7822e2016-12-06 10:05:30 -08001079 case HInductionVarAnalysis::kWrapAround:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001080 return GenerateLastValueWrapAround(context, loop, info, trip, graph, block, lower);
Aart Bikc071a012016-12-01 10:22:31 -08001081 case HInductionVarAnalysis::kPeriodic:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001082 return GenerateLastValuePeriodic(
1083 context, loop, info, trip, graph, block, lower, needs_taken_test);
Aart Bikc071a012016-12-01 10:22:31 -08001084 default:
1085 return false;
Aart Bik16d3a652016-09-09 10:33:50 -07001086 }
1087 }
Aart Bik97412c922016-02-19 20:14:38 -08001088 // Code generation for taken test: generate the code when requested or otherwise analyze
1089 // if code generation is feasible when taken test is needed.
1090 if (taken_test != nullptr) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001091 return GenerateCode(context,
1092 loop,
1093 trip->op_b,
1094 /*trip=*/ nullptr,
1095 graph,
1096 block,
1097 /*is_min=*/ false,
1098 taken_test);
Aart Bik97412c922016-02-19 20:14:38 -08001099 } else if (*needs_taken_test) {
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001100 if (!GenerateCode(context,
1101 loop,
1102 trip->op_b,
1103 /*trip=*/ nullptr,
1104 /*graph=*/ nullptr,
1105 /*block=*/ nullptr,
1106 /*is_min=*/ false,
1107 /*result=*/ nullptr)) {
Aart Bik97412c922016-02-19 20:14:38 -08001108 return false;
1109 }
1110 }
1111 // Code generation for lower and upper.
1112 return
1113 // Success on lower if invariant (not set), or code can be generated.
1114 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001115 GenerateCode(context, loop, info, trip, graph, block, /*is_min=*/ true, lower)) &&
Aart Bik97412c922016-02-19 20:14:38 -08001116 // And success on upper.
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001117 GenerateCode(context, loop, info, trip, graph, block, /*is_min=*/ false, upper);
Aart Bikaec3cce2015-10-14 17:44:55 -07001118}
1119
Santiago Aboy Solanes4f18b942022-07-21 10:31:21 +01001120bool InductionVarRange::GenerateLastValueLinear(const HBasicBlock* context,
1121 const HLoopInformation* loop,
1122 HInductionVarAnalysis::InductionInfo* info,
1123 HInductionVarAnalysis::InductionInfo* trip,
1124 HGraph* graph,
1125 HBasicBlock* block,
1126 bool is_min,
1127 /*out*/ HInstruction** result) const {
1128 DataType::Type type = info->type;
1129 // Avoid any narrowing linear induction or any type mismatch between the linear induction and the
1130 // trip count expression.
Santiago Aboy Solanesdb692462022-08-17 16:34:40 +01001131 if (HInductionVarAnalysis::IsNarrowingLinear(info) || trip->type != type) {
Santiago Aboy Solanes4f18b942022-07-21 10:31:21 +01001132 return false;
1133 }
1134
1135 // Stride value must be a known constant that fits into int32.
1136 int64_t stride_value = 0;
1137 if (!IsConstant(context, loop, info->op_a, kExact, &stride_value) ||
1138 !CanLongValueFitIntoInt(stride_value)) {
1139 return false;
1140 }
1141
1142 // We require `a` to be a constant value that didn't overflow.
1143 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
1144 Value val_a = GetVal(context, loop, trip, trip, is_min_a);
1145 HInstruction* opb;
1146 if (!IsConstantValue(val_a) ||
1147 !GenerateCode(context, loop, info->op_b, trip, graph, block, is_min, &opb)) {
1148 return false;
1149 }
1150
1151 if (graph != nullptr) {
1152 ArenaAllocator* allocator = graph->GetAllocator();
1153 HInstruction* oper;
1154 HInstruction* opa = graph->GetConstant(type, val_a.b_constant);
1155 if (stride_value == 1) {
1156 oper = new (allocator) HAdd(type, opa, opb);
1157 } else if (stride_value == -1) {
1158 oper = new (graph->GetAllocator()) HSub(type, opb, opa);
1159 } else {
1160 HInstruction* mul = new (allocator) HMul(type, graph->GetConstant(type, stride_value), opa);
1161 oper = new (allocator) HAdd(type, Insert(block, mul), opb);
1162 }
1163 *result = Insert(block, oper);
1164 }
1165 return true;
1166}
1167
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001168bool InductionVarRange::GenerateLastValuePolynomial(const HBasicBlock* context,
1169 const HLoopInformation* loop,
1170 HInductionVarAnalysis::InductionInfo* info,
Aart Bikdf7822e2016-12-06 10:05:30 -08001171 HInductionVarAnalysis::InductionInfo* trip,
1172 HGraph* graph,
1173 HBasicBlock* block,
1174 /*out*/HInstruction** result) const {
1175 DCHECK(info != nullptr);
1176 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPolynomial);
1177 // Detect known coefficients and trip count (always taken).
1178 int64_t a = 0;
1179 int64_t b = 0;
1180 int64_t m = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001181 if (IsConstant(context, loop, info->op_a->op_a, kExact, &a) &&
1182 IsConstant(context, loop, info->op_a->op_b, kExact, &b) &&
1183 IsConstant(context, loop, trip->op_a, kExact, &m) &&
1184 m >= 1) {
Aart Bikd0a022d2016-12-13 11:22:31 -08001185 // Evaluate bounds on sum_i=0^m-1(a * i + b) + c for known
Aart Bikdf7822e2016-12-06 10:05:30 -08001186 // maximum index value m as a * (m * (m-1)) / 2 + b * m + c.
Aart Bike6bd0272016-12-16 13:57:52 -08001187 HInstruction* c = nullptr;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001188 if (GenerateCode(context,
1189 loop,
1190 info->op_b,
1191 /*trip=*/ nullptr,
1192 graph,
1193 block,
1194 /*is_min=*/ false,
1195 graph ? &c : nullptr)) {
Aart Bikdf7822e2016-12-06 10:05:30 -08001196 if (graph != nullptr) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001197 DataType::Type type = info->type;
Aart Bikdf7822e2016-12-06 10:05:30 -08001198 int64_t sum = a * ((m * (m - 1)) / 2) + b * m;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001199 if (type != DataType::Type::kInt64) {
Aart Bike6bd0272016-12-16 13:57:52 -08001200 sum = static_cast<int32_t>(sum); // okay to truncate
1201 }
1202 *result =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001203 Insert(block, new (graph->GetAllocator()) HAdd(type, graph->GetConstant(type, sum), c));
Aart Bikdf7822e2016-12-06 10:05:30 -08001204 }
1205 return true;
1206 }
1207 }
1208 return false;
1209}
1210
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001211bool InductionVarRange::GenerateLastValueGeometric(const HBasicBlock* context,
1212 const HLoopInformation* loop,
1213 HInductionVarAnalysis::InductionInfo* info,
Aart Bikc071a012016-12-01 10:22:31 -08001214 HInductionVarAnalysis::InductionInfo* trip,
1215 HGraph* graph,
1216 HBasicBlock* block,
1217 /*out*/HInstruction** result) const {
1218 DCHECK(info != nullptr);
Aart Bikdf7822e2016-12-06 10:05:30 -08001219 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kGeometric);
Aart Bikc071a012016-12-01 10:22:31 -08001220 // Detect known base and trip count (always taken).
1221 int64_t f = 0;
Aart Bike6bd0272016-12-16 13:57:52 -08001222 int64_t m = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001223 if (IsInt64AndGet(info->fetch, &f) &&
1224 f >= 1 &&
1225 IsConstant(context, loop, trip->op_a, kExact, &m) &&
1226 m >= 1) {
Aart Bikc071a012016-12-01 10:22:31 -08001227 HInstruction* opa = nullptr;
1228 HInstruction* opb = nullptr;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001229 if (GenerateCode(
1230 context, loop, info->op_a, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, &opa) &&
1231 GenerateCode(
1232 context, loop, info->op_b, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, &opb)) {
Aart Bikc071a012016-12-01 10:22:31 -08001233 if (graph != nullptr) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001234 DataType::Type type = info->type;
Aart Bikd3ba6262017-01-30 14:37:12 -08001235 // Compute f ^ m for known maximum index value m.
1236 bool overflow = false;
1237 int64_t fpow = IntPow(f, m, &overflow);
1238 if (info->operation == HInductionVarAnalysis::kDiv) {
1239 // For division, any overflow truncates to zero.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001240 if (overflow || (type != DataType::Type::kInt64 && !CanLongValueFitIntoInt(fpow))) {
Aart Bikd3ba6262017-01-30 14:37:12 -08001241 fpow = 0;
1242 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001243 } else if (type != DataType::Type::kInt64) {
Aart Bikd3ba6262017-01-30 14:37:12 -08001244 // For multiplication, okay to truncate to required precision.
1245 DCHECK(info->operation == HInductionVarAnalysis::kMul);
1246 fpow = static_cast<int32_t>(fpow);
1247 }
1248 // Generate code.
Aart Bike6bd0272016-12-16 13:57:52 -08001249 if (fpow == 0) {
Aart Bikc071a012016-12-01 10:22:31 -08001250 // Special case: repeated mul/div always yields zero.
Aart Bike6bd0272016-12-16 13:57:52 -08001251 *result = graph->GetConstant(type, 0);
Aart Bikc071a012016-12-01 10:22:31 -08001252 } else {
Aart Bike6bd0272016-12-16 13:57:52 -08001253 // Last value: a * f ^ m + b or a * f ^ -m + b.
Aart Bike6bd0272016-12-16 13:57:52 -08001254 HInstruction* e = nullptr;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001255 ArenaAllocator* allocator = graph->GetAllocator();
Aart Bike6bd0272016-12-16 13:57:52 -08001256 if (info->operation == HInductionVarAnalysis::kMul) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001257 e = new (allocator) HMul(type, opa, graph->GetConstant(type, fpow));
Aart Bike6bd0272016-12-16 13:57:52 -08001258 } else {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001259 e = new (allocator) HDiv(type, opa, graph->GetConstant(type, fpow), kNoDexPc);
Aart Bike6bd0272016-12-16 13:57:52 -08001260 }
Vladimir Markoca6fff82017-10-03 14:49:14 +01001261 *result = Insert(block, new (allocator) HAdd(type, Insert(block, e), opb));
Aart Bikc071a012016-12-01 10:22:31 -08001262 }
1263 }
1264 return true;
1265 }
1266 }
1267 return false;
1268}
1269
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001270bool InductionVarRange::GenerateLastValueWrapAround(const HBasicBlock* context,
1271 const HLoopInformation* loop,
1272 HInductionVarAnalysis::InductionInfo* info,
Aart Bikdf7822e2016-12-06 10:05:30 -08001273 HInductionVarAnalysis::InductionInfo* trip,
1274 HGraph* graph,
1275 HBasicBlock* block,
1276 /*out*/HInstruction** result) const {
1277 DCHECK(info != nullptr);
1278 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kWrapAround);
1279 // Count depth.
1280 int32_t depth = 0;
1281 for (; info->induction_class == HInductionVarAnalysis::kWrapAround;
1282 info = info->op_b, ++depth) {}
1283 // Handle wrap(x, wrap(.., y)) if trip count reaches an invariant at end.
Aart Bike6bd0272016-12-16 13:57:52 -08001284 // TODO: generalize, but be careful to adjust the terminal.
1285 int64_t m = 0;
Aart Bikdf7822e2016-12-06 10:05:30 -08001286 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001287 IsConstant(context, loop, trip->op_a, kExact, &m) &&
1288 m >= depth) {
1289 return GenerateCode(
1290 context, loop, info, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, result);
Aart Bikdf7822e2016-12-06 10:05:30 -08001291 }
1292 return false;
1293}
1294
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001295bool InductionVarRange::GenerateLastValuePeriodic(const HBasicBlock* context,
1296 const HLoopInformation* loop,
1297 HInductionVarAnalysis::InductionInfo* info,
Aart Bik9abf8942016-10-14 09:49:42 -07001298 HInductionVarAnalysis::InductionInfo* trip,
1299 HGraph* graph,
1300 HBasicBlock* block,
1301 /*out*/HInstruction** result,
1302 /*out*/bool* needs_taken_test) const {
Aart Bikc071a012016-12-01 10:22:31 -08001303 DCHECK(info != nullptr);
Aart Bikdf7822e2016-12-06 10:05:30 -08001304 DCHECK_EQ(info->induction_class, HInductionVarAnalysis::kPeriodic);
Aart Bik8523ea12017-06-01 15:45:09 -07001305 // Count period and detect all-invariants.
Aart Bike6bd0272016-12-16 13:57:52 -08001306 int64_t period = 1;
Aart Bik8523ea12017-06-01 15:45:09 -07001307 bool all_invariants = true;
1308 HInductionVarAnalysis::InductionInfo* p = info;
1309 for (; p->induction_class == HInductionVarAnalysis::kPeriodic; p = p->op_b, ++period) {
1310 DCHECK_EQ(p->op_a->induction_class, HInductionVarAnalysis::kInvariant);
1311 if (p->op_a->operation != HInductionVarAnalysis::kFetch) {
1312 all_invariants = false;
1313 }
1314 }
1315 DCHECK_EQ(p->induction_class, HInductionVarAnalysis::kInvariant);
1316 if (p->operation != HInductionVarAnalysis::kFetch) {
1317 all_invariants = false;
1318 }
1319 // Don't rely on FP arithmetic to be precise, unless the full period
1320 // consist of pre-computed expressions only.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001321 if (info->type == DataType::Type::kFloat32 || info->type == DataType::Type::kFloat64) {
Aart Bik8523ea12017-06-01 15:45:09 -07001322 if (!all_invariants) {
1323 return false;
1324 }
1325 }
Aart Bike6bd0272016-12-16 13:57:52 -08001326 // Handle any periodic(x, periodic(.., y)) for known maximum index value m.
1327 int64_t m = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001328 if (IsConstant(context, loop, trip->op_a, kExact, &m) && m >= 1) {
Aart Bike6bd0272016-12-16 13:57:52 -08001329 int64_t li = m % period;
1330 for (int64_t i = 0; i < li; info = info->op_b, i++) {}
1331 if (info->induction_class == HInductionVarAnalysis::kPeriodic) {
1332 info = info->op_a;
1333 }
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001334 return GenerateCode(
1335 context, loop, info, /*trip=*/ nullptr, graph, block, /*is_min=*/ false, result);
Aart Bik9abf8942016-10-14 09:49:42 -07001336 }
Aart Bike6bd0272016-12-16 13:57:52 -08001337 // Handle periodic(x, y) using even/odd-select on trip count. Enter trip count expression
1338 // directly to obtain the maximum index value t even if taken test is needed.
1339 HInstruction* x = nullptr;
1340 HInstruction* y = nullptr;
1341 HInstruction* t = nullptr;
1342 if (period == 2 &&
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001343 GenerateCode(context,
1344 loop,
1345 info->op_a,
1346 /*trip=*/ nullptr,
1347 graph,
1348 block,
1349 /*is_min=*/ false,
1350 graph ? &x : nullptr) &&
1351 GenerateCode(context,
1352 loop,
1353 info->op_b,
1354 /*trip=*/ nullptr,
1355 graph,
1356 block,
1357 /*is_min=*/ false,
1358 graph ? &y : nullptr) &&
1359 GenerateCode(context,
1360 loop,
1361 trip->op_a,
1362 /*trip=*/ nullptr,
1363 graph,
1364 block,
1365 /*is_min=*/ false,
1366 graph ? &t : nullptr)) {
Aart Bike6bd0272016-12-16 13:57:52 -08001367 // During actual code generation (graph != nullptr), generate is_even ? x : y.
Aart Bik9abf8942016-10-14 09:49:42 -07001368 if (graph != nullptr) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001369 DataType::Type type = trip->type;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001370 ArenaAllocator* allocator = graph->GetAllocator();
Aart Bike6bd0272016-12-16 13:57:52 -08001371 HInstruction* msk =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001372 Insert(block, new (allocator) HAnd(type, t, graph->GetConstant(type, 1)));
Aart Bike6bd0272016-12-16 13:57:52 -08001373 HInstruction* is_even =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001374 Insert(block, new (allocator) HEqual(msk, graph->GetConstant(type, 0), kNoDexPc));
1375 *result = Insert(block, new (graph->GetAllocator()) HSelect(is_even, x, y, kNoDexPc));
Aart Bik9abf8942016-10-14 09:49:42 -07001376 }
1377 // Guard select with taken test if needed.
1378 if (*needs_taken_test) {
Aart Bike6bd0272016-12-16 13:57:52 -08001379 HInstruction* is_taken = nullptr;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001380 if (GenerateCode(context,
1381 loop,
1382 trip->op_b,
1383 /*trip=*/ nullptr,
1384 graph,
1385 block,
1386 /*is_min=*/ false,
1387 graph ? &is_taken : nullptr)) {
Aart Bike6bd0272016-12-16 13:57:52 -08001388 if (graph != nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001389 ArenaAllocator* allocator = graph->GetAllocator();
1390 *result = Insert(block, new (allocator) HSelect(is_taken, *result, x, kNoDexPc));
Aart Bike6bd0272016-12-16 13:57:52 -08001391 }
1392 *needs_taken_test = false; // taken care of
1393 } else {
Aart Bik9abf8942016-10-14 09:49:42 -07001394 return false;
Aart Bik9abf8942016-10-14 09:49:42 -07001395 }
Aart Bik9abf8942016-10-14 09:49:42 -07001396 }
1397 return true;
1398 }
1399 return false;
1400}
1401
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001402bool InductionVarRange::GenerateCode(const HBasicBlock* context,
1403 const HLoopInformation* loop,
1404 HInductionVarAnalysis::InductionInfo* info,
Aart Bikaec3cce2015-10-14 17:44:55 -07001405 HInductionVarAnalysis::InductionInfo* trip,
1406 HGraph* graph, // when set, code is generated
1407 HBasicBlock* block,
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001408 bool is_min,
1409 /*out*/HInstruction** result) const {
Aart Bikaec3cce2015-10-14 17:44:55 -07001410 if (info != nullptr) {
Aart Bik16d3a652016-09-09 10:33:50 -07001411 // If during codegen, the result is not needed (nullptr), simply return success.
1412 if (graph != nullptr && result == nullptr) {
1413 return true;
1414 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001415 // Handle current operation.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001416 DataType::Type type = info->type;
Aart Bikaec3cce2015-10-14 17:44:55 -07001417 HInstruction* opa = nullptr;
1418 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -07001419 switch (info->induction_class) {
1420 case HInductionVarAnalysis::kInvariant:
Aart Bik8e02e3e2017-02-28 14:41:55 -08001421 // Invariants (note that since invariants only have other invariants as
1422 // sub expressions, viz. no induction, there is no need to adjust is_min).
Aart Bikaec3cce2015-10-14 17:44:55 -07001423 switch (info->operation) {
1424 case HInductionVarAnalysis::kAdd:
Aart Bik8e02e3e2017-02-28 14:41:55 -08001425 case HInductionVarAnalysis::kSub:
1426 case HInductionVarAnalysis::kMul:
1427 case HInductionVarAnalysis::kDiv:
1428 case HInductionVarAnalysis::kRem:
1429 case HInductionVarAnalysis::kXor:
Aart Bik389b3db2015-10-28 14:23:40 -07001430 case HInductionVarAnalysis::kLT:
1431 case HInductionVarAnalysis::kLE:
1432 case HInductionVarAnalysis::kGT:
1433 case HInductionVarAnalysis::kGE:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001434 if (GenerateCode(context, loop, info->op_a, trip, graph, block, is_min, &opa) &&
1435 GenerateCode(context, loop, info->op_b, trip, graph, block, is_min, &opb)) {
Aart Bikaec3cce2015-10-14 17:44:55 -07001436 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -07001437 HInstruction* operation = nullptr;
1438 switch (info->operation) {
1439 case HInductionVarAnalysis::kAdd:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001440 operation = new (graph->GetAllocator()) HAdd(type, opa, opb); break;
Aart Bik8e02e3e2017-02-28 14:41:55 -08001441 case HInductionVarAnalysis::kSub:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001442 operation = new (graph->GetAllocator()) HSub(type, opa, opb); break;
Aart Bik8e02e3e2017-02-28 14:41:55 -08001443 case HInductionVarAnalysis::kMul:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001444 operation = new (graph->GetAllocator()) HMul(type, opa, opb, kNoDexPc); break;
Aart Bik8e02e3e2017-02-28 14:41:55 -08001445 case HInductionVarAnalysis::kDiv:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001446 operation = new (graph->GetAllocator()) HDiv(type, opa, opb, kNoDexPc); break;
Aart Bikdf7822e2016-12-06 10:05:30 -08001447 case HInductionVarAnalysis::kRem:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001448 operation = new (graph->GetAllocator()) HRem(type, opa, opb, kNoDexPc); break;
Aart Bik9abf8942016-10-14 09:49:42 -07001449 case HInductionVarAnalysis::kXor:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001450 operation = new (graph->GetAllocator()) HXor(type, opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -07001451 case HInductionVarAnalysis::kLT:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001452 operation = new (graph->GetAllocator()) HLessThan(opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -07001453 case HInductionVarAnalysis::kLE:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001454 operation = new (graph->GetAllocator()) HLessThanOrEqual(opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -07001455 case HInductionVarAnalysis::kGT:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001456 operation = new (graph->GetAllocator()) HGreaterThan(opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -07001457 case HInductionVarAnalysis::kGE:
Vladimir Markoca6fff82017-10-03 14:49:14 +01001458 operation = new (graph->GetAllocator()) HGreaterThanOrEqual(opa, opb); break;
Aart Bik389b3db2015-10-28 14:23:40 -07001459 default:
1460 LOG(FATAL) << "unknown operation";
1461 }
1462 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -07001463 }
1464 return true;
1465 }
1466 break;
Aart Bik8e02e3e2017-02-28 14:41:55 -08001467 case HInductionVarAnalysis::kNeg:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001468 if (GenerateCode(context, loop, info->op_b, trip, graph, block, !is_min, &opb)) {
Aart Bikaec3cce2015-10-14 17:44:55 -07001469 if (graph != nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001470 *result = Insert(block, new (graph->GetAllocator()) HNeg(type, opb));
Aart Bikaec3cce2015-10-14 17:44:55 -07001471 }
1472 return true;
1473 }
1474 break;
1475 case HInductionVarAnalysis::kFetch:
Aart Bik0d345cf2016-03-16 10:49:38 -07001476 if (graph != nullptr) {
1477 *result = info->fetch; // already in HIR
Aart Bikaec3cce2015-10-14 17:44:55 -07001478 }
Aart Bik0d345cf2016-03-16 10:49:38 -07001479 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -07001480 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -07001481 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001482 if (UseFullTripCount(context, loop, is_min)) {
1483 // Generate the full trip count (do not subtract 1 as we do in loop body).
1484 return GenerateCode(
1485 context, loop, info->op_a, trip, graph, block, /*is_min=*/ false, result);
Aart Bikaec3cce2015-10-14 17:44:55 -07001486 }
1487 FALLTHROUGH_INTENDED;
1488 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -07001489 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -07001490 if (is_min) {
1491 if (graph != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -08001492 *result = graph->GetConstant(type, 0);
Aart Bikaec3cce2015-10-14 17:44:55 -07001493 }
1494 return true;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001495 } else if (IsContextInBody(context, loop)) {
1496 if (GenerateCode(context, loop, info->op_a, trip, graph, block, is_min, &opb)) {
Aart Bikaec3cce2015-10-14 17:44:55 -07001497 if (graph != nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001498 ArenaAllocator* allocator = graph->GetAllocator();
Aart Bike6bd0272016-12-16 13:57:52 -08001499 *result =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001500 Insert(block, new (allocator) HSub(type, opb, graph->GetConstant(type, 1)));
Aart Bikaec3cce2015-10-14 17:44:55 -07001501 }
1502 return true;
1503 }
1504 }
1505 break;
Aart Bik8e02e3e2017-02-28 14:41:55 -08001506 case HInductionVarAnalysis::kNop:
1507 LOG(FATAL) << "unexpected invariant nop";
1508 } // switch invariant operation
Aart Bikaec3cce2015-10-14 17:44:55 -07001509 break;
Aart Bik389b3db2015-10-28 14:23:40 -07001510 case HInductionVarAnalysis::kLinear: {
Aart Bik16d3a652016-09-09 10:33:50 -07001511 // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
1512 // be restricted to a unit stride to avoid arithmetic wrap-around situations that
1513 // are harder to guard against. For a last value, requesting min/max based on any
Aart Bike6bd0272016-12-16 13:57:52 -08001514 // known stride yields right value. Always avoid any narrowing linear induction or
1515 // any type mismatch between the linear induction and the trip count expression.
1516 // TODO: careful runtime type conversions could generalize this latter restriction.
1517 if (!HInductionVarAnalysis::IsNarrowingLinear(info) && trip->type == type) {
1518 int64_t stride_value = 0;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001519 if (IsConstant(context, loop, info->op_a, kExact, &stride_value) &&
Aart Bike6bd0272016-12-16 13:57:52 -08001520 CanLongValueFitIntoInt(stride_value)) {
1521 const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001522 if (GenerateCode(context, loop, trip, trip, graph, block, is_min_a, &opa) &&
1523 GenerateCode(context, loop, info->op_b, trip, graph, block, is_min, &opb)) {
Aart Bike6bd0272016-12-16 13:57:52 -08001524 if (graph != nullptr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001525 ArenaAllocator* allocator = graph->GetAllocator();
Aart Bike6bd0272016-12-16 13:57:52 -08001526 HInstruction* oper;
1527 if (stride_value == 1) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001528 oper = new (allocator) HAdd(type, opa, opb);
Aart Bike6bd0272016-12-16 13:57:52 -08001529 } else if (stride_value == -1) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01001530 oper = new (graph->GetAllocator()) HSub(type, opb, opa);
Aart Bike6bd0272016-12-16 13:57:52 -08001531 } else {
1532 HInstruction* mul =
Vladimir Markoca6fff82017-10-03 14:49:14 +01001533 new (allocator) HMul(type, graph->GetConstant(type, stride_value), opa);
1534 oper = new (allocator) HAdd(type, Insert(block, mul), opb);
Aart Bike6bd0272016-12-16 13:57:52 -08001535 }
1536 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -07001537 }
Aart Bike6bd0272016-12-16 13:57:52 -08001538 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -07001539 }
1540 }
1541 }
1542 break;
Aart Bik4a342772015-11-30 10:17:46 -08001543 }
Aart Bikc071a012016-12-01 10:22:31 -08001544 case HInductionVarAnalysis::kPolynomial:
1545 case HInductionVarAnalysis::kGeometric:
1546 break;
Aart Bik4a342772015-11-30 10:17:46 -08001547 case HInductionVarAnalysis::kWrapAround:
1548 case HInductionVarAnalysis::kPeriodic: {
1549 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
1550 // values are easy to test at runtime without complications of arithmetic wrap-around.
Vladimir Marko8d100ba2022-03-04 10:13:10 +00001551 Value extreme = GetVal(context, loop, info, trip, is_min);
Aart Bik97412c922016-02-19 20:14:38 -08001552 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -08001553 if (graph != nullptr) {
Aart Bike6bd0272016-12-16 13:57:52 -08001554 *result = graph->GetConstant(type, extreme.b_constant);
Aart Bik4a342772015-11-30 10:17:46 -08001555 }
1556 return true;
1557 }
1558 break;
1559 }
Aart Bik8e02e3e2017-02-28 14:41:55 -08001560 } // switch induction class
Aart Bikaec3cce2015-10-14 17:44:55 -07001561 }
1562 return false;
1563}
1564
Aart Bik16d3a652016-09-09 10:33:50 -07001565void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
1566 HInstruction* fetch,
1567 HInstruction* replacement) {
1568 if (info != nullptr) {
1569 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
1570 info->operation == HInductionVarAnalysis::kFetch &&
1571 info->fetch == fetch) {
1572 info->fetch = replacement;
1573 }
1574 ReplaceInduction(info->op_a, fetch, replacement);
1575 ReplaceInduction(info->op_b, fetch, replacement);
1576 }
1577}
1578
Aart Bikd14c5952015-09-08 15:25:15 -07001579} // namespace art