blob: 9566c29adf493c035354b910b4d2dfa6a75bd392 [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 Bik389b3db2015-10-28 14:23:40 -070078/** Helper method to insert an instruction. */
79static HInstruction* Insert(HBasicBlock* block, HInstruction* instruction) {
80 DCHECK(block != nullptr);
81 DCHECK(block->GetLastInstruction() != nullptr) << block->GetBlockId();
Aart Bikaec3cce2015-10-14 17:44:55 -070082 DCHECK(instruction != nullptr);
Aart Bik389b3db2015-10-28 14:23:40 -070083 block->InsertInstructionBefore(instruction, block->GetLastInstruction());
Aart Bikaec3cce2015-10-14 17:44:55 -070084 return instruction;
85}
86
Aart Bikd14c5952015-09-08 15:25:15 -070087//
88// Public class methods.
89//
90
91InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
92 : induction_analysis_(induction_analysis) {
Aart Bikb3365e02015-09-21 14:45:05 -070093 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -070094}
95
Aart Bik1fc3afb2016-02-02 13:26:16 -080096bool InductionVarRange::GetInductionRange(HInstruction* context,
Aart Bik389b3db2015-10-28 14:23:40 -070097 HInstruction* instruction,
98 /*out*/Value* min_val,
99 /*out*/Value* max_val,
100 /*out*/bool* needs_finite_test) {
101 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
102 if (loop != nullptr) {
103 // Set up loop information.
104 HBasicBlock* header = loop->GetHeader();
105 bool in_body = context->GetBlock() != header;
106 HInductionVarAnalysis::InductionInfo* info =
107 induction_analysis_->LookupInfo(loop, instruction);
108 HInductionVarAnalysis::InductionInfo* trip =
109 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
110 // Find range.
111 *min_val = GetVal(info, trip, in_body, /* is_min */ true);
112 *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
113 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
Aart Bik1fc3afb2016-02-02 13:26:16 -0800114 return true;
Aart Bik389b3db2015-10-28 14:23:40 -0700115 }
Aart Bik1fc3afb2016-02-02 13:26:16 -0800116 return false; // Nothing known
Aart Bikd14c5952015-09-08 15:25:15 -0700117}
118
Aart Bik7d57d7f2015-12-09 14:39:48 -0800119bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const {
Aart Bikb738d4f2015-12-03 11:23:35 -0800120 Value v1 = RefineOuter(*min_val, /* is_min */ true);
121 Value v2 = RefineOuter(*max_val, /* is_min */ false);
122 if (v1.instruction != min_val->instruction || v2.instruction != max_val->instruction) {
123 *min_val = v1;
124 *max_val = v2;
125 return true;
126 }
127 return false;
128}
129
Aart Bikaec3cce2015-10-14 17:44:55 -0700130bool InductionVarRange::CanGenerateCode(HInstruction* context,
131 HInstruction* instruction,
Aart Bik389b3db2015-10-28 14:23:40 -0700132 /*out*/bool* needs_finite_test,
133 /*out*/bool* needs_taken_test) {
134 return GenerateCode(context,
135 instruction,
136 nullptr, nullptr, nullptr, nullptr, nullptr, // nothing generated yet
137 needs_finite_test,
138 needs_taken_test);
Aart Bikaec3cce2015-10-14 17:44:55 -0700139}
140
Aart Bik389b3db2015-10-28 14:23:40 -0700141void InductionVarRange::GenerateRangeCode(HInstruction* context,
142 HInstruction* instruction,
143 HGraph* graph,
144 HBasicBlock* block,
145 /*out*/HInstruction** lower,
146 /*out*/HInstruction** upper) {
147 bool b1, b2; // unused
148 if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
149 LOG(FATAL) << "Failed precondition: GenerateCode()";
150 }
151}
152
153void InductionVarRange::GenerateTakenTest(HInstruction* context,
154 HGraph* graph,
155 HBasicBlock* block,
156 /*out*/HInstruction** taken_test) {
157 bool b1, b2; // unused
158 if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
159 LOG(FATAL) << "Failed precondition: GenerateCode()";
160 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700161}
162
Aart Bikd14c5952015-09-08 15:25:15 -0700163//
164// Private class methods.
165//
166
Aart Bik7d57d7f2015-12-09 14:39:48 -0800167bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700168 if (info != nullptr) {
169 if (info->induction_class == HInductionVarAnalysis::kLinear) {
170 return true;
171 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
172 return NeedsTripCount(info->op_b);
173 }
Aart Bikd14c5952015-09-08 15:25:15 -0700174 }
Aart Bik389b3db2015-10-28 14:23:40 -0700175 return false;
176}
177
Aart Bik7d57d7f2015-12-09 14:39:48 -0800178bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700179 if (trip != nullptr) {
180 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
181 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
182 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
183 }
184 }
185 return false;
186}
187
Aart Bik7d57d7f2015-12-09 14:39:48 -0800188bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700189 if (trip != nullptr) {
190 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
191 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
192 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
193 }
194 }
195 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700196}
197
Aart Bik7d57d7f2015-12-09 14:39:48 -0800198InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
199 HInductionVarAnalysis::InductionInfo* trip,
200 bool in_body,
201 bool is_min) const {
202 // Detect common situation where an offset inside the trip count cancels out during range
203 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
204 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
205 // with intermediate results that only incorporate single instructions.
206 if (trip != nullptr) {
207 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
208 if (trip_expr->operation == HInductionVarAnalysis::kSub) {
209 int32_t min_value = 0;
210 int32_t stride_value = 0;
211 if (IsConstantRange(info->op_a, &min_value, &stride_value) && min_value == stride_value) {
212 if (!is_min && stride_value == 1) {
213 // Test original trip's negative operand (trip_expr->op_b) against
214 // the offset of the linear induction.
215 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
216 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
217 HInductionVarAnalysis::InductionInfo cancelled_trip(
218 trip->induction_class, trip->operation, trip_expr->op_a, trip->op_b, nullptr);
219 return GetVal(&cancelled_trip, trip, in_body, is_min);
220 }
221 } else if (is_min && stride_value == -1) {
222 // Test original trip's positive operand (trip_expr->op_a) against
223 // the offset of the linear induction.
224 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
225 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
226 HInductionVarAnalysis::InductionInfo neg(
227 HInductionVarAnalysis::kInvariant,
228 HInductionVarAnalysis::kNeg,
229 nullptr,
230 trip_expr->op_b,
231 nullptr);
232 HInductionVarAnalysis::InductionInfo cancelled_trip(
233 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr);
234 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
235 }
236 }
237 }
238 }
239 }
240 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
241 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
242 GetVal(info->op_b, trip, in_body, is_min));
243}
244
Aart Bikd14c5952015-09-08 15:25:15 -0700245InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700246 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700247 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800248 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700249 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
250 // more likely range analysis will compare the same instructions as terminal nodes.
251 int32_t value;
252 if (IsIntAndGet(instruction, &value)) {
253 return Value(value);
254 } else if (instruction->IsAdd()) {
255 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700256 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700257 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700258 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700259 }
Aart Bikb738d4f2015-12-03 11:23:35 -0800260 } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
261 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
Aart Bikb3365e02015-09-21 14:45:05 -0700262 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700263 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
Aart Bik22f05872015-10-27 15:56:28 -0700264 if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700265 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700266 }
267 }
268 return Value(instruction, 1, 0);
269}
270
Aart Bikcd26feb2015-09-23 17:50:50 -0700271InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
272 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700273 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800274 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700275 if (info != nullptr) {
276 switch (info->induction_class) {
277 case HInductionVarAnalysis::kInvariant:
278 // Invariants.
279 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700280 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700281 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
282 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700283 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700284 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
285 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700286 case HInductionVarAnalysis::kNeg: // second reversed!
287 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700288 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700289 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700290 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700291 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700292 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700293 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700294 return GetFetch(info->fetch, trip, in_body, is_min);
295 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700296 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700297 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700298 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700299 }
300 FALLTHROUGH_INTENDED;
301 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700302 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700303 if (is_min) {
304 return Value(0);
305 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700306 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700307 }
308 break;
309 default:
310 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700311 }
312 break;
Aart Bik7d57d7f2015-12-09 14:39:48 -0800313 case HInductionVarAnalysis::kLinear: {
314 return GetLinear(info, trip, in_body, is_min);
315 }
Aart Bikd14c5952015-09-08 15:25:15 -0700316 case HInductionVarAnalysis::kWrapAround:
317 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700318 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
319 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700320 }
321 }
Aart Bikb3365e02015-09-21 14:45:05 -0700322 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700323}
324
325InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
326 HInductionVarAnalysis::InductionInfo* info2,
327 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700328 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800329 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700330 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
331 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
332 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
333 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800334 // Try to refine certain failure.
335 if (v1_min.a_constant && v1_max.a_constant) {
336 v1_min = RefineOuter(v1_min, /* is_min */ true);
337 v1_max = RefineOuter(v1_max, /* is_min */ false);
338 }
339 // Positive or negative range?
Aart Bikb3365e02015-09-21 14:45:05 -0700340 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700341 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700342 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
343 return is_min ? MulValue(v1_min, v2_min)
344 : MulValue(v1_max, v2_max);
345 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
346 return is_min ? MulValue(v1_max, v2_min)
347 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700348 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800349 } else if (v1_max.is_known && v1_max.a_constant == 0 && v1_max.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700350 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700351 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
352 return is_min ? MulValue(v1_min, v2_max)
353 : MulValue(v1_max, v2_min);
354 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
355 return is_min ? MulValue(v1_max, v2_max)
356 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700357 }
358 }
Aart Bikb3365e02015-09-21 14:45:05 -0700359 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700360}
361
362InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
363 HInductionVarAnalysis::InductionInfo* info2,
364 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700365 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800366 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700367 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
368 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
369 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
370 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800371 // Positive or negative range?
Aart Bikb3365e02015-09-21 14:45:05 -0700372 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700373 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700374 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
375 return is_min ? DivValue(v1_min, v2_max)
376 : DivValue(v1_max, v2_min);
377 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
378 return is_min ? DivValue(v1_max, v2_max)
379 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700380 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800381 } else if (v1_max.is_known && v1_max.a_constant == 0 && v1_max.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700382 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700383 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
384 return is_min ? DivValue(v1_min, v2_min)
385 : DivValue(v1_max, v2_max);
386 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
387 return is_min ? DivValue(v1_max, v2_min)
388 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700389 }
390 }
Aart Bikb3365e02015-09-21 14:45:05 -0700391 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700392}
393
Aart Bik7d57d7f2015-12-09 14:39:48 -0800394bool InductionVarRange::IsConstantRange(HInductionVarAnalysis::InductionInfo* info,
395 int32_t *min_value,
396 int32_t *max_value) const {
397 bool in_body = true; // no known trip count
398 Value v_min = GetVal(info, nullptr, in_body, /* is_min */ true);
399 Value v_max = GetVal(info, nullptr, in_body, /* is_min */ false);
400 do {
401 if (v_min.is_known && v_min.a_constant == 0 && v_max.is_known && v_max.a_constant == 0) {
402 *min_value = v_min.b_constant;
403 *max_value = v_max.b_constant;
Aart Bikaec3cce2015-10-14 17:44:55 -0700404 return true;
405 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800406 } while (RefineOuter(&v_min, &v_max));
Aart Bik9401f532015-09-28 16:25:56 -0700407 return false;
408}
409
Aart Bik7d57d7f2015-12-09 14:39:48 -0800410InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700411 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700412 const int32_t b = v1.b_constant + v2.b_constant;
413 if (v1.a_constant == 0) {
414 return Value(v2.instruction, v2.a_constant, b);
415 } else if (v2.a_constant == 0) {
416 return Value(v1.instruction, v1.a_constant, b);
417 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
418 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
419 }
420 }
Aart Bikb3365e02015-09-21 14:45:05 -0700421 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700422}
423
Aart Bik7d57d7f2015-12-09 14:39:48 -0800424InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700425 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700426 const int32_t b = v1.b_constant - v2.b_constant;
427 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
428 return Value(v2.instruction, -v2.a_constant, b);
429 } else if (v2.a_constant == 0) {
430 return Value(v1.instruction, v1.a_constant, b);
431 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
432 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
433 }
434 }
Aart Bikb3365e02015-09-21 14:45:05 -0700435 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700436}
437
Aart Bik7d57d7f2015-12-09 14:39:48 -0800438InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700439 if (v1.is_known && v2.is_known) {
440 if (v1.a_constant == 0) {
441 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
442 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
443 }
444 } else if (v2.a_constant == 0) {
445 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
446 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
447 }
Aart Bikd14c5952015-09-08 15:25:15 -0700448 }
449 }
Aart Bikb3365e02015-09-21 14:45:05 -0700450 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700451}
452
Aart Bik7d57d7f2015-12-09 14:39:48 -0800453InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700454 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700455 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
456 return Value(v1.b_constant / v2.b_constant);
457 }
458 }
Aart Bikb3365e02015-09-21 14:45:05 -0700459 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700460}
461
Aart Bik7d57d7f2015-12-09 14:39:48 -0800462InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700463 if (v1.is_known && v2.is_known) {
464 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700465 return Value(v1.instruction, v1.a_constant,
466 is_min ? std::min(v1.b_constant, v2.b_constant)
467 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700468 }
Aart Bikd14c5952015-09-08 15:25:15 -0700469 }
Aart Bikb3365e02015-09-21 14:45:05 -0700470 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700471}
472
Aart Bik7d57d7f2015-12-09 14:39:48 -0800473InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) const {
Aart Bikb738d4f2015-12-03 11:23:35 -0800474 if (v.instruction != nullptr) {
475 HLoopInformation* loop =
476 v.instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
477 if (loop != nullptr) {
478 // Set up loop information.
479 bool in_body = true; // use is always in body of outer loop
480 HInductionVarAnalysis::InductionInfo* info =
481 induction_analysis_->LookupInfo(loop, v.instruction);
482 HInductionVarAnalysis::InductionInfo* trip =
483 induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction());
484 // Try to refine "a x instruction + b" with outer loop range information on instruction.
485 return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)),
486 Value(v.b_constant));
487 }
488 }
489 return v;
490}
491
Aart Bikaec3cce2015-10-14 17:44:55 -0700492bool InductionVarRange::GenerateCode(HInstruction* context,
493 HInstruction* instruction,
494 HGraph* graph,
495 HBasicBlock* block,
496 /*out*/HInstruction** lower,
497 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700498 /*out*/HInstruction** taken_test,
499 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800500 /*out*/bool* needs_taken_test) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700501 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
502 if (loop != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700503 // Set up loop information.
Aart Bikaec3cce2015-10-14 17:44:55 -0700504 HBasicBlock* header = loop->GetHeader();
505 bool in_body = context->GetBlock() != header;
Aart Bik389b3db2015-10-28 14:23:40 -0700506 HInductionVarAnalysis::InductionInfo* info =
507 induction_analysis_->LookupInfo(loop, instruction);
508 if (info == nullptr) {
509 return false; // nothing to analyze
510 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700511 HInductionVarAnalysis::InductionInfo* trip =
512 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
Aart Bik4a342772015-11-30 10:17:46 -0800513 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
514 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
515 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
516 // code does not use the trip-count explicitly (since there could be an implicit relation
517 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik389b3db2015-10-28 14:23:40 -0700518 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
Aart Bik4a342772015-11-30 10:17:46 -0800519 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik389b3db2015-10-28 14:23:40 -0700520 // Code generation for taken test: generate the code when requested or otherwise analyze
521 // if code generation is feasible when taken test is needed.
522 if (taken_test != nullptr) {
523 return GenerateCode(
524 trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
525 } else if (*needs_taken_test) {
526 if (!GenerateCode(
527 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
528 return false;
Aart Bikaec3cce2015-10-14 17:44:55 -0700529 }
Aart Bik389b3db2015-10-28 14:23:40 -0700530 }
531 // Code generation for lower and upper.
532 return
Aart Bikaec3cce2015-10-14 17:44:55 -0700533 // Success on lower if invariant (not set), or code can be generated.
534 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
535 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
536 // And success on upper.
537 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700538 }
539 return false;
540}
541
542bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
543 HInductionVarAnalysis::InductionInfo* trip,
544 HGraph* graph, // when set, code is generated
545 HBasicBlock* block,
546 /*out*/HInstruction** result,
547 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800548 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700549 if (info != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700550 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700551 Primitive::Type type = Primitive::kPrimInt;
552 HInstruction* opa = nullptr;
553 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700554 switch (info->induction_class) {
555 case HInductionVarAnalysis::kInvariant:
556 // Invariants.
557 switch (info->operation) {
558 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700559 case HInductionVarAnalysis::kLT:
560 case HInductionVarAnalysis::kLE:
561 case HInductionVarAnalysis::kGT:
562 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700563 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
564 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
565 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700566 HInstruction* operation = nullptr;
567 switch (info->operation) {
568 case HInductionVarAnalysis::kAdd:
569 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
570 case HInductionVarAnalysis::kLT:
571 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
572 case HInductionVarAnalysis::kLE:
573 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
574 case HInductionVarAnalysis::kGT:
575 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
576 case HInductionVarAnalysis::kGE:
577 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
578 default:
579 LOG(FATAL) << "unknown operation";
580 }
581 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700582 }
583 return true;
584 }
585 break;
586 case HInductionVarAnalysis::kSub: // second reversed!
587 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
588 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
589 if (graph != nullptr) {
590 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
591 }
592 return true;
593 }
594 break;
595 case HInductionVarAnalysis::kNeg: // reversed!
596 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
597 if (graph != nullptr) {
598 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
599 }
600 return true;
601 }
602 break;
603 case HInductionVarAnalysis::kFetch:
Aart Bik4a342772015-11-30 10:17:46 -0800604 if (info->fetch->GetType() == type) {
605 if (graph != nullptr) {
606 *result = info->fetch; // already in HIR
607 }
608 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700609 }
Aart Bik4a342772015-11-30 10:17:46 -0800610 break;
Aart Bikaec3cce2015-10-14 17:44:55 -0700611 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700612 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700613 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700614 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700615 }
616 FALLTHROUGH_INTENDED;
617 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700618 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700619 if (is_min) {
620 if (graph != nullptr) {
621 *result = graph->GetIntConstant(0);
622 }
623 return true;
624 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700625 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700626 if (graph != nullptr) {
627 *result = Insert(block,
628 new (graph->GetArena())
629 HSub(type, opb, graph->GetIntConstant(1)));
630 }
631 return true;
632 }
633 }
634 break;
635 default:
636 break;
637 }
638 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700639 case HInductionVarAnalysis::kLinear: {
Aart Bik4a342772015-11-30 10:17:46 -0800640 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
641 // to avoid arithmetic wrap-around situations that are hard to guard against.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800642 int32_t min_value = 0;
Aart Bik4a342772015-11-30 10:17:46 -0800643 int32_t stride_value = 0;
Aart Bik7d57d7f2015-12-09 14:39:48 -0800644 if (IsConstantRange(info->op_a, &min_value, &stride_value) && min_value == stride_value) {
Aart Bik4a342772015-11-30 10:17:46 -0800645 if (stride_value == 1 || stride_value == -1) {
646 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
647 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
648 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
649 if (graph != nullptr) {
650 HInstruction* oper;
651 if (stride_value == 1) {
652 oper = new (graph->GetArena()) HAdd(type, opa, opb);
653 } else {
654 oper = new (graph->GetArena()) HSub(type, opb, opa);
Aart Bik389b3db2015-10-28 14:23:40 -0700655 }
Aart Bik4a342772015-11-30 10:17:46 -0800656 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700657 }
Aart Bik4a342772015-11-30 10:17:46 -0800658 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700659 }
660 }
661 }
662 break;
Aart Bik4a342772015-11-30 10:17:46 -0800663 }
664 case HInductionVarAnalysis::kWrapAround:
665 case HInductionVarAnalysis::kPeriodic: {
666 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
667 // values are easy to test at runtime without complications of arithmetic wrap-around.
668 Value extreme = GetVal(info, trip, in_body, is_min);
669 if (extreme.is_known && extreme.a_constant == 0) {
670 if (graph != nullptr) {
671 *result = graph->GetIntConstant(extreme.b_constant);
672 }
673 return true;
674 }
675 break;
676 }
Aart Bik389b3db2015-10-28 14:23:40 -0700677 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700678 break;
679 }
680 }
681 return false;
682}
683
Aart Bikd14c5952015-09-08 15:25:15 -0700684} // namespace art