OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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/flow_graph_range_analysis.h" | 5 #include "vm/flow_graph_range_analysis.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
9 | 9 |
10 namespace dart { | 10 namespace dart { |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 if (IsIntegerDefinition(current)) { | 238 if (IsIntegerDefinition(current)) { |
239 values_.Add(current); | 239 values_.Add(current); |
240 } | 240 } |
241 } | 241 } |
242 } | 242 } |
243 | 243 |
244 JoinEntryInstr* join = block->AsJoinEntry(); | 244 JoinEntryInstr* join = block->AsJoinEntry(); |
245 if (join != NULL) { | 245 if (join != NULL) { |
246 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | 246 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
247 PhiInstr* current = phi_it.Current(); | 247 PhiInstr* current = phi_it.Current(); |
248 if ((current->Type()->ToCid() == kSmiCid) || | 248 if (current->Type()->IsInt()) { |
249 (current->representation() == kUnboxedInt32)) { | |
250 values_.Add(current); | 249 values_.Add(current); |
251 } | 250 } |
252 } | 251 } |
253 } | 252 } |
254 | 253 |
255 for (ForwardInstructionIterator instr_it(block); | 254 for (ForwardInstructionIterator instr_it(block); |
256 !instr_it.Done(); | 255 !instr_it.Done(); |
257 instr_it.Advance()) { | 256 instr_it.Advance()) { |
258 Instruction* current = instr_it.Current(); | 257 Instruction* current = instr_it.Current(); |
259 Definition* defn = current->AsDefinition(); | 258 Definition* defn = current->AsDefinition(); |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
510 // and will have a range assigned to it. | 509 // and will have a range assigned to it. |
511 // Note: that we can't return NULL here because it is used as lattice's | 510 // Note: that we can't return NULL here because it is used as lattice's |
512 // bottom element to indicate that the range was not computed *yet*. | 511 // bottom element to indicate that the range was not computed *yet*. |
513 return &smi_range_; | 512 return &smi_range_; |
514 } | 513 } |
515 | 514 |
516 return range; | 515 return range; |
517 } | 516 } |
518 | 517 |
519 | 518 |
519 const Range* RangeAnalysis::GetIntRange(Value* value) const { | |
520 Definition* defn = value->definition(); | |
521 const Range* range = defn->range(); | |
522 | |
523 if ((range == NULL) && !defn->Type()->IsInt()) { | |
524 // Type propagator determined that reaching type for this use is int. | |
525 // However the definition itself is not a int-definition and | |
526 // thus it will never have range assigned to it. Just return the widest | |
527 // range possible for this value. | |
528 // It is safe to return Int64 range as this is the widest possible range | |
529 // supported by our unboxing operations - if this definition produces | |
530 // Bigint outside of Int64 we will deoptimize whenever we actually try | |
531 // to unbox it. | |
532 // Note: that we can't return NULL here because it is used as lattice's | |
533 // bottom element to indicate that the range was not computed *yet*. | |
534 return &int64_range_; | |
535 } | |
536 | |
537 return range; | |
538 } | |
539 | |
540 | |
520 static bool AreEqualDefinitions(Definition* a, Definition* b) { | 541 static bool AreEqualDefinitions(Definition* a, Definition* b) { |
521 a = UnwrapConstraint(a); | 542 a = UnwrapConstraint(a); |
522 b = UnwrapConstraint(b); | 543 b = UnwrapConstraint(b); |
523 return (a == b) || | 544 return (a == b) || |
524 (a->AllowsCSE() && | 545 (a->AllowsCSE() && |
525 a->Dependencies().IsNone() && | 546 a->Dependencies().IsNone() && |
526 b->AllowsCSE() && | 547 b->AllowsCSE() && |
527 b->Dependencies().IsNone() && | 548 b->Dependencies().IsNone() && |
528 a->Equals(b)); | 549 a->Equals(b)); |
529 } | 550 } |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
632 switch (op) { | 653 switch (op) { |
633 case WIDEN: return 'W'; | 654 case WIDEN: return 'W'; |
634 case NARROW: return 'N'; | 655 case NARROW: return 'N'; |
635 case NONE: return 'I'; | 656 case NONE: return 'I'; |
636 } | 657 } |
637 UNREACHABLE(); | 658 UNREACHABLE(); |
638 return ' '; | 659 return ' '; |
639 } | 660 } |
640 | 661 |
641 | 662 |
663 static RangeBoundary::RangeSize RangeSizeForPhi(Definition* phi) { | |
664 ASSERT(phi->IsPhi()); | |
665 if (phi->Type()->ToCid() == kSmiCid) { | |
666 return RangeBoundary::kRangeBoundarySmi; | |
667 } else if (phi->representation() == kUnboxedInt32) { | |
668 return RangeBoundary::kRangeBoundaryInt32; | |
669 } else if (phi->Type()->IsInt()) { | |
670 return RangeBoundary::kRangeBoundaryInt64; | |
671 } else { | |
672 UNREACHABLE(); | |
673 return RangeBoundary::kRangeBoundaryInt64; | |
674 } | |
675 } | |
676 | |
677 | |
642 bool RangeAnalysis::InferRange(JoinOperator op, | 678 bool RangeAnalysis::InferRange(JoinOperator op, |
643 Definition* defn, | 679 Definition* defn, |
644 intptr_t iteration) { | 680 intptr_t iteration) { |
645 Range range; | 681 Range range; |
646 defn->InferRange(this, &range); | 682 defn->InferRange(this, &range); |
647 | 683 |
648 if (!Range::IsUnknown(&range)) { | 684 if (!Range::IsUnknown(&range)) { |
649 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { | 685 if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { |
650 // TODO(vegorov): we are currently supporting only smi/int32 phis. | 686 const RangeBoundary::RangeSize size = RangeSizeForPhi(defn); |
651 ASSERT((defn->Type()->ToCid() == kSmiCid) || | |
652 (defn->representation() == kUnboxedInt32)); | |
653 const RangeBoundary::RangeSize size = (defn->Type()->ToCid() == kSmiCid) ? | |
654 RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32; | |
655 if (op == WIDEN) { | 687 if (op == WIDEN) { |
656 range = Range(WidenMin(defn->range(), &range, size), | 688 range = Range(WidenMin(defn->range(), &range, size), |
657 WidenMax(defn->range(), &range, size)); | 689 WidenMax(defn->range(), &range, size)); |
658 } else if (op == NARROW) { | 690 } else if (op == NARROW) { |
659 range = Range(NarrowMin(defn->range(), &range, size), | 691 range = Range(NarrowMin(defn->range(), &range, size), |
660 NarrowMax(defn->range(), &range, size)); | 692 NarrowMax(defn->range(), &range, size)); |
661 } | 693 } |
662 } | 694 } |
663 | 695 |
664 if (!range.Equals(defn->range())) { | 696 if (!range.Equals(defn->range())) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
748 Definition* definition = initial[i]; | 780 Definition* definition = initial[i]; |
749 if (set->Contains(definition->ssa_temp_index())) { | 781 if (set->Contains(definition->ssa_temp_index())) { |
750 definitions_.Add(definition); | 782 definitions_.Add(definition); |
751 } | 783 } |
752 } | 784 } |
753 CollectDefinitions(set); | 785 CollectDefinitions(set); |
754 | 786 |
755 // Perform an iteration of range inference just propagating ranges | 787 // Perform an iteration of range inference just propagating ranges |
756 // through the graph as-is without applying widening or narrowing. | 788 // through the graph as-is without applying widening or narrowing. |
757 // This helps to improve precision of initial bounds. | 789 // This helps to improve precision of initial bounds. |
758 Iterate(NONE, 1); | 790 Iterate(NONE, 2); |
Florian Schneider
2014/11/10 16:10:47
Maybe a comment why 2 iterations help.
| |
759 | 791 |
760 // Perform fix-point iteration of range inference applying widening | 792 // Perform fix-point iteration of range inference applying widening |
761 // operator to phis to ensure fast convergence. | 793 // operator to phis to ensure fast convergence. |
762 // Widening simply maps growing bounds to the respective range bound. | 794 // Widening simply maps growing bounds to the respective range bound. |
763 Iterate(WIDEN, kMaxInt32); | 795 Iterate(WIDEN, kMaxInt32); |
764 | 796 |
765 if (FLAG_trace_range_analysis) { | 797 if (FLAG_trace_range_analysis) { |
766 FlowGraphPrinter::PrintGraph("Range Analysis (WIDEN)", flow_graph_); | 798 FlowGraphPrinter::PrintGraph("Range Analysis (WIDEN)", flow_graph_); |
767 } | 799 } |
768 | 800 |
(...skipping 1816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2585 } | 2617 } |
2586 | 2618 |
2587 | 2619 |
2588 void Definition::InferRange(RangeAnalysis* analysis, Range* range) { | 2620 void Definition::InferRange(RangeAnalysis* analysis, Range* range) { |
2589 if (Type()->ToCid() == kSmiCid) { | 2621 if (Type()->ToCid() == kSmiCid) { |
2590 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 2622 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
2591 } else if (IsMintDefinition()) { | 2623 } else if (IsMintDefinition()) { |
2592 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 2624 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
2593 } else if (IsInt32Definition()) { | 2625 } else if (IsInt32Definition()) { |
2594 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); | 2626 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
2627 } else if (Type()->IsInt()) { | |
2628 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | |
2595 } else { | 2629 } else { |
2596 // Only Smi and Mint supported. | 2630 // Only Smi and Mint supported. |
2597 UNREACHABLE(); | 2631 UNREACHABLE(); |
2598 } | 2632 } |
2599 } | 2633 } |
2600 | 2634 |
2601 | 2635 |
2602 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { | 2636 static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { |
2603 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); | 2637 return a.IsSymbol() && (UnwrapConstraint(a.symbol()) == symbol); |
2604 } | 2638 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2685 Definition* unwrapped = UnwrapConstraint(a.symbol()); | 2719 Definition* unwrapped = UnwrapConstraint(a.symbol()); |
2686 if ((unwrapped != a.symbol()) && | 2720 if ((unwrapped != a.symbol()) && |
2687 DominatesPhi(unwrapped->GetBlock(), phi_block)) { | 2721 DominatesPhi(unwrapped->GetBlock(), phi_block)) { |
2688 return RangeBoundary::FromDefinition(unwrapped, a.offset()); | 2722 return RangeBoundary::FromDefinition(unwrapped, a.offset()); |
2689 } | 2723 } |
2690 | 2724 |
2691 return limit; | 2725 return limit; |
2692 } | 2726 } |
2693 | 2727 |
2694 | 2728 |
2729 static const Range* GetInputRange(RangeAnalysis* analysis, | |
2730 RangeBoundary::RangeSize size, | |
2731 Value* input) { | |
2732 switch (size) { | |
2733 case RangeBoundary::kRangeBoundarySmi: | |
2734 return analysis->GetSmiRange(input); | |
2735 case RangeBoundary::kRangeBoundaryInt32: | |
2736 return input->definition()->range(); | |
2737 case RangeBoundary::kRangeBoundaryInt64: | |
2738 return analysis->GetIntRange(input); | |
2739 default: | |
2740 UNREACHABLE(); | |
2741 return NULL; | |
2742 } | |
2743 } | |
2744 | |
2745 | |
2695 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2746 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
2696 ASSERT((Type()->ToCid() == kSmiCid) || (representation() == kUnboxedInt32)); | 2747 const RangeBoundary::RangeSize size = RangeSizeForPhi(this); |
2697 const RangeBoundary::RangeSize size = (Type()->ToCid() == kSmiCid) ? | |
2698 RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32; | |
2699 for (intptr_t i = 0; i < InputCount(); i++) { | 2748 for (intptr_t i = 0; i < InputCount(); i++) { |
2700 Value* input = InputAt(i); | 2749 Value* input = InputAt(i); |
2701 const Range* input_range = (size == RangeBoundary::kRangeBoundarySmi) ? | |
2702 analysis->GetSmiRange(input) : input->definition()->range(); | |
2703 Join(range, | 2750 Join(range, |
2704 input->definition(), input_range, size); | 2751 input->definition(), |
2752 GetInputRange(analysis, size, input), | |
2753 size); | |
2705 } | 2754 } |
2706 | 2755 |
2707 BlockEntryInstr* phi_block = GetBlock(); | 2756 BlockEntryInstr* phi_block = GetBlock(); |
2708 range->set_min(EnsureAcyclicSymbol( | 2757 range->set_min(EnsureAcyclicSymbol( |
2709 phi_block, range->min(), RangeBoundary::MinSmi())); | 2758 phi_block, range->min(), RangeBoundary::MinSmi())); |
2710 range->set_max(EnsureAcyclicSymbol( | 2759 range->set_max(EnsureAcyclicSymbol( |
2711 phi_block, range->max(), RangeBoundary::MaxSmi())); | 2760 phi_block, range->max(), RangeBoundary::MaxSmi())); |
2712 } | 2761 } |
2713 | 2762 |
2714 | 2763 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2788 break; | 2837 break; |
2789 case kTypedDataInt16ArrayCid: | 2838 case kTypedDataInt16ArrayCid: |
2790 *range = Range(RangeBoundary::FromConstant(-32768), | 2839 *range = Range(RangeBoundary::FromConstant(-32768), |
2791 RangeBoundary::FromConstant(32767)); | 2840 RangeBoundary::FromConstant(32767)); |
2792 break; | 2841 break; |
2793 case kTypedDataUint16ArrayCid: | 2842 case kTypedDataUint16ArrayCid: |
2794 *range = Range(RangeBoundary::FromConstant(0), | 2843 *range = Range(RangeBoundary::FromConstant(0), |
2795 RangeBoundary::FromConstant(65535)); | 2844 RangeBoundary::FromConstant(65535)); |
2796 break; | 2845 break; |
2797 case kTypedDataInt32ArrayCid: | 2846 case kTypedDataInt32ArrayCid: |
2798 if (Typed32BitIsSmi()) { | 2847 *range = Range(RangeBoundary::FromConstant(kMinInt32), |
Florian Schneider
2014/11/10 16:10:47
Is Typed32BitIsSmi() still used anywhere?
| |
2799 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 2848 RangeBoundary::FromConstant(kMaxInt32)); |
2800 } else { | |
2801 *range = Range(RangeBoundary::FromConstant(kMinInt32), | |
2802 RangeBoundary::FromConstant(kMaxInt32)); | |
2803 } | |
2804 break; | 2849 break; |
2805 case kTypedDataUint32ArrayCid: | 2850 case kTypedDataUint32ArrayCid: |
2806 if (Typed32BitIsSmi()) { | 2851 *range = Range(RangeBoundary::FromConstant(0), |
2807 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 2852 RangeBoundary::FromConstant(kMaxUint32)); |
2808 } else { | |
2809 *range = Range(RangeBoundary::FromConstant(0), | |
2810 RangeBoundary::FromConstant(kMaxUint32)); | |
2811 } | |
2812 break; | 2853 break; |
2813 case kOneByteStringCid: | 2854 case kOneByteStringCid: |
2814 *range = Range(RangeBoundary::FromConstant(0), | 2855 *range = Range(RangeBoundary::FromConstant(0), |
2815 RangeBoundary::FromConstant(0xFF)); | 2856 RangeBoundary::FromConstant(0xFF)); |
2816 break; | 2857 break; |
2817 case kTwoByteStringCid: | 2858 case kTwoByteStringCid: |
2818 *range = Range(RangeBoundary::FromConstant(0), | 2859 *range = Range(RangeBoundary::FromConstant(0), |
2819 RangeBoundary::FromConstant(0xFFFF)); | 2860 RangeBoundary::FromConstant(0xFFFF)); |
2820 break; | 2861 break; |
2821 default: | 2862 default: |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2908 | 2949 |
2909 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2950 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
2910 const Range* value_range = value()->definition()->range(); | 2951 const Range* value_range = value()->definition()->range(); |
2911 if (!Range::IsUnknown(value_range)) { | 2952 if (!Range::IsUnknown(value_range)) { |
2912 *range = *value_range; | 2953 *range = *value_range; |
2913 } | 2954 } |
2914 } | 2955 } |
2915 | 2956 |
2916 | 2957 |
2917 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 2958 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
2918 if (value()->definition()->Type()->ToCid() == kSmiCid) { | 2959 if (value()->Type()->ToCid() == kSmiCid) { |
2919 const Range* value_range = analysis->GetSmiRange(value()); | 2960 const Range* value_range = analysis->GetSmiRange(value()); |
2920 if (!Range::IsUnknown(value_range)) { | 2961 if (!Range::IsUnknown(value_range)) { |
2921 *range = *value_range; | 2962 *range = *value_range; |
2922 } | 2963 } |
2923 } else if (value()->definition()->IsMintDefinition() || | 2964 } else if (RangeAnalysis::IsIntegerDefinition(value()->definition())) { |
2924 value()->definition()->IsInt32Definition()) { | 2965 const Range* value_range = analysis->GetIntRange(value()); |
2925 const Range* value_range = value()->definition()->range(); | |
2926 if (!Range::IsUnknown(value_range)) { | 2966 if (!Range::IsUnknown(value_range)) { |
2927 *range = *value_range; | 2967 *range = *value_range; |
2928 } | 2968 } |
2929 } else if (value()->Type()->ToCid() == kSmiCid) { | 2969 } else if (value()->Type()->ToCid() == kSmiCid) { |
2930 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 2970 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
2931 } else { | 2971 } else { |
2932 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); | 2972 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
2933 } | 2973 } |
2934 } | 2974 } |
2935 | 2975 |
2936 | 2976 |
2977 void UnboxUint32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | |
2978 const Range* value_range = NULL; | |
2979 | |
2980 if (value()->Type()->ToCid() == kSmiCid) { | |
2981 value_range = analysis->GetSmiRange(value()); | |
2982 } else if (RangeAnalysis::IsIntegerDefinition(value()->definition())) { | |
2983 value_range = analysis->GetIntRange(value()); | |
2984 } else { | |
2985 *range = Range(RangeBoundary::FromConstant(0), | |
2986 RangeBoundary::FromConstant(kMaxUint32)); | |
2987 return; | |
2988 } | |
2989 | |
2990 if (!Range::IsUnknown(value_range)) { | |
2991 if (value_range->IsPositive()) { | |
2992 *range = *value_range; | |
2993 } else { | |
2994 *range = Range(RangeBoundary::FromConstant(0), | |
2995 RangeBoundary::FromConstant(kMaxUint32)); | |
2996 } | |
2997 } | |
2998 } | |
2999 | |
3000 | |
2937 void UnboxInt64Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 3001 void UnboxInt64Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
2938 const Range* value_range = value()->definition()->range(); | 3002 const Range* value_range = value()->definition()->range(); |
2939 if (value_range != NULL) { | 3003 if (value_range != NULL) { |
2940 *range = *value_range; | 3004 *range = *value_range; |
2941 } else if (!value()->definition()->IsMintDefinition() && | 3005 } else if (!value()->definition()->IsMintDefinition() && |
2942 (value()->definition()->Type()->ToCid() != kSmiCid)) { | 3006 (value()->definition()->Type()->ToCid() != kSmiCid)) { |
2943 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 3007 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
2944 } | 3008 } |
2945 } | 3009 } |
2946 | 3010 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3027 } | 3091 } |
3028 } while (CanonicalizeMaxBoundary(&max) || | 3092 } while (CanonicalizeMaxBoundary(&max) || |
3029 CanonicalizeMinBoundary(&canonical_length)); | 3093 CanonicalizeMinBoundary(&canonical_length)); |
3030 | 3094 |
3031 // Failed to prove that maximum is bounded with array length. | 3095 // Failed to prove that maximum is bounded with array length. |
3032 return false; | 3096 return false; |
3033 } | 3097 } |
3034 | 3098 |
3035 | 3099 |
3036 } // namespace dart | 3100 } // namespace dart |
OLD | NEW |