blob: db12819060fd5b76207c9519c62aa51cce53d169 [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 Bikb3365e02015-09-21 14:45:05 -070048/** Returns true for 32/64-bit integral constant. */
Aart Bikd14c5952015-09-08 15:25:15 -070049static bool IsIntAndGet(HInstruction* instruction, int32_t* value) {
50 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()) {
54 const int64_t c = instruction->AsLongConstant()->GetValue();
Aart Bikb3365e02015-09-21 14:45:05 -070055 if (CanLongValueFitIntoInt(c)) {
56 *value = static_cast<int32_t>(c);
Aart Bikd14c5952015-09-08 15:25:15 -070057 return true;
58 }
59 }
60 return false;
61}
62
Aart Bikb3365e02015-09-21 14:45:05 -070063/**
64 * An upper bound a * (length / a) + b, where a > 0, can be conservatively rewritten as length + b
65 * because length >= 0 is true. This makes it more likely the bound is useful to clients.
66 */
67static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) {
68 int32_t value;
69 if (v.a_constant > 1 &&
70 v.instruction->IsDiv() &&
71 v.instruction->InputAt(0)->IsArrayLength() &&
72 IsIntAndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
73 return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
74 }
75 return v;
76}
77
Aart Bikd14c5952015-09-08 15:25:15 -070078//
79// Public class methods.
80//
81
82InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
83 : induction_analysis_(induction_analysis) {
Aart Bikb3365e02015-09-21 14:45:05 -070084 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -070085}
86
87InductionVarRange::Value InductionVarRange::GetMinInduction(HInstruction* context,
88 HInstruction* instruction) {
Aart Bik9401f532015-09-28 16:25:56 -070089 return GetInduction(context, instruction, /* is_min */ true);
Aart Bikd14c5952015-09-08 15:25:15 -070090}
91
92InductionVarRange::Value InductionVarRange::GetMaxInduction(HInstruction* context,
93 HInstruction* instruction) {
Aart Bik9401f532015-09-28 16:25:56 -070094 return SimplifyMax(GetInduction(context, instruction, /* is_min */ false));
Aart Bikd14c5952015-09-08 15:25:15 -070095}
96
97//
98// Private class methods.
99//
100
Aart Bik9401f532015-09-28 16:25:56 -0700101InductionVarRange::Value InductionVarRange::GetInduction(HInstruction* context,
102 HInstruction* instruction,
103 bool is_min) {
104 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
105 if (loop != nullptr) {
106 HBasicBlock* header = loop->GetHeader();
107 bool in_body = context->GetBlock() != header;
108 return GetVal(induction_analysis_->LookupInfo(loop, instruction),
109 induction_analysis_->LookupInfo(loop, header->GetLastInstruction()),
110 in_body,
111 is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700112 }
Aart Bik9401f532015-09-28 16:25:56 -0700113 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700114}
115
116InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700117 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700118 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700119 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700120 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
121 // more likely range analysis will compare the same instructions as terminal nodes.
122 int32_t value;
123 if (IsIntAndGet(instruction, &value)) {
124 return Value(value);
125 } else if (instruction->IsAdd()) {
126 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700127 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700128 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700129 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700130 }
Aart Bikb3365e02015-09-21 14:45:05 -0700131 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700132 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
133 if (trip != nullptr && in_body && instruction == trip->op_b->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700134 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700135 }
136 }
137 return Value(instruction, 1, 0);
138}
139
Aart Bikcd26feb2015-09-23 17:50:50 -0700140InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
141 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700142 bool in_body,
Aart Bikcd26feb2015-09-23 17:50:50 -0700143 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700144 if (info != nullptr) {
145 switch (info->induction_class) {
146 case HInductionVarAnalysis::kInvariant:
147 // Invariants.
148 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700149 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700150 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
151 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700152 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700153 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
154 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700155 case HInductionVarAnalysis::kNeg: // second reversed!
156 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700157 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700158 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700159 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700160 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700161 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700162 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700163 return GetFetch(info->fetch, trip, in_body, is_min);
164 case HInductionVarAnalysis::kTripCountInLoop:
165 if (!in_body) {
166 return is_min ? Value(0)
167 : GetVal(info->op_b, trip, in_body, is_min); // one extra!
168 }
169 FALLTHROUGH_INTENDED;
170 case HInductionVarAnalysis::kTripCountInBody:
171 if (in_body) {
172 return is_min ? Value(0)
173 : SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1));
174 }
175 break;
176 default:
177 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700178 }
179 break;
180 case HInductionVarAnalysis::kLinear:
Aart Bikcd26feb2015-09-23 17:50:50 -0700181 // Linear induction a * i + b, for normalized 0 <= i < TC.
Aart Bik9401f532015-09-28 16:25:56 -0700182 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
183 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700184 case HInductionVarAnalysis::kWrapAround:
185 case HInductionVarAnalysis::kPeriodic:
Aart Bikcd26feb2015-09-23 17:50:50 -0700186 // Merge values in the wrap-around/periodic.
Aart Bik9401f532015-09-28 16:25:56 -0700187 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
188 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700189 }
190 }
Aart Bikb3365e02015-09-21 14:45:05 -0700191 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700192}
193
194InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
195 HInductionVarAnalysis::InductionInfo* info2,
196 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700197 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700198 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700199 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
200 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
201 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
202 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700203 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700204 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700205 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
206 return is_min ? MulValue(v1_min, v2_min)
207 : MulValue(v1_max, v2_max);
208 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
209 return is_min ? MulValue(v1_max, v2_min)
210 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700211 }
Aart Bikb3365e02015-09-21 14:45:05 -0700212 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700213 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700214 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
215 return is_min ? MulValue(v1_min, v2_max)
216 : MulValue(v1_max, v2_min);
217 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
218 return is_min ? MulValue(v1_max, v2_max)
219 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700220 }
221 }
Aart Bikb3365e02015-09-21 14:45:05 -0700222 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700223}
224
225InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
226 HInductionVarAnalysis::InductionInfo* info2,
227 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700228 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700229 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700230 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
231 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
232 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
233 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700234 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700235 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700236 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
237 return is_min ? DivValue(v1_min, v2_max)
238 : DivValue(v1_max, v2_min);
239 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
240 return is_min ? DivValue(v1_max, v2_max)
241 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700242 }
Aart Bikb3365e02015-09-21 14:45:05 -0700243 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700244 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700245 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
246 return is_min ? DivValue(v1_min, v2_min)
247 : DivValue(v1_max, v2_max);
248 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
249 return is_min ? DivValue(v1_max, v2_min)
250 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700251 }
252 }
Aart Bikb3365e02015-09-21 14:45:05 -0700253 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700254}
255
Aart Bik9401f532015-09-28 16:25:56 -0700256bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) {
257 Value v_min = GetVal(info, nullptr, false, /* is_min */ true);
258 Value v_max = GetVal(info, nullptr, false, /* is_min */ false);
259 if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
260 *value = v_min.b_constant;
261 return true;
262 }
263 return false;
264}
265
Aart Bikb3365e02015-09-21 14:45:05 -0700266InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) {
267 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700268 const int32_t b = v1.b_constant + v2.b_constant;
269 if (v1.a_constant == 0) {
270 return Value(v2.instruction, v2.a_constant, b);
271 } else if (v2.a_constant == 0) {
272 return Value(v1.instruction, v1.a_constant, b);
273 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
274 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
275 }
276 }
Aart Bikb3365e02015-09-21 14:45:05 -0700277 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700278}
279
Aart Bikb3365e02015-09-21 14:45:05 -0700280InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) {
281 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700282 const int32_t b = v1.b_constant - v2.b_constant;
283 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
284 return Value(v2.instruction, -v2.a_constant, b);
285 } else if (v2.a_constant == 0) {
286 return Value(v1.instruction, v1.a_constant, b);
287 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
288 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
289 }
290 }
Aart Bikb3365e02015-09-21 14:45:05 -0700291 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700292}
293
Aart Bikb3365e02015-09-21 14:45:05 -0700294InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) {
295 if (v1.is_known && v2.is_known) {
296 if (v1.a_constant == 0) {
297 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
298 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
299 }
300 } else if (v2.a_constant == 0) {
301 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
302 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
303 }
Aart Bikd14c5952015-09-08 15:25:15 -0700304 }
305 }
Aart Bikb3365e02015-09-21 14:45:05 -0700306 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700307}
308
Aart Bikb3365e02015-09-21 14:45:05 -0700309InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) {
310 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700311 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
312 return Value(v1.b_constant / v2.b_constant);
313 }
314 }
Aart Bikb3365e02015-09-21 14:45:05 -0700315 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700316}
317
Aart Bikcd26feb2015-09-23 17:50:50 -0700318InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) {
Aart Bikb3365e02015-09-21 14:45:05 -0700319 if (v1.is_known && v2.is_known) {
320 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700321 return Value(v1.instruction, v1.a_constant,
322 is_min ? std::min(v1.b_constant, v2.b_constant)
323 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700324 }
Aart Bikd14c5952015-09-08 15:25:15 -0700325 }
Aart Bikb3365e02015-09-21 14:45:05 -0700326 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700327}
328
329} // namespace art