blob: 119a80b6f4659cba57d6befe990c22a86742955a [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) {
89 HLoopInformation* loop = context->GetBlock()->GetLoopInformation();
Aart Bikb3365e02015-09-21 14:45:05 -070090 if (loop != nullptr) {
Aart Bikcd26feb2015-09-23 17:50:50 -070091 return GetVal(induction_analysis_->LookupInfo(loop, instruction),
92 GetTripCount(loop, context), /* is_min */ true);
Aart Bikd14c5952015-09-08 15:25:15 -070093 }
Aart Bikb3365e02015-09-21 14:45:05 -070094 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -070095}
96
97InductionVarRange::Value InductionVarRange::GetMaxInduction(HInstruction* context,
98 HInstruction* instruction) {
99 HLoopInformation* loop = context->GetBlock()->GetLoopInformation();
Aart Bikb3365e02015-09-21 14:45:05 -0700100 if (loop != nullptr) {
101 return SimplifyMax(
Aart Bikcd26feb2015-09-23 17:50:50 -0700102 GetVal(induction_analysis_->LookupInfo(loop, instruction),
103 GetTripCount(loop, context), /* is_min */ false));
Aart Bikd14c5952015-09-08 15:25:15 -0700104 }
Aart Bikb3365e02015-09-21 14:45:05 -0700105 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700106}
107
108//
109// Private class methods.
110//
111
112HInductionVarAnalysis::InductionInfo* InductionVarRange::GetTripCount(HLoopInformation* loop,
113 HInstruction* context) {
114 // The trip-count expression is only valid when the top-test is taken at least once,
115 // that means, when the analyzed context appears outside the loop header itself.
116 // Early-exit loops are okay, since in those cases, the trip-count is conservative.
Aart Bikb3365e02015-09-21 14:45:05 -0700117 //
118 // TODO: deal with runtime safety issues on TCs
119 //
Aart Bikd14c5952015-09-08 15:25:15 -0700120 if (context->GetBlock() != loop->GetHeader()) {
121 HInductionVarAnalysis::InductionInfo* trip =
122 induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction());
123 if (trip != nullptr) {
124 // Wrap the trip-count representation in its own unusual NOP node, so that range analysis
125 // is able to determine the [0, TC - 1] interval without having to construct constants.
126 return induction_analysis_->CreateInvariantOp(HInductionVarAnalysis::kNop, trip, trip);
127 }
128 }
129 return nullptr;
130}
131
132InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700133 HInductionVarAnalysis::InductionInfo* trip,
Aart Bikb3365e02015-09-21 14:45:05 -0700134 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700135 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
136 // more likely range analysis will compare the same instructions as terminal nodes.
137 int32_t value;
138 if (IsIntAndGet(instruction, &value)) {
139 return Value(value);
140 } else if (instruction->IsAdd()) {
141 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bikb3365e02015-09-21 14:45:05 -0700142 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700143 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bikb3365e02015-09-21 14:45:05 -0700144 return AddValue(GetFetch(instruction->InputAt(0), trip, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700145 }
Aart Bikb3365e02015-09-21 14:45:05 -0700146 } else if (is_min) {
147 // Special case for finding minimum: minimum of trip-count is 1.
Aart Bik22af3be2015-09-10 12:50:58 -0700148 if (trip != nullptr && instruction == trip->op_b->fetch) {
149 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700150 }
151 }
152 return Value(instruction, 1, 0);
153}
154
Aart Bikcd26feb2015-09-23 17:50:50 -0700155InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
156 HInductionVarAnalysis::InductionInfo* trip,
157 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700158 if (info != nullptr) {
159 switch (info->induction_class) {
160 case HInductionVarAnalysis::kInvariant:
161 // Invariants.
162 switch (info->operation) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700163 case HInductionVarAnalysis::kNop: // normalized: 0 or TC-1
Aart Bikd14c5952015-09-08 15:25:15 -0700164 DCHECK_EQ(info->op_a, info->op_b);
Aart Bikcd26feb2015-09-23 17:50:50 -0700165 return is_min ? Value(0)
166 : SubValue(GetVal(info->op_b, trip, is_min), Value(1));
Aart Bikd14c5952015-09-08 15:25:15 -0700167 case HInductionVarAnalysis::kAdd:
Aart Bikcd26feb2015-09-23 17:50:50 -0700168 return AddValue(GetVal(info->op_a, trip, is_min),
169 GetVal(info->op_b, trip, is_min));
170 case HInductionVarAnalysis::kSub: // second reversed!
171 return SubValue(GetVal(info->op_a, trip, is_min),
172 GetVal(info->op_b, trip, !is_min));
173 case HInductionVarAnalysis::kNeg: // second reversed!
174 return SubValue(Value(0),
175 GetVal(info->op_b, trip, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700176 case HInductionVarAnalysis::kMul:
Aart Bikcd26feb2015-09-23 17:50:50 -0700177 return GetMul(info->op_a, info->op_b, trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700178 case HInductionVarAnalysis::kDiv:
Aart Bikcd26feb2015-09-23 17:50:50 -0700179 return GetDiv(info->op_a, info->op_b, trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700180 case HInductionVarAnalysis::kFetch:
Aart Bikcd26feb2015-09-23 17:50:50 -0700181 return GetFetch(info->fetch, trip, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700182 }
183 break;
184 case HInductionVarAnalysis::kLinear:
Aart Bikcd26feb2015-09-23 17:50:50 -0700185 // Linear induction a * i + b, for normalized 0 <= i < TC.
186 return AddValue(GetMul(info->op_a, trip, trip, is_min),
187 GetVal(info->op_b, trip, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700188 case HInductionVarAnalysis::kWrapAround:
189 case HInductionVarAnalysis::kPeriodic:
Aart Bikcd26feb2015-09-23 17:50:50 -0700190 // Merge values in the wrap-around/periodic.
191 return MergeVal(GetVal(info->op_a, trip, is_min),
192 GetVal(info->op_b, trip, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700193 }
194 }
Aart Bikb3365e02015-09-21 14:45:05 -0700195 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700196}
197
198InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
199 HInductionVarAnalysis::InductionInfo* info2,
200 HInductionVarAnalysis::InductionInfo* trip,
Aart Bikb3365e02015-09-21 14:45:05 -0700201 bool is_min) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700202 Value v1_min = GetVal(info1, trip, /* is_min */ true);
203 Value v1_max = GetVal(info1, trip, /* is_min */ false);
204 Value v2_min = GetVal(info2, trip, /* is_min */ true);
205 Value v2_max = GetVal(info2, trip, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700206 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700207 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700208 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
209 return is_min ? MulValue(v1_min, v2_min)
210 : MulValue(v1_max, v2_max);
211 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
212 return is_min ? MulValue(v1_max, v2_min)
213 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700214 }
Aart Bikb3365e02015-09-21 14:45:05 -0700215 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700216 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700217 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
218 return is_min ? MulValue(v1_min, v2_max)
219 : MulValue(v1_max, v2_min);
220 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
221 return is_min ? MulValue(v1_max, v2_max)
222 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700223 }
224 }
Aart Bikb3365e02015-09-21 14:45:05 -0700225 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700226}
227
228InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
229 HInductionVarAnalysis::InductionInfo* info2,
230 HInductionVarAnalysis::InductionInfo* trip,
Aart Bikb3365e02015-09-21 14:45:05 -0700231 bool is_min) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700232 Value v1_min = GetVal(info1, trip, /* is_min */ true);
233 Value v1_max = GetVal(info1, trip, /* is_min */ false);
234 Value v2_min = GetVal(info2, trip, /* is_min */ true);
235 Value v2_max = GetVal(info2, trip, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700236 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700237 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700238 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
239 return is_min ? DivValue(v1_min, v2_max)
240 : DivValue(v1_max, v2_min);
241 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
242 return is_min ? DivValue(v1_max, v2_max)
243 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700244 }
Aart Bikb3365e02015-09-21 14:45:05 -0700245 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700246 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700247 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
248 return is_min ? DivValue(v1_min, v2_min)
249 : DivValue(v1_max, v2_max);
250 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
251 return is_min ? DivValue(v1_max, v2_min)
252 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700253 }
254 }
Aart Bikb3365e02015-09-21 14:45:05 -0700255 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700256}
257
Aart Bikb3365e02015-09-21 14:45:05 -0700258InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) {
259 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700260 const int32_t b = v1.b_constant + v2.b_constant;
261 if (v1.a_constant == 0) {
262 return Value(v2.instruction, v2.a_constant, b);
263 } else if (v2.a_constant == 0) {
264 return Value(v1.instruction, v1.a_constant, b);
265 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
266 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
267 }
268 }
Aart Bikb3365e02015-09-21 14:45:05 -0700269 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700270}
271
Aart Bikb3365e02015-09-21 14:45:05 -0700272InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) {
273 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700274 const int32_t b = v1.b_constant - v2.b_constant;
275 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
276 return Value(v2.instruction, -v2.a_constant, b);
277 } else if (v2.a_constant == 0) {
278 return Value(v1.instruction, v1.a_constant, b);
279 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
280 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
281 }
282 }
Aart Bikb3365e02015-09-21 14:45:05 -0700283 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700284}
285
Aart Bikb3365e02015-09-21 14:45:05 -0700286InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) {
287 if (v1.is_known && v2.is_known) {
288 if (v1.a_constant == 0) {
289 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
290 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
291 }
292 } else if (v2.a_constant == 0) {
293 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
294 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
295 }
Aart Bikd14c5952015-09-08 15:25:15 -0700296 }
297 }
Aart Bikb3365e02015-09-21 14:45:05 -0700298 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700299}
300
Aart Bikb3365e02015-09-21 14:45:05 -0700301InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) {
302 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700303 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
304 return Value(v1.b_constant / v2.b_constant);
305 }
306 }
Aart Bikb3365e02015-09-21 14:45:05 -0700307 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700308}
309
Aart Bikcd26feb2015-09-23 17:50:50 -0700310InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) {
Aart Bikb3365e02015-09-21 14:45:05 -0700311 if (v1.is_known && v2.is_known) {
312 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700313 return Value(v1.instruction, v1.a_constant,
314 is_min ? std::min(v1.b_constant, v2.b_constant)
315 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700316 }
Aart Bikd14c5952015-09-08 15:25:15 -0700317 }
Aart Bikb3365e02015-09-21 14:45:05 -0700318 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700319}
320
321} // namespace art