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