blob: d6c35157265d51a6c943770cb470b0748e88b5de [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 Yang64197522014-12-05 15:56:23 -080031 ValueBound(HInstruction* instruction, int constant) {
32 if (instruction != nullptr && instruction->IsIntConstant()) {
33 // Normalizing ValueBound with constant instruction.
34 int instr_const = instruction->AsIntConstant()->GetValue();
35 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
52 // Try to detect useful value bound format from an instruction, e.g.
53 // a constant or array length related value.
54 static ValueBound DetectValueBoundFromValue(HInstruction* instruction, bool* found) {
55 DCHECK(instruction != nullptr);
Mingyao Yangf384f882014-10-22 16:08:18 -070056 if (instruction->IsIntConstant()) {
Mingyao Yang64197522014-12-05 15:56:23 -080057 *found = true;
58 return ValueBound(nullptr, instruction->AsIntConstant()->GetValue());
Mingyao Yangf384f882014-10-22 16:08:18 -070059 }
Mingyao Yang64197522014-12-05 15:56:23 -080060
61 if (instruction->IsArrayLength()) {
62 *found = true;
63 return ValueBound(instruction, 0);
64 }
65 // Try to detect (array.length + c) format.
66 if (instruction->IsAdd()) {
67 HAdd* add = instruction->AsAdd();
68 HInstruction* left = add->GetLeft();
69 HInstruction* right = add->GetRight();
70 if (left->IsArrayLength() && right->IsIntConstant()) {
71 *found = true;
72 return ValueBound(left, right->AsIntConstant()->GetValue());
73 }
74 }
75
76 // No useful bound detected.
77 *found = false;
78 return ValueBound::Max();
Mingyao Yangf384f882014-10-22 16:08:18 -070079 }
80
81 HInstruction* GetInstruction() const { return instruction_; }
82 int GetConstant() const { return constant_; }
83
84 bool IsRelativeToArrayLength() const {
85 return instruction_ != nullptr && instruction_->IsArrayLength();
86 }
87
88 bool IsConstant() const {
89 return instruction_ == nullptr;
90 }
91
92 static ValueBound Min() { return ValueBound(nullptr, INT_MIN); }
93 static ValueBound Max() { return ValueBound(nullptr, INT_MAX); }
94
95 bool Equals(ValueBound bound) const {
96 return instruction_ == bound.instruction_ && constant_ == bound.constant_;
97 }
98
99 // Returns if it's certain bound1 >= bound2.
100 bool GreaterThanOrEqual(ValueBound bound) const {
101 if (instruction_ == bound.instruction_) {
102 if (instruction_ == nullptr) {
103 // Pure constant.
104 return constant_ >= bound.constant_;
105 }
106 // There might be overflow/underflow. Be conservative for now.
107 return false;
108 }
109 // Not comparable. Just return false.
110 return false;
111 }
112
113 // Returns if it's certain bound1 <= bound2.
114 bool LessThanOrEqual(ValueBound bound) const {
115 if (instruction_ == bound.instruction_) {
116 if (instruction_ == nullptr) {
117 // Pure constant.
118 return constant_ <= bound.constant_;
119 }
120 if (IsRelativeToArrayLength()) {
121 // Array length is guaranteed to be no less than 0.
122 // No overflow/underflow can happen if both constants are negative.
123 if (constant_ <= 0 && bound.constant_ <= 0) {
124 return constant_ <= bound.constant_;
125 }
126 // There might be overflow/underflow. Be conservative for now.
127 return false;
128 }
129 }
130
131 // In case the array length is some constant, we can
132 // still compare.
133 if (IsConstant() && bound.IsRelativeToArrayLength()) {
134 HInstruction* array = bound.GetInstruction()->AsArrayLength()->InputAt(0);
135 if (array->IsNullCheck()) {
136 array = array->AsNullCheck()->InputAt(0);
137 }
138 if (array->IsNewArray()) {
139 HInstruction* len = array->InputAt(0);
140 if (len->IsIntConstant()) {
141 int len_const = len->AsIntConstant()->GetValue();
142 return constant_ <= len_const + bound.GetConstant();
143 }
144 }
145 }
146
147 // Not comparable. Just return false.
148 return false;
149 }
150
151 // Try to narrow lower bound. Returns the greatest of the two if possible.
152 // Pick one if they are not comparable.
153 static ValueBound NarrowLowerBound(ValueBound bound1, ValueBound bound2) {
154 if (bound1.instruction_ == bound2.instruction_) {
155 // Same instruction, compare the constant part.
156 return ValueBound(bound1.instruction_,
157 std::max(bound1.constant_, bound2.constant_));
158 }
159
160 // Not comparable. Just pick one. We may lose some info, but that's ok.
161 // Favor constant as lower bound.
162 return bound1.IsConstant() ? bound1 : bound2;
163 }
164
165 // Try to narrow upper bound. Returns the lowest of the two if possible.
166 // Pick one if they are not comparable.
167 static ValueBound NarrowUpperBound(ValueBound bound1, ValueBound bound2) {
168 if (bound1.instruction_ == bound2.instruction_) {
169 // Same instruction, compare the constant part.
170 return ValueBound(bound1.instruction_,
171 std::min(bound1.constant_, bound2.constant_));
172 }
173
174 // Not comparable. Just pick one. We may lose some info, but that's ok.
175 // Favor array length as upper bound.
176 return bound1.IsRelativeToArrayLength() ? bound1 : bound2;
177 }
178
179 // Add a constant to a ValueBound. If the constant part of the ValueBound
180 // overflows/underflows, then we can't accurately represent it. For correctness,
181 // just return Max/Min() depending on whether the returned ValueBound is used for
182 // lower/upper bound.
Mingyao Yang64197522014-12-05 15:56:23 -0800183 ValueBound Add(int c, bool* overflow_or_underflow) const {
Mingyao Yangf384f882014-10-22 16:08:18 -0700184 *overflow_or_underflow = false;
185 if (c == 0) {
186 return *this;
187 }
188
189 int new_constant;
190 if (c > 0) {
191 if (constant_ > INT_MAX - c) {
192 // Constant part overflows.
193 *overflow_or_underflow = true;
Mingyao Yang64197522014-12-05 15:56:23 -0800194 return Max();
Mingyao Yangf384f882014-10-22 16:08:18 -0700195 } else {
196 new_constant = constant_ + c;
197 }
198 } else {
199 if (constant_ < INT_MIN - c) {
200 // Constant part underflows.
201 *overflow_or_underflow = true;
Mingyao Yang64197522014-12-05 15:56:23 -0800202 return Max();
Mingyao Yangf384f882014-10-22 16:08:18 -0700203 } else {
204 new_constant = constant_ + c;
205 }
206 }
207 return ValueBound(instruction_, new_constant);
208 }
209
210 private:
Mingyao Yangf384f882014-10-22 16:08:18 -0700211 HInstruction* instruction_;
212 int constant_;
213};
214
215/**
216 * Represent a range of lower bound and upper bound, both being inclusive.
217 * Currently a ValueRange may be generated as a result of the following:
218 * comparisons related to array bounds, array bounds check, add/sub on top
219 * of an existing value range, or a loop phi corresponding to an
220 * incrementing/decrementing array index (MonotonicValueRange).
221 */
222class ValueRange : public ArenaObject<kArenaAllocMisc> {
223 public:
224 ValueRange(ArenaAllocator* allocator, ValueBound lower, ValueBound upper)
225 : allocator_(allocator), lower_(lower), upper_(upper) {}
226
227 virtual ~ValueRange() {}
228
229 virtual const MonotonicValueRange* AsMonotonicValueRange() const { return nullptr; }
230 bool IsMonotonicValueRange() const {
231 return AsMonotonicValueRange() != nullptr;
232 }
233
234 ArenaAllocator* GetAllocator() const { return allocator_; }
235 ValueBound GetLower() const { return lower_; }
236 ValueBound GetUpper() const { return upper_; }
237
238 // If it's certain that this value range fits in other_range.
239 virtual bool FitsIn(ValueRange* other_range) const {
240 if (other_range == nullptr) {
241 return true;
242 }
243 DCHECK(!other_range->IsMonotonicValueRange());
244 return lower_.GreaterThanOrEqual(other_range->lower_) &&
245 upper_.LessThanOrEqual(other_range->upper_);
246 }
247
248 // Returns the intersection of this and range.
249 // If it's not possible to do intersection because some
250 // bounds are not comparable, it's ok to pick either bound.
251 virtual ValueRange* Narrow(ValueRange* range) {
252 if (range == nullptr) {
253 return this;
254 }
255
256 if (range->IsMonotonicValueRange()) {
257 return this;
258 }
259
260 return new (allocator_) ValueRange(
261 allocator_,
262 ValueBound::NarrowLowerBound(lower_, range->lower_),
263 ValueBound::NarrowUpperBound(upper_, range->upper_));
264 }
265
266 // Shift a range by a constant. If either bound can't be represented
267 // as (instruction+c) format due to possible overflow/underflow,
268 // return the full integer range.
269 ValueRange* Add(int constant) const {
270 bool overflow_or_underflow;
Mingyao Yang64197522014-12-05 15:56:23 -0800271 ValueBound lower = lower_.Add(constant, &overflow_or_underflow);
Mingyao Yangf384f882014-10-22 16:08:18 -0700272 if (overflow_or_underflow) {
273 // We can't accurately represent the bounds anymore.
274 return FullIntRange();
275 }
Mingyao Yang64197522014-12-05 15:56:23 -0800276 ValueBound upper = upper_.Add(constant, &overflow_or_underflow);
Mingyao Yangf384f882014-10-22 16:08:18 -0700277 if (overflow_or_underflow) {
278 // We can't accurately represent the bounds anymore.
279 return FullIntRange();
280 }
281 return new (allocator_) ValueRange(allocator_, lower, upper);
282 }
283
284 // Return [INT_MIN, INT_MAX].
285 ValueRange* FullIntRange() const {
286 return new (allocator_) ValueRange(allocator_, ValueBound::Min(), ValueBound::Max());
287 }
288
289 private:
290 ArenaAllocator* const allocator_;
291 const ValueBound lower_; // inclusive
292 const ValueBound upper_; // inclusive
293
294 DISALLOW_COPY_AND_ASSIGN(ValueRange);
295};
296
297/**
298 * A monotonically incrementing/decrementing value range, e.g.
299 * the variable i in "for (int i=0; i<array.length; i++)".
300 * Special care needs to be taken to account for overflow/underflow
301 * of such value ranges.
302 */
303class MonotonicValueRange : public ValueRange {
304 public:
Mingyao Yang64197522014-12-05 15:56:23 -0800305 MonotonicValueRange(ArenaAllocator* allocator,
306 HInstruction* initial,
307 int increment,
308 ValueBound bound)
309 // To be conservative, give it full range [INT_MIN, INT_MAX] in case it's
310 // used as a regular value range, due to possible overflow/underflow.
311 : ValueRange(allocator, ValueBound::Min(), ValueBound::Max()),
312 initial_(initial),
313 increment_(increment),
314 bound_(bound) {}
Mingyao Yangf384f882014-10-22 16:08:18 -0700315
316 virtual ~MonotonicValueRange() {}
317
318 const MonotonicValueRange* AsMonotonicValueRange() const OVERRIDE { return this; }
319
320 // If it's certain that this value range fits in other_range.
321 bool FitsIn(ValueRange* other_range) const OVERRIDE {
322 if (other_range == nullptr) {
323 return true;
324 }
325 DCHECK(!other_range->IsMonotonicValueRange());
326 return false;
327 }
328
329 // Try to narrow this MonotonicValueRange given another range.
330 // Ideally it will return a normal ValueRange. But due to
331 // possible overflow/underflow, that may not be possible.
332 ValueRange* Narrow(ValueRange* range) OVERRIDE {
333 if (range == nullptr) {
334 return this;
335 }
336 DCHECK(!range->IsMonotonicValueRange());
337
338 if (increment_ > 0) {
339 // Monotonically increasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800340 ValueBound lower = ValueBound::NarrowLowerBound(bound_, range->GetLower());
Mingyao Yangf384f882014-10-22 16:08:18 -0700341
342 // We currently conservatively assume max array length is INT_MAX. If we can
343 // make assumptions about the max array length, e.g. due to the max heap size,
344 // divided by the element size (such as 4 bytes for each integer array), we can
345 // lower this number and rule out some possible overflows.
346 int max_array_len = INT_MAX;
347
348 int upper = INT_MAX;
349 if (range->GetUpper().IsConstant()) {
350 upper = range->GetUpper().GetConstant();
351 } else if (range->GetUpper().IsRelativeToArrayLength()) {
352 int constant = range->GetUpper().GetConstant();
353 if (constant <= 0) {
354 // Normal case. e.g. <= array.length - 1, <= array.length - 2, etc.
355 upper = max_array_len + constant;
356 } else {
357 // There might be overflow. Give up narrowing.
358 return this;
359 }
360 } else {
361 // There might be overflow. Give up narrowing.
362 return this;
363 }
364
365 // If we can prove for the last number in sequence of initial_,
366 // initial_ + increment_, initial_ + 2 x increment_, ...
367 // that's <= upper, (last_num_in_sequence + increment_) doesn't trigger overflow,
368 // then this MonoticValueRange is narrowed to a normal value range.
369
370 // Be conservative first, assume last number in the sequence hits upper.
371 int last_num_in_sequence = upper;
372 if (initial_->IsIntConstant()) {
373 int initial_constant = initial_->AsIntConstant()->GetValue();
374 if (upper <= initial_constant) {
375 last_num_in_sequence = upper;
376 } else {
377 // Cast to int64_t for the substraction part to avoid int overflow.
378 last_num_in_sequence = initial_constant +
379 ((int64_t)upper - (int64_t)initial_constant) / increment_ * increment_;
380 }
381 }
382 if (last_num_in_sequence <= INT_MAX - increment_) {
383 // No overflow. The sequence will be stopped by the upper bound test as expected.
384 return new (GetAllocator()) ValueRange(GetAllocator(), lower, range->GetUpper());
385 }
386
387 // There might be overflow. Give up narrowing.
388 return this;
389 } else {
390 DCHECK_NE(increment_, 0);
391 // Monotonically decreasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800392 ValueBound upper = ValueBound::NarrowUpperBound(bound_, range->GetUpper());
Mingyao Yangf384f882014-10-22 16:08:18 -0700393
394 // Need to take care of underflow. Try to prove underflow won't happen
395 // for common cases. Basically need to be able to prove for any value
396 // that's >= range->GetLower(), it won't be positive with value+increment.
397 if (range->GetLower().IsConstant()) {
398 int constant = range->GetLower().GetConstant();
399 if (constant >= INT_MIN - increment_) {
400 return new (GetAllocator()) ValueRange(GetAllocator(), range->GetLower(), upper);
401 }
402 }
403
404 // There might be underflow. Give up narrowing.
405 return this;
406 }
407 }
408
409 private:
Mingyao Yangf384f882014-10-22 16:08:18 -0700410 HInstruction* const initial_;
411 const int increment_;
Mingyao Yang64197522014-12-05 15:56:23 -0800412 ValueBound bound_; // Additional value bound info for initial_;
Mingyao Yangf384f882014-10-22 16:08:18 -0700413
414 DISALLOW_COPY_AND_ASSIGN(MonotonicValueRange);
415};
416
417class BCEVisitor : public HGraphVisitor {
418 public:
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800419 explicit BCEVisitor(HGraph* graph)
Mingyao Yangf384f882014-10-22 16:08:18 -0700420 : HGraphVisitor(graph),
421 maps_(graph->GetBlocks().Size()) {}
422
423 private:
424 // Return the map of proven value ranges at the beginning of a basic block.
425 ArenaSafeMap<int, ValueRange*>* GetValueRangeMap(HBasicBlock* basic_block) {
426 int block_id = basic_block->GetBlockId();
427 if (maps_.at(block_id) == nullptr) {
428 std::unique_ptr<ArenaSafeMap<int, ValueRange*>> map(
429 new ArenaSafeMap<int, ValueRange*>(
430 std::less<int>(), GetGraph()->GetArena()->Adapter()));
431 maps_.at(block_id) = std::move(map);
432 }
433 return maps_.at(block_id).get();
434 }
435
436 // Traverse up the dominator tree to look for value range info.
437 ValueRange* LookupValueRange(HInstruction* instruction, HBasicBlock* basic_block) {
438 while (basic_block != nullptr) {
439 ArenaSafeMap<int, ValueRange*>* map = GetValueRangeMap(basic_block);
440 if (map->find(instruction->GetId()) != map->end()) {
441 return map->Get(instruction->GetId());
442 }
443 basic_block = basic_block->GetDominator();
444 }
445 // Didn't find any.
446 return nullptr;
447 }
448
Mingyao Yangf384f882014-10-22 16:08:18 -0700449 // Narrow the value range of 'instruction' at the end of 'basic_block' with 'range',
450 // and push the narrowed value range to 'successor'.
451 void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
452 HBasicBlock* successor, ValueRange* range) {
453 ValueRange* existing_range = LookupValueRange(instruction, basic_block);
454 ValueRange* narrowed_range = (existing_range == nullptr) ?
455 range : existing_range->Narrow(range);
456 if (narrowed_range != nullptr) {
457 GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
458 }
459 }
460
461 // Handle "if (left cmp_cond right)".
462 void HandleIf(HIf* instruction, HInstruction* left, HInstruction* right, IfCondition cond) {
463 HBasicBlock* block = instruction->GetBlock();
464
465 HBasicBlock* true_successor = instruction->IfTrueSuccessor();
466 // There should be no critical edge at this point.
467 DCHECK_EQ(true_successor->GetPredecessors().Size(), 1u);
468
469 HBasicBlock* false_successor = instruction->IfFalseSuccessor();
470 // There should be no critical edge at this point.
471 DCHECK_EQ(false_successor->GetPredecessors().Size(), 1u);
472
Mingyao Yang64197522014-12-05 15:56:23 -0800473 bool found;
474 ValueBound bound = ValueBound::DetectValueBoundFromValue(right, &found);
Mingyao Yangf384f882014-10-22 16:08:18 -0700475 ValueBound lower = bound;
476 ValueBound upper = bound;
477 if (!found) {
478 // No constant or array.length+c bound found.
479 // For i<j, we can still use j's upper bound as i's upper bound. Same for lower.
480 ValueRange* range = LookupValueRange(right, block);
481 if (range != nullptr) {
482 lower = range->GetLower();
483 upper = range->GetUpper();
484 } else {
485 lower = ValueBound::Min();
486 upper = ValueBound::Max();
487 }
488 }
489
490 bool overflow_or_underflow;
491 if (cond == kCondLT || cond == kCondLE) {
492 if (!upper.Equals(ValueBound::Max())) {
493 int compensation = (cond == kCondLT) ? -1 : 0; // upper bound is inclusive
Mingyao Yang64197522014-12-05 15:56:23 -0800494 ValueBound new_upper = upper.Add(compensation, &overflow_or_underflow);
495 if (overflow_or_underflow) {
496 new_upper = ValueBound::Max();
497 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700498 ValueRange* new_range = new (GetGraph()->GetArena())
499 ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
500 ApplyRangeFromComparison(left, block, true_successor, new_range);
501 }
502
503 // array.length as a lower bound isn't considered useful.
504 if (!lower.Equals(ValueBound::Min()) && !lower.IsRelativeToArrayLength()) {
505 int compensation = (cond == kCondLE) ? 1 : 0; // lower bound is inclusive
Mingyao Yang64197522014-12-05 15:56:23 -0800506 ValueBound new_lower = lower.Add(compensation, &overflow_or_underflow);
507 if (overflow_or_underflow) {
508 new_lower = ValueBound::Min();
509 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700510 ValueRange* new_range = new (GetGraph()->GetArena())
511 ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
512 ApplyRangeFromComparison(left, block, false_successor, new_range);
513 }
514 } else if (cond == kCondGT || cond == kCondGE) {
515 // array.length as a lower bound isn't considered useful.
516 if (!lower.Equals(ValueBound::Min()) && !lower.IsRelativeToArrayLength()) {
517 int compensation = (cond == kCondGT) ? 1 : 0; // lower bound is inclusive
Mingyao Yang64197522014-12-05 15:56:23 -0800518 ValueBound new_lower = lower.Add(compensation, &overflow_or_underflow);
519 if (overflow_or_underflow) {
520 new_lower = ValueBound::Min();
521 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700522 ValueRange* new_range = new (GetGraph()->GetArena())
523 ValueRange(GetGraph()->GetArena(), new_lower, ValueBound::Max());
524 ApplyRangeFromComparison(left, block, true_successor, new_range);
525 }
526
527 if (!upper.Equals(ValueBound::Max())) {
528 int compensation = (cond == kCondGE) ? -1 : 0; // upper bound is inclusive
Mingyao Yang64197522014-12-05 15:56:23 -0800529 ValueBound new_upper = upper.Add(compensation, &overflow_or_underflow);
530 if (overflow_or_underflow) {
531 new_upper = ValueBound::Max();
532 }
Mingyao Yangf384f882014-10-22 16:08:18 -0700533 ValueRange* new_range = new (GetGraph()->GetArena())
534 ValueRange(GetGraph()->GetArena(), ValueBound::Min(), new_upper);
535 ApplyRangeFromComparison(left, block, false_successor, new_range);
536 }
537 }
538 }
539
540 void VisitBoundsCheck(HBoundsCheck* bounds_check) {
541 HBasicBlock* block = bounds_check->GetBlock();
542 HInstruction* index = bounds_check->InputAt(0);
543 HInstruction* array_length = bounds_check->InputAt(1);
544 ValueRange* index_range = LookupValueRange(index, block);
545
546 if (index_range != nullptr) {
Mingyao Yang64197522014-12-05 15:56:23 -0800547 ValueBound lower = ValueBound(nullptr, 0); // constant 0
548 ValueBound upper = ValueBound(array_length, -1); // array_length - 1
Mingyao Yangf384f882014-10-22 16:08:18 -0700549 ValueRange* array_range = new (GetGraph()->GetArena())
550 ValueRange(GetGraph()->GetArena(), lower, upper);
551 if (index_range->FitsIn(array_range)) {
552 ReplaceBoundsCheck(bounds_check, index);
553 return;
554 }
555 }
556
557 if (index->IsIntConstant()) {
558 ValueRange* array_length_range = LookupValueRange(array_length, block);
559 int constant = index->AsIntConstant()->GetValue();
560 if (array_length_range != nullptr &&
561 array_length_range->GetLower().IsConstant()) {
562 if (constant < array_length_range->GetLower().GetConstant()) {
563 ReplaceBoundsCheck(bounds_check, index);
564 return;
565 }
566 }
567
568 // Once we have an array access like 'array[5] = 1', we record array.length >= 6.
Mingyao Yang64197522014-12-05 15:56:23 -0800569 ValueBound lower = ValueBound(nullptr, constant + 1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700570 ValueBound upper = ValueBound::Max();
571 ValueRange* range = new (GetGraph()->GetArena())
572 ValueRange(GetGraph()->GetArena(), lower, upper);
573 ValueRange* existing_range = LookupValueRange(array_length, block);
574 ValueRange* new_range = range;
575 if (existing_range != nullptr) {
576 new_range = range->Narrow(existing_range);
577 }
578 GetValueRangeMap(block)->Overwrite(array_length->GetId(), new_range);
579 }
580 }
581
582 void ReplaceBoundsCheck(HInstruction* bounds_check, HInstruction* index) {
583 bounds_check->ReplaceWith(index);
584 bounds_check->GetBlock()->RemoveInstruction(bounds_check);
585 }
586
587 void VisitPhi(HPhi* phi) {
588 if (phi->IsLoopHeaderPhi() && phi->GetType() == Primitive::kPrimInt) {
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800589 DCHECK_EQ(phi->InputCount(), 2U);
Mingyao Yangf384f882014-10-22 16:08:18 -0700590 HInstruction* instruction = phi->InputAt(1);
591 if (instruction->IsAdd()) {
592 HAdd* add = instruction->AsAdd();
593 HInstruction* left = add->GetLeft();
594 HInstruction* right = add->GetRight();
595 if (left == phi && right->IsIntConstant()) {
596 HInstruction* initial_value = phi->InputAt(0);
597 ValueRange* range = nullptr;
Mingyao Yang64197522014-12-05 15:56:23 -0800598 int increment = right->AsIntConstant()->GetValue();
599 if (increment == 0) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700600 // Add constant 0. It's really a fixed value.
601 range = new (GetGraph()->GetArena()) ValueRange(
602 GetGraph()->GetArena(),
Mingyao Yang64197522014-12-05 15:56:23 -0800603 ValueBound(initial_value, 0),
604 ValueBound(initial_value, 0));
Mingyao Yangf384f882014-10-22 16:08:18 -0700605 } else {
606 // Monotonically increasing/decreasing.
Mingyao Yang64197522014-12-05 15:56:23 -0800607 bool found;
608 ValueBound bound = ValueBound::DetectValueBoundFromValue(
609 initial_value, &found);
610 if (!found) {
611 // No constant or array.length+c bound found.
612 // For i=j, we can still use j's upper bound as i's upper bound.
613 // Same for lower.
614 ValueRange* initial_range = LookupValueRange(initial_value, phi->GetBlock());
615 if (initial_range != nullptr) {
616 bound = increment > 0 ? initial_range->GetLower() :
617 initial_range->GetUpper();
618 } else {
619 bound = increment > 0 ? ValueBound::Min() : ValueBound::Max();
620 }
621 }
622 range = new (GetGraph()->GetArena()) MonotonicValueRange(
Mingyao Yangf384f882014-10-22 16:08:18 -0700623 GetGraph()->GetArena(),
624 initial_value,
Mingyao Yang64197522014-12-05 15:56:23 -0800625 increment,
626 bound);
Mingyao Yangf384f882014-10-22 16:08:18 -0700627 }
628 GetValueRangeMap(phi->GetBlock())->Overwrite(phi->GetId(), range);
629 }
630 }
631 }
632 }
633
634 void VisitIf(HIf* instruction) {
635 if (instruction->InputAt(0)->IsCondition()) {
636 HCondition* cond = instruction->InputAt(0)->AsCondition();
637 IfCondition cmp = cond->GetCondition();
638 if (cmp == kCondGT || cmp == kCondGE ||
639 cmp == kCondLT || cmp == kCondLE) {
640 HInstruction* left = cond->GetLeft();
641 HInstruction* right = cond->GetRight();
642 HandleIf(instruction, left, right, cmp);
643 }
644 }
645 }
646
647 void VisitAdd(HAdd* add) {
648 HInstruction* right = add->GetRight();
649 if (right->IsIntConstant()) {
650 ValueRange* left_range = LookupValueRange(add->GetLeft(), add->GetBlock());
651 if (left_range == nullptr) {
652 return;
653 }
654 ValueRange* range = left_range->Add(right->AsIntConstant()->GetValue());
655 if (range != nullptr) {
656 GetValueRangeMap(add->GetBlock())->Overwrite(add->GetId(), range);
657 }
658 }
659 }
660
661 void VisitSub(HSub* sub) {
662 HInstruction* left = sub->GetLeft();
663 HInstruction* right = sub->GetRight();
664 if (right->IsIntConstant()) {
665 ValueRange* left_range = LookupValueRange(left, sub->GetBlock());
666 if (left_range == nullptr) {
667 return;
668 }
669 ValueRange* range = left_range->Add(-right->AsIntConstant()->GetValue());
670 if (range != nullptr) {
671 GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
672 return;
673 }
674 }
675
676 // Here we are interested in the typical triangular case of nested loops,
677 // such as the inner loop 'for (int j=0; j<array.length-i; j++)' where i
678 // is the index for outer loop. In this case, we know j is bounded by array.length-1.
679 if (left->IsArrayLength()) {
680 HInstruction* array_length = left->AsArrayLength();
681 ValueRange* right_range = LookupValueRange(right, sub->GetBlock());
682 if (right_range != nullptr) {
683 ValueBound lower = right_range->GetLower();
684 ValueBound upper = right_range->GetUpper();
685 if (lower.IsConstant() && upper.IsRelativeToArrayLength()) {
686 HInstruction* upper_inst = upper.GetInstruction();
687 if (upper_inst->IsArrayLength() &&
688 upper_inst->AsArrayLength() == array_length) {
689 // (array.length - v) where v is in [c1, array.length + c2]
690 // gets [-c2, array.length - c1] as its value range.
691 ValueRange* range = new (GetGraph()->GetArena()) ValueRange(
692 GetGraph()->GetArena(),
Mingyao Yang64197522014-12-05 15:56:23 -0800693 ValueBound(nullptr, - upper.GetConstant()),
694 ValueBound(array_length, - lower.GetConstant()));
Mingyao Yangf384f882014-10-22 16:08:18 -0700695 GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
696 }
697 }
698 }
699 }
700 }
701
702 std::vector<std::unique_ptr<ArenaSafeMap<int, ValueRange*>>> maps_;
703
704 DISALLOW_COPY_AND_ASSIGN(BCEVisitor);
705};
706
707void BoundsCheckElimination::Run() {
708 BCEVisitor visitor(graph_);
709 // Reverse post order guarantees a node's dominators are visited first.
710 // We want to visit in the dominator-based order since if a value is known to
711 // be bounded by a range at one instruction, it must be true that all uses of
712 // that value dominated by that instruction fits in that range. Range of that
713 // value can be narrowed further down in the dominator tree.
714 //
715 // TODO: only visit blocks that dominate some array accesses.
716 visitor.VisitReversePostOrder();
717}
718
719} // namespace art