blob: b40ef5aa4183ea3b67390031691634a818e23a1c [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 Bikaec3cce2015-10-14 17:44:55 -0700122bool InductionVarRange::CanGenerateCode(HInstruction* context,
123 HInstruction* instruction,
Aart Bik389b3db2015-10-28 14:23:40 -0700124 /*out*/bool* needs_finite_test,
125 /*out*/bool* needs_taken_test) {
126 return GenerateCode(context,
127 instruction,
128 nullptr, nullptr, nullptr, nullptr, nullptr, // nothing generated yet
129 needs_finite_test,
130 needs_taken_test);
Aart Bikaec3cce2015-10-14 17:44:55 -0700131}
132
Aart Bik389b3db2015-10-28 14:23:40 -0700133void InductionVarRange::GenerateRangeCode(HInstruction* context,
134 HInstruction* instruction,
135 HGraph* graph,
136 HBasicBlock* block,
137 /*out*/HInstruction** lower,
138 /*out*/HInstruction** upper) {
139 bool b1, b2; // unused
140 if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
141 LOG(FATAL) << "Failed precondition: GenerateCode()";
142 }
143}
144
145void InductionVarRange::GenerateTakenTest(HInstruction* context,
146 HGraph* graph,
147 HBasicBlock* block,
148 /*out*/HInstruction** taken_test) {
149 bool b1, b2; // unused
150 if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
151 LOG(FATAL) << "Failed precondition: GenerateCode()";
152 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700153}
154
Aart Bikd14c5952015-09-08 15:25:15 -0700155//
156// Private class methods.
157//
158
Aart Bik389b3db2015-10-28 14:23:40 -0700159bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) {
160 if (info != nullptr) {
161 if (info->induction_class == HInductionVarAnalysis::kLinear) {
162 return true;
163 } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
164 return NeedsTripCount(info->op_b);
165 }
Aart Bikd14c5952015-09-08 15:25:15 -0700166 }
Aart Bik389b3db2015-10-28 14:23:40 -0700167 return false;
168}
169
170bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) {
171 if (trip != nullptr) {
172 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
173 return trip->operation == HInductionVarAnalysis::kTripCountInBody ||
174 trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe;
175 }
176 }
177 return false;
178}
179
180bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) {
181 if (trip != nullptr) {
182 if (trip->induction_class == HInductionVarAnalysis::kInvariant) {
183 return trip->operation == HInductionVarAnalysis::kTripCountInBodyUnsafe ||
184 trip->operation == HInductionVarAnalysis::kTripCountInLoopUnsafe;
185 }
186 }
187 return false;
Aart Bikd14c5952015-09-08 15:25:15 -0700188}
189
190InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700191 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700192 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700193 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700194 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
195 // more likely range analysis will compare the same instructions as terminal nodes.
196 int32_t value;
197 if (IsIntAndGet(instruction, &value)) {
198 return Value(value);
199 } else if (instruction->IsAdd()) {
200 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700201 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700202 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700203 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700204 }
Aart Bikb3365e02015-09-21 14:45:05 -0700205 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700206 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
Aart Bik22f05872015-10-27 15:56:28 -0700207 if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700208 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700209 }
210 }
211 return Value(instruction, 1, 0);
212}
213
Aart Bikcd26feb2015-09-23 17:50:50 -0700214InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
215 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700216 bool in_body,
Aart Bikcd26feb2015-09-23 17:50:50 -0700217 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700218 if (info != nullptr) {
219 switch (info->induction_class) {
220 case HInductionVarAnalysis::kInvariant:
221 // Invariants.
222 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700223 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700224 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
225 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700226 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700227 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
228 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700229 case HInductionVarAnalysis::kNeg: // second reversed!
230 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700231 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700232 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700233 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700234 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700235 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700236 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700237 return GetFetch(info->fetch, trip, in_body, is_min);
238 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700239 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700240 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700241 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700242 }
243 FALLTHROUGH_INTENDED;
244 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700245 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700246 if (is_min) {
247 return Value(0);
248 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700249 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700250 }
251 break;
252 default:
253 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700254 }
255 break;
256 case HInductionVarAnalysis::kLinear:
Aart Bikcd26feb2015-09-23 17:50:50 -0700257 // Linear induction a * i + b, for normalized 0 <= i < TC.
Aart Bik9401f532015-09-28 16:25:56 -0700258 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
259 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700260 case HInductionVarAnalysis::kWrapAround:
261 case HInductionVarAnalysis::kPeriodic:
Aart Bikcd26feb2015-09-23 17:50:50 -0700262 // Merge values in the wrap-around/periodic.
Aart Bik9401f532015-09-28 16:25:56 -0700263 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
264 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700265 }
266 }
Aart Bikb3365e02015-09-21 14:45:05 -0700267 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700268}
269
270InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
271 HInductionVarAnalysis::InductionInfo* info2,
272 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700273 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700274 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700275 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
276 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
277 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
278 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700279 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700280 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700281 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
282 return is_min ? MulValue(v1_min, v2_min)
283 : MulValue(v1_max, v2_max);
284 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
285 return is_min ? MulValue(v1_max, v2_min)
286 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700287 }
Aart Bikb3365e02015-09-21 14:45:05 -0700288 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700289 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700290 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
291 return is_min ? MulValue(v1_min, v2_max)
292 : MulValue(v1_max, v2_min);
293 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
294 return is_min ? MulValue(v1_max, v2_max)
295 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700296 }
297 }
Aart Bikb3365e02015-09-21 14:45:05 -0700298 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700299}
300
301InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
302 HInductionVarAnalysis::InductionInfo* info2,
303 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700304 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700305 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700306 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
307 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
308 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
309 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700310 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700311 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700312 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
313 return is_min ? DivValue(v1_min, v2_max)
314 : DivValue(v1_max, v2_min);
315 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
316 return is_min ? DivValue(v1_max, v2_max)
317 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700318 }
Aart Bikb3365e02015-09-21 14:45:05 -0700319 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700320 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700321 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
322 return is_min ? DivValue(v1_min, v2_min)
323 : DivValue(v1_max, v2_max);
324 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
325 return is_min ? DivValue(v1_max, v2_min)
326 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700327 }
328 }
Aart Bikb3365e02015-09-21 14:45:05 -0700329 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700330}
331
Aart Bik9401f532015-09-28 16:25:56 -0700332bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) {
333 Value v_min = GetVal(info, nullptr, false, /* is_min */ true);
334 Value v_max = GetVal(info, nullptr, false, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700335 if (v_min.is_known && v_max.is_known) {
336 if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
337 *value = v_min.b_constant;
338 return true;
339 }
Aart Bik9401f532015-09-28 16:25:56 -0700340 }
341 return false;
342}
343
Aart Bikb3365e02015-09-21 14:45:05 -0700344InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) {
345 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700346 const int32_t b = v1.b_constant + v2.b_constant;
347 if (v1.a_constant == 0) {
348 return Value(v2.instruction, v2.a_constant, b);
349 } else if (v2.a_constant == 0) {
350 return Value(v1.instruction, v1.a_constant, b);
351 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
352 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
353 }
354 }
Aart Bikb3365e02015-09-21 14:45:05 -0700355 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700356}
357
Aart Bikb3365e02015-09-21 14:45:05 -0700358InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) {
359 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700360 const int32_t b = v1.b_constant - v2.b_constant;
361 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
362 return Value(v2.instruction, -v2.a_constant, b);
363 } else if (v2.a_constant == 0) {
364 return Value(v1.instruction, v1.a_constant, b);
365 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
366 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
367 }
368 }
Aart Bikb3365e02015-09-21 14:45:05 -0700369 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700370}
371
Aart Bikb3365e02015-09-21 14:45:05 -0700372InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) {
373 if (v1.is_known && v2.is_known) {
374 if (v1.a_constant == 0) {
375 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
376 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
377 }
378 } else if (v2.a_constant == 0) {
379 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
380 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
381 }
Aart Bikd14c5952015-09-08 15:25:15 -0700382 }
383 }
Aart Bikb3365e02015-09-21 14:45:05 -0700384 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700385}
386
Aart Bikb3365e02015-09-21 14:45:05 -0700387InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) {
388 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700389 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
390 return Value(v1.b_constant / v2.b_constant);
391 }
392 }
Aart Bikb3365e02015-09-21 14:45:05 -0700393 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700394}
395
Aart Bikcd26feb2015-09-23 17:50:50 -0700396InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) {
Aart Bikb3365e02015-09-21 14:45:05 -0700397 if (v1.is_known && v2.is_known) {
398 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700399 return Value(v1.instruction, v1.a_constant,
400 is_min ? std::min(v1.b_constant, v2.b_constant)
401 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700402 }
Aart Bikd14c5952015-09-08 15:25:15 -0700403 }
Aart Bikb3365e02015-09-21 14:45:05 -0700404 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700405}
406
Aart Bikaec3cce2015-10-14 17:44:55 -0700407bool InductionVarRange::GenerateCode(HInstruction* context,
408 HInstruction* instruction,
409 HGraph* graph,
410 HBasicBlock* block,
411 /*out*/HInstruction** lower,
412 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700413 /*out*/HInstruction** taken_test,
414 /*out*/bool* needs_finite_test,
415 /*out*/bool* needs_taken_test) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700416 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
417 if (loop != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700418 // Set up loop information.
Aart Bikaec3cce2015-10-14 17:44:55 -0700419 HBasicBlock* header = loop->GetHeader();
420 bool in_body = context->GetBlock() != header;
Aart Bik389b3db2015-10-28 14:23:40 -0700421 HInductionVarAnalysis::InductionInfo* info =
422 induction_analysis_->LookupInfo(loop, instruction);
423 if (info == nullptr) {
424 return false; // nothing to analyze
425 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700426 HInductionVarAnalysis::InductionInfo* trip =
427 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
Aart Bik389b3db2015-10-28 14:23:40 -0700428 // Determine what tests are needed.
429 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
430 *needs_taken_test = NeedsTripCount(info) && IsBodyTripCount(trip);
431 // Code generation for taken test: generate the code when requested or otherwise analyze
432 // if code generation is feasible when taken test is needed.
433 if (taken_test != nullptr) {
434 return GenerateCode(
435 trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
436 } else if (*needs_taken_test) {
437 if (!GenerateCode(
438 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
439 return false;
Aart Bikaec3cce2015-10-14 17:44:55 -0700440 }
Aart Bik389b3db2015-10-28 14:23:40 -0700441 }
442 // Code generation for lower and upper.
443 return
Aart Bikaec3cce2015-10-14 17:44:55 -0700444 // Success on lower if invariant (not set), or code can be generated.
445 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
446 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
447 // And success on upper.
448 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700449 }
450 return false;
451}
452
453bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
454 HInductionVarAnalysis::InductionInfo* trip,
455 HGraph* graph, // when set, code is generated
456 HBasicBlock* block,
457 /*out*/HInstruction** result,
458 bool in_body,
459 bool is_min) {
460 if (info != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700461 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700462 Primitive::Type type = Primitive::kPrimInt;
463 HInstruction* opa = nullptr;
464 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700465 switch (info->induction_class) {
466 case HInductionVarAnalysis::kInvariant:
467 // Invariants.
468 switch (info->operation) {
469 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700470 case HInductionVarAnalysis::kLT:
471 case HInductionVarAnalysis::kLE:
472 case HInductionVarAnalysis::kGT:
473 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700474 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
475 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
476 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700477 HInstruction* operation = nullptr;
478 switch (info->operation) {
479 case HInductionVarAnalysis::kAdd:
480 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
481 case HInductionVarAnalysis::kLT:
482 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
483 case HInductionVarAnalysis::kLE:
484 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
485 case HInductionVarAnalysis::kGT:
486 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
487 case HInductionVarAnalysis::kGE:
488 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
489 default:
490 LOG(FATAL) << "unknown operation";
491 }
492 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700493 }
494 return true;
495 }
496 break;
497 case HInductionVarAnalysis::kSub: // second reversed!
498 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
499 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
500 if (graph != nullptr) {
501 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
502 }
503 return true;
504 }
505 break;
506 case HInductionVarAnalysis::kNeg: // reversed!
507 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
508 if (graph != nullptr) {
509 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
510 }
511 return true;
512 }
513 break;
514 case HInductionVarAnalysis::kFetch:
515 if (graph != nullptr) {
516 *result = info->fetch; // already in HIR
517 }
518 return true;
519 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700520 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700521 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700522 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700523 }
524 FALLTHROUGH_INTENDED;
525 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700526 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700527 if (is_min) {
528 if (graph != nullptr) {
529 *result = graph->GetIntConstant(0);
530 }
531 return true;
532 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700533 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700534 if (graph != nullptr) {
535 *result = Insert(block,
536 new (graph->GetArena())
537 HSub(type, opb, graph->GetIntConstant(1)));
538 }
539 return true;
540 }
541 }
542 break;
543 default:
544 break;
545 }
546 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700547 case HInductionVarAnalysis::kLinear: {
548 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
549 // to avoid arithmetic wrap-around situations that are hard to guard against.
550 int32_t stride_value = 0;
551 if (GetConstant(info->op_a, &stride_value)) {
552 if (stride_value == 1 || stride_value == -1) {
553 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
554 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
555 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
556 if (graph != nullptr) {
557 HInstruction* oper;
558 if (stride_value == 1) {
559 oper = new (graph->GetArena()) HAdd(type, opa, opb);
560 } else {
561 oper = new (graph->GetArena()) HSub(type, opb, opa);
562 }
563 *result = Insert(block, oper);
564 }
565 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700566 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700567 }
568 }
569 }
570 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700571 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700572 break;
573 }
574 }
575 return false;
576}
577
Aart Bikd14c5952015-09-08 15:25:15 -0700578} // namespace art