Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Side by Side Diff: runtime/vm/flow_graph_range_analysis.cc

Issue 682993008: Improve precision of range analysis by allowing it to track ranges across all int typed phis. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698