blob: f9b6910acdea53fa7486ca26e6bd3ccf6d7851ed [file] [log] [blame]
Aart Bikd14c5952015-09-08 15:25:15 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Aart Bikd14c5952015-09-08 15:25:15 -070017#include "induction_var_range.h"
18
Aart Bikcd26feb2015-09-23 17:50:50 -070019#include <limits>
20
Aart Bikd14c5952015-09-08 15:25:15 -070021namespace art {
22
Aart Bikb3365e02015-09-21 14:45:05 -070023/** Returns true if 64-bit constant fits in 32-bit constant. */
24static bool CanLongValueFitIntoInt(int64_t c) {
Aart Bikcd26feb2015-09-23 17:50:50 -070025 return std::numeric_limits<int32_t>::min() <= c && c <= std::numeric_limits<int32_t>::max();
Aart Bikd14c5952015-09-08 15:25:15 -070026}
27
Aart Bikb3365e02015-09-21 14:45:05 -070028/** Returns true if 32-bit addition can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070029static bool IsSafeAdd(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070030 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070031}
32
Aart Bikb3365e02015-09-21 14:45:05 -070033/** Returns true if 32-bit subtraction can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070034static bool IsSafeSub(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070035 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070036}
37
Aart Bikb3365e02015-09-21 14:45:05 -070038/** Returns true if 32-bit multiplication can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070039static bool IsSafeMul(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070040 return CanLongValueFitIntoInt(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070041}
42
Aart Bikb3365e02015-09-21 14:45:05 -070043/** Returns true if 32-bit division can be done safely. */
Aart Bikd14c5952015-09-08 15:25:15 -070044static bool IsSafeDiv(int32_t c1, int32_t c2) {
Aart Bikb3365e02015-09-21 14:45:05 -070045 return c2 != 0 && CanLongValueFitIntoInt(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
Aart Bikd14c5952015-09-08 15:25:15 -070046}
47
Aart Bik97412c922016-02-19 20:14:38 -080048/** Returns true for 32/64-bit constant instruction. */
49static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
Aart Bikd14c5952015-09-08 15:25:15 -070050 if (instruction->IsIntConstant()) {
Aart Bikb3365e02015-09-21 14:45:05 -070051 *value = instruction->AsIntConstant()->GetValue();
52 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070053 } else if (instruction->IsLongConstant()) {
Aart Bik97412c922016-02-19 20:14:38 -080054 *value = instruction->AsLongConstant()->GetValue();
55 return true;
Aart Bikd14c5952015-09-08 15:25:15 -070056 }
57 return false;
58}
59
Aart Bikb3365e02015-09-21 14:45:05 -070060/**
61 * An upper bound a * (length / a) + b, where a > 0, can be conservatively rewritten as length + b
62 * because length >= 0 is true. This makes it more likely the bound is useful to clients.
63 */
64static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) {
Aart Bik97412c922016-02-19 20:14:38 -080065 int64_t value;
66 if (v.is_known &&
67 v.a_constant > 1 &&
Aart Bikb3365e02015-09-21 14:45:05 -070068 v.instruction->IsDiv() &&
69 v.instruction->InputAt(0)->IsArrayLength() &&
70 IsIntAndGet(v.instruction->InputAt(1), &value) && v.a_constant == value) {
71 return InductionVarRange::Value(v.instruction->InputAt(0), 1, v.b_constant);
72 }
73 return v;
74}
75
Aart Bik97412c922016-02-19 20:14:38 -080076/** Helper method to test for a constant value. */
77static bool IsConstantValue(InductionVarRange::Value v) {
78 return v.is_known && v.a_constant == 0;
79}
80
81/** Helper method to test for same constant value. */
82static bool IsSameConstantValue(InductionVarRange::Value v1, InductionVarRange::Value v2) {
83 return IsConstantValue(v1) && IsConstantValue(v2) && v1.b_constant == v2.b_constant;
84}
85
Aart Bik389b3db2015-10-28 14:23:40 -070086/** Helper method to insert an instruction. */
87static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
88 DCHECK(block != nullptr);
89 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -070090 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -070091 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -070092 return instruction;
93}
94
Aart Bikd14c5952015-09-08 15:25:15 -070095//
96// Public class methods.
97//
98
99InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
100 : induction_analysis_(induction_analysis) {
Aart Bikb3365e02015-09-21 14:45:05 -0700101 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -0700102}
103
Aart Bik1fc3afb2016-02-02 13:26:16 -0800104bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -0700105 HInstruction* instruction,
106 /*out*/Value* min_val,
107 /*out*/Value* max_val,
108 /*out*/bool* needs_finite_test) {
109 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
Aart Bik97412c922016-02-19 20:14:38 -0800110 if (loop == nullptr) {
111 return false; // no loop
Aart Bik389b3db2015-10-28 14:23:40 -0700112 }
Aart Bik97412c922016-02-19 20:14:38 -0800113 HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
114 if (info == nullptr) {
115 return false; // no induction information
116 }
117 // Set up loop information.
118 HBasicBlock* header = loop->GetHeader();
119 bool in_body = context->GetBlock() != header;
120 HInductionVarAnalysis::InductionInfo* trip =
121 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
122 // Find range.
123 *min_val = GetVal(info, trip, in_body, /* is_min */ true);
124 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
125 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
126 return true;
Aart Bikd14c5952015-09-08 15:25:15 -0700127}
128
Aart Bik97412c922016-02-19 20:14:38 -0800129bool InductionVarRange::RefineOuter(/*in-out*/ Value* min_val,
130 /*in-out*/ Value* max_val) const {
131 Value v1_min = RefineOuter(*min_val, /* is_min */ true);
132 Value v2_max = RefineOuter(*max_val, /* is_min */ false);
133 // The refined range is safe if both sides refine the same instruction. Otherwise, since two
134 // different ranges are combined, the new refined range is safe to pass back to the client if
135 // the extremes of the computed ranges ensure no arithmetic wrap-around anomalies occur.
136 if (min_val->instruction != max_val->instruction) {
137 Value v1_max = RefineOuter(*min_val, /* is_min */ false);
138 Value v2_min = RefineOuter(*max_val, /* is_min */ true);
139 if (!IsConstantValue(v1_max) ||
140 !IsConstantValue(v2_min) ||
141 v1_max.b_constant > v2_min.b_constant) {
142 return false;
143 }
144 }
145 // Did something change?
146 if (v1_min.instruction != min_val->instruction || v2_max.instruction != max_val->instruction) {
147 *min_val = v1_min;
148 *max_val = v2_max;
Aart Bikb738d4f2015-12-03 11:23:35 -0800149 return true;
150 }
151 return false;
152}
153
Aart Bikaec3cce2015-10-14 17:44:55 -0700154bool InductionVarRange::CanGenerateCode(HInstruction* context,
155 HInstruction* instruction,
Aart Bik389b3db2015-10-28 14:23:40 -0700156 /*out*/bool* needs_finite_test,
157 /*out*/bool* needs_taken_test) {
158 return GenerateCode(context,
159 instruction,
160 nullptr, nullptr, nullptr, nullptr, nullptr, // nothing generated yet
161 needs_finite_test,
162 needs_taken_test);
Aart Bikaec3cce2015-10-14 17:44:55 -0700163}
164
Aart Bik389b3db2015-10-28 14:23:40 -0700165void InductionVarRange::GenerateRangeCode(HInstruction* context,
166 HInstruction* instruction,
167 HGraph* graph,
168 HBasicBlock* block,
169 /*out*/HInstruction** lower,
170 /*out*/HInstruction** upper) {
171 bool b1, b2; // unused
172 if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
173 LOG(FATAL) << "Failed precondition: GenerateCode()";
174 }
175}
176
177void InductionVarRange::GenerateTakenTest(HInstruction* context,
178 HGraph* graph,
179 HBasicBlock* block,
180 /*out*/HInstruction** taken_test) {
181 bool b1, b2; // unused
182 if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
183 LOG(FATAL) << "Failed precondition: GenerateCode()";
184 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700185}
186
Aart Bikd14c5952015-09-08 15:25:15 -0700187//
188// Private class methods.
189//
190
Aart Bik97412c922016-02-19 20:14:38 -0800191bool InductionVarRange::IsConstant(HInductionVarAnalysis::InductionInfo* info,
192 ConstantRequest request,
193 /*out*/ int64_t *value) const {
194 if (info != nullptr) {
195 // A direct 32-bit or 64-bit constant fetch. This immediately satisfies
196 // any of the three requests (kExact, kAtMost, and KAtLeast).
197 if (info->induction_class == HInductionVarAnalysis::kInvariant &&
198 info->operation == HInductionVarAnalysis::kFetch) {
199 if (IsIntAndGet(info->fetch, value)) {
200 return true;
201 }
202 }
203 // Try range analysis while traversing outward on loops.
204 bool in_body = true; // no known trip count
205 Value v_min = GetVal(info, nullptr, in_body, /* is_min */ true);
206 Value v_max = GetVal(info, nullptr, in_body, /* is_min */ false);
207 do {
208 // Make sure *both* extremes are known to avoid arithmetic wrap-around anomalies.
209 if (IsConstantValue(v_min) && IsConstantValue(v_max) && v_min.b_constant <= v_max.b_constant) {
210 if ((request == kExact && v_min.b_constant == v_max.b_constant) || request == kAtMost) {
211 *value = v_max.b_constant;
212 return true;
213 } else if (request == kAtLeast) {
214 *value = v_min.b_constant;
215 return true;
216 }
217 }
218 } while (RefineOuter(&v_min, &v_max));
Aart Bik358af832016-02-24 14:17:53 -0800219 // Exploit array length + c >= c, with c <= 0 to avoid arithmetic wrap-around anomalies
220 // (e.g. array length == maxint and c == 1 would yield minint).
221 if (request == kAtLeast) {
222 if (v_min.a_constant == 1 && v_min.b_constant <= 0 && v_min.instruction->IsArrayLength()) {
223 *value = v_min.b_constant;
224 return true;
225 }
226 }
Aart Bik97412c922016-02-19 20:14:38 -0800227 }
228 return false;
229}
230
Aart Bik7d57d7f2015-12-09 14:39:48 -0800231bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700232 if (info != nullptr) {
233 if (info->induction_class == HInductionVarAnalysis::kLinear) {
234 return true;
235 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
236 return NeedsTripCount(info->op_b);
237 }
Aart Bikd14c5952015-09-08 15:25:15 -0700238 }
Aart Bik389b3db2015-10-28 14:23:40 -0700239 return false;
240}
241
Aart Bik7d57d7f2015-12-09 14:39:48 -0800242bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700243 if (trip != nullptr) {
244 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
245 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
246 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
247 }
248 }
249 return false;
250}
251
Aart Bik7d57d7f2015-12-09 14:39:48 -0800252bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700253 if (trip != nullptr) {
254 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
255 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
256 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
257 }
258 }
259 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700260}
261
Aart Bik7d57d7f2015-12-09 14:39:48 -0800262InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
263 HInductionVarAnalysis::InductionInfo* trip,
264 bool in_body,
265 bool is_min) const {
266 // Detect common situation where an offset inside the trip count cancels out during range
267 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
268 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
269 // with intermediate results that only incorporate single instructions.
270 if (trip != nullptr) {
271 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
272 if (trip_expr->operation == HInductionVarAnalysis::kSub) {
Aart Bik97412c922016-02-19 20:14:38 -0800273 int64_t stride_value = 0;
274 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik7d57d7f2015-12-09 14:39:48 -0800275 if (!is_min && stride_value == 1) {
Aart Bik97412c922016-02-19 20:14:38 -0800276 // Test original trip's negative operand (trip_expr->op_b) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800277 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
278 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
279 HInductionVarAnalysis::InductionInfo cancelled_trip(
280 trip->induction_class, trip->operation, trip_expr->op_a, trip->op_b, nullptr);
281 return GetVal(&cancelled_trip, trip, in_body, is_min);
282 }
283 } else if (is_min && stride_value == -1) {
Aart Bik97412c922016-02-19 20:14:38 -0800284 // Test original trip's positive operand (trip_expr->op_a) against offset of induction.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800285 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
286 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
287 HInductionVarAnalysis::InductionInfo neg(
288 HInductionVarAnalysis::kInvariant,
289 HInductionVarAnalysis::kNeg,
290 nullptr,
291 trip_expr->op_b,
292 nullptr);
293 HInductionVarAnalysis::InductionInfo cancelled_trip(
294 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr);
295 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
296 }
297 }
298 }
299 }
300 }
301 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
302 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
303 GetVal(info->op_b, trip, in_body, is_min));
304}
305
Aart Bikd14c5952015-09-08 15:25:15 -0700306InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700307 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700308 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800309 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700310 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
311 // more likely range analysis will compare the same instructions as terminal nodes.
Aart Bik97412c922016-02-19 20:14:38 -0800312 int64_t value;
313 if (IsIntAndGet(instruction, &value) && CanLongValueFitIntoInt(value)) {
314 return Value(static_cast<int32_t>(value));
Aart Bikd14c5952015-09-08 15:25:15 -0700315 } else if (instruction->IsAdd()) {
Aart Bik97412c922016-02-19 20:14:38 -0800316 if (IsIntAndGet(instruction->InputAt(0), &value) && CanLongValueFitIntoInt(value)) {
317 return AddValue(Value(static_cast<int32_t>(value)),
318 GetFetch(instruction->InputAt(1), trip, in_body, is_min));
319 } else if (IsIntAndGet(instruction->InputAt(1), &value) && CanLongValueFitIntoInt(value)) {
320 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min),
321 Value(static_cast<int32_t>(value)));
Aart Bik22af3be2015-09-10 12:50:58 -0700322 }
Aart Bikb738d4f2015-12-03 11:23:35 -0800323 } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
324 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
Aart Bikb3365e02015-09-21 14:45:05 -0700325 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700326 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
Aart Bik22f05872015-10-27 15:56:28 -0700327 if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700328 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700329 }
330 }
331 return Value(instruction, 1, 0);
332}
333
Aart Bikcd26feb2015-09-23 17:50:50 -0700334InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
335 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700336 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800337 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700338 if (info != nullptr) {
339 switch (info->induction_class) {
340 case HInductionVarAnalysis::kInvariant:
341 // Invariants.
342 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700343 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700344 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
345 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700346 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700347 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
348 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700349 case HInductionVarAnalysis::kNeg: // second reversed!
350 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700351 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700352 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700353 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700354 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700355 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700356 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700357 return GetFetch(info->fetch, trip, in_body, is_min);
358 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700359 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700360 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700361 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700362 }
363 FALLTHROUGH_INTENDED;
364 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700365 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700366 if (is_min) {
367 return Value(0);
368 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700369 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700370 }
371 break;
372 default:
373 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700374 }
375 break;
Aart Bik7d57d7f2015-12-09 14:39:48 -0800376 case HInductionVarAnalysis::kLinear: {
377 return GetLinear(info, trip, in_body, is_min);
378 }
Aart Bikd14c5952015-09-08 15:25:15 -0700379 case HInductionVarAnalysis::kWrapAround:
380 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700381 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
382 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700383 }
384 }
Aart Bikb3365e02015-09-21 14:45:05 -0700385 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700386}
387
388InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
389 HInductionVarAnalysis::InductionInfo* info2,
390 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700391 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800392 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700393 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
394 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
395 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
396 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800397 // Try to refine first operand.
398 if (!IsConstantValue(v1_min) && !IsConstantValue(v1_max)) {
399 RefineOuter(&v1_min, &v1_max);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800400 }
Aart Bik97412c922016-02-19 20:14:38 -0800401 // Constant times range.
402 if (IsSameConstantValue(v1_min, v1_max)) {
403 return MulRangeAndConstant(v2_min, v2_max, v1_min, is_min);
404 } else if (IsSameConstantValue(v2_min, v2_max)) {
405 return MulRangeAndConstant(v1_min, v1_max, v2_min, is_min);
406 }
407 // Positive range vs. positive or negative range.
408 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
409 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
410 return is_min ? MulValue(v1_min, v2_min) : MulValue(v1_max, v2_max);
411 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
412 return is_min ? MulValue(v1_max, v2_min) : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700413 }
Aart Bik97412c922016-02-19 20:14:38 -0800414 }
415 // Negative range vs. positive or negative range.
416 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
417 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
418 return is_min ? MulValue(v1_min, v2_max) : MulValue(v1_max, v2_min);
419 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
420 return is_min ? MulValue(v1_max, v2_max) : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700421 }
422 }
Aart Bikb3365e02015-09-21 14:45:05 -0700423 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700424}
425
426InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
427 HInductionVarAnalysis::InductionInfo* info2,
428 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700429 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800430 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700431 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
432 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
433 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
434 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik97412c922016-02-19 20:14:38 -0800435 // Range divided by constant.
436 if (IsSameConstantValue(v2_min, v2_max)) {
437 return DivRangeAndConstant(v1_min, v1_max, v2_min, is_min);
438 }
439 // Positive range vs. positive or negative range.
440 if (IsConstantValue(v1_min) && v1_min.b_constant >= 0) {
441 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
442 return is_min ? DivValue(v1_min, v2_max) : DivValue(v1_max, v2_min);
443 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
444 return is_min ? DivValue(v1_max, v2_max) : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700445 }
Aart Bik97412c922016-02-19 20:14:38 -0800446 }
447 // Negative range vs. positive or negative range.
448 if (IsConstantValue(v1_max) && v1_max.b_constant <= 0) {
449 if (IsConstantValue(v2_min) && v2_min.b_constant >= 0) {
450 return is_min ? DivValue(v1_min, v2_min) : DivValue(v1_max, v2_max);
451 } else if (IsConstantValue(v2_max) && v2_max.b_constant <= 0) {
452 return is_min ? DivValue(v1_max, v2_min) : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700453 }
454 }
Aart Bikb3365e02015-09-21 14:45:05 -0700455 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700456}
457
Aart Bik97412c922016-02-19 20:14:38 -0800458InductionVarRange::Value InductionVarRange::MulRangeAndConstant(Value v_min,
459 Value v_max,
460 Value c,
461 bool is_min) const {
462 return is_min == (c.b_constant >= 0) ? MulValue(v_min, c) : MulValue(v_max, c);
463}
464
465InductionVarRange::Value InductionVarRange::DivRangeAndConstant(Value v_min,
466 Value v_max,
467 Value c,
468 bool is_min) const {
469 return is_min == (c.b_constant >= 0) ? DivValue(v_min, c) : DivValue(v_max, c);
Aart Bik9401f532015-09-28 16:25:56 -0700470}
471
Aart Bik7d57d7f2015-12-09 14:39:48 -0800472InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700473 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700474 const int32_t b = v1.b_constant + v2.b_constant;
475 if (v1.a_constant == 0) {
476 return Value(v2.instruction, v2.a_constant, b);
477 } else if (v2.a_constant == 0) {
478 return Value(v1.instruction, v1.a_constant, b);
479 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
480 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
481 }
482 }
Aart Bikb3365e02015-09-21 14:45:05 -0700483 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700484}
485
Aart Bik7d57d7f2015-12-09 14:39:48 -0800486InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700487 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700488 const int32_t b = v1.b_constant - v2.b_constant;
489 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
490 return Value(v2.instruction, -v2.a_constant, b);
491 } else if (v2.a_constant == 0) {
492 return Value(v1.instruction, v1.a_constant, b);
493 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
494 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
495 }
496 }
Aart Bikb3365e02015-09-21 14:45:05 -0700497 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700498}
499
Aart Bik7d57d7f2015-12-09 14:39:48 -0800500InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700501 if (v1.is_known && v2.is_known) {
502 if (v1.a_constant == 0) {
503 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
504 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
505 }
506 } else if (v2.a_constant == 0) {
507 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
508 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
509 }
Aart Bikd14c5952015-09-08 15:25:15 -0700510 }
511 }
Aart Bikb3365e02015-09-21 14:45:05 -0700512 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700513}
514
Aart Bik7d57d7f2015-12-09 14:39:48 -0800515InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700516 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700517 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
518 return Value(v1.b_constant / v2.b_constant);
519 }
520 }
Aart Bikb3365e02015-09-21 14:45:05 -0700521 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700522}
523
Aart Bik7d57d7f2015-12-09 14:39:48 -0800524InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700525 if (v1.is_known && v2.is_known) {
526 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700527 return Value(v1.instruction, v1.a_constant,
528 is_min ? std::min(v1.b_constant, v2.b_constant)
529 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700530 }
Aart Bikd14c5952015-09-08 15:25:15 -0700531 }
Aart Bikb3365e02015-09-21 14:45:05 -0700532 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700533}
534
Aart Bik7d57d7f2015-12-09 14:39:48 -0800535InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) const {
Aart Bik97412c922016-02-19 20:14:38 -0800536 if (v.instruction == nullptr) {
537 return v; // nothing to refine
Aart Bikb738d4f2015-12-03 11:23:35 -0800538 }
Aart Bik97412c922016-02-19 20:14:38 -0800539 HLoopInformation* loop =
540 v.instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
541 if (loop == nullptr) {
542 return v; // no loop
543 }
544 HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, v.instruction);
545 if (info == nullptr) {
546 return v; // no induction information
547 }
548 // Set up loop information.
549 HBasicBlock* header = loop->GetHeader();
550 bool in_body = true; // inner always in more outer
551 HInductionVarAnalysis::InductionInfo* trip =
552 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
553 // Try to refine "a x instruction + b" with outer loop range information on instruction.
554 return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)), Value(v.b_constant));
Aart Bikb738d4f2015-12-03 11:23:35 -0800555}
556
Aart Bikaec3cce2015-10-14 17:44:55 -0700557bool InductionVarRange::GenerateCode(HInstruction* context,
558 HInstruction* instruction,
559 HGraph* graph,
560 HBasicBlock* block,
561 /*out*/HInstruction** lower,
562 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700563 /*out*/HInstruction** taken_test,
564 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800565 /*out*/bool* needs_taken_test) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700566 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
Aart Bik97412c922016-02-19 20:14:38 -0800567 if (loop == nullptr) {
568 return false; // no loop
Aart Bikaec3cce2015-10-14 17:44:55 -0700569 }
Aart Bik97412c922016-02-19 20:14:38 -0800570 HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
571 if (info == nullptr) {
572 return false; // no induction information
573 }
574 // Set up loop information.
575 HBasicBlock* header = loop->GetHeader();
576 bool in_body = context->GetBlock() != header;
577 HInductionVarAnalysis::InductionInfo* trip =
578 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
579 if (trip == nullptr) {
580 return false; // codegen relies on trip count
581 }
582 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
583 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
584 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
585 // code does not use the trip-count explicitly (since there could be an implicit relation
586 // between e.g. an invariant subscript and a not-taken condition).
587 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
588 *needs_taken_test = IsBodyTripCount(trip);
589 // Code generation for taken test: generate the code when requested or otherwise analyze
590 // if code generation is feasible when taken test is needed.
591 if (taken_test != nullptr) {
592 return GenerateCode(trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
593 } else if (*needs_taken_test) {
594 if (!GenerateCode(
595 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
596 return false;
597 }
598 }
599 // Code generation for lower and upper.
600 return
601 // Success on lower if invariant (not set), or code can be generated.
602 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
603 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
604 // And success on upper.
605 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700606}
607
608bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
609 HInductionVarAnalysis::InductionInfo* trip,
610 HGraph* graph, // when set, code is generated
611 HBasicBlock* block,
612 /*out*/HInstruction** result,
613 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800614 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700615 if (info != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700616 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700617 Primitive::Type type = Primitive::kPrimInt;
618 HInstruction* opa = nullptr;
619 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700620 switch (info->induction_class) {
621 case HInductionVarAnalysis::kInvariant:
622 // Invariants.
623 switch (info->operation) {
624 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700625 case HInductionVarAnalysis::kLT:
626 case HInductionVarAnalysis::kLE:
627 case HInductionVarAnalysis::kGT:
628 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700629 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
630 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
631 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700632 HInstruction* operation = nullptr;
633 switch (info->operation) {
634 case HInductionVarAnalysis::kAdd:
635 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
636 case HInductionVarAnalysis::kLT:
637 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
638 case HInductionVarAnalysis::kLE:
639 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
640 case HInductionVarAnalysis::kGT:
641 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
642 case HInductionVarAnalysis::kGE:
643 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
644 default:
645 LOG(FATAL) << "unknown operation";
646 }
647 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700648 }
649 return true;
650 }
651 break;
652 case HInductionVarAnalysis::kSub: // second reversed!
653 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
654 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
655 if (graph != nullptr) {
656 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
657 }
658 return true;
659 }
660 break;
661 case HInductionVarAnalysis::kNeg: // reversed!
662 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
663 if (graph != nullptr) {
664 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
665 }
666 return true;
667 }
668 break;
669 case HInductionVarAnalysis::kFetch:
Aart Bik4a342772015-11-30 10:17:46 -0800670 if (info->fetch->GetType() == type) {
671 if (graph != nullptr) {
672 *result = info->fetch; // already in HIR
673 }
674 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700675 }
Aart Bik4a342772015-11-30 10:17:46 -0800676 break;
Aart Bikaec3cce2015-10-14 17:44:55 -0700677 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700678 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700679 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700680 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700681 }
682 FALLTHROUGH_INTENDED;
683 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700684 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700685 if (is_min) {
686 if (graph != nullptr) {
687 *result = graph->GetIntConstant(0);
688 }
689 return true;
690 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700691 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700692 if (graph != nullptr) {
693 *result = Insert(block,
694 new (graph->GetArena())
695 HSub(type, opb, graph->GetIntConstant(1)));
696 }
697 return true;
698 }
699 }
700 break;
701 default:
702 break;
703 }
704 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700705 case HInductionVarAnalysis::kLinear: {
Aart Bik4a342772015-11-30 10:17:46 -0800706 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
707 // to avoid arithmetic wrap-around situations that are hard to guard against.
Aart Bik97412c922016-02-19 20:14:38 -0800708 int64_t stride_value = 0;
709 if (IsConstant(info->op_a, kExact, &stride_value)) {
Aart Bik4a342772015-11-30 10:17:46 -0800710 if (stride_value == 1 || stride_value == -1) {
711 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
712 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
713 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
714 if (graph != nullptr) {
715 HInstruction* oper;
716 if (stride_value == 1) {
717 oper = new (graph->GetArena()) HAdd(type, opa, opb);
718 } else {
719 oper = new (graph->GetArena()) HSub(type, opb, opa);
Aart Bik389b3db2015-10-28 14:23:40 -0700720 }
Aart Bik4a342772015-11-30 10:17:46 -0800721 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700722 }
Aart Bik4a342772015-11-30 10:17:46 -0800723 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700724 }
725 }
726 }
727 break;
Aart Bik4a342772015-11-30 10:17:46 -0800728 }
729 case HInductionVarAnalysis::kWrapAround:
730 case HInductionVarAnalysis::kPeriodic: {
731 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
732 // values are easy to test at runtime without complications of arithmetic wrap-around.
733 Value extreme = GetVal(info, trip, in_body, is_min);
Aart Bik97412c922016-02-19 20:14:38 -0800734 if (IsConstantValue(extreme)) {
Aart Bik4a342772015-11-30 10:17:46 -0800735 if (graph != nullptr) {
736 *result = graph->GetIntConstant(extreme.b_constant);
737 }
738 return true;
739 }
740 break;
741 }
Aart Bik389b3db2015-10-28 14:23:40 -0700742 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700743 break;
744 }
745 }
746 return false;
747}
748
Aart Bikd14c5952015-09-08 15:25:15 -0700749} // namespace art