blob: 9d0cde7c9ff07251f7662bd49fe063119a30472e [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 Bikb738d4f2015-12-03 11:23:35 -0800122bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) {
123 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 Bik389b3db2015-10-28 14:23:40 -0700170bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) {
171 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
181bool InductionVarRange::IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) {
182 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
191bool InductionVarRange::IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) {
192 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
201InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
Aart Bik22af3be2015-09-10 12:50:58 -0700202 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700203 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700204 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700205 // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
206 // more likely range analysis will compare the same instructions as terminal nodes.
207 int32_t value;
208 if (IsIntAndGet(instruction, &value)) {
209 return Value(value);
210 } else if (instruction->IsAdd()) {
211 if (IsIntAndGet(instruction->InputAt(0), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700212 return AddValue(Value(value), GetFetch(instruction->InputAt(1), trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700213 } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
Aart Bik9401f532015-09-28 16:25:56 -0700214 return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value));
Aart Bik22af3be2015-09-10 12:50:58 -0700215 }
Aart Bikb738d4f2015-12-03 11:23:35 -0800216 } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
217 return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min);
Aart Bikb3365e02015-09-21 14:45:05 -0700218 } else if (is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700219 // Special case for finding minimum: minimum of trip-count in loop-body is 1.
Aart Bik22f05872015-10-27 15:56:28 -0700220 if (trip != nullptr && in_body && instruction == trip->op_a->fetch) {
Aart Bik22af3be2015-09-10 12:50:58 -0700221 return Value(1);
Aart Bikd14c5952015-09-08 15:25:15 -0700222 }
223 }
224 return Value(instruction, 1, 0);
225}
226
Aart Bikcd26feb2015-09-23 17:50:50 -0700227InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::InductionInfo* info,
228 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700229 bool in_body,
Aart Bikcd26feb2015-09-23 17:50:50 -0700230 bool is_min) {
Aart Bikd14c5952015-09-08 15:25:15 -0700231 if (info != nullptr) {
232 switch (info->induction_class) {
233 case HInductionVarAnalysis::kInvariant:
234 // Invariants.
235 switch (info->operation) {
Aart Bikd14c5952015-09-08 15:25:15 -0700236 case HInductionVarAnalysis::kAdd:
Aart Bik9401f532015-09-28 16:25:56 -0700237 return AddValue(GetVal(info->op_a, trip, in_body, is_min),
238 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700239 case HInductionVarAnalysis::kSub: // second reversed!
Aart Bik9401f532015-09-28 16:25:56 -0700240 return SubValue(GetVal(info->op_a, trip, in_body, is_min),
241 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikcd26feb2015-09-23 17:50:50 -0700242 case HInductionVarAnalysis::kNeg: // second reversed!
243 return SubValue(Value(0),
Aart Bik9401f532015-09-28 16:25:56 -0700244 GetVal(info->op_b, trip, in_body, !is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700245 case HInductionVarAnalysis::kMul:
Aart Bik9401f532015-09-28 16:25:56 -0700246 return GetMul(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700247 case HInductionVarAnalysis::kDiv:
Aart Bik9401f532015-09-28 16:25:56 -0700248 return GetDiv(info->op_a, info->op_b, trip, in_body, is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700249 case HInductionVarAnalysis::kFetch:
Aart Bik9401f532015-09-28 16:25:56 -0700250 return GetFetch(info->fetch, trip, in_body, is_min);
251 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700252 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700253 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700254 return GetVal(info->op_a, trip, in_body, is_min);
Aart Bik9401f532015-09-28 16:25:56 -0700255 }
256 FALLTHROUGH_INTENDED;
257 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700258 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700259 if (is_min) {
260 return Value(0);
261 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700262 return SubValue(GetVal(info->op_a, trip, in_body, is_min), Value(1));
Aart Bik9401f532015-09-28 16:25:56 -0700263 }
264 break;
265 default:
266 break;
Aart Bikd14c5952015-09-08 15:25:15 -0700267 }
268 break;
269 case HInductionVarAnalysis::kLinear:
Aart Bikcd26feb2015-09-23 17:50:50 -0700270 // Linear induction a * i + b, for normalized 0 <= i < TC.
Aart Bik9401f532015-09-28 16:25:56 -0700271 return AddValue(GetMul(info->op_a, trip, trip, in_body, is_min),
272 GetVal(info->op_b, trip, in_body, is_min));
Aart Bikd14c5952015-09-08 15:25:15 -0700273 case HInductionVarAnalysis::kWrapAround:
274 case HInductionVarAnalysis::kPeriodic:
Aart Bikcd26feb2015-09-23 17:50:50 -0700275 // Merge values in the wrap-around/periodic.
Aart Bik9401f532015-09-28 16:25:56 -0700276 return MergeVal(GetVal(info->op_a, trip, in_body, is_min),
277 GetVal(info->op_b, trip, in_body, is_min), is_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700278 }
279 }
Aart Bikb3365e02015-09-21 14:45:05 -0700280 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700281}
282
283InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
284 HInductionVarAnalysis::InductionInfo* info2,
285 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700286 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700287 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700288 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
289 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
290 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
291 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700292 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700293 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700294 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
295 return is_min ? MulValue(v1_min, v2_min)
296 : MulValue(v1_max, v2_max);
297 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
298 return is_min ? MulValue(v1_max, v2_min)
299 : MulValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700300 }
Aart Bikb3365e02015-09-21 14:45:05 -0700301 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700302 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700303 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
304 return is_min ? MulValue(v1_min, v2_max)
305 : MulValue(v1_max, v2_min);
306 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
307 return is_min ? MulValue(v1_max, v2_max)
308 : MulValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700309 }
310 }
Aart Bikb3365e02015-09-21 14:45:05 -0700311 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700312}
313
314InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
315 HInductionVarAnalysis::InductionInfo* info2,
316 HInductionVarAnalysis::InductionInfo* trip,
Aart Bik9401f532015-09-28 16:25:56 -0700317 bool in_body,
Aart Bikb3365e02015-09-21 14:45:05 -0700318 bool is_min) {
Aart Bik9401f532015-09-28 16:25:56 -0700319 Value v1_min = GetVal(info1, trip, in_body, /* is_min */ true);
320 Value v1_max = GetVal(info1, trip, in_body, /* is_min */ false);
321 Value v2_min = GetVal(info2, trip, in_body, /* is_min */ true);
322 Value v2_max = GetVal(info2, trip, in_body, /* is_min */ false);
Aart Bikb3365e02015-09-21 14:45:05 -0700323 if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700324 // Positive range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700325 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
326 return is_min ? DivValue(v1_min, v2_max)
327 : DivValue(v1_max, v2_min);
328 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
329 return is_min ? DivValue(v1_max, v2_max)
330 : DivValue(v1_min, v2_min);
Aart Bikd14c5952015-09-08 15:25:15 -0700331 }
Aart Bikb3365e02015-09-21 14:45:05 -0700332 } else if (v1_min.is_known && v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700333 // Negative range vs. positive or negative range.
Aart Bikb3365e02015-09-21 14:45:05 -0700334 if (v2_min.is_known && v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
335 return is_min ? DivValue(v1_min, v2_min)
336 : DivValue(v1_max, v2_max);
337 } else if (v2_max.is_known && v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
338 return is_min ? DivValue(v1_max, v2_min)
339 : DivValue(v1_min, v2_max);
Aart Bikd14c5952015-09-08 15:25:15 -0700340 }
341 }
Aart Bikb3365e02015-09-21 14:45:05 -0700342 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700343}
344
Aart Bik9401f532015-09-28 16:25:56 -0700345bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) {
346 Value v_min = GetVal(info, nullptr, false, /* is_min */ true);
347 Value v_max = GetVal(info, nullptr, false, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700348 if (v_min.is_known && v_max.is_known) {
349 if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) {
350 *value = v_min.b_constant;
351 return true;
352 }
Aart Bik9401f532015-09-28 16:25:56 -0700353 }
354 return false;
355}
356
Aart Bikb3365e02015-09-21 14:45:05 -0700357InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2) {
358 if (v1.is_known && v2.is_known && IsSafeAdd(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700359 const int32_t b = v1.b_constant + v2.b_constant;
360 if (v1.a_constant == 0) {
361 return Value(v2.instruction, v2.a_constant, b);
362 } else if (v2.a_constant == 0) {
363 return Value(v1.instruction, v1.a_constant, b);
364 } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
365 return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
366 }
367 }
Aart Bikb3365e02015-09-21 14:45:05 -0700368 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700369}
370
Aart Bikb3365e02015-09-21 14:45:05 -0700371InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2) {
372 if (v1.is_known && v2.is_known && IsSafeSub(v1.b_constant, v2.b_constant)) {
Aart Bikd14c5952015-09-08 15:25:15 -0700373 const int32_t b = v1.b_constant - v2.b_constant;
374 if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
375 return Value(v2.instruction, -v2.a_constant, b);
376 } else if (v2.a_constant == 0) {
377 return Value(v1.instruction, v1.a_constant, b);
378 } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
379 return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
380 }
381 }
Aart Bikb3365e02015-09-21 14:45:05 -0700382 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700383}
384
Aart Bikb3365e02015-09-21 14:45:05 -0700385InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2) {
386 if (v1.is_known && v2.is_known) {
387 if (v1.a_constant == 0) {
388 if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
389 return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
390 }
391 } else if (v2.a_constant == 0) {
392 if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
393 return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
394 }
Aart Bikd14c5952015-09-08 15:25:15 -0700395 }
396 }
Aart Bikb3365e02015-09-21 14:45:05 -0700397 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700398}
399
Aart Bikb3365e02015-09-21 14:45:05 -0700400InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2) {
401 if (v1.is_known && v2.is_known && v1.a_constant == 0 && v2.a_constant == 0) {
Aart Bikd14c5952015-09-08 15:25:15 -0700402 if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
403 return Value(v1.b_constant / v2.b_constant);
404 }
405 }
Aart Bikb3365e02015-09-21 14:45:05 -0700406 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700407}
408
Aart Bikcd26feb2015-09-23 17:50:50 -0700409InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is_min) {
Aart Bikb3365e02015-09-21 14:45:05 -0700410 if (v1.is_known && v2.is_known) {
411 if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
Aart Bikcd26feb2015-09-23 17:50:50 -0700412 return Value(v1.instruction, v1.a_constant,
413 is_min ? std::min(v1.b_constant, v2.b_constant)
414 : std::max(v1.b_constant, v2.b_constant));
Aart Bikb3365e02015-09-21 14:45:05 -0700415 }
Aart Bikd14c5952015-09-08 15:25:15 -0700416 }
Aart Bikb3365e02015-09-21 14:45:05 -0700417 return Value();
Aart Bikd14c5952015-09-08 15:25:15 -0700418}
419
Aart Bikb738d4f2015-12-03 11:23:35 -0800420InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) {
421 if (v.instruction != nullptr) {
422 HLoopInformation* loop =
423 v.instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop
424 if (loop != nullptr) {
425 // Set up loop information.
426 bool in_body = true; // use is always in body of outer loop
427 HInductionVarAnalysis::InductionInfo* info =
428 induction_analysis_->LookupInfo(loop, v.instruction);
429 HInductionVarAnalysis::InductionInfo* trip =
430 induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction());
431 // Try to refine "a x instruction + b" with outer loop range information on instruction.
432 return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)),
433 Value(v.b_constant));
434 }
435 }
436 return v;
437}
438
Aart Bikaec3cce2015-10-14 17:44:55 -0700439bool InductionVarRange::GenerateCode(HInstruction* context,
440 HInstruction* instruction,
441 HGraph* graph,
442 HBasicBlock* block,
443 /*out*/HInstruction** lower,
444 /*out*/HInstruction** upper,
Aart Bik389b3db2015-10-28 14:23:40 -0700445 /*out*/HInstruction** taken_test,
446 /*out*/bool* needs_finite_test,
447 /*out*/bool* needs_taken_test) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700448 HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop
449 if (loop != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700450 // Set up loop information.
Aart Bikaec3cce2015-10-14 17:44:55 -0700451 HBasicBlock* header = loop->GetHeader();
452 bool in_body = context->GetBlock() != header;
Aart Bik389b3db2015-10-28 14:23:40 -0700453 HInductionVarAnalysis::InductionInfo* info =
454 induction_analysis_->LookupInfo(loop, instruction);
455 if (info == nullptr) {
456 return false; // nothing to analyze
457 }
Aart Bikaec3cce2015-10-14 17:44:55 -0700458 HInductionVarAnalysis::InductionInfo* trip =
459 induction_analysis_->LookupInfo(loop, header->GetLastInstruction());
Aart Bik4a342772015-11-30 10:17:46 -0800460 // Determine what tests are needed. A finite test is needed if the evaluation code uses the
461 // trip-count and the loop maybe unsafe (because in such cases, the index could "overshoot"
462 // the computed range). A taken test is needed for any unknown trip-count, even if evaluation
463 // code does not use the trip-count explicitly (since there could be an implicit relation
464 // between e.g. an invariant subscript and a not-taken condition).
Aart Bik389b3db2015-10-28 14:23:40 -0700465 *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
Aart Bik4a342772015-11-30 10:17:46 -0800466 *needs_taken_test = IsBodyTripCount(trip);
Aart Bik389b3db2015-10-28 14:23:40 -0700467 // Code generation for taken test: generate the code when requested or otherwise analyze
468 // if code generation is feasible when taken test is needed.
469 if (taken_test != nullptr) {
470 return GenerateCode(
471 trip->op_b, nullptr, graph, block, taken_test, in_body, /* is_min */ false);
472 } else if (*needs_taken_test) {
473 if (!GenerateCode(
474 trip->op_b, nullptr, nullptr, nullptr, nullptr, in_body, /* is_min */ false)) {
475 return false;
Aart Bikaec3cce2015-10-14 17:44:55 -0700476 }
Aart Bik389b3db2015-10-28 14:23:40 -0700477 }
478 // Code generation for lower and upper.
479 return
Aart Bikaec3cce2015-10-14 17:44:55 -0700480 // Success on lower if invariant (not set), or code can be generated.
481 ((info->induction_class == HInductionVarAnalysis::kInvariant) ||
482 GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) &&
483 // And success on upper.
484 GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
Aart Bikaec3cce2015-10-14 17:44:55 -0700485 }
486 return false;
487}
488
489bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
490 HInductionVarAnalysis::InductionInfo* trip,
491 HGraph* graph, // when set, code is generated
492 HBasicBlock* block,
493 /*out*/HInstruction** result,
494 bool in_body,
495 bool is_min) {
496 if (info != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700497 // Handle current operation.
Aart Bikaec3cce2015-10-14 17:44:55 -0700498 Primitive::Type type = Primitive::kPrimInt;
499 HInstruction* opa = nullptr;
500 HInstruction* opb = nullptr;
Aart Bikaec3cce2015-10-14 17:44:55 -0700501 switch (info->induction_class) {
502 case HInductionVarAnalysis::kInvariant:
503 // Invariants.
504 switch (info->operation) {
505 case HInductionVarAnalysis::kAdd:
Aart Bik389b3db2015-10-28 14:23:40 -0700506 case HInductionVarAnalysis::kLT:
507 case HInductionVarAnalysis::kLE:
508 case HInductionVarAnalysis::kGT:
509 case HInductionVarAnalysis::kGE:
Aart Bikaec3cce2015-10-14 17:44:55 -0700510 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
511 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
512 if (graph != nullptr) {
Aart Bik389b3db2015-10-28 14:23:40 -0700513 HInstruction* operation = nullptr;
514 switch (info->operation) {
515 case HInductionVarAnalysis::kAdd:
516 operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
517 case HInductionVarAnalysis::kLT:
518 operation = new (graph->GetArena()) HLessThan(opa, opb); break;
519 case HInductionVarAnalysis::kLE:
520 operation = new (graph->GetArena()) HLessThanOrEqual(opa, opb); break;
521 case HInductionVarAnalysis::kGT:
522 operation = new (graph->GetArena()) HGreaterThan(opa, opb); break;
523 case HInductionVarAnalysis::kGE:
524 operation = new (graph->GetArena()) HGreaterThanOrEqual(opa, opb); break;
525 default:
526 LOG(FATAL) << "unknown operation";
527 }
528 *result = Insert(block, operation);
Aart Bikaec3cce2015-10-14 17:44:55 -0700529 }
530 return true;
531 }
532 break;
533 case HInductionVarAnalysis::kSub: // second reversed!
534 if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) &&
535 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
536 if (graph != nullptr) {
537 *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb));
538 }
539 return true;
540 }
541 break;
542 case HInductionVarAnalysis::kNeg: // reversed!
543 if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) {
544 if (graph != nullptr) {
545 *result = Insert(block, new (graph->GetArena()) HNeg(type, opb));
546 }
547 return true;
548 }
549 break;
550 case HInductionVarAnalysis::kFetch:
Aart Bik4a342772015-11-30 10:17:46 -0800551 if (info->fetch->GetType() == type) {
552 if (graph != nullptr) {
553 *result = info->fetch; // already in HIR
554 }
555 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700556 }
Aart Bik4a342772015-11-30 10:17:46 -0800557 break;
Aart Bikaec3cce2015-10-14 17:44:55 -0700558 case HInductionVarAnalysis::kTripCountInLoop:
Aart Bik389b3db2015-10-28 14:23:40 -0700559 case HInductionVarAnalysis::kTripCountInLoopUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700560 if (!in_body && !is_min) { // one extra!
Aart Bik22f05872015-10-27 15:56:28 -0700561 return GenerateCode(info->op_a, trip, graph, block, result, in_body, is_min);
Aart Bikaec3cce2015-10-14 17:44:55 -0700562 }
563 FALLTHROUGH_INTENDED;
564 case HInductionVarAnalysis::kTripCountInBody:
Aart Bik389b3db2015-10-28 14:23:40 -0700565 case HInductionVarAnalysis::kTripCountInBodyUnsafe:
Aart Bikaec3cce2015-10-14 17:44:55 -0700566 if (is_min) {
567 if (graph != nullptr) {
568 *result = graph->GetIntConstant(0);
569 }
570 return true;
571 } else if (in_body) {
Aart Bik22f05872015-10-27 15:56:28 -0700572 if (GenerateCode(info->op_a, trip, graph, block, &opb, in_body, is_min)) {
Aart Bikaec3cce2015-10-14 17:44:55 -0700573 if (graph != nullptr) {
574 *result = Insert(block,
575 new (graph->GetArena())
576 HSub(type, opb, graph->GetIntConstant(1)));
577 }
578 return true;
579 }
580 }
581 break;
582 default:
583 break;
584 }
585 break;
Aart Bik389b3db2015-10-28 14:23:40 -0700586 case HInductionVarAnalysis::kLinear: {
Aart Bik4a342772015-11-30 10:17:46 -0800587 // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
588 // to avoid arithmetic wrap-around situations that are hard to guard against.
589 int32_t stride_value = 0;
590 if (GetConstant(info->op_a, &stride_value)) {
591 if (stride_value == 1 || stride_value == -1) {
592 const bool is_min_a = stride_value == 1 ? is_min : !is_min;
593 if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) &&
594 GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
595 if (graph != nullptr) {
596 HInstruction* oper;
597 if (stride_value == 1) {
598 oper = new (graph->GetArena()) HAdd(type, opa, opb);
599 } else {
600 oper = new (graph->GetArena()) HSub(type, opb, opa);
Aart Bik389b3db2015-10-28 14:23:40 -0700601 }
Aart Bik4a342772015-11-30 10:17:46 -0800602 *result = Insert(block, oper);
Aart Bikaec3cce2015-10-14 17:44:55 -0700603 }
Aart Bik4a342772015-11-30 10:17:46 -0800604 return true;
Aart Bikaec3cce2015-10-14 17:44:55 -0700605 }
606 }
607 }
608 break;
Aart Bik4a342772015-11-30 10:17:46 -0800609 }
610 case HInductionVarAnalysis::kWrapAround:
611 case HInductionVarAnalysis::kPeriodic: {
612 // Wrap-around and periodic inductions are restricted to constants only, so that extreme
613 // values are easy to test at runtime without complications of arithmetic wrap-around.
614 Value extreme = GetVal(info, trip, in_body, is_min);
615 if (extreme.is_known && extreme.a_constant == 0) {
616 if (graph != nullptr) {
617 *result = graph->GetIntConstant(extreme.b_constant);
618 }
619 return true;
620 }
621 break;
622 }
Aart Bik389b3db2015-10-28 14:23:40 -0700623 default:
Aart Bikaec3cce2015-10-14 17:44:55 -0700624 break;
625 }
626 }
627 return false;
628}
629
Aart Bikd14c5952015-09-08 15:25:15 -0700630} // namespace art