blob: ae15fcf3816772d61719144b10ffda2e52b93238 [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 Bik389b3db2015-10-28 14:23:40 -070096void InductionVarRange::GetInductionRange(HInstruction* context,
97 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);
114 } else {
115 // No loop to analyze.
116 *min_val = Value();
117 *max_val = Value();
118 *needs_finite_test = false;
119 }
Aart Bikd14c5952015-09-08 15:25:15 -0700120}
121
Aart Bik7d57d7f2015-12-09 14:39:48 -0800122bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const {
Aart Bikb738d4f2015-12-03 11:23:35 -0800123 Value v1 = RefineOuter(*min_val, /* is_min */ true);
124 Value v2 = RefineOuter(*max_val, /* is_min */ false);
125 if (v1.instruction != min_val->instruction || v2.instruction != max_val->instruction) {
126 *min_val = v1;
127 *max_val = v2;
128 return true;
129 }
130 return false;
131}
132
Aart Bikaec3cce2015-10-14 17:44:55 -0700133bool InductionVarRange::CanGenerateCode(HInstruction* context,
134 HInstruction* instruction,
Aart Bik389b3db2015-10-28 14:23:40 -0700135 /*out*/bool* needs_finite_test,
136 /*out*/bool* needs_taken_test) {
137 return GenerateCode(context,
138 instruction,
139 nullptr, nullptr, nullptr, nullptr, nullptr, // nothing generated yet
140 needs_finite_test,
141 needs_taken_test);
Aart Bikaec3cce2015-10-14 17:44:55 -0700142}
143
Aart Bik389b3db2015-10-28 14:23:40 -0700144void InductionVarRange::GenerateRangeCode(HInstruction* context,
145 HInstruction* instruction,
146 HGraph* graph,
147 HBasicBlock* block,
148 /*out*/HInstruction** lower,
149 /*out*/HInstruction** upper) {
150 bool b1, b2; // unused
151 if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
152 LOG(FATAL) << "Failed precondition: GenerateCode()";
153 }
154}
155
156void InductionVarRange::GenerateTakenTest(HInstruction* context,
157 HGraph* graph,
158 HBasicBlock* block,
159 /*out*/HInstruction** taken_test) {
160 bool b1, b2; // unused
161 if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
162 LOG(FATAL) << "Failed precondition: GenerateCode()";
163 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700164}
165
Aart Bikd14c5952015-09-08 15:25:15 -0700166//
167// Private class methods.
168//
169
Aart Bik7d57d7f2015-12-09 14:39:48 -0800170bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700171 if (info != nullptr) {
172 if (info->induction_class == HInductionVarAnalysis::kLinear) {
173 return true;
174 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
175 return NeedsTripCount(info->op_b);
176 }
Aart Bikd14c5952015-09-08 15:25:15 -0700177 }
Aart Bik389b3db2015-10-28 14:23:40 -0700178 return false;
179}
180
Aart Bik7d57d7f2015-12-09 14:39:48 -0800181bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700182 if (trip != nullptr) {
183 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
184 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
185 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
186 }
187 }
188 return false;
189}
190
Aart Bik7d57d7f2015-12-09 14:39:48 -0800191bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const {
Aart Bik389b3db2015-10-28 14:23:40 -0700192 if (trip != nullptr) {
193 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
194 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
195 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
196 }
197 }
198 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700199}
200
Aart Bik7d57d7f2015-12-09 14:39:48 -0800201InductionVarRange::Value InductionVarRange::GetLinear(HInductionVarAnalysis::InductionInfo* info,
202 HInductionVarAnalysis::InductionInfo* trip,
203 bool in_body,
204 bool is_min) const {
205 // Detect common situation where an offset inside the trip count cancels out during range
206 // analysis (finding max a * (TC - 1) + OFFSET for a == 1 and TC = UPPER - OFFSET or finding
207 // min a * (TC - 1) + OFFSET for a == -1 and TC = OFFSET - UPPER) to avoid losing information
208 // with intermediate results that only incorporate single instructions.
209 if (trip != nullptr) {
210 HInductionVarAnalysis::InductionInfo* trip_expr = trip->op_a;
211 if (trip_expr->operation == HInductionVarAnalysis::kSub) {
212 int32_t min_value = 0;
213 int32_t stride_value = 0;
214 if (IsConstantRange(info->op_a, &min_value, &stride_value) && min_value == stride_value) {
215 if (!is_min && stride_value == 1) {
216 // Test original trip's negative operand (trip_expr->op_b) against
217 // the offset of the linear induction.
218 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_b, info->op_b)) {
219 // Analyze cancelled trip with just the positive operand (trip_expr->op_a).
220 HInductionVarAnalysis::InductionInfo cancelled_trip(
221 trip->induction_class, trip->operation, trip_expr->op_a, trip->op_b, nullptr);
222 return GetVal(&cancelled_trip, trip, in_body, is_min);
223 }
224 } else if (is_min && stride_value == -1) {
225 // Test original trip's positive operand (trip_expr->op_a) against
226 // the offset of the linear induction.
227 if (HInductionVarAnalysis::InductionEqual(trip_expr->op_a, info->op_b)) {
228 // Analyze cancelled trip with just the negative operand (trip_expr->op_b).
229 HInductionVarAnalysis::InductionInfo neg(
230 HInductionVarAnalysis::kInvariant,
231 HInductionVarAnalysis::kNeg,
232 nullptr,
233 trip_expr->op_b,
234 nullptr);
235 HInductionVarAnalysis::InductionInfo cancelled_trip(
236 trip->induction_class, trip->operation, &neg, trip->op_b, nullptr);
237 return SubValue(Value(0), GetVal(&cancelled_trip, trip, in_body, !is_min));
238 }
239 }
240 }
241 }
242 }
243 // General rule of linear induction a * i + b, for normalized 0 <= i < TC.
244 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
245 GetVal(info->op_b, trip, in_body, is_min));
246}
247
Aart Bikd14c5952015-09-08 15:25:15 -0700248InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700249 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700250 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800251 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700252 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
253 // more likely range analysis will compare the same instructions as terminal nodes.
254 int32_t value;
255 if (IsIntAndGet(instruction, &value)) {
256 return Value(value);
257 } else if (instruction->IsAdd()) {
258 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700259 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700260 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700261 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700262 }
Aart Bikb738d4f2015-12-03 11:23:35 -0800263 } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
264 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
Aart Bikb3365e02015-09-21 14:45:05 -0700265 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700266 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
Aart Bik22f05872015-10-27 15:56:28 -0700267 if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700268 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700269 }
270 }
271 return Value(instruction, 1, 0);
272}
273
Aart Bikcd26feb2015-09-23 17:50:50 -0700274InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
275 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700276 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800277 bool is_min) const {
Aart Bikd14c5952015-09-08 15:25:15 -0700278 if (info != nullptr) {
279 switch (info->induction_class) {
280 case HInductionVarAnalysis::kInvariant:
281 // Invariants.
282 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700283 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700284 return AddValue(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::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700287 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
288 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700289 case HInductionVarAnalysis::kNeg: // second reversed!
290 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700291 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700292 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700293 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700294 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700295 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700296 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700297 return GetFetch(info->fetch, trip, in_body, is_min);
298 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700299 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700300 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700301 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700302 }
303 FALLTHROUGH_INTENDED;
304 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700305 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700306 if (is_min) {
307 return Value(0);
308 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700309 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700310 }
311 break;
312 default:
313 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700314 }
315 break;
Aart Bik7d57d7f2015-12-09 14:39:48 -0800316 case HInductionVarAnalysis::kLinear: {
317 return GetLinear(info, trip, in_body, is_min);
318 }
Aart Bikd14c5952015-09-08 15:25:15 -0700319 case HInductionVarAnalysis::kWrapAround:
320 case HInductionVarAnalysis::kPeriodic:
Aart Bik9401f532015-09-28 16:25:56 -0700321 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
322 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700323 }
324 }
Aart Bikb3365e02015-09-21 14:45:05 -0700325 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700326}
327
328InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
329 HInductionVarAnalysis::InductionInfo* info2,
330 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700331 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800332 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700333 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
334 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
335 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
336 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800337 // Try to refine certain failure.
338 if (v1_min.a_constant && v1_max.a_constant) {
339 v1_min = RefineOuter(v1_min, /* is_min */ true);
340 v1_max = RefineOuter(v1_max, /* is_min */ false);
341 }
342 // Positive or negative range?
Aart Bikb3365e02015-09-21 14:45:05 -0700343 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700344 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700345 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
346 return is_min ? MulValue(v1_min, v2_min)
347 : MulValue(v1_max, v2_max);
348 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
349 return is_min ? MulValue(v1_max, v2_min)
350 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700351 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800352 } else if (v1_max.is_known && v1_max.a_constant == 0 && v1_max.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700353 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700354 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
355 return is_min ? MulValue(v1_min, v2_max)
356 : MulValue(v1_max, v2_min);
357 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
358 return is_min ? MulValue(v1_max, v2_max)
359 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700360 }
361 }
Aart Bikb3365e02015-09-21 14:45:05 -0700362 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700363}
364
365InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
366 HInductionVarAnalysis::InductionInfo* info2,
367 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700368 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800369 bool is_min) const {
Aart Bik9401f532015-09-28 16:25:56 -0700370 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
371 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
372 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
373 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bik7d57d7f2015-12-09 14:39:48 -0800374 // Positive or negative range?
Aart Bikb3365e02015-09-21 14:45:05 -0700375 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700376 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700377 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
378 return is_min ? DivValue(v1_min, v2_max)
379 : DivValue(v1_max, v2_min);
380 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
381 return is_min ? DivValue(v1_max, v2_max)
382 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700383 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800384 } else if (v1_max.is_known && v1_max.a_constant == 0 && v1_max.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700385 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700386 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
387 return is_min ? DivValue(v1_min, v2_min)
388 : DivValue(v1_max, v2_max);
389 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
390 return is_min ? DivValue(v1_max, v2_min)
391 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700392 }
393 }
Aart Bikb3365e02015-09-21 14:45:05 -0700394 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700395}
396
Aart Bik7d57d7f2015-12-09 14:39:48 -0800397bool InductionVarRange::IsConstantRange(HInductionVarAnalysis::InductionInfo* info,
398 int32_t *min_value,
399 int32_t *max_value) const {
400 bool in_body = true; // no known trip count
401 Value v_min = GetVal(info, nullptr, in_body, /* is_min */ true);
402 Value v_max = GetVal(info, nullptr, in_body, /* is_min */ false);
403 do {
404 if (v_min.is_known && v_min.a_constant == 0 && v_max.is_known && v_max.a_constant == 0) {
405 *min_value = v_min.b_constant;
406 *max_value = v_max.b_constant;
Aart Bikaec3cce2015-10-14 17:44:55 -0700407 return true;
408 }
Aart Bik7d57d7f2015-12-09 14:39:48 -0800409 } while (RefineOuter(&v_min, &v_max));
Aart Bik9401f532015-09-28 16:25:56 -0700410 return false;
411}
412
Aart Bik7d57d7f2015-12-09 14:39:48 -0800413InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700414 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700415 const int32_t b = v1.b_constant + v2.b_constant;
416 if (v1.a_constant == 0) {
417 return Value(v2.instruction, v2.a_constant, b);
418 } else if (v2.a_constant == 0) {
419 return Value(v1.instruction, v1.a_constant, b);
420 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
421 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
422 }
423 }
Aart Bikb3365e02015-09-21 14:45:05 -0700424 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700425}
426
Aart Bik7d57d7f2015-12-09 14:39:48 -0800427InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700428 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700429 const int32_t b = v1.b_constant - v2.b_constant;
430 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
431 return Value(v2.instruction, -v2.a_constant, b);
432 } else if (v2.a_constant == 0) {
433 return Value(v1.instruction, v1.a_constant, b);
434 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
435 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
436 }
437 }
Aart Bikb3365e02015-09-21 14:45:05 -0700438 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700439}
440
Aart Bik7d57d7f2015-12-09 14:39:48 -0800441InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700442 if (v1.is_known && v2.is_known) {
443 if (v1.a_constant == 0) {
444 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
445 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
446 }
447 } else if (v2.a_constant == 0) {
448 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
449 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
450 }
Aart Bikd14c5952015-09-08 15:25:15 -0700451 }
452 }
Aart Bikb3365e02015-09-21 14:45:05 -0700453 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700454}
455
Aart Bik7d57d7f2015-12-09 14:39:48 -0800456InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700457 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700458 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
459 return Value(v1.b_constant / v2.b_constant);
460 }
461 }
Aart Bikb3365e02015-09-21 14:45:05 -0700462 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700463}
464
Aart Bik7d57d7f2015-12-09 14:39:48 -0800465InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) const {
Aart Bikb3365e02015-09-21 14:45:05 -0700466 if (v1.is_known && v2.is_known) {
467 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700468 return Value(v1.instruction, v1.a_constant,
469 is_min ? std::min(v1.b_constant, v2.b_constant)
470 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700471 }
Aart Bikd14c5952015-09-08 15:25:15 -0700472 }
Aart Bikb3365e02015-09-21 14:45:05 -0700473 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700474}
475
Aart Bik7d57d7f2015-12-09 14:39:48 -0800476InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) const {
Aart Bikb738d4f2015-12-03 11:23:35 -0800477 if (v.instruction != nullptr) {
478 HLoopInformation* loop =
479 v.instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
480 if (loop != nullptr) {
481 // Set up loop information.
482 bool in_body = true; // use is always in body of outer loop
483 HInductionVarAnalysis::InductionInfo* info =
484 induction_analysis_->LookupInfo(loop, v.instruction);
485 HInductionVarAnalysis::InductionInfo* trip =
486 induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction());
487 // Try to refine "a x instruction + b" with outer loop range information on instruction.
488 return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)),
489 Value(v.b_constant));
490 }
491 }
492 return v;
493}
494
Aart Bikaec3cce2015-10-14 17:44:55 -0700495bool InductionVarRange::GenerateCode(HInstruction* context,
496 HInstruction* instruction,
497 HGraph* graph,
498 HBasicBlock* block,
499 /*out*/HInstruction** lower,
500 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700501 /*out*/HInstruction** taken_test,
502 /*out*/bool* needs_finite_test,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800503 /*out*/bool* needs_taken_test) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700504 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
505 if (loop != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700506 // Set up loop information.
Aart Bikaec3cce2015-10-14 17:44:55 -0700507 HBasicBlock* header = loop->GetHeader();
508 bool in_body = context->GetBlock() != header;
Aart Bik389b3db2015-10-28 14:23:40 -0700509 HInductionVarAnalysis::InductionInfo* info =
510 induction_analysis_->LookupInfo(loop, instruction);
511 if (info == nullptr) {
512 return false; // nothing to analyze
513 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700514 HInductionVarAnalysis::InductionInfo* trip =
515 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
Aart Bik4a342772015-11-30 10:17:46 -0800516 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
517 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
518 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
519 // code does not use the trip-count explicitly (since there could be an implicit relation
520 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik389b3db2015-10-28 14:23:40 -0700521 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
Aart Bik4a342772015-11-30 10:17:46 -0800522 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik389b3db2015-10-28 14:23:40 -0700523 // Code generation for taken test: generate the code when requested or otherwise analyze
524 // if code generation is feasible when taken test is needed.
525 if (taken_test != nullptr) {
526 return GenerateCode(
527 trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
528 } else if (*needs_taken_test) {
529 if (!GenerateCode(
530 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
531 return false;
Aart Bikaec3cce2015-10-14 17:44:55 -0700532 }
Aart Bik389b3db2015-10-28 14:23:40 -0700533 }
534 // Code generation for lower and upper.
535 return
Aart Bikaec3cce2015-10-14 17:44:55 -0700536 // Success on lower if invariant (not set), or code can be generated.
537 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
538 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
539 // And success on upper.
540 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700541 }
542 return false;
543}
544
545bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
546 HInductionVarAnalysis::InductionInfo* trip,
547 HGraph* graph, // when set, code is generated
548 HBasicBlock* block,
549 /*out*/HInstruction** result,
550 bool in_body,
Aart Bik7d57d7f2015-12-09 14:39:48 -0800551 bool is_min) const {
Aart Bikaec3cce2015-10-14 17:44:55 -0700552 if (info != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700553 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700554 Primitive::Type type = Primitive::kPrimInt;
555 HInstruction* opa = nullptr;
556 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700557 switch (info->induction_class) {
558 case HInductionVarAnalysis::kInvariant:
559 // Invariants.
560 switch (info->operation) {
561 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700562 case HInductionVarAnalysis::kLT:
563 case HInductionVarAnalysis::kLE:
564 case HInductionVarAnalysis::kGT:
565 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700566 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
567 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
568 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700569 HInstruction* operation = nullptr;
570 switch (info->operation) {
571 case HInductionVarAnalysis::kAdd:
572 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
573 case HInductionVarAnalysis::kLT:
574 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
575 case HInductionVarAnalysis::kLE:
576 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
577 case HInductionVarAnalysis::kGT:
578 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
579 case HInductionVarAnalysis::kGE:
580 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
581 default:
582 LOG(FATAL) << "unknown operation";
583 }
584 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700585 }
586 return true;
587 }
588 break;
589 case HInductionVarAnalysis::kSub: // second reversed!
590 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
591 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
592 if (graph != nullptr) {
593 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
594 }
595 return true;
596 }
597 break;
598 case HInductionVarAnalysis::kNeg: // reversed!
599 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
600 if (graph != nullptr) {
601 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
602 }
603 return true;
604 }
605 break;
606 case HInductionVarAnalysis::kFetch:
Aart Bik4a342772015-11-30 10:17:46 -0800607 if (info->fetch->GetType() == type) {
608 if (graph != nullptr) {
609 *result = info->fetch; // already in HIR
610 }
611 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700612 }
Aart Bik4a342772015-11-30 10:17:46 -0800613 break;
Aart Bikaec3cce2015-10-14 17:44:55 -0700614 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700615 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700616 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700617 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700618 }
619 FALLTHROUGH_INTENDED;
620 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700621 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700622 if (is_min) {
623 if (graph != nullptr) {
624 *result = graph->GetIntConstant(0);
625 }
626 return true;
627 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700628 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700629 if (graph != nullptr) {
630 *result = Insert(block,
631 new (graph->GetArena())
632 HSub(type, opb, graph->GetIntConstant(1)));
633 }
634 return true;
635 }
636 }
637 break;
638 default:
639 break;
640 }
641 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700642 case HInductionVarAnalysis::kLinear: {
Aart Bik4a342772015-11-30 10:17:46 -0800643 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
644 // to avoid arithmetic wrap-around situations that are hard to guard against.
Aart Bik7d57d7f2015-12-09 14:39:48 -0800645 int32_t min_value = 0;
Aart Bik4a342772015-11-30 10:17:46 -0800646 int32_t stride_value = 0;
Aart Bik7d57d7f2015-12-09 14:39:48 -0800647 if (IsConstantRange(info->op_a, &min_value, &stride_value) && min_value == stride_value) {
Aart Bik4a342772015-11-30 10:17:46 -0800648 if (stride_value == 1 || stride_value == -1) {
649 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
650 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
651 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
652 if (graph != nullptr) {
653 HInstruction* oper;
654 if (stride_value == 1) {
655 oper = new (graph->GetArena()) HAdd(type, opa, opb);
656 } else {
657 oper = new (graph->GetArena()) HSub(type, opb, opa);
Aart Bik389b3db2015-10-28 14:23:40 -0700658 }
Aart Bik4a342772015-11-30 10:17:46 -0800659 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700660 }
Aart Bik4a342772015-11-30 10:17:46 -0800661 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700662 }
663 }
664 }
665 break;
Aart Bik4a342772015-11-30 10:17:46 -0800666 }
667 case HInductionVarAnalysis::kWrapAround:
668 case HInductionVarAnalysis::kPeriodic: {
669 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
670 // values are easy to test at runtime without complications of arithmetic wrap-around.
671 Value extreme = GetVal(info, trip, in_body, is_min);
672 if (extreme.is_known && extreme.a_constant == 0) {
673 if (graph != nullptr) {
674 *result = graph->GetIntConstant(extreme.b_constant);
675 }
676 return true;
677 }
678 break;
679 }
Aart Bik389b3db2015-10-28 14:23:40 -0700680 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700681 break;
682 }
683 }
684 return false;
685}
686
Aart Bikd14c5952015-09-08 15:25:15 -0700687} // namespace art