blob: f4842f96966be614252cc3c71af0422d67f35485 [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 Bikaec3cce2015-10-14 17:44:55 -070078static HInstruction* Insert(HBasicBlock* preheader, HInstruction* instruction) {
79 DCHECK(preheader != nullptr);
80 DCHECK(instruction != nullptr);
81 preheader->InsertInstructionBefore(instruction, preheader->GetLastInstruction());
82 return instruction;
83}
84
Aart Bikd14c5952015-09-08 15:25:15 -070085//
86// Public class methods.
87//
88
89InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
90 : induction_analysis_(induction_analysis) {
Aart Bikb3365e02015-09-21 14:45:05 -070091 DCHECK(induction_analysis != nullptr);
Aart Bikd14c5952015-09-08 15:25:15 -070092}
93
94InductionVarRange::Value InductionVarRange::GetMinInduction(HInstruction* context,
95 HInstruction* instruction) {
Aart Bik9401f532015-09-28 16:25:56 -070096 return GetInduction(context, instruction, /* is_min */ true);
Aart Bikd14c5952015-09-08 15:25:15 -070097}
98
99InductionVarRange::Value InductionVarRange::GetMaxInduction(HInstruction* context,
100 HInstruction* instruction) {
Aart Bik9401f532015-09-28 16:25:56 -0700101 return SimplifyMax(GetInduction(context, instruction, /* is_min */ false));
Aart Bikd14c5952015-09-08 15:25:15 -0700102}
103
Aart Bikaec3cce2015-10-14 17:44:55 -0700104bool InductionVarRange::CanGenerateCode(HInstruction* context,
105 HInstruction* instruction,
106 /*out*/bool* top_test) {
107 return GenerateCode(context, instruction, nullptr, nullptr, nullptr, nullptr, top_test);
108}
109
110bool InductionVarRange::GenerateCode(HInstruction* context,
111 HInstruction* instruction,
112 HGraph* graph,
113 HBasicBlock* block,
114 /*out*/HInstruction** lower,
115 /*out*/HInstruction** upper) {
116 return GenerateCode(context, instruction, graph, block, lower, upper, nullptr);
117}
118
Aart Bikd14c5952015-09-08 15:25:15 -0700119//
120// Private class methods.
121//
122
Aart Bik9401f532015-09-28 16:25:56 -0700123InductionVarRange::Value InductionVarRange::GetInduction(HInstruction* context,
124 HInstruction* instruction,
125 bool is_min) {
126 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
127 if (loop != nullptr) {
128 HBasicBlock* header = loop->GetHeader();
129 bool in_body = context->GetBlock() != header;
130 return GetVal(induction_analysis_->LookupInfo(loop, instruction),
131 induction_analysis_->LookupInfo(loop, header->GetLastInstruction()),
132 in_body,
133 is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700134 }
Aart Bik9401f532015-09-28 16:25:56 -0700135 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700136}
137
138InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700139 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700140 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700141 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700142 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
143 // more likely range analysis will compare the same instructions as terminal nodes.
144 int32_t value;
145 if (IsIntAndGet(instruction, &value)) {
146 return Value(value);
147 } else if (instruction->IsAdd()) {
148 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700149 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700150 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700151 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700152 }
Aart Bikb3365e02015-09-21 14:45:05 -0700153 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700154 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
155 if (trip != nullptr && in_body && instruction == trip->op_b->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700156 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700157 }
158 }
159 return Value(instruction, 1, 0);
160}
161
Aart Bikcd26feb2015-09-23 17:50:50 -0700162InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
163 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700164 bool in_body,
Aart Bikcd26feb2015-09-23 17:50:50 -0700165 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700166 if (info != nullptr) {
167 switch (info->induction_class) {
168 case HInductionVarAnalysis::kInvariant:
169 // Invariants.
170 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700171 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700172 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
173 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700174 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700175 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
176 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700177 case HInductionVarAnalysis::kNeg: // second reversed!
178 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700179 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700180 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700181 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700182 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700183 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700184 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700185 return GetFetch(info->fetch, trip, in_body, is_min);
186 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bikaec3cce2015-10-14 17:44:55 -0700187 if (!in_body && !is_min) { // one extra!
188 return GetVal(info->op_b, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700189 }
190 FALLTHROUGH_INTENDED;
191 case HInductionVarAnalysis::kTripCountInBody:
Aart Bikaec3cce2015-10-14 17:44:55 -0700192 if (is_min) {
193 return Value(0);
194 } else if (in_body) {
195 return SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700196 }
197 break;
198 default:
199 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700200 }
201 break;
202 case HInductionVarAnalysis::kLinear:
Aart Bikcd26feb2015-09-23 17:50:50 -0700203 // Linear induction a * i + b, for normalized 0 <= i < TC.
Aart Bik9401f532015-09-28 16:25:56 -0700204 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
205 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700206 case HInductionVarAnalysis::kWrapAround:
207 case HInductionVarAnalysis::kPeriodic:
Aart Bikcd26feb2015-09-23 17:50:50 -0700208 // Merge values in the wrap-around/periodic.
Aart Bik9401f532015-09-28 16:25:56 -0700209 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
210 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700211 }
212 }
Aart Bikb3365e02015-09-21 14:45:05 -0700213 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700214}
215
216InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
217 HInductionVarAnalysis::InductionInfo* info2,
218 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700219 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700220 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700221 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
222 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
223 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
224 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700225 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700226 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700227 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
228 return is_min ? MulValue(v1_min, v2_min)
229 : MulValue(v1_max, v2_max);
230 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
231 return is_min ? MulValue(v1_max, v2_min)
232 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700233 }
Aart Bikb3365e02015-09-21 14:45:05 -0700234 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700235 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700236 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
237 return is_min ? MulValue(v1_min, v2_max)
238 : MulValue(v1_max, v2_min);
239 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
240 return is_min ? MulValue(v1_max, v2_max)
241 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700242 }
243 }
Aart Bikb3365e02015-09-21 14:45:05 -0700244 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700245}
246
247InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
248 HInductionVarAnalysis::InductionInfo* info2,
249 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700250 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700251 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700252 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
253 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
254 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
255 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700256 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700257 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700258 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
259 return is_min ? DivValue(v1_min, v2_max)
260 : DivValue(v1_max, v2_min);
261 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
262 return is_min ? DivValue(v1_max, v2_max)
263 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700264 }
Aart Bikb3365e02015-09-21 14:45:05 -0700265 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700266 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700267 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
268 return is_min ? DivValue(v1_min, v2_min)
269 : DivValue(v1_max, v2_max);
270 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
271 return is_min ? DivValue(v1_max, v2_min)
272 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700273 }
274 }
Aart Bikb3365e02015-09-21 14:45:05 -0700275 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700276}
277
Aart Bik9401f532015-09-28 16:25:56 -0700278bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) {
279 Value v_min = GetVal(info, nullptr, false, /* is_min */ true);
280 Value v_max = GetVal(info, nullptr, false, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700281 if (v_min.is_known && v_max.is_known) {
282 if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
283 *value = v_min.b_constant;
284 return true;
285 }
Aart Bik9401f532015-09-28 16:25:56 -0700286 }
287 return false;
288}
289
Aart Bikb3365e02015-09-21 14:45:05 -0700290InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) {
291 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700292 const int32_t b = v1.b_constant + v2.b_constant;
293 if (v1.a_constant == 0) {
294 return Value(v2.instruction, v2.a_constant, b);
295 } else if (v2.a_constant == 0) {
296 return Value(v1.instruction, v1.a_constant, b);
297 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
298 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
299 }
300 }
Aart Bikb3365e02015-09-21 14:45:05 -0700301 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700302}
303
Aart Bikb3365e02015-09-21 14:45:05 -0700304InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) {
305 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700306 const int32_t b = v1.b_constant - v2.b_constant;
307 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
308 return Value(v2.instruction, -v2.a_constant, b);
309 } else if (v2.a_constant == 0) {
310 return Value(v1.instruction, v1.a_constant, b);
311 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
312 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
313 }
314 }
Aart Bikb3365e02015-09-21 14:45:05 -0700315 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700316}
317
Aart Bikb3365e02015-09-21 14:45:05 -0700318InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) {
319 if (v1.is_known && v2.is_known) {
320 if (v1.a_constant == 0) {
321 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
322 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
323 }
324 } else if (v2.a_constant == 0) {
325 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
326 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
327 }
Aart Bikd14c5952015-09-08 15:25:15 -0700328 }
329 }
Aart Bikb3365e02015-09-21 14:45:05 -0700330 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700331}
332
Aart Bikb3365e02015-09-21 14:45:05 -0700333InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) {
334 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700335 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
336 return Value(v1.b_constant / v2.b_constant);
337 }
338 }
Aart Bikb3365e02015-09-21 14:45:05 -0700339 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700340}
341
Aart Bikcd26feb2015-09-23 17:50:50 -0700342InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) {
Aart Bikb3365e02015-09-21 14:45:05 -0700343 if (v1.is_known && v2.is_known) {
344 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700345 return Value(v1.instruction, v1.a_constant,
346 is_min ? std::min(v1.b_constant, v2.b_constant)
347 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700348 }
Aart Bikd14c5952015-09-08 15:25:15 -0700349 }
Aart Bikb3365e02015-09-21 14:45:05 -0700350 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700351}
352
Aart Bikaec3cce2015-10-14 17:44:55 -0700353bool InductionVarRange::GenerateCode(HInstruction* context,
354 HInstruction* instruction,
355 HGraph* graph,
356 HBasicBlock* block,
357 /*out*/HInstruction** lower,
358 /*out*/HInstruction** upper,
359 /*out*/bool* top_test) {
360 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
361 if (loop != nullptr) {
362 HBasicBlock* header = loop->GetHeader();
363 bool in_body = context->GetBlock() != header;
364 HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction);
365 HInductionVarAnalysis::InductionInfo* trip =
366 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
367 if (info != nullptr && trip != nullptr) {
368 if (top_test != nullptr) {
369 *top_test = trip->operation != HInductionVarAnalysis::kTripCountInLoop;
370 }
371 return
372 // Success on lower if invariant (not set), or code can be generated.
373 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
374 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
375 // And success on upper.
376 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
377 }
378 }
379 return false;
380}
381
382bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
383 HInductionVarAnalysis::InductionInfo* trip,
384 HGraph* graph, // when set, code is generated
385 HBasicBlock* block,
386 /*out*/HInstruction** result,
387 bool in_body,
388 bool is_min) {
389 if (info != nullptr) {
390 Primitive::Type type = Primitive::kPrimInt;
391 HInstruction* opa = nullptr;
392 HInstruction* opb = nullptr;
393 int32_t value = 0;
394 switch (info->induction_class) {
395 case HInductionVarAnalysis::kInvariant:
396 // Invariants.
397 switch (info->operation) {
398 case HInductionVarAnalysis::kAdd:
399 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
400 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
401 if (graph != nullptr) {
402 *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb));
403 }
404 return true;
405 }
406 break;
407 case HInductionVarAnalysis::kSub: // second reversed!
408 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
409 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
410 if (graph != nullptr) {
411 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
412 }
413 return true;
414 }
415 break;
416 case HInductionVarAnalysis::kNeg: // reversed!
417 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
418 if (graph != nullptr) {
419 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
420 }
421 return true;
422 }
423 break;
424 case HInductionVarAnalysis::kFetch:
425 if (graph != nullptr) {
426 *result = info->fetch; // already in HIR
427 }
428 return true;
429 case HInductionVarAnalysis::kTripCountInLoop:
430 if (!in_body && !is_min) { // one extra!
431 return GenerateCode(info->op_b, trip, graph, block, result, in_body, is_min);
432 }
433 FALLTHROUGH_INTENDED;
434 case HInductionVarAnalysis::kTripCountInBody:
435 if (is_min) {
436 if (graph != nullptr) {
437 *result = graph->GetIntConstant(0);
438 }
439 return true;
440 } else if (in_body) {
441 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
442 if (graph != nullptr) {
443 *result = Insert(block,
444 new (graph->GetArena())
445 HSub(type, opb, graph->GetIntConstant(1)));
446 }
447 return true;
448 }
449 }
450 break;
451 default:
452 break;
453 }
454 break;
455 case HInductionVarAnalysis::kLinear:
456 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
457 // to avoid arithmetic wrap-around situations that are hard to guard against.
458 if (GetConstant(info->op_a, &value)) {
459 if (value == 1 || value == -1) {
460 const bool is_min_a = value == 1 ? is_min : !is_min;
461 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
462 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
463 if (graph != nullptr) {
464 *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb));
465 }
466 return true;
467 }
468 }
469 }
470 break;
471 default: // TODO(ajcbik): add more cases
472 break;
473 }
474 }
475 return false;
476}
477
Aart Bikd14c5952015-09-08 15:25:15 -0700478} // namespace art