OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 2431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2442 intptr_t use_index = instr->env()->Length(); // Start index after inner. | 2442 intptr_t use_index = instr->env()->Length(); // Start index after inner. |
2443 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 2443 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
2444 Value* value = it.CurrentValue(); | 2444 Value* value = it.CurrentValue(); |
2445 value->set_instruction(instr); | 2445 value->set_instruction(instr); |
2446 value->set_use_index(use_index++); | 2446 value->set_use_index(use_index++); |
2447 value->definition()->AddEnvUse(value); | 2447 value->definition()->AddEnvUse(value); |
2448 } | 2448 } |
2449 } | 2449 } |
2450 | 2450 |
2451 | 2451 |
2452 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, intptr_t offs) { | 2452 RangeBoundary RangeBoundary::FromDefinition(Definition* defn, int64_t offs) { |
2453 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { | 2453 if (defn->IsConstant() && defn->AsConstant()->value().IsSmi()) { |
2454 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); | 2454 return FromConstant(Smi::Cast(defn->AsConstant()->value()).Value() + offs); |
2455 } | 2455 } |
2456 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); | 2456 return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs); |
2457 } | 2457 } |
2458 | 2458 |
2459 | 2459 |
2460 RangeBoundary RangeBoundary::LowerBound() const { | 2460 RangeBoundary RangeBoundary::LowerBound() const { |
2461 if (IsNegativeInfinity()) return *this; | 2461 if (IsInfinity()) { |
2462 return NegativeInfinity(); | |
2463 } | |
2462 if (IsConstant()) return *this; | 2464 if (IsConstant()) return *this; |
2463 return Add(Range::ConstantMin(symbol()->range()), | 2465 return Add(Range::ConstantMin(symbol()->range()), |
2464 RangeBoundary::FromConstant(offset_), | 2466 RangeBoundary::FromConstant(offset_), |
2465 NegativeInfinity()); | 2467 NegativeInfinity()); |
2466 } | 2468 } |
2467 | 2469 |
2468 | 2470 |
2469 RangeBoundary RangeBoundary::UpperBound() const { | 2471 RangeBoundary RangeBoundary::UpperBound() const { |
2470 if (IsPositiveInfinity()) return *this; | 2472 if (IsInfinity()) { |
2473 return PositiveInfinity(); | |
2474 } | |
2471 if (IsConstant()) return *this; | 2475 if (IsConstant()) return *this; |
2472 return Add(Range::ConstantMax(symbol()->range()), | 2476 return Add(Range::ConstantMax(symbol()->range()), |
2473 RangeBoundary::FromConstant(offset_), | 2477 RangeBoundary::FromConstant(offset_), |
2474 PositiveInfinity()); | 2478 PositiveInfinity()); |
2475 } | 2479 } |
2476 | 2480 |
2477 | 2481 |
2482 RangeBoundary RangeBoundary::Add(const RangeBoundary& a, | |
2483 const RangeBoundary& b, | |
2484 const RangeBoundary& overflow) { | |
2485 ASSERT(a.IsConstant() && b.IsConstant()); | |
2486 | |
2487 if (Utils::WillAddOverflow(a.ConstantValue(), b.ConstantValue())) { | |
2488 return overflow; | |
2489 } | |
2490 | |
2491 int64_t result = a.ConstantValue() + b.ConstantValue(); | |
2492 | |
2493 return RangeBoundary::FromConstant(result); | |
2494 } | |
2495 | |
2496 | |
2497 RangeBoundary RangeBoundary::Sub(const RangeBoundary& a, | |
2498 const RangeBoundary& b, | |
2499 const RangeBoundary& overflow) { | |
2500 ASSERT(a.IsConstant() && b.IsConstant()); | |
2501 | |
2502 if (Utils::WillSubOverflow(a.ConstantValue(), b.ConstantValue())) { | |
2503 return overflow; | |
2504 } | |
2505 | |
2506 int64_t result = a.ConstantValue() - b.ConstantValue(); | |
2507 | |
2508 return RangeBoundary::FromConstant(result); | |
2509 } | |
2510 | |
2511 | |
2512 bool RangeBoundary::SymbolicAdd(const RangeBoundary& a, | |
2513 const RangeBoundary& b, | |
2514 RangeBoundary* result) { | |
2515 if (a.IsSymbol() && b.IsConstant()) { | |
2516 if (Utils::WillAddOverflow(a.offset(), b.ConstantValue())) { | |
2517 return false; | |
2518 } | |
2519 | |
2520 const int64_t offset = a.offset() + b.ConstantValue(); | |
2521 | |
2522 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2523 return true; | |
2524 } else if (b.IsSymbol() && a.IsConstant()) { | |
2525 return SymbolicAdd(b, a, result); | |
2526 } | |
2527 return false; | |
2528 } | |
2529 | |
2530 | |
2531 bool RangeBoundary::SymbolicSub(const RangeBoundary& a, | |
2532 const RangeBoundary& b, | |
2533 RangeBoundary* result) { | |
2534 if (a.IsSymbol() && b.IsConstant()) { | |
2535 if (Utils::WillSubOverflow(a.offset(), b.ConstantValue())) { | |
2536 return false; | |
2537 } | |
2538 | |
2539 const int64_t offset = a.offset() - b.ConstantValue(); | |
2540 | |
2541 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2542 return true; | |
2543 } | |
2544 return false; | |
2545 } | |
2546 | |
2547 | |
2478 static Definition* UnwrapConstraint(Definition* defn) { | 2548 static Definition* UnwrapConstraint(Definition* defn) { |
2479 while (defn->IsConstraint()) { | 2549 while (defn->IsConstraint()) { |
2480 defn = defn->AsConstraint()->value()->definition(); | 2550 defn = defn->AsConstraint()->value()->definition(); |
2481 } | 2551 } |
2482 return defn; | 2552 return defn; |
2483 } | 2553 } |
2484 | 2554 |
2485 | 2555 |
2486 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 2556 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
2487 a = UnwrapConstraint(a); | 2557 a = UnwrapConstraint(a); |
2488 b = UnwrapConstraint(b); | 2558 b = UnwrapConstraint(b); |
2489 return (a == b) || | 2559 return (a == b) || |
2490 (a->AllowsCSE() && | 2560 (a->AllowsCSE() && |
2491 a->Dependencies().IsNone() && | 2561 a->Dependencies().IsNone() && |
2492 b->AllowsCSE() && | 2562 b->AllowsCSE() && |
2493 b->Dependencies().IsNone() && | 2563 b->Dependencies().IsNone() && |
2494 a->Equals(b)); | 2564 a->Equals(b)); |
2495 } | 2565 } |
2496 | 2566 |
2497 | 2567 |
2498 // Returns true if two range boundaries refer to the same symbol. | 2568 // Returns true if two range boundaries refer to the same symbol. |
2499 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { | 2569 static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { |
2500 return a.IsSymbol() && b.IsSymbol() && | 2570 return a.IsSymbol() && b.IsSymbol() && |
2501 AreEqualDefinitions(a.symbol(), b.symbol()); | 2571 AreEqualDefinitions(a.symbol(), b.symbol()); |
2502 } | 2572 } |
2503 | 2573 |
2504 | 2574 |
2505 // Returns true if range has a least specific minimum value. | 2575 bool RangeBoundary::Equals(const RangeBoundary& other) const { |
2506 static bool IsMinSmi(Range* range) { | 2576 if (IsConstant() && other.IsConstant()) { |
2507 return (range == NULL) || | 2577 return ConstantValue() == other.ConstantValue(); |
2508 (range->min().IsConstant() && | 2578 } else if (IsInfinity() && other.IsInfinity()) { |
2509 (range->min().value() <= Smi::kMinValue)); | 2579 return kind() == other.kind(); |
2580 } else if (IsSymbol() && other.IsSymbol()) { | |
2581 return (offset() == other.offset()) && DependOnSameSymbol(*this, other); | |
2582 } else if (IsUnknown() && other.IsUnknown()) { | |
2583 return true; | |
2584 } | |
2585 return false; | |
2510 } | 2586 } |
2511 | 2587 |
2512 | 2588 |
2513 // Returns true if range has a least specific maximium value. | 2589 RangeBoundary RangeBoundary::Shl(const RangeBoundary& value_boundary, |
2514 static bool IsMaxSmi(Range* range) { | 2590 int64_t shift_count, |
2515 return (range == NULL) || | 2591 const RangeBoundary& overflow) { |
2516 (range->max().IsConstant() && | 2592 ASSERT(value_boundary.IsConstant()); |
2517 (range->max().value() >= Smi::kMaxValue)); | 2593 ASSERT(shift_count >= 0); |
2518 } | 2594 int64_t limit = 64 - shift_count; |
2595 int64_t value = static_cast<int64_t>(value_boundary.ConstantValue()); | |
2519 | 2596 |
2597 if ((value == 0) || | |
2598 (shift_count == 0) || | |
2599 ((limit > 0) && (Utils::IsInt(limit, value)))) { | |
2600 // Result stays in 64 bit range. | |
2601 int64_t result = value << shift_count; | |
2602 return Smi::IsValid64(result) ? RangeBoundary(result) : overflow; | |
2603 } | |
2520 | 2604 |
2521 // Returns true if two range boundaries can be proven to be equal. | 2605 return overflow; |
2522 static bool IsEqual(const RangeBoundary& a, const RangeBoundary& b) { | |
2523 if (a.IsConstant() && b.IsConstant()) { | |
2524 return a.value() == b.value(); | |
2525 } else if (a.IsSymbol() && b.IsSymbol()) { | |
2526 return (a.offset() == b.offset()) && DependOnSameSymbol(a, b); | |
2527 } else { | |
2528 return false; | |
2529 } | |
2530 } | 2606 } |
2531 | 2607 |
2532 | 2608 |
2533 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, | 2609 static RangeBoundary CanonicalizeBoundary(const RangeBoundary& a, |
2534 const RangeBoundary& overflow) { | 2610 const RangeBoundary& overflow) { |
2535 if (a.IsConstant() || a.IsNegativeInfinity() || a.IsPositiveInfinity()) { | 2611 if (a.IsConstant() || a.IsInfinity()) { |
2536 return a; | 2612 return a; |
2537 } | 2613 } |
2538 | 2614 |
2539 intptr_t offset = a.offset(); | 2615 int64_t offset = a.offset(); |
2540 Definition* symbol = a.symbol(); | 2616 Definition* symbol = a.symbol(); |
2541 | 2617 |
2542 bool changed; | 2618 bool changed; |
2543 do { | 2619 do { |
2544 changed = false; | 2620 changed = false; |
2545 if (symbol->IsConstraint()) { | 2621 if (symbol->IsConstraint()) { |
2546 symbol = symbol->AsConstraint()->value()->definition(); | 2622 symbol = symbol->AsConstraint()->value()->definition(); |
2547 changed = true; | 2623 changed = true; |
2548 } else if (symbol->IsBinarySmiOp()) { | 2624 } else if (symbol->IsBinarySmiOp()) { |
2549 BinarySmiOpInstr* op = symbol->AsBinarySmiOp(); | 2625 BinarySmiOpInstr* op = symbol->AsBinarySmiOp(); |
2550 Definition* left = op->left()->definition(); | 2626 Definition* left = op->left()->definition(); |
2551 Definition* right = op->right()->definition(); | 2627 Definition* right = op->right()->definition(); |
2552 switch (op->op_kind()) { | 2628 switch (op->op_kind()) { |
2553 case Token::kADD: | 2629 case Token::kADD: |
2554 if (right->IsConstant()) { | 2630 if (right->IsConstant()) { |
2555 offset += Smi::Cast(right->AsConstant()->value()).Value(); | 2631 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value(); |
2632 if (Utils::WillAddOverflow(offset, rhs)) { | |
2633 return overflow; | |
2634 } | |
2635 offset += rhs; | |
2556 symbol = left; | 2636 symbol = left; |
2557 changed = true; | 2637 changed = true; |
2558 } else if (left->IsConstant()) { | 2638 } else if (left->IsConstant()) { |
2559 offset += Smi::Cast(left->AsConstant()->value()).Value(); | 2639 int64_t rhs = Smi::Cast(left->AsConstant()->value()).Value(); |
2640 if (Utils::WillAddOverflow(offset, rhs)) { | |
2641 return overflow; | |
2642 } | |
2643 offset += rhs; | |
2560 symbol = right; | 2644 symbol = right; |
2561 changed = true; | 2645 changed = true; |
2562 } | 2646 } |
2563 break; | 2647 break; |
2564 | 2648 |
2565 case Token::kSUB: | 2649 case Token::kSUB: |
2566 if (right->IsConstant()) { | 2650 if (right->IsConstant()) { |
2567 offset -= Smi::Cast(right->AsConstant()->value()).Value(); | 2651 int64_t rhs = Smi::Cast(right->AsConstant()->value()).Value(); |
2652 if (Utils::WillSubOverflow(offset, rhs)) { | |
2653 return overflow; | |
2654 } | |
2655 offset -= rhs; | |
2568 symbol = left; | 2656 symbol = left; |
2569 changed = true; | 2657 changed = true; |
2570 } | 2658 } |
2571 break; | 2659 break; |
2572 | 2660 |
2573 default: | 2661 default: |
2574 break; | 2662 break; |
2575 } | 2663 } |
2576 } | 2664 } |
2577 | |
2578 if (!Smi::IsValid(offset)) return overflow; | |
2579 } while (changed); | 2665 } while (changed); |
2580 | 2666 |
2581 return RangeBoundary::FromDefinition(symbol, offset); | 2667 return RangeBoundary::FromDefinition(symbol, offset); |
2582 } | 2668 } |
2583 | 2669 |
2584 | 2670 |
2585 static bool CanonicalizeMaxBoundary(RangeBoundary* a) { | 2671 static bool CanonicalizeMaxBoundary(RangeBoundary* a) { |
2586 if (!a->IsSymbol()) return false; | 2672 if (!a->IsSymbol()) return false; |
2587 | 2673 |
2588 Range* range = a->symbol()->range(); | 2674 Range* range = a->symbol()->range(); |
2589 if ((range == NULL) || !range->max().IsSymbol()) return false; | 2675 if ((range == NULL) || !range->max().IsSymbol()) return false; |
2590 | 2676 |
2591 const intptr_t offset = range->max().offset() + a->offset(); | |
2592 | 2677 |
2593 if (!Smi::IsValid(offset)) { | 2678 if (Utils::WillAddOverflow(range->max().offset(), a->offset())) { |
2594 *a = RangeBoundary::PositiveInfinity(); | 2679 *a = RangeBoundary::PositiveInfinity(); |
2595 return true; | 2680 return true; |
2596 } | 2681 } |
2597 | 2682 |
2683 const int64_t offset = range->max().offset() + a->offset(); | |
2684 | |
2685 | |
2598 *a = CanonicalizeBoundary( | 2686 *a = CanonicalizeBoundary( |
2599 RangeBoundary::FromDefinition(range->max().symbol(), offset), | 2687 RangeBoundary::FromDefinition(range->max().symbol(), offset), |
2600 RangeBoundary::PositiveInfinity()); | 2688 RangeBoundary::PositiveInfinity()); |
2601 | 2689 |
2602 return true; | 2690 return true; |
2603 } | 2691 } |
2604 | 2692 |
2605 | 2693 |
2606 static bool CanonicalizeMinBoundary(RangeBoundary* a) { | 2694 static bool CanonicalizeMinBoundary(RangeBoundary* a) { |
2607 if (!a->IsSymbol()) return false; | 2695 if (!a->IsSymbol()) return false; |
2608 | 2696 |
2609 Range* range = a->symbol()->range(); | 2697 Range* range = a->symbol()->range(); |
2610 if ((range == NULL) || !range->min().IsSymbol()) return false; | 2698 if ((range == NULL) || !range->min().IsSymbol()) return false; |
2611 | 2699 |
2612 const intptr_t offset = range->min().offset() + a->offset(); | 2700 if (Utils::WillAddOverflow(range->min().offset(), a->offset())) { |
2613 if (!Smi::IsValid(offset)) { | |
2614 *a = RangeBoundary::NegativeInfinity(); | 2701 *a = RangeBoundary::NegativeInfinity(); |
2615 return true; | 2702 return true; |
2616 } | 2703 } |
2617 | 2704 |
2705 const int64_t offset = range->min().offset() + a->offset(); | |
2706 | |
2618 *a = CanonicalizeBoundary( | 2707 *a = CanonicalizeBoundary( |
2619 RangeBoundary::FromDefinition(range->min().symbol(), offset), | 2708 RangeBoundary::FromDefinition(range->min().symbol(), offset), |
2620 RangeBoundary::NegativeInfinity()); | 2709 RangeBoundary::NegativeInfinity()); |
2621 | 2710 |
2622 return true; | 2711 return true; |
2623 } | 2712 } |
2624 | 2713 |
2625 | 2714 |
2626 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b) { | 2715 RangeBoundary RangeBoundary::Min(RangeBoundary a, RangeBoundary b, |
2716 RangeSize size) { | |
2717 ASSERT(!(a.IsNegativeInfinity() || b.IsNegativeInfinity())); | |
2718 ASSERT(!a.IsUnknown() || !b.IsUnknown()); | |
2719 if (a.IsUnknown() && !b.IsUnknown()) { | |
2720 return b; | |
2721 } | |
2722 if (!a.IsUnknown() && b.IsUnknown()) { | |
2723 return a; | |
2724 } | |
2725 if (size == kRangeBoundarySmi) { | |
2726 if (a.IsSmiMaximumOrAbove() && !b.IsSmiMaximumOrAbove()) { | |
2727 return b; | |
2728 } | |
2729 if (!a.IsSmiMaximumOrAbove() && b.IsSmiMaximumOrAbove()) { | |
2730 return a; | |
2731 } | |
2732 } else { | |
2733 ASSERT(size == kRangeBoundaryInt64); | |
2734 if (a.IsMaximumOrAbove() && !b.IsMaximumOrAbove()) { | |
2735 return b; | |
2736 } | |
2737 if (!a.IsMaximumOrAbove() && b.IsMaximumOrAbove()) { | |
2738 return a; | |
2739 } | |
2740 } | |
2741 | |
2742 if (a.Equals(b)) { | |
2743 return b; | |
2744 } | |
2745 | |
2746 { | |
2747 RangeBoundary canonical_a = | |
2748 CanonicalizeBoundary(a, RangeBoundary::PositiveInfinity()); | |
2749 RangeBoundary canonical_b = | |
2750 CanonicalizeBoundary(b, RangeBoundary::PositiveInfinity()); | |
2751 do { | |
2752 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2753 a = canonical_a; | |
2754 b = canonical_b; | |
2755 break; | |
2756 } | |
2757 } while (CanonicalizeMaxBoundary(&canonical_a) || | |
2758 CanonicalizeMaxBoundary(&canonical_b)); | |
2759 } | |
2760 | |
2627 if (DependOnSameSymbol(a, b)) { | 2761 if (DependOnSameSymbol(a, b)) { |
2628 return (a.offset() <= b.offset()) ? a : b; | 2762 return (a.offset() <= b.offset()) ? a : b; |
2629 } | 2763 } |
2630 | 2764 |
2631 const intptr_t min_a = a.LowerBound().Clamp().value(); | 2765 const int64_t min_a = a.UpperBound().Clamp(size).ConstantValue(); |
2632 const intptr_t min_b = b.LowerBound().Clamp().value(); | 2766 const int64_t min_b = b.UpperBound().Clamp(size).ConstantValue(); |
2633 | 2767 |
2634 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); | 2768 return RangeBoundary::FromConstant(Utils::Minimum(min_a, min_b)); |
2635 } | 2769 } |
2636 | 2770 |
2637 | 2771 |
2638 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b) { | 2772 RangeBoundary RangeBoundary::Max(RangeBoundary a, RangeBoundary b, |
2639 if (DependOnSameSymbol(a, b)) { | 2773 RangeSize size) { |
2640 return (a.offset() >= b.offset()) ? a : b; | 2774 ASSERT(!(a.IsPositiveInfinity() || b.IsPositiveInfinity())); |
2775 ASSERT(!a.IsUnknown() || !b.IsUnknown()); | |
2776 if (a.IsUnknown() && !b.IsUnknown()) { | |
2777 return b; | |
2778 } | |
2779 if (!a.IsUnknown() && b.IsUnknown()) { | |
2780 return a; | |
2781 } | |
2782 if (size == kRangeBoundarySmi) { | |
2783 if (a.IsSmiMinimumOrBelow() && !b.IsSmiMinimumOrBelow()) { | |
2784 return b; | |
2785 } | |
2786 if (!a.IsSmiMinimumOrBelow() && b.IsSmiMinimumOrBelow()) { | |
2787 return a; | |
2788 } | |
2789 } else { | |
2790 ASSERT(size == kRangeBoundaryInt64); | |
2791 if (a.IsMinimumOrBelow() && !b.IsMinimumOrBelow()) { | |
2792 return b; | |
2793 } | |
2794 if (!a.IsMinimumOrBelow() && b.IsMinimumOrBelow()) { | |
2795 return a; | |
2796 } | |
2797 } | |
2798 if (a.Equals(b)) { | |
2799 return b; | |
2641 } | 2800 } |
2642 | 2801 |
2643 const intptr_t max_a = a.UpperBound().Clamp().value(); | 2802 { |
2644 const intptr_t max_b = b.UpperBound().Clamp().value(); | 2803 RangeBoundary canonical_a = |
2804 CanonicalizeBoundary(a, RangeBoundary::NegativeInfinity()); | |
2805 RangeBoundary canonical_b = | |
2806 CanonicalizeBoundary(b, RangeBoundary::NegativeInfinity()); | |
2807 | |
2808 do { | |
2809 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2810 a = canonical_a; | |
2811 b = canonical_b; | |
2812 break; | |
2813 } | |
2814 } while (CanonicalizeMinBoundary(&canonical_a) || | |
2815 CanonicalizeMinBoundary(&canonical_b)); | |
2816 } | |
2817 | |
2818 if (DependOnSameSymbol(a, b)) { | |
2819 return (a.offset() <= b.offset()) ? b : a; | |
2820 } | |
2821 | |
2822 const int64_t max_a = a.LowerBound().Clamp(size).ConstantValue(); | |
2823 const int64_t max_b = b.LowerBound().Clamp(size).ConstantValue(); | |
2645 | 2824 |
2646 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 2825 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
2647 } | 2826 } |
2648 | 2827 |
2649 | 2828 |
2829 int64_t RangeBoundary::ConstantValue() const { | |
2830 ASSERT(IsConstant()); | |
2831 return value_; | |
2832 } | |
2833 | |
2834 | |
2650 void Definition::InferRange() { | 2835 void Definition::InferRange() { |
2651 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. | 2836 if (Type()->ToCid() == kSmiCid) { |
2652 if (range_ == NULL) { | 2837 if (range_ == NULL) { |
2653 range_ = Range::Unknown(); | 2838 range_ = Range::UnknownSmi(); |
2839 } | |
2840 } else if (IsMintDefinition()) { | |
2841 if (range_ == NULL) { | |
2842 range_ = Range::Unknown(); | |
2843 } | |
2844 } else { | |
2845 // Only Smi and Mint supported. | |
2846 UNREACHABLE(); | |
2654 } | 2847 } |
2655 } | 2848 } |
2656 | 2849 |
2657 | 2850 |
2658 void ConstantInstr::InferRange() { | 2851 void ConstantInstr::InferRange() { |
2659 ASSERT(value_.IsSmi()); | 2852 if (value_.IsSmi()) { |
2660 if (range_ == NULL) { | 2853 if (range_ == NULL) { |
2661 intptr_t value = Smi::Cast(value_).Value(); | 2854 int64_t value = Smi::Cast(value_).Value(); |
2662 range_ = new Range(RangeBoundary::FromConstant(value), | 2855 range_ = new Range(RangeBoundary::FromConstant(value), |
2663 RangeBoundary::FromConstant(value)); | 2856 RangeBoundary::FromConstant(value)); |
2857 } | |
2858 } else if (value_.IsMint()) { | |
2859 if (range_ == NULL) { | |
2860 int64_t value = Mint::Cast(value_).value(); | |
2861 range_ = new Range(RangeBoundary::FromConstant(value), | |
2862 RangeBoundary::FromConstant(value)); | |
2863 } | |
2864 } else { | |
2865 // Only Smi and Mint supported. | |
2866 UNREACHABLE(); | |
2664 } | 2867 } |
2665 } | 2868 } |
2666 | 2869 |
2870 | |
2871 void UnboxIntegerInstr::InferRange() { | |
2872 if (range_ == NULL) { | |
2873 Definition* unboxed = value()->definition(); | |
2874 if (unboxed == NULL) { | |
Vyacheslav Egorov (Google)
2014/06/19 17:27:29
When is this true? How can we be unboxing "nothing
Cutch
2014/06/19 18:39:35
Switched to an ASSERT.
| |
2875 range_ = Range::Unknown(); | |
2876 return; | |
2877 } | |
2878 Range* range = unboxed->range(); | |
2879 if (range == NULL) { | |
2880 range_ = Range::Unknown(); | |
2881 return; | |
2882 } | |
2883 range_ = new Range(range->min(), range->max()); | |
2884 } | |
2885 } | |
2886 | |
2667 | 2887 |
2668 void ConstraintInstr::InferRange() { | 2888 void ConstraintInstr::InferRange() { |
2669 Range* value_range = value()->definition()->range(); | 2889 Range* value_range = value()->definition()->range(); |
2670 | 2890 |
2671 RangeBoundary min; | 2891 RangeBoundary min; |
2672 RangeBoundary max; | 2892 RangeBoundary max; |
2673 | 2893 |
2674 if (IsMinSmi(value_range) && !IsMinSmi(constraint())) { | 2894 { |
2675 min = constraint()->min(); | 2895 RangeBoundary value_min = (value_range == NULL) ? |
2676 } else if (IsMinSmi(constraint()) && !IsMinSmi(value_range)) { | 2896 RangeBoundary() : value_range->min(); |
2677 min = value_range->min(); | 2897 RangeBoundary constraint_min = constraint()->min(); |
2678 } else if ((value_range != NULL) && | 2898 min = RangeBoundary::Max(value_min, constraint_min, |
2679 IsEqual(constraint()->min(), value_range->min())) { | 2899 RangeBoundary::kRangeBoundarySmi); |
Vyacheslav Egorov (Google)
2014/06/19 17:27:29
Add an assertion that value()->definition() is a S
Cutch
2014/06/19 18:39:35
This doesn't work because some Constraints are ins
Vyacheslav Egorov (Google)
2014/06/19 18:42:29
In this case you can see reaching type for value()
Cutch
2014/06/19 20:21:50
Got it. Thanks!
| |
2680 min = constraint()->min(); | |
2681 } else { | |
2682 if (value_range != NULL) { | |
2683 RangeBoundary canonical_a = | |
2684 CanonicalizeBoundary(constraint()->min(), | |
2685 RangeBoundary::NegativeInfinity()); | |
2686 RangeBoundary canonical_b = | |
2687 CanonicalizeBoundary(value_range->min(), | |
2688 RangeBoundary::NegativeInfinity()); | |
2689 | |
2690 do { | |
2691 if (DependOnSameSymbol(canonical_a, canonical_b)) { | |
2692 min = (canonical_a.offset() <= canonical_b.offset()) ? canonical_b | |
2693 : canonical_a; | |
2694 } | |
2695 } while (CanonicalizeMinBoundary(&canonical_a) || | |
2696 CanonicalizeMinBoundary(&canonical_b)); | |
2697 } | |
2698 | |
2699 if (min.IsUnknown()) { | |
2700 min = RangeBoundary::Max(Range::ConstantMin(value_range), | |
2701 Range::ConstantMin(constraint())); | |
2702 } | |
2703 } | 2900 } |
2704 | 2901 |
2705 if (IsMaxSmi(value_range) && !IsMaxSmi(constraint())) { | 2902 ASSERT(!min.IsUnknown()); |
2706 max = constraint()->max(); | |
2707 } else if (IsMaxSmi(constraint()) && !IsMaxSmi(value_range)) { | |
2708 max = value_range->max(); | |
2709 } else if ((value_range != NULL) && | |
2710 IsEqual(constraint()->max(), value_range->max())) { | |
2711 max = constraint()->max(); | |
2712 } else { | |
2713 if (value_range != NULL) { | |
2714 RangeBoundary canonical_b = | |
2715 CanonicalizeBoundary(value_range->max(), | |
2716 RangeBoundary::PositiveInfinity()); | |
2717 RangeBoundary canonical_a = | |
2718 CanonicalizeBoundary(constraint()->max(), | |
2719 RangeBoundary::PositiveInfinity()); | |
2720 | 2903 |
2721 do { | 2904 { |
2722 if (DependOnSameSymbol(canonical_a, canonical_b)) { | 2905 RangeBoundary value_max = (value_range == NULL) ? |
2723 max = (canonical_a.offset() <= canonical_b.offset()) ? canonical_a | 2906 RangeBoundary() : value_range->max(); |
2724 : canonical_b; | 2907 RangeBoundary constraint_max = constraint()->max(); |
2725 break; | 2908 max = RangeBoundary::Min(value_max, constraint_max, |
2726 } | 2909 RangeBoundary::kRangeBoundarySmi); |
2727 } while (CanonicalizeMaxBoundary(&canonical_a) || | 2910 } |
2728 CanonicalizeMaxBoundary(&canonical_b)); | |
2729 } | |
2730 | 2911 |
2731 if (max.IsUnknown()) { | 2912 ASSERT(!max.IsUnknown()); |
2732 max = RangeBoundary::Min(Range::ConstantMax(value_range), | |
2733 Range::ConstantMax(constraint())); | |
2734 } | |
2735 } | |
2736 | 2913 |
2737 range_ = new Range(min, max); | 2914 range_ = new Range(min, max); |
2738 | 2915 |
2739 // Mark branches that generate unsatisfiable constraints as constant. | 2916 // Mark branches that generate unsatisfiable constraints as constant. |
2740 if (target() != NULL && range_->IsUnsatisfiable()) { | 2917 if (target() != NULL && range_->IsUnsatisfiable()) { |
2741 BranchInstr* branch = | 2918 BranchInstr* branch = |
2742 target()->PredecessorAt(0)->last_instruction()->AsBranch(); | 2919 target()->PredecessorAt(0)->last_instruction()->AsBranch(); |
2743 if (target() == branch->true_successor()) { | 2920 if (target() == branch->true_successor()) { |
2744 // True unreachable. | 2921 // True unreachable. |
2745 if (FLAG_trace_constant_propagation) { | 2922 if (FLAG_trace_constant_propagation) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2798 RangeBoundary::FromConstant(255)); | 2975 RangeBoundary::FromConstant(255)); |
2799 break; | 2976 break; |
2800 case kTypedDataInt16ArrayCid: | 2977 case kTypedDataInt16ArrayCid: |
2801 range_ = new Range(RangeBoundary::FromConstant(-32768), | 2978 range_ = new Range(RangeBoundary::FromConstant(-32768), |
2802 RangeBoundary::FromConstant(32767)); | 2979 RangeBoundary::FromConstant(32767)); |
2803 break; | 2980 break; |
2804 case kTypedDataUint16ArrayCid: | 2981 case kTypedDataUint16ArrayCid: |
2805 range_ = new Range(RangeBoundary::FromConstant(0), | 2982 range_ = new Range(RangeBoundary::FromConstant(0), |
2806 RangeBoundary::FromConstant(65535)); | 2983 RangeBoundary::FromConstant(65535)); |
2807 break; | 2984 break; |
2985 case kTypedDataInt32ArrayCid: | |
2986 range_ = new Range(RangeBoundary::FromConstant(kMinInt32), | |
Vyacheslav Egorov (Google)
2014/06/19 17:27:29
CanDeoptimize() versions of Int32/Uint32 loads sho
Cutch
2014/06/19 18:39:35
Done.
| |
2987 RangeBoundary::FromConstant(kMaxInt32)); | |
2988 break; | |
2989 case kTypedDataUint32ArrayCid: | |
2990 range_ = new Range(RangeBoundary::FromConstant(0), | |
2991 RangeBoundary::FromConstant(kMaxUint32)); | |
2992 break; | |
2808 case kOneByteStringCid: | 2993 case kOneByteStringCid: |
2809 range_ = new Range(RangeBoundary::FromConstant(0), | 2994 range_ = new Range(RangeBoundary::FromConstant(0), |
2810 RangeBoundary::FromConstant(0xFF)); | 2995 RangeBoundary::FromConstant(0xFF)); |
2811 break; | 2996 break; |
2812 case kTwoByteStringCid: | 2997 case kTwoByteStringCid: |
2813 range_ = new Range(RangeBoundary::FromConstant(0), | 2998 range_ = new Range(RangeBoundary::FromConstant(0), |
2814 RangeBoundary::FromConstant(0xFFFF)); | 2999 RangeBoundary::FromConstant(0xFFFF)); |
2815 break; | 3000 break; |
2816 default: | 3001 default: |
2817 Definition::InferRange(); | 3002 Definition::InferRange(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2912 && !comparison->AsStrictCompare()->needs_number_check(); | 3097 && !comparison->AsStrictCompare()->needs_number_check(); |
2913 } | 3098 } |
2914 if (comparison->operation_cid() != kSmiCid) { | 3099 if (comparison->operation_cid() != kSmiCid) { |
2915 // Non-smi comparisons are not supported by if-conversion. | 3100 // Non-smi comparisons are not supported by if-conversion. |
2916 return false; | 3101 return false; |
2917 } | 3102 } |
2918 return is_smi_result; | 3103 return is_smi_result; |
2919 } | 3104 } |
2920 | 3105 |
2921 | 3106 |
2922 void PhiInstr::InferRange() { | 3107 void PhiInstr::InferRange() { |
Vyacheslav Egorov (Google)
2014/06/19 17:27:30
Assert that Phi is not a Mint?
Cutch
2014/06/19 18:39:35
I've asserted that Phi is a smi.
| |
2923 RangeBoundary new_min; | 3108 RangeBoundary new_min; |
2924 RangeBoundary new_max; | 3109 RangeBoundary new_max; |
2925 | 3110 |
2926 for (intptr_t i = 0; i < InputCount(); i++) { | 3111 for (intptr_t i = 0; i < InputCount(); i++) { |
2927 Range* input_range = InputAt(i)->definition()->range(); | 3112 Range* input_range = InputAt(i)->definition()->range(); |
2928 if (input_range == NULL) { | 3113 if (input_range == NULL) { |
2929 range_ = Range::Unknown(); | 3114 range_ = Range::UnknownSmi(); |
2930 return; | 3115 return; |
2931 } | 3116 } |
2932 | 3117 |
2933 if (new_min.IsUnknown()) { | 3118 if (new_min.IsUnknown()) { |
2934 new_min = Range::ConstantMin(input_range); | 3119 new_min = Range::ConstantMin(input_range); |
2935 } else { | 3120 } else { |
2936 new_min = RangeBoundary::Min(new_min, Range::ConstantMin(input_range)); | 3121 new_min = RangeBoundary::Min(new_min, |
3122 Range::ConstantMinSmi(input_range), | |
3123 RangeBoundary::kRangeBoundarySmi); | |
2937 } | 3124 } |
2938 | 3125 |
2939 if (new_max.IsUnknown()) { | 3126 if (new_max.IsUnknown()) { |
2940 new_max = Range::ConstantMax(input_range); | 3127 new_max = Range::ConstantMax(input_range); |
2941 } else { | 3128 } else { |
2942 new_max = RangeBoundary::Max(new_max, Range::ConstantMax(input_range)); | 3129 new_max = RangeBoundary::Max(new_max, |
3130 Range::ConstantMaxSmi(input_range), | |
3131 RangeBoundary::kRangeBoundarySmi); | |
2943 } | 3132 } |
2944 } | 3133 } |
2945 | 3134 |
2946 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); | 3135 ASSERT(new_min.IsUnknown() == new_max.IsUnknown()); |
2947 if (new_min.IsUnknown()) { | 3136 if (new_min.IsUnknown()) { |
2948 range_ = Range::Unknown(); | 3137 range_ = Range::UnknownSmi(); |
2949 return; | 3138 return; |
2950 } | 3139 } |
2951 | 3140 |
2952 range_ = new Range(new_min, new_max); | 3141 range_ = new Range(new_min, new_max); |
2953 } | 3142 } |
2954 | 3143 |
2955 | 3144 |
2956 bool PhiInstr::IsRedundant() const { | 3145 bool PhiInstr::IsRedundant() const { |
2957 ASSERT(InputCount() > 1); | 3146 ASSERT(InputCount() > 1); |
2958 Definition* first = InputAt(0)->definition(); | 3147 Definition* first = InputAt(0)->definition(); |
2959 for (intptr_t i = 1; i < InputCount(); ++i) { | 3148 for (intptr_t i = 1; i < InputCount(); ++i) { |
2960 Definition* def = InputAt(i)->definition(); | 3149 Definition* def = InputAt(i)->definition(); |
2961 if (def != first) return false; | 3150 if (def != first) return false; |
2962 } | 3151 } |
2963 return true; | 3152 return true; |
2964 } | 3153 } |
2965 | 3154 |
2966 | 3155 |
2967 static bool SymbolicSub(const RangeBoundary& a, | |
2968 const RangeBoundary& b, | |
2969 RangeBoundary* result) { | |
2970 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2971 const intptr_t offset = a.offset() - b.value(); | |
2972 if (!Smi::IsValid(offset)) return false; | |
2973 | |
2974 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2975 return true; | |
2976 } | |
2977 return false; | |
2978 } | |
2979 | |
2980 | |
2981 static bool SymbolicAdd(const RangeBoundary& a, | |
2982 const RangeBoundary& b, | |
2983 RangeBoundary* result) { | |
2984 if (a.IsSymbol() && b.IsConstant() && !b.Overflowed()) { | |
2985 const intptr_t offset = a.offset() + b.value(); | |
2986 if (!Smi::IsValid(offset)) return false; | |
2987 | |
2988 *result = RangeBoundary::FromDefinition(a.symbol(), offset); | |
2989 return true; | |
2990 } else if (b.IsSymbol() && a.IsConstant() && !a.Overflowed()) { | |
2991 const intptr_t offset = b.offset() + a.value(); | |
2992 if (!Smi::IsValid(offset)) return false; | |
2993 | |
2994 *result = RangeBoundary::FromDefinition(b.symbol(), offset); | |
2995 return true; | |
2996 } | |
2997 return false; | |
2998 } | |
2999 | |
3000 | |
3001 static bool IsArrayLength(Definition* defn) { | 3156 static bool IsArrayLength(Definition* defn) { |
3157 if (defn == NULL) { | |
3158 return false; | |
3159 } | |
3002 LoadFieldInstr* load = defn->AsLoadField(); | 3160 LoadFieldInstr* load = defn->AsLoadField(); |
3003 return (load != NULL) && load->IsImmutableLengthLoad(); | 3161 return (load != NULL) && load->IsImmutableLengthLoad(); |
3004 } | 3162 } |
3005 | 3163 |
3006 | 3164 |
3007 static int64_t ConstantAbsMax(const Range* range) { | |
3008 if (range == NULL) return Smi::kMaxValue; | |
3009 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).value()); | |
3010 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).value()); | |
3011 return abs_min > abs_max ? abs_min : abs_max; | |
3012 } | |
3013 | |
3014 | |
3015 static bool OnlyPositiveOrZero(const Range* a, const Range* b) { | |
3016 if ((a == NULL) || (b == NULL)) return false; | |
3017 if (Range::ConstantMin(a).value() < 0) return false; | |
3018 if (Range::ConstantMin(b).value() < 0) return false; | |
3019 return true; | |
3020 } | |
3021 | |
3022 | |
3023 static bool OnlyNegativeOrZero(const Range* a, const Range* b) { | |
3024 if ((a == NULL) || (b == NULL)) return false; | |
3025 if (Range::ConstantMax(a).value() > 0) return false; | |
3026 if (Range::ConstantMax(b).value() > 0) return false; | |
3027 return true; | |
3028 } | |
3029 | |
3030 | |
3031 void BinarySmiOpInstr::InferRange() { | 3165 void BinarySmiOpInstr::InferRange() { |
3032 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 3166 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
3033 // right and a non-constant on the left. | 3167 // right and a non-constant on the left. |
3034 Definition* left_defn = left()->definition(); | 3168 Definition* left_defn = left()->definition(); |
3035 | 3169 |
3036 Range* left_range = left_defn->range(); | 3170 Range* left_range = left_defn->range(); |
3037 Range* right_range = right()->definition()->range(); | 3171 Range* right_range = right()->definition()->range(); |
3038 | 3172 |
3039 if ((left_range == NULL) || (right_range == NULL)) { | 3173 if ((left_range == NULL) || (right_range == NULL)) { |
3040 range_ = new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); | 3174 range_ = Range::UnknownSmi(); |
3041 return; | 3175 return; |
3042 } | 3176 } |
3043 | 3177 |
3044 RangeBoundary left_min = | 3178 Range* possible_range = Range::BinaryOp(op_kind(), |
3045 IsArrayLength(left_defn) ? | 3179 left_range, |
3046 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | 3180 right_range, |
3181 left_defn); | |
3047 | 3182 |
3048 RangeBoundary left_max = | 3183 if ((range_ == NULL) && (possible_range == NULL)) { |
3049 IsArrayLength(left_defn) ? | 3184 // Initialize. |
3050 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | 3185 range_ = Range::UnknownSmi(); |
3051 | 3186 return; |
3052 RangeBoundary min; | |
3053 RangeBoundary max; | |
3054 switch (op_kind()) { | |
3055 case Token::kADD: | |
3056 if (!SymbolicAdd(left_min, right_range->min(), &min)) { | |
3057 min = | |
3058 RangeBoundary::Add(Range::ConstantMin(left_range), | |
3059 Range::ConstantMin(right_range), | |
3060 RangeBoundary::NegativeInfinity()); | |
3061 } | |
3062 | |
3063 if (!SymbolicAdd(left_max, right_range->max(), &max)) { | |
3064 max = | |
3065 RangeBoundary::Add(Range::ConstantMax(right_range), | |
3066 Range::ConstantMax(left_range), | |
3067 RangeBoundary::PositiveInfinity()); | |
3068 } | |
3069 break; | |
3070 | |
3071 case Token::kSUB: | |
3072 if (!SymbolicSub(left_min, right_range->max(), &min)) { | |
3073 min = | |
3074 RangeBoundary::Sub(Range::ConstantMin(left_range), | |
3075 Range::ConstantMax(right_range), | |
3076 RangeBoundary::NegativeInfinity()); | |
3077 } | |
3078 | |
3079 if (!SymbolicSub(left_max, right_range->min(), &max)) { | |
3080 max = | |
3081 RangeBoundary::Sub(Range::ConstantMax(left_range), | |
3082 Range::ConstantMin(right_range), | |
3083 RangeBoundary::PositiveInfinity()); | |
3084 } | |
3085 break; | |
3086 | |
3087 case Token::kMUL: { | |
3088 const int64_t left_max = ConstantAbsMax(left_range); | |
3089 const int64_t right_max = ConstantAbsMax(right_range); | |
3090 ASSERT(left_max <= -kSmiMin); | |
3091 ASSERT(right_max <= -kSmiMin); | |
3092 if ((left_max == 0) || (right_max <= kMaxInt64 / left_max)) { | |
3093 // Product of left and right max values stays in 64 bit range. | |
3094 const int64_t result_max = left_max * right_max; | |
3095 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3096 const intptr_t r_min = | |
3097 OnlyPositiveOrZero(left_range, right_range) ? 0 : -result_max; | |
3098 min = RangeBoundary::FromConstant(r_min); | |
3099 const intptr_t r_max = | |
3100 OnlyNegativeOrZero(left_range, right_range) ? 0 : result_max; | |
3101 max = RangeBoundary::FromConstant(r_max); | |
3102 break; | |
3103 } | |
3104 } | |
3105 if (range_ == NULL) { | |
3106 range_ = Range::Unknown(); | |
3107 } | |
3108 return; | |
3109 } | |
3110 case Token::kSHL: { | |
3111 Range::Shl(left_range, right_range, &min, &max); | |
3112 break; | |
3113 } | |
3114 case Token::kBIT_AND: | |
3115 if (Range::ConstantMin(right_range).value() >= 0) { | |
3116 min = RangeBoundary::FromConstant(0); | |
3117 max = Range::ConstantMax(right_range); | |
3118 break; | |
3119 } | |
3120 if (Range::ConstantMin(left_range).value() >= 0) { | |
3121 min = RangeBoundary::FromConstant(0); | |
3122 max = Range::ConstantMax(left_range); | |
3123 break; | |
3124 } | |
3125 | |
3126 if (range_ == NULL) { | |
3127 range_ = Range::Unknown(); | |
3128 } | |
3129 return; | |
3130 | |
3131 default: | |
3132 if (range_ == NULL) { | |
3133 range_ = Range::Unknown(); | |
3134 } | |
3135 return; | |
3136 } | 3187 } |
3137 | 3188 |
3138 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | 3189 if (possible_range == NULL) { |
3139 set_overflow(min.LowerBound().Overflowed() || max.UpperBound().Overflowed()); | 3190 // Nothing new. |
3191 return; | |
3192 } | |
3140 | 3193 |
3141 if (min.IsConstant()) min.Clamp(); | 3194 range_ = possible_range; |
3142 if (max.IsConstant()) max.Clamp(); | |
3143 | 3195 |
3144 range_ = new Range(min, max); | 3196 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); |
3197 // Calculate overflowed status before clamping. | |
3198 const bool overflowed = range_->min().LowerBound().OverflowedSmi() || | |
3199 range_->max().UpperBound().OverflowedSmi(); | |
3200 | |
3201 // Clamp value to be within smi range. | |
3202 range_->Clamp(RangeBoundary::kRangeBoundarySmi); | |
3203 | |
3204 set_overflow(overflowed); | |
3145 } | 3205 } |
3146 | 3206 |
3147 | 3207 |
3208 void BinaryMintOpInstr::InferRange() { | |
3209 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | |
3210 // the right and a non-constant on the left. | |
3211 Definition* left_defn = left()->definition(); | |
3212 | |
3213 Range* left_range = left_defn->range(); | |
3214 Range* right_range = right()->definition()->range(); | |
3215 | |
3216 if ((left_range == NULL) || (right_range == NULL)) { | |
3217 range_ = Range::Unknown(); | |
3218 return; | |
3219 } | |
3220 | |
3221 Range* possible_range = Range::BinaryOp(op_kind(), | |
3222 left_range, | |
3223 right_range, | |
3224 left_defn); | |
3225 | |
3226 if ((range_ == NULL) && (possible_range == NULL)) { | |
3227 // Initialize. | |
3228 range_ = Range::Unknown(); | |
3229 return; | |
3230 } | |
3231 | |
3232 if (possible_range == NULL) { | |
3233 // Nothing new. | |
3234 return; | |
3235 } | |
3236 | |
3237 range_ = possible_range; | |
3238 | |
3239 ASSERT(!range_->min().IsUnknown() && !range_->max().IsUnknown()); | |
3240 | |
3241 // Clamp value to be within mint range. | |
3242 range_->Clamp(RangeBoundary::kRangeBoundaryInt64); | |
Vyacheslav Egorov (Google)
2014/06/19 17:27:29
Any reason for not computing overflow state to mat
Cutch
2014/06/19 18:39:35
We currently don't track overflow / truncating on
| |
3243 } | |
3244 | |
3245 | |
3148 bool Range::IsPositive() const { | 3246 bool Range::IsPositive() const { |
3149 if (min().IsNegativeInfinity()) { | 3247 if (min().IsNegativeInfinity()) { |
3150 return false; | 3248 return false; |
3151 } | 3249 } |
3152 if (min().LowerBound().value() < 0) { | 3250 if (min().LowerBound().ConstantValue() < 0) { |
3153 return false; | 3251 return false; |
3154 } | 3252 } |
3155 if (max().IsPositiveInfinity()) { | 3253 if (max().IsPositiveInfinity()) { |
3156 return true; | 3254 return true; |
3157 } | 3255 } |
3158 return max().UpperBound().value() >= 0; | 3256 return max().UpperBound().ConstantValue() >= 0; |
3159 } | 3257 } |
3160 | 3258 |
3161 | 3259 |
3162 bool Range::IsNegative() const { | 3260 bool Range::OnlyLessThanOrEqualTo(int64_t val) const { |
3163 if (max().IsPositiveInfinity()) { | |
3164 return false; | |
3165 } | |
3166 if (max().UpperBound().value() >= 0) { | |
3167 return false; | |
3168 } | |
3169 if (min().IsNegativeInfinity()) { | |
3170 return true; | |
3171 } | |
3172 return min().LowerBound().value() < 0; | |
3173 } | |
3174 | |
3175 | |
3176 bool Range::OnlyLessThanOrEqualTo(intptr_t val) const { | |
3177 if (max().IsPositiveInfinity()) { | 3261 if (max().IsPositiveInfinity()) { |
3178 // Cannot be true. | 3262 // Cannot be true. |
3179 return false; | 3263 return false; |
3180 } | 3264 } |
3181 if (max().UpperBound().value() > val) { | 3265 if (max().UpperBound().ConstantValue() > val) { |
3182 // Not true. | 3266 // Not true. |
3183 return false; | 3267 return false; |
3184 } | 3268 } |
3185 if (!min().IsNegativeInfinity()) { | 3269 return true; |
3186 if (min().LowerBound().value() > val) { | 3270 } |
3187 // Lower bound is > value. | 3271 |
3188 return false; | 3272 |
3189 } | 3273 bool Range::OnlyGreaterThanOrEqualTo(int64_t val) const { |
3274 if (min().IsNegativeInfinity()) { | |
3275 return false; | |
3276 } | |
3277 if (min().LowerBound().ConstantValue() < val) { | |
3278 return false; | |
3190 } | 3279 } |
3191 return true; | 3280 return true; |
3192 } | 3281 } |
3193 | 3282 |
3194 | 3283 |
3195 // Inclusive. | 3284 // Inclusive. |
3196 bool Range::IsWithin(intptr_t min_int, intptr_t max_int) const { | 3285 bool Range::IsWithin(int64_t min_int, int64_t max_int) const { |
3197 RangeBoundary lower_min = min().LowerBound(); | 3286 RangeBoundary lower_min = min().LowerBound(); |
3198 if (lower_min.IsNegativeInfinity() || (lower_min.value() < min_int)) { | 3287 if (lower_min.IsNegativeInfinity() || (lower_min.ConstantValue() < min_int)) { |
3199 return false; | 3288 return false; |
3200 } | 3289 } |
3201 RangeBoundary upper_max = max().UpperBound(); | 3290 RangeBoundary upper_max = max().UpperBound(); |
3202 if (upper_max.IsPositiveInfinity() || (upper_max.value() > max_int)) { | 3291 if (upper_max.IsPositiveInfinity() || (upper_max.ConstantValue() > max_int)) { |
3203 return false; | 3292 return false; |
3204 } | 3293 } |
3205 return true; | 3294 return true; |
3206 } | 3295 } |
3207 | 3296 |
3208 | 3297 |
3209 bool Range::Overlaps(intptr_t min_int, intptr_t max_int) const { | 3298 bool Range::Overlaps(int64_t min_int, int64_t max_int) const { |
3210 const intptr_t this_min = min().IsNegativeInfinity() ? | 3299 RangeBoundary lower = min().LowerBound(); |
3211 kIntptrMin : min().LowerBound().value(); | 3300 RangeBoundary upper = max().UpperBound(); |
3212 const intptr_t this_max = max().IsPositiveInfinity() ? | 3301 const int64_t this_min = lower.IsNegativeInfinity() ? |
3213 kIntptrMax : max().UpperBound().value(); | 3302 RangeBoundary::kMin : lower.ConstantValue(); |
3303 const int64_t this_max = upper.IsPositiveInfinity() ? | |
3304 RangeBoundary::kMax : upper.ConstantValue(); | |
3214 if ((this_min <= min_int) && (min_int <= this_max)) return true; | 3305 if ((this_min <= min_int) && (min_int <= this_max)) return true; |
3215 if ((this_min <= max_int) && (max_int <= this_max)) return true; | 3306 if ((this_min <= max_int) && (max_int <= this_max)) return true; |
3216 if ((min_int < this_min) && (max_int > this_max)) return true; | 3307 if ((min_int < this_min) && (max_int > this_max)) return true; |
3217 return false; | 3308 return false; |
3218 } | 3309 } |
3219 | 3310 |
3220 | 3311 |
3221 bool Range::IsUnsatisfiable() const { | 3312 bool Range::IsUnsatisfiable() const { |
3222 // Infinity case: [+inf, ...] || [..., -inf] | 3313 // Infinity case: [+inf, ...] || [..., -inf] |
3223 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { | 3314 if (min().IsPositiveInfinity() || max().IsNegativeInfinity()) { |
3224 return true; | 3315 return true; |
3225 } | 3316 } |
3226 // Constant case: For example [0, -1]. | 3317 // Constant case: For example [0, -1]. |
3227 if (Range::ConstantMin(this).value() > Range::ConstantMax(this).value()) { | 3318 if (Range::ConstantMin(this).ConstantValue() > |
3319 Range::ConstantMax(this).ConstantValue()) { | |
3228 return true; | 3320 return true; |
3229 } | 3321 } |
3230 // Symbol case: For example [v+1, v]. | 3322 // Symbol case: For example [v+1, v]. |
3231 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { | 3323 if (DependOnSameSymbol(min(), max()) && min().offset() > max().offset()) { |
3232 return true; | 3324 return true; |
3233 } | 3325 } |
3234 return false; | 3326 return false; |
3235 } | 3327 } |
3236 | 3328 |
3237 | 3329 |
3238 void Range::Shl(Range* left, | 3330 void Range::Clamp(RangeBoundary::RangeSize size) { |
3239 Range* right, | 3331 min_ = min_.Clamp(size); |
3332 max_ = max_.Clamp(size); | |
3333 } | |
3334 | |
3335 | |
3336 void Range::Shl(const Range* left, | |
3337 const Range* right, | |
3240 RangeBoundary* result_min, | 3338 RangeBoundary* result_min, |
3241 RangeBoundary* result_max) { | 3339 RangeBoundary* result_max) { |
3340 ASSERT(left != NULL); | |
3341 ASSERT(right != NULL); | |
3342 ASSERT(result_min != NULL); | |
3343 ASSERT(result_max != NULL); | |
3242 RangeBoundary left_max = Range::ConstantMax(left); | 3344 RangeBoundary left_max = Range::ConstantMax(left); |
3243 RangeBoundary left_min = Range::ConstantMin(left); | 3345 RangeBoundary left_min = Range::ConstantMin(left); |
3244 // A negative shift count always deoptimizes (and throws), so the minimum | 3346 // A negative shift count always deoptimizes (and throws), so the minimum |
3245 // shift count is zero. | 3347 // shift count is zero. |
3246 intptr_t right_max = Utils::Maximum(Range::ConstantMax(right).value(), | 3348 int64_t right_max = Utils::Maximum(Range::ConstantMax(right).ConstantValue(), |
3247 static_cast<intptr_t>(0)); | 3349 static_cast<int64_t>(0)); |
3248 intptr_t right_min = Utils::Maximum(Range::ConstantMin(right).value(), | 3350 int64_t right_min = Utils::Maximum(Range::ConstantMin(right).ConstantValue(), |
3249 static_cast<intptr_t>(0)); | 3351 static_cast<int64_t>(0)); |
3250 | 3352 |
3251 *result_min = RangeBoundary::Shl( | 3353 *result_min = RangeBoundary::Shl( |
3252 left_min, | 3354 left_min, |
3253 left_min.value() > 0 ? right_min : right_max, | 3355 left_min.ConstantValue() > 0 ? right_min : right_max, |
3254 left_min.value() > 0 | 3356 left_min.ConstantValue() > 0 |
3255 ? RangeBoundary::PositiveInfinity() | 3357 ? RangeBoundary::PositiveInfinity() |
3256 : RangeBoundary::NegativeInfinity()); | 3358 : RangeBoundary::NegativeInfinity()); |
3257 | 3359 |
3258 *result_max = RangeBoundary::Shl( | 3360 *result_max = RangeBoundary::Shl( |
3259 left_max, | 3361 left_max, |
3260 left_max.value() > 0 ? right_max : right_min, | 3362 left_max.ConstantValue() > 0 ? right_max : right_min, |
3261 left_max.value() > 0 | 3363 left_max.ConstantValue() > 0 |
3262 ? RangeBoundary::PositiveInfinity() | 3364 ? RangeBoundary::PositiveInfinity() |
3263 : RangeBoundary::NegativeInfinity()); | 3365 : RangeBoundary::NegativeInfinity()); |
3264 } | 3366 } |
3265 | 3367 |
3266 | 3368 |
3369 bool Range::And(const Range* left_range, | |
3370 const Range* right_range, | |
3371 RangeBoundary* min, | |
3372 RangeBoundary* max) { | |
3373 ASSERT(left_range != NULL); | |
3374 ASSERT(right_range != NULL); | |
3375 ASSERT(min != NULL); | |
3376 ASSERT(max != NULL); | |
3377 | |
3378 if (Range::ConstantMin(right_range).ConstantValue() >= 0) { | |
3379 *min = RangeBoundary::FromConstant(0); | |
3380 *max = Range::ConstantMax(right_range); | |
3381 return true; | |
3382 } | |
3383 | |
3384 if (Range::ConstantMin(left_range).ConstantValue() >= 0) { | |
3385 *min = RangeBoundary::FromConstant(0); | |
3386 *max = Range::ConstantMax(left_range); | |
3387 return true; | |
3388 } | |
3389 | |
3390 return false; | |
3391 } | |
3392 | |
3393 | |
3394 void Range::Add(const Range* left_range, | |
3395 const Range* right_range, | |
3396 RangeBoundary* min, | |
Vyacheslav Egorov (Google)
2014/06/19 17:27:29
s/min/result_min/ and the same for max.
Cutch
2014/06/19 18:39:35
Done here and elsewhere.
| |
3397 RangeBoundary* max, | |
3398 Definition* left_defn) { | |
3399 ASSERT(left_range != NULL); | |
3400 ASSERT(right_range != NULL); | |
3401 ASSERT(min != NULL); | |
3402 ASSERT(max != NULL); | |
3403 | |
3404 RangeBoundary left_min = | |
3405 IsArrayLength(left_defn) ? | |
3406 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | |
3407 | |
3408 RangeBoundary left_max = | |
3409 IsArrayLength(left_defn) ? | |
3410 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | |
3411 | |
3412 if (!RangeBoundary::SymbolicAdd(left_min, right_range->min(), min)) { | |
3413 *min = RangeBoundary::Add(left_range->min().LowerBound(), | |
3414 right_range->min().LowerBound(), | |
3415 RangeBoundary::NegativeInfinity()); | |
3416 } | |
3417 if (!RangeBoundary::SymbolicAdd(left_max, right_range->max(), max)) { | |
3418 *max = RangeBoundary::Add(right_range->max().UpperBound(), | |
3419 left_range->max().UpperBound(), | |
3420 RangeBoundary::PositiveInfinity()); | |
3421 } | |
3422 } | |
3423 | |
3424 | |
3425 void Range::Sub(const Range* left_range, | |
3426 const Range* right_range, | |
3427 RangeBoundary* min, | |
3428 RangeBoundary* max, | |
3429 Definition* left_defn) { | |
3430 ASSERT(left_range != NULL); | |
3431 ASSERT(right_range != NULL); | |
3432 ASSERT(min != NULL); | |
3433 ASSERT(max != NULL); | |
3434 | |
3435 RangeBoundary left_min = | |
3436 IsArrayLength(left_defn) ? | |
3437 RangeBoundary::FromDefinition(left_defn) : left_range->min(); | |
3438 | |
3439 RangeBoundary left_max = | |
3440 IsArrayLength(left_defn) ? | |
3441 RangeBoundary::FromDefinition(left_defn) : left_range->max(); | |
3442 | |
3443 if (!RangeBoundary::SymbolicSub(left_min, right_range->max(), min)) { | |
3444 *min = RangeBoundary::Sub(left_range->min().LowerBound(), | |
3445 right_range->max().UpperBound(), | |
3446 RangeBoundary::NegativeInfinity()); | |
3447 } | |
3448 if (!RangeBoundary::SymbolicSub(left_max, right_range->min(), max)) { | |
3449 *max = RangeBoundary::Sub(left_range->max().UpperBound(), | |
3450 right_range->min().LowerBound(), | |
3451 RangeBoundary::PositiveInfinity()); | |
3452 } | |
3453 } | |
3454 | |
3455 | |
3456 bool Range::Mul(const Range* left_range, | |
3457 const Range* right_range, | |
3458 RangeBoundary* min, | |
3459 RangeBoundary* max) { | |
3460 ASSERT(left_range != NULL); | |
3461 ASSERT(right_range != NULL); | |
3462 ASSERT(min != NULL); | |
3463 ASSERT(max != NULL); | |
3464 | |
3465 const int64_t left_max = ConstantAbsMax(left_range); | |
3466 const int64_t right_max = ConstantAbsMax(right_range); | |
3467 if ((left_max <= -kSmiMin) && (right_max <= -kSmiMin) && | |
3468 ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) { | |
3469 // Product of left and right max values stays in 64 bit range. | |
3470 const int64_t result_max = left_max * right_max; | |
3471 if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { | |
3472 const intptr_t r_min = | |
3473 OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -result_max; | |
3474 *min = RangeBoundary::FromConstant(r_min); | |
3475 const intptr_t r_max = | |
3476 OnlyNegativeOrZero(*left_range, *right_range) ? 0 : result_max; | |
3477 *max = RangeBoundary::FromConstant(r_max); | |
3478 return true; | |
3479 } | |
3480 } | |
3481 return false; | |
3482 } | |
3483 | |
3484 | |
3485 // Both the a and b ranges are >= 0. | |
3486 bool Range::OnlyPositiveOrZero(const Range& a, const Range& b) { | |
3487 return a.OnlyGreaterThanOrEqualTo(0) && b.OnlyGreaterThanOrEqualTo(0); | |
3488 } | |
3489 | |
3490 | |
3491 // Both the a and b ranges are <= 0. | |
3492 bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { | |
3493 return a.OnlyLessThanOrEqualTo(0) && b.OnlyLessThanOrEqualTo(0); | |
3494 } | |
3495 | |
3496 | |
3497 // Return the maximum absolute value included in range. | |
3498 int64_t Range::ConstantAbsMax(const Range* range) { | |
3499 if (range == NULL) { | |
3500 return RangeBoundary::kMax; | |
3501 } | |
3502 const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue()); | |
3503 const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue()); | |
3504 return Utils::Maximum(abs_min, abs_max); | |
3505 } | |
3506 | |
3507 | |
3508 Range* Range::BinaryOp(const Token::Kind op, | |
3509 const Range* left_range, | |
3510 const Range* right_range, | |
3511 Definition* left_defn) { | |
3512 ASSERT(left_range != NULL); | |
3513 ASSERT(right_range != NULL); | |
3514 | |
3515 // Both left and right ranges are finite. | |
3516 ASSERT(left_range->IsFinite()); | |
3517 ASSERT(right_range->IsFinite()); | |
3518 | |
3519 RangeBoundary min; | |
3520 RangeBoundary max; | |
3521 ASSERT(min.IsUnknown() && max.IsUnknown()); | |
3522 | |
3523 switch (op) { | |
3524 case Token::kADD: | |
3525 Range::Add(left_range, right_range, &min, &max, left_defn); | |
3526 break; | |
3527 case Token::kSUB: | |
3528 Range::Sub(left_range, right_range, &min, &max, left_defn); | |
3529 break; | |
3530 case Token::kMUL: { | |
3531 if (!Range::Mul(left_range, right_range, &min, &max)) { | |
3532 return NULL; | |
3533 } | |
3534 break; | |
3535 } | |
3536 case Token::kSHL: { | |
3537 Range::Shl(left_range, right_range, &min, &max); | |
3538 break; | |
3539 } | |
3540 case Token::kBIT_AND: | |
3541 if (!Range::And(left_range, right_range, &min, &max)) { | |
3542 return NULL; | |
3543 } | |
3544 break; | |
3545 default: | |
3546 return NULL; | |
3547 break; | |
3548 } | |
3549 | |
3550 ASSERT(!min.IsUnknown() && !max.IsUnknown()); | |
3551 | |
3552 return new Range(min, max); | |
3553 } | |
3554 | |
3555 | |
3267 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3556 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
3268 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3557 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
3269 } | 3558 } |
3270 | 3559 |
3271 | 3560 |
3272 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { | 3561 bool CheckArrayBoundInstr::IsRedundant(RangeBoundary length) { |
3273 Range* index_range = index()->definition()->range(); | 3562 Range* index_range = index()->definition()->range(); |
3274 | 3563 |
3275 // Range of the index is unknown can't decide if the check is redundant. | 3564 // Range of the index is unknown can't decide if the check is redundant. |
3276 if (index_range == NULL) { | 3565 if (index_range == NULL) { |
3277 return false; | 3566 return false; |
3278 } | 3567 } |
3279 | 3568 |
3280 // Range of the index is not positive. Check can't be redundant. | 3569 // Range of the index is not positive. Check can't be redundant. |
3281 if (Range::ConstantMin(index_range).value() < 0) { | 3570 if (Range::ConstantMinSmi(index_range).ConstantValue() < 0) { |
3282 return false; | 3571 return false; |
3283 } | 3572 } |
3284 | 3573 |
3285 RangeBoundary max = CanonicalizeBoundary(index_range->max(), | 3574 RangeBoundary max = CanonicalizeBoundary(index_range->max(), |
3286 RangeBoundary::PositiveInfinity()); | 3575 RangeBoundary::PositiveInfinity()); |
3287 | 3576 |
3288 if (max.Overflowed()) { | 3577 if (max.OverflowedSmi()) { |
3289 return false; | 3578 return false; |
3290 } | 3579 } |
3291 | 3580 |
3292 | 3581 |
3293 RangeBoundary max_upper = max.UpperBound(); | 3582 RangeBoundary max_upper = max.UpperBound(); |
3294 RangeBoundary length_lower = length.LowerBound(); | 3583 RangeBoundary length_lower = length.LowerBound(); |
3295 | 3584 |
3296 if (max_upper.Overflowed() || length_lower.Overflowed()) { | 3585 if (max_upper.OverflowedSmi() || length_lower.OverflowedSmi()) { |
3297 return false; | 3586 return false; |
3298 } | 3587 } |
3299 | 3588 |
3300 // Try to compare constant boundaries. | 3589 // Try to compare constant boundaries. |
3301 if (max_upper.value() < length_lower.value()) { | 3590 if (max_upper.ConstantValue() < length_lower.ConstantValue()) { |
3302 return true; | 3591 return true; |
3303 } | 3592 } |
3304 | 3593 |
3305 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); | 3594 length = CanonicalizeBoundary(length, RangeBoundary::PositiveInfinity()); |
3306 if (length.Overflowed()) { | 3595 if (length.OverflowedSmi()) { |
3307 return false; | 3596 return false; |
3308 } | 3597 } |
3309 | 3598 |
3310 // Try symbolic comparison. | 3599 // Try symbolic comparison. |
3311 do { | 3600 do { |
3312 if (DependOnSameSymbol(max, length)) return max.offset() < length.offset(); | 3601 if (DependOnSameSymbol(max, length)) return max.offset() < length.offset(); |
3313 } while (CanonicalizeMaxBoundary(&max) || CanonicalizeMinBoundary(&length)); | 3602 } while (CanonicalizeMaxBoundary(&max) || CanonicalizeMinBoundary(&length)); |
3314 | 3603 |
3315 // Failed to prove that maximum is bounded with array length. | 3604 // Failed to prove that maximum is bounded with array length. |
3316 return false; | 3605 return false; |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3589 case Token::kTRUNCDIV: return 0; | 3878 case Token::kTRUNCDIV: return 0; |
3590 case Token::kMOD: return 1; | 3879 case Token::kMOD: return 1; |
3591 default: UNIMPLEMENTED(); return -1; | 3880 default: UNIMPLEMENTED(); return -1; |
3592 } | 3881 } |
3593 } | 3882 } |
3594 | 3883 |
3595 | 3884 |
3596 #undef __ | 3885 #undef __ |
3597 | 3886 |
3598 } // namespace dart | 3887 } // namespace dart |
OLD | NEW |