blob: bcee5638fc9f24faa87a5e9488ea8e383c2ea5ad [file] [log] [blame]
Mingyao Yangf384f882014-10-22 16:08:18 -07001/*
2 * Copyright (C) 2014 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
17#include "bounds_check_elimination.h"
18#include "nodes.h"
19#include "utils/arena_containers.h"
20
21namespace art {
22
23class MonotonicValueRange;
24
25/**
26 * A value bound is represented as a pair of value and constant,
27 * e.g. array.length - 1.
28 */
29class ValueBound : public ValueObject {
30 public:
Mingyao Yang0304e182015-01-30 16:41:29 -080031 ValueBound(HInstruction* instruction, int32_t constant) {
Mingyao Yang64197522014-12-05 15:56:23 -080032 if (instruction != nullptr && instruction->IsIntConstant()) {
Mingyao Yang0304e182015-01-30 16:41:29 -080033 // Normalize ValueBound with constant instruction.
34 int32_t instr_const = instruction->AsIntConstant()->GetValue();
Mingyao Yang64197522014-12-05 15:56:23 -080035 if (constant >= 0 && (instr_const <= INT_MAX - constant)) {
36 // No overflow.
37 instruction_ = nullptr;
38 constant_ = instr_const + constant;
39 return;
40 }
41 if (constant < 0 && (instr_const >= INT_MIN - constant)) {
42 // No underflow.
43 instruction_ = nullptr;
44 constant_ = instr_const + constant;
45 return;
46 }
Mingyao Yangf384f882014-10-22 16:08:18 -070047 }
Mingyao Yang64197522014-12-05 15:56:23 -080048 instruction_ = instruction;
49 constant_ = constant;
50 }
51
Mingyao Yang0304e182015-01-30 16:41:29 -080052 static bool IsAddOrSubAConstant(HInstruction* instruction,
53 HInstruction** left_instruction,
54 int* right_constant) {
55 if (instruction->IsAdd() || instruction->IsSub()) {
56 HBinaryOperation* bin_op = instruction->AsBinaryOperation();
57 HInstruction* left = bin_op->GetLeft();
58 HInstruction* right = bin_op->GetRight();
59 if (right->IsIntConstant()) {
60 *left_instruction = left;
61 int32_t c = right->AsIntConstant()->GetValue();
62 *right_constant = instruction->IsAdd() ? c : -c;
63 return true;
64 }
65 }
66 *left_instruction = nullptr;
67 *right_constant = 0;
68 return false;
69 }
70
Mingyao Yang64197522014-12-05 15:56:23 -080071 // Try to detect useful value bound format from an instruction, e.g.
72 // a constant or array length related value.
73 static ValueBound DetectValueBoundFromValue(HInstruction* instruction, bool* found) {
74 DCHECK(instruction != nullptr);
Mingyao Yangf384f882014-10-22 16:08:18 -070075 if (instruction->IsIntConstant()) {
Mingyao Yang64197522014-12-05 15:56:23 -080076 *found = true;
77 return ValueBound(nullptr, instruction->AsIntConstant()->GetValue());
Mingyao Yangf384f882014-10-22 16:08:18 -070078 }
Mingyao Yang64197522014-12-05 15:56:23 -080079
80 if (instruction->IsArrayLength()) {
81 *found = true;
82 return ValueBound(instruction, 0);
83 }
84 // Try to detect (array.length + c) format.
Mingyao Yang0304e182015-01-30 16:41:29 -080085 HInstruction *left;
86 int32_t right;
87 if (IsAddOrSubAConstant(instruction, &left, &right)) {
88 if (left->IsArrayLength()) {
Mingyao Yang64197522014-12-05 15:56:23 -080089 *found = true;
Mingyao Yang0304e182015-01-30 16:41:29 -080090 return ValueBound(left, right);
Mingyao Yang64197522014-12-05 15:56:23 -080091 }
92 }
93
94 // No useful bound detected.
95 *found = false;
96 return ValueBound::Max();
Mingyao Yangf384f882014-10-22 16:08:18 -070097 }
98
99 HInstruction* GetInstruction() const { return instruction_; }
Mingyao Yang0304e182015-01-30 16:41:29 -0800100 int32_t GetConstant() const { return constant_; }
Mingyao Yangf384f882014-10-22 16:08:18 -0700101
Mingyao Yang0304e182015-01-30 16:41:29 -0800102 bool IsRelatedToArrayLength() const {
103 // Some bounds are created with HNewArray* as the instruction instead
104 // of HArrayLength*. They are treated the same.
105 return (instruction_ != nullptr) &&
106 (instruction_->IsArrayLength() || instruction_->IsNewArray());
Mingyao Yangf384f882014-10-22 16:08:18 -0700107 }
108
109 bool IsConstant() const {
110 return instruction_ == nullptr;
111 }
112
113 static ValueBound Min() { return ValueBound(nullptr, INT_MIN); }
114 static ValueBound Max() { return ValueBound(nullptr, INT_MAX); }
115
116 bool Equals(ValueBound bound) const {
117 return instruction_ == bound.instruction_ && constant_ == bound.constant_;
118 }
119
Mingyao Yang0304e182015-01-30 16:41:29 -0800120 static HInstruction* FromArrayLengthToNewArrayIfPossible(HInstruction* instruction) {
121 // Null check on the NewArray should have been eliminated by instruction
122 // simplifier already.
123 if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) {
124 return instruction->InputAt(0)->AsNewArray();
125 }
126 return instruction;
127 }
128
129 static bool Equal(HInstruction* instruction1, HInstruction* instruction2) {
130 if (instruction1 == instruction2) {
131 return true;
132 }
133
134 if (instruction1 == nullptr || instruction2 == nullptr) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700135 return false;
136 }
Mingyao Yang0304e182015-01-30 16:41:29 -0800137
138 // Some bounds are created with HNewArray* as the instruction instead
139 // of HArrayLength*. They are treated the same.
140 instruction1 = FromArrayLengthToNewArrayIfPossible(instruction1);
141 instruction2 = FromArrayLengthToNewArrayIfPossible(instruction2);
142 return instruction1 == instruction2;
143 }
144
145 // Returns if it's certain this->bound >= `bound`.
146 bool GreaterThanOrEqualTo(ValueBound bound) const {
147 if (Equal(instruction_, bound.instruction_)) {
148 return constant_ >= bound.constant_;
149 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700150 // Not comparable. Just return false.
151 return false;
152 }
153
Mingyao Yang0304e182015-01-30 16:41:29 -0800154 // Returns if it's certain this->bound <= `bound`.
155 bool LessThanOrEqualTo(ValueBound bound) const {
156 if (Equal(instruction_, bound.instruction_)) {
157 return constant_ <= bound.constant_;
Mingyao Yangf384f882014-10-22 16:08:18 -0700158 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700159 // Not comparable. Just return false.
160 return false;
161 }
162
163 // Try to narrow lower bound. Returns the greatest of the two if possible.
164 // Pick one if they are not comparable.
165 static ValueBound NarrowLowerBound(ValueBound bound1, ValueBound bound2) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800166 if (bound1.GreaterThanOrEqualTo(bound2)) {
167 return bound1;
168 }
169 if (bound2.GreaterThanOrEqualTo(bound1)) {
170 return bound2;
Mingyao Yangf384f882014-10-22 16:08:18 -0700171 }
172
173 // Not comparable. Just pick one. We may lose some info, but that's ok.
174 // Favor constant as lower bound.
175 return bound1.IsConstant() ? bound1 : bound2;
176 }
177
178 // Try to narrow upper bound. Returns the lowest of the two if possible.
179 // Pick one if they are not comparable.
180 static ValueBound NarrowUpperBound(ValueBound bound1, ValueBound bound2) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800181 if (bound1.LessThanOrEqualTo(bound2)) {
182 return bound1;
183 }
184 if (bound2.LessThanOrEqualTo(bound1)) {
185 return bound2;
Mingyao Yangf384f882014-10-22 16:08:18 -0700186 }
187
188 // Not comparable. Just pick one. We may lose some info, but that's ok.
189 // Favor array length as upper bound.
Mingyao Yang0304e182015-01-30 16:41:29 -0800190 return bound1.IsRelatedToArrayLength() ? bound1 : bound2;
Mingyao Yangf384f882014-10-22 16:08:18 -0700191 }
192
Mingyao Yang0304e182015-01-30 16:41:29 -0800193 // Add a constant to a ValueBound.
194 // `overflow` or `underflow` will return whether the resulting bound may
195 // overflow or underflow an int.
196 ValueBound Add(int32_t c, bool* overflow, bool* underflow) const {
197 *overflow = *underflow = false;
Mingyao Yangf384f882014-10-22 16:08:18 -0700198 if (c == 0) {
199 return *this;
200 }
201
Mingyao Yang0304e182015-01-30 16:41:29 -0800202 int32_t new_constant;
Mingyao Yangf384f882014-10-22 16:08:18 -0700203 if (c > 0) {
204 if (constant_ > INT_MAX - c) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800205 *overflow = true;
Mingyao Yang64197522014-12-05 15:56:23 -0800206 return Max();
Mingyao Yangf384f882014-10-22 16:08:18 -0700207 }
Mingyao Yang0304e182015-01-30 16:41:29 -0800208
209 new_constant = constant_ + c;
210 // (array.length + non-positive-constant) won't overflow an int.
211 if (IsConstant() || (IsRelatedToArrayLength() && new_constant <= 0)) {
212 return ValueBound(instruction_, new_constant);
213 }
214 // Be conservative.
215 *overflow = true;
216 return Max();
Mingyao Yangf384f882014-10-22 16:08:18 -0700217 } else {
218 if (constant_ < INT_MIN - c) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800219 *underflow = true;
220 return Min();
Mingyao Yangf384f882014-10-22 16:08:18 -0700221 }
Mingyao Yang0304e182015-01-30 16:41:29 -0800222
223 new_constant = constant_ + c;
224 // Regardless of the value new_constant, (array.length+new_constant) will
225 // never underflow since array.length is no less than 0.
226 if (IsConstant() || IsRelatedToArrayLength()) {
227 return ValueBound(instruction_, new_constant);
228 }
229 // Be conservative.
230 *underflow = true;
231 return Min();
Mingyao Yangf384f882014-10-22 16:08:18 -0700232 }
233 return ValueBound(instruction_, new_constant);
234 }
235
236 private:
Mingyao Yangf384f882014-10-22 16:08:18 -0700237 HInstruction* instruction_;
Mingyao Yang0304e182015-01-30 16:41:29 -0800238 int32_t constant_;
Mingyao Yangf384f882014-10-22 16:08:18 -0700239};
240
241/**
242 * Represent a range of lower bound and upper bound, both being inclusive.
243 * Currently a ValueRange may be generated as a result of the following:
244 * comparisons related to array bounds, array bounds check, add/sub on top
Mingyao Yang0304e182015-01-30 16:41:29 -0800245 * of an existing value range, NewArray or a loop phi corresponding to an
Mingyao Yangf384f882014-10-22 16:08:18 -0700246 * incrementing/decrementing array index (MonotonicValueRange).
247 */
248class ValueRange : public ArenaObject<kArenaAllocMisc> {
249 public:
250 ValueRange(ArenaAllocator* allocator, ValueBound lower, ValueBound upper)
251 : allocator_(allocator), lower_(lower), upper_(upper) {}
252
253 virtual ~ValueRange() {}
254
255 virtual const MonotonicValueRange* AsMonotonicValueRange() const { return nullptr; }
256 bool IsMonotonicValueRange() const {
257 return AsMonotonicValueRange() != nullptr;
258 }
259
260 ArenaAllocator* GetAllocator() const { return allocator_; }
261 ValueBound GetLower() const { return lower_; }
262 ValueBound GetUpper() const { return upper_; }
263
264 // If it's certain that this value range fits in other_range.
265 virtual bool FitsIn(ValueRange* other_range) const {
266 if (other_range == nullptr) {
267 return true;
268 }
269 DCHECK(!other_range->IsMonotonicValueRange());
Mingyao Yang0304e182015-01-30 16:41:29 -0800270 return lower_.GreaterThanOrEqualTo(other_range->lower_) &&
271 upper_.LessThanOrEqualTo(other_range->upper_);
Mingyao Yangf384f882014-10-22 16:08:18 -0700272 }
273
274 // Returns the intersection of this and range.
275 // If it's not possible to do intersection because some
276 // bounds are not comparable, it's ok to pick either bound.
277 virtual ValueRange* Narrow(ValueRange* range) {
278 if (range == nullptr) {
279 return this;
280 }
281
282 if (range->IsMonotonicValueRange()) {
283 return this;
284 }
285
286 return new (allocator_) ValueRange(
287 allocator_,
288 ValueBound::NarrowLowerBound(lower_, range->lower_),
289 ValueBound::NarrowUpperBound(upper_, range->upper_));
290 }
291
Mingyao Yang0304e182015-01-30 16:41:29 -0800292 // Shift a range by a constant.
293 ValueRange* Add(int32_t constant) const {
294 bool overflow, underflow;
295 ValueBound lower = lower_.Add(constant, &overflow, &underflow);
296 if (underflow) {
297 // Lower bound underflow will wrap around to positive values
298 // and invalidate the upper bound.
299 return nullptr;
Mingyao Yangf384f882014-10-22 16:08:18 -0700300 }
Mingyao Yang0304e182015-01-30 16:41:29 -0800301 ValueBound upper = upper_.Add(constant, &overflow, &underflow);
302 if (overflow) {
303 // Upper bound overflow will wrap around to negative values
304 // and invalidate the lower bound.
305 return nullptr;
Mingyao Yangf384f882014-10-22 16:08:18 -0700306 }
307 return new (allocator_) ValueRange(allocator_, lower, upper);
308 }
309
Mingyao Yangf384f882014-10-22 16:08:18 -0700310 private:
311 ArenaAllocator* const allocator_;
312 const ValueBound lower_; // inclusive
313 const ValueBound upper_; // inclusive
314
315 DISALLOW_COPY_AND_ASSIGN(ValueRange);
316};
317
318/**
319 * A monotonically incrementing/decrementing value range, e.g.
320 * the variable i in "for (int i=0; i<array.length; i++)".
321 * Special care needs to be taken to account for overflow/underflow
322 * of such value ranges.
323 */
324class MonotonicValueRange : public ValueRange {
325 public:
Mingyao Yang64197522014-12-05 15:56:23 -0800326 MonotonicValueRange(ArenaAllocator* allocator,
327 HInstruction* initial,
Mingyao Yang0304e182015-01-30 16:41:29 -0800328 int32_t increment,
Mingyao Yang64197522014-12-05 15:56:23 -0800329 ValueBound bound)
330 // To be conservative, give it full range [INT_MIN, INT_MAX] in case it's
331 // used as a regular value range, due to possible overflow/underflow.
332 : ValueRange(allocator, ValueBound::Min(), ValueBound::Max()),
333 initial_(initial),
334 increment_(increment),
335 bound_(bound) {}
Mingyao Yangf384f882014-10-22 16:08:18 -0700336
337 virtual ~MonotonicValueRange() {}
338
339 const MonotonicValueRange* AsMonotonicValueRange() const OVERRIDE { return this; }
340
341 // If it's certain that this value range fits in other_range.
342 bool FitsIn(ValueRange* other_range) const OVERRIDE {
343 if (other_range == nullptr) {
344 return true;
345 }
346 DCHECK(!other_range->IsMonotonicValueRange());
347 return false;
348 }
349
350 // Try to narrow this MonotonicValueRange given another range.
351 // Ideally it will return a normal ValueRange. But due to
352 // possible overflow/underflow, that may not be possible.
353 ValueRange* Narrow(ValueRange* range) OVERRIDE {
354 if (range == nullptr) {
355 return this;
356 }
357 DCHECK(!range->IsMonotonicValueRange());
358
359 if (increment_ > 0) {
360 // Monotonically increasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800361 ValueBound lower = ValueBound::NarrowLowerBound(bound_, range->GetLower());
Mingyao Yangf384f882014-10-22 16:08:18 -0700362
363 // We currently conservatively assume max array length is INT_MAX. If we can
364 // make assumptions about the max array length, e.g. due to the max heap size,
365 // divided by the element size (such as 4 bytes for each integer array), we can
366 // lower this number and rule out some possible overflows.
Mingyao Yang0304e182015-01-30 16:41:29 -0800367 int32_t max_array_len = INT_MAX;
Mingyao Yangf384f882014-10-22 16:08:18 -0700368
Mingyao Yang0304e182015-01-30 16:41:29 -0800369 // max possible integer value of range's upper value.
370 int32_t upper = INT_MAX;
371 // Try to lower upper.
372 ValueBound upper_bound = range->GetUpper();
373 if (upper_bound.IsConstant()) {
374 upper = upper_bound.GetConstant();
375 } else if (upper_bound.IsRelatedToArrayLength() && upper_bound.GetConstant() <= 0) {
376 // Normal case. e.g. <= array.length - 1.
377 upper = max_array_len + upper_bound.GetConstant();
Mingyao Yangf384f882014-10-22 16:08:18 -0700378 }
379
380 // If we can prove for the last number in sequence of initial_,
381 // initial_ + increment_, initial_ + 2 x increment_, ...
382 // that's <= upper, (last_num_in_sequence + increment_) doesn't trigger overflow,
383 // then this MonoticValueRange is narrowed to a normal value range.
384
385 // Be conservative first, assume last number in the sequence hits upper.
Mingyao Yang0304e182015-01-30 16:41:29 -0800386 int32_t last_num_in_sequence = upper;
Mingyao Yangf384f882014-10-22 16:08:18 -0700387 if (initial_->IsIntConstant()) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800388 int32_t initial_constant = initial_->AsIntConstant()->GetValue();
Mingyao Yangf384f882014-10-22 16:08:18 -0700389 if (upper <= initial_constant) {
390 last_num_in_sequence = upper;
391 } else {
Mingyao Yang0304e182015-01-30 16:41:29 -0800392 // Cast to int64_t for the substraction part to avoid int32_t overflow.
Mingyao Yangf384f882014-10-22 16:08:18 -0700393 last_num_in_sequence = initial_constant +
394 ((int64_t)upper - (int64_t)initial_constant) / increment_ * increment_;
395 }
396 }
397 if (last_num_in_sequence <= INT_MAX - increment_) {
398 // No overflow. The sequence will be stopped by the upper bound test as expected.
399 return new (GetAllocator()) ValueRange(GetAllocator(), lower, range->GetUpper());
400 }
401
402 // There might be overflow. Give up narrowing.
403 return this;
404 } else {
405 DCHECK_NE(increment_, 0);
406 // Monotonically decreasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800407 ValueBound upper = ValueBound::NarrowUpperBound(bound_, range->GetUpper());
Mingyao Yangf384f882014-10-22 16:08:18 -0700408
409 // Need to take care of underflow. Try to prove underflow won't happen
Mingyao Yang0304e182015-01-30 16:41:29 -0800410 // for common cases.
Mingyao Yangf384f882014-10-22 16:08:18 -0700411 if (range->GetLower().IsConstant()) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800412 int32_t constant = range->GetLower().GetConstant();
Mingyao Yangf384f882014-10-22 16:08:18 -0700413 if (constant >= INT_MIN - increment_) {
414 return new (GetAllocator()) ValueRange(GetAllocator(), range->GetLower(), upper);
415 }
416 }
417
Mingyao Yang0304e182015-01-30 16:41:29 -0800418 // For non-constant lower bound, just assume might be underflow. Give up narrowing.
Mingyao Yangf384f882014-10-22 16:08:18 -0700419 return this;
420 }
421 }
422
423 private:
Mingyao Yangf384f882014-10-22 16:08:18 -0700424 HInstruction* const initial_;
Mingyao Yang0304e182015-01-30 16:41:29 -0800425 const int32_t increment_;
Mingyao Yang64197522014-12-05 15:56:23 -0800426 ValueBound bound_; // Additional value bound info for initial_;
Mingyao Yangf384f882014-10-22 16:08:18 -0700427
428 DISALLOW_COPY_AND_ASSIGN(MonotonicValueRange);
429};
430
431class BCEVisitor : public HGraphVisitor {
432 public:
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800433 explicit BCEVisitor(HGraph* graph)
Mingyao Yangf384f882014-10-22 16:08:18 -0700434 : HGraphVisitor(graph),
435 maps_(graph->GetBlocks().Size()) {}
436
437 private:
438 // Return the map of proven value ranges at the beginning of a basic block.
439 ArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) {
440 int block_id = basic_block->GetBlockId();
441 if (maps_.at(block_id) == nullptr) {
442 std::unique_ptr<ArenaSafeMap<int, ValueRange*>> map(
443 new ArenaSafeMap<int, ValueRange*>(
444 std::less<int>(), GetGraph()->GetArena()->Adapter()));
445 maps_.at(block_id) = std::move(map);
446 }
447 return maps_.at(block_id).get();
448 }
449
450 // Traverse up the dominator tree to look for value range info.
451 ValueRange* LookupValueRange(HInstruction* instruction, HBasicBlock* basic_block) {
452 while (basic_block != nullptr) {
453 ArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block);
454 if (map->find(instruction->GetId()) != map->end()) {
455 return map->Get(instruction->GetId());
456 }
457 basic_block = basic_block->GetDominator();
458 }
459 // Didn't find any.
460 return nullptr;
461 }
462
Mingyao Yang0304e182015-01-30 16:41:29 -0800463 // Narrow the value range of `instruction` at the end of `basic_block` with `range`,
464 // and push the narrowed value range to `successor`.
Mingyao Yangf384f882014-10-22 16:08:18 -0700465 void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
466 HBasicBlock* successor, ValueRange* range) {
467 ValueRange* existing_range = LookupValueRange(instruction, basic_block);
468 ValueRange* narrowed_range = (existing_range == nullptr) ?
469 range : existing_range->Narrow(range);
470 if (narrowed_range != nullptr) {
471 GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
472 }
473 }
474
475 // Handle "if (left cmp_cond right)".
476 void HandleIf(HIf* instruction, HInstruction* left, HInstruction* right, IfCondition cond) {
477 HBasicBlock* block = instruction->GetBlock();
478
479 HBasicBlock* true_successor = instruction->IfTrueSuccessor();
480 // There should be no critical edge at this point.
481 DCHECK_EQ(true_successor->GetPredecessors().Size(), 1u);
482
483 HBasicBlock* false_successor = instruction->IfFalseSuccessor();
484 // There should be no critical edge at this point.
485 DCHECK_EQ(false_successor->GetPredecessors().Size(), 1u);
486
Mingyao Yang64197522014-12-05 15:56:23 -0800487 bool found;
488 ValueBound bound = ValueBound::DetectValueBoundFromValue(right, &found);
Mingyao Yang0304e182015-01-30 16:41:29 -0800489 // Each comparison can establish a lower bound and an upper bound
490 // for the left hand side.
Mingyao Yangf384f882014-10-22 16:08:18 -0700491 ValueBound lower = bound;
492 ValueBound upper = bound;
493 if (!found) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800494 // No constant or array.length+c format bound found.
Mingyao Yangf384f882014-10-22 16:08:18 -0700495 // For i<j, we can still use j's upper bound as i's upper bound. Same for lower.
496 ValueRange* range = LookupValueRange(right, block);
497 if (range != nullptr) {
498 lower = range->GetLower();
499 upper = range->GetUpper();
500 } else {
501 lower = ValueBound::Min();
502 upper = ValueBound::Max();
503 }
504 }
505
Mingyao Yang0304e182015-01-30 16:41:29 -0800506 bool overflow, underflow;
Mingyao Yangf384f882014-10-22 16:08:18 -0700507 if (cond == kCondLT || cond == kCondLE) {
508 if (!upper.Equals(ValueBound::Max())) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800509 int32_t compensation = (cond == kCondLT) ? -1 : 0; // upper bound is inclusive
510 ValueBound new_upper = upper.Add(compensation, &overflow, &underflow);
511 if (overflow || underflow) {
512 return;
Mingyao Yang64197522014-12-05 15:56:23 -0800513 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700514 ValueRange* new_range = new (GetGraph()->GetArena())
515 ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
516 ApplyRangeFromComparison(left, block, true_successor, new_range);
517 }
518
519 // array.length as a lower bound isn't considered useful.
Mingyao Yang0304e182015-01-30 16:41:29 -0800520 if (!lower.Equals(ValueBound::Min()) && !lower.IsRelatedToArrayLength()) {
521 int32_t compensation = (cond == kCondLE) ? 1 : 0; // lower bound is inclusive
522 ValueBound new_lower = lower.Add(compensation, &overflow, &underflow);
523 if (overflow || underflow) {
524 return;
Mingyao Yang64197522014-12-05 15:56:23 -0800525 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700526 ValueRange* new_range = new (GetGraph()->GetArena())
527 ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
528 ApplyRangeFromComparison(left, block, false_successor, new_range);
529 }
530 } else if (cond == kCondGT || cond == kCondGE) {
531 // array.length as a lower bound isn't considered useful.
Mingyao Yang0304e182015-01-30 16:41:29 -0800532 if (!lower.Equals(ValueBound::Min()) && !lower.IsRelatedToArrayLength()) {
533 int32_t compensation = (cond == kCondGT) ? 1 : 0; // lower bound is inclusive
534 ValueBound new_lower = lower.Add(compensation, &overflow, &underflow);
535 if (overflow || underflow) {
536 return;
Mingyao Yang64197522014-12-05 15:56:23 -0800537 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700538 ValueRange* new_range = new (GetGraph()->GetArena())
539 ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
540 ApplyRangeFromComparison(left, block, true_successor, new_range);
541 }
542
543 if (!upper.Equals(ValueBound::Max())) {
Mingyao Yang0304e182015-01-30 16:41:29 -0800544 int32_t compensation = (cond == kCondGE) ? -1 : 0; // upper bound is inclusive
545 ValueBound new_upper = upper.Add(compensation, &overflow, &underflow);
546 if (overflow || underflow) {
547 return;
Mingyao Yang64197522014-12-05 15:56:23 -0800548 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700549 ValueRange* new_range = new (GetGraph()->GetArena())
550 ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
551 ApplyRangeFromComparison(left, block, false_successor, new_range);
552 }
553 }
554 }
555
556 void VisitBoundsCheck(HBoundsCheck* bounds_check) {
557 HBasicBlock* block = bounds_check->GetBlock();
558 HInstruction* index = bounds_check->InputAt(0);
559 HInstruction* array_length = bounds_check->InputAt(1);
Mingyao Yang0304e182015-01-30 16:41:29 -0800560 DCHECK(array_length->IsIntConstant() || array_length->IsArrayLength());
Mingyao Yangf384f882014-10-22 16:08:18 -0700561
Mingyao Yang0304e182015-01-30 16:41:29 -0800562 if (!index->IsIntConstant()) {
563 ValueRange* index_range = LookupValueRange(index, block);
564 if (index_range != nullptr) {
565 ValueBound lower = ValueBound(nullptr, 0); // constant 0
566 ValueBound upper = ValueBound(array_length, -1); // array_length - 1
567 ValueRange* array_range = new (GetGraph()->GetArena())
568 ValueRange(GetGraph()->GetArena(), lower, upper);
569 if (index_range->FitsIn(array_range)) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700570 ReplaceBoundsCheck(bounds_check, index);
571 return;
572 }
573 }
Mingyao Yang0304e182015-01-30 16:41:29 -0800574 } else {
575 int32_t constant = index->AsIntConstant()->GetValue();
576 if (constant < 0) {
577 // Will always throw exception.
578 return;
579 }
580 if (array_length->IsIntConstant()) {
581 if (constant < array_length->AsIntConstant()->GetValue()) {
582 ReplaceBoundsCheck(bounds_check, index);
583 }
584 return;
585 }
586
587 DCHECK(array_length->IsArrayLength());
588 ValueRange* existing_range = LookupValueRange(array_length, block);
589 if (existing_range != nullptr) {
590 ValueBound lower = existing_range->GetLower();
591 DCHECK(lower.IsConstant());
592 if (constant < lower.GetConstant()) {
593 ReplaceBoundsCheck(bounds_check, index);
594 return;
595 } else {
596 // Existing range isn't strong enough to eliminate the bounds check.
597 // Fall through to update the array_length range with info from this
598 // bounds check.
599 }
600 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700601
602 // Once we have an array access like 'array[5] = 1', we record array.length >= 6.
Mingyao Yang0304e182015-01-30 16:41:29 -0800603 // We currently don't do it for non-constant index since a valid array[i] can't prove
604 // a valid array[i-1] yet due to the lower bound side.
Mingyao Yang64197522014-12-05 15:56:23 -0800605 ValueBound lower = ValueBound(nullptr, constant + 1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700606 ValueBound upper = ValueBound::Max();
607 ValueRange* range = new (GetGraph()->GetArena())
608 ValueRange(GetGraph()->GetArena(), lower, upper);
Mingyao Yang0304e182015-01-30 16:41:29 -0800609 GetValueRangeMap(block)->Overwrite(array_length->GetId(), range);
Mingyao Yangf384f882014-10-22 16:08:18 -0700610 }
611 }
612
613 void ReplaceBoundsCheck(HInstruction* bounds_check, HInstruction* index) {
614 bounds_check->ReplaceWith(index);
615 bounds_check->GetBlock()->RemoveInstruction(bounds_check);
616 }
617
618 void VisitPhi(HPhi* phi) {
619 if (phi->IsLoopHeaderPhi() && phi->GetType() == Primitive::kPrimInt) {
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800620 DCHECK_EQ(phi->InputCount(), 2U);
Mingyao Yangf384f882014-10-22 16:08:18 -0700621 HInstruction* instruction = phi->InputAt(1);
Mingyao Yang0304e182015-01-30 16:41:29 -0800622 HInstruction *left;
623 int32_t increment;
624 if (ValueBound::IsAddOrSubAConstant(instruction, &left, &increment)) {
625 if (left == phi) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700626 HInstruction* initial_value = phi->InputAt(0);
627 ValueRange* range = nullptr;
Mingyao Yang64197522014-12-05 15:56:23 -0800628 if (increment == 0) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700629 // Add constant 0. It's really a fixed value.
630 range = new (GetGraph()->GetArena()) ValueRange(
631 GetGraph()->GetArena(),
Mingyao Yang64197522014-12-05 15:56:23 -0800632 ValueBound(initial_value, 0),
633 ValueBound(initial_value, 0));
Mingyao Yangf384f882014-10-22 16:08:18 -0700634 } else {
635 // Monotonically increasing/decreasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800636 bool found;
637 ValueBound bound = ValueBound::DetectValueBoundFromValue(
638 initial_value, &found);
639 if (!found) {
640 // No constant or array.length+c bound found.
641 // For i=j, we can still use j's upper bound as i's upper bound.
642 // Same for lower.
643 ValueRange* initial_range = LookupValueRange(initial_value, phi->GetBlock());
644 if (initial_range != nullptr) {
645 bound = increment > 0 ? initial_range->GetLower() :
646 initial_range->GetUpper();
647 } else {
648 bound = increment > 0 ? ValueBound::Min() : ValueBound::Max();
649 }
650 }
651 range = new (GetGraph()->GetArena()) MonotonicValueRange(
Mingyao Yangf384f882014-10-22 16:08:18 -0700652 GetGraph()->GetArena(),
653 initial_value,
Mingyao Yang64197522014-12-05 15:56:23 -0800654 increment,
655 bound);
Mingyao Yangf384f882014-10-22 16:08:18 -0700656 }
657 GetValueRangeMap(phi->GetBlock())->Overwrite(phi->GetId(), range);
658 }
659 }
660 }
661 }
662
663 void VisitIf(HIf* instruction) {
664 if (instruction->InputAt(0)->IsCondition()) {
665 HCondition* cond = instruction->InputAt(0)->AsCondition();
666 IfCondition cmp = cond->GetCondition();
667 if (cmp == kCondGT || cmp == kCondGE ||
668 cmp == kCondLT || cmp == kCondLE) {
669 HInstruction* left = cond->GetLeft();
670 HInstruction* right = cond->GetRight();
671 HandleIf(instruction, left, right, cmp);
672 }
673 }
674 }
675
676 void VisitAdd(HAdd* add) {
677 HInstruction* right = add->GetRight();
678 if (right->IsIntConstant()) {
679 ValueRange* left_range = LookupValueRange(add->GetLeft(), add->GetBlock());
680 if (left_range == nullptr) {
681 return;
682 }
683 ValueRange* range = left_range->Add(right->AsIntConstant()->GetValue());
684 if (range != nullptr) {
685 GetValueRangeMap(add->GetBlock())->Overwrite(add->GetId(), range);
686 }
687 }
688 }
689
690 void VisitSub(HSub* sub) {
691 HInstruction* left = sub->GetLeft();
692 HInstruction* right = sub->GetRight();
693 if (right->IsIntConstant()) {
694 ValueRange* left_range = LookupValueRange(left, sub->GetBlock());
695 if (left_range == nullptr) {
696 return;
697 }
698 ValueRange* range = left_range->Add(-right->AsIntConstant()->GetValue());
699 if (range != nullptr) {
700 GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
701 return;
702 }
703 }
704
705 // Here we are interested in the typical triangular case of nested loops,
706 // such as the inner loop 'for (int j=0; j<array.length-i; j++)' where i
707 // is the index for outer loop. In this case, we know j is bounded by array.length-1.
708 if (left->IsArrayLength()) {
709 HInstruction* array_length = left->AsArrayLength();
710 ValueRange* right_range = LookupValueRange(right, sub->GetBlock());
711 if (right_range != nullptr) {
712 ValueBound lower = right_range->GetLower();
713 ValueBound upper = right_range->GetUpper();
Mingyao Yang0304e182015-01-30 16:41:29 -0800714 if (lower.IsConstant() && upper.IsRelatedToArrayLength()) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700715 HInstruction* upper_inst = upper.GetInstruction();
Mingyao Yang0304e182015-01-30 16:41:29 -0800716 // Make sure it's the same array.
717 if (ValueBound::Equal(array_length, upper_inst)) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700718 // (array.length - v) where v is in [c1, array.length + c2]
719 // gets [-c2, array.length - c1] as its value range.
720 ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
721 GetGraph()->GetArena(),
Mingyao Yang64197522014-12-05 15:56:23 -0800722 ValueBound(nullptr, - upper.GetConstant()),
723 ValueBound(array_length, - lower.GetConstant()));
Mingyao Yangf384f882014-10-22 16:08:18 -0700724 GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
725 }
726 }
727 }
728 }
729 }
730
Mingyao Yang0304e182015-01-30 16:41:29 -0800731 void VisitNewArray(HNewArray* new_array) {
732 HInstruction* len = new_array->InputAt(0);
733 if (!len->IsIntConstant()) {
734 HInstruction *left;
735 int32_t right_const;
736 if (ValueBound::IsAddOrSubAConstant(len, &left, &right_const)) {
737 // (left + right_const) is used as size to new the array.
738 // We record "-right_const <= left <= new_array - right_const";
739 ValueBound lower = ValueBound(nullptr, -right_const);
740 // We use new_array for the bound instead of new_array.length,
741 // which isn't available as an instruction yet. new_array will
742 // be treated the same as new_array.length when it's used in a ValueBound.
743 ValueBound upper = ValueBound(new_array, -right_const);
744 ValueRange* range = new (GetGraph()->GetArena())
745 ValueRange(GetGraph()->GetArena(), lower, upper);
746 GetValueRangeMap(new_array->GetBlock())->Overwrite(left->GetId(), range);
747 }
748 }
749 }
750
Mingyao Yangf384f882014-10-22 16:08:18 -0700751 std::vector<std::unique_ptr<ArenaSafeMap<int, ValueRange*>>> maps_;
752
753 DISALLOW_COPY_AND_ASSIGN(BCEVisitor);
754};
755
756void BoundsCheckElimination::Run() {
757 BCEVisitor visitor(graph_);
758 // Reverse post order guarantees a node's dominators are visited first.
759 // We want to visit in the dominator-based order since if a value is known to
760 // be bounded by a range at one instruction, it must be true that all uses of
761 // that value dominated by that instruction fits in that range. Range of that
762 // value can be narrowed further down in the dominator tree.
763 //
764 // TODO: only visit blocks that dominate some array accesses.
765 visitor.VisitReversePostOrder();
766}
767
768} // namespace art