| 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 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 Definition* defn = value->definition(); | 499 Definition* defn = value->definition(); |
| 500 const Range* range = defn->range(); | 500 const Range* range = defn->range(); |
| 501 | 501 |
| 502 if ((range == NULL) && (defn->Type()->ToCid() != kSmiCid)) { | 502 if ((range == NULL) && (defn->Type()->ToCid() != kSmiCid)) { |
| 503 // Type propagator determined that reaching type for this use is Smi. | 503 // Type propagator determined that reaching type for this use is Smi. |
| 504 // However the definition itself is not a smi-definition and | 504 // However the definition itself is not a smi-definition and |
| 505 // thus it will never have range assigned to it. Just return the widest | 505 // thus it will never have range assigned to it. Just return the widest |
| 506 // range possible for this value. | 506 // range possible for this value. |
| 507 // We don't need to handle kMintCid here because all external mints | 507 // We don't need to handle kMintCid here because all external mints |
| 508 // (e.g. results of loads or function call) can be used only after they | 508 // (e.g. results of loads or function call) can be used only after they |
| 509 // pass through UnboxIntegerInstr which is considered as mint-definition | 509 // pass through UnboxInt64Instr which is considered as mint-definition |
| 510 // and will have a range assigned to it. | 510 // and will have a range assigned to it. |
| 511 // Note: that we can't return NULL here because it is used as lattice's | 511 // 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*. | 512 // bottom element to indicate that the range was not computed *yet*. |
| 513 return &smi_range_; | 513 return &smi_range_; |
| 514 } | 514 } |
| 515 | 515 |
| 516 return range; | 516 return range; |
| 517 } | 517 } |
| 518 | 518 |
| 519 | 519 |
| (...skipping 1120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1640 FlowGraphPrinter printer(*flow_graph_); | 1640 FlowGraphPrinter printer(*flow_graph_); |
| 1641 printer.PrintBlocks(); | 1641 printer.PrintBlocks(); |
| 1642 } | 1642 } |
| 1643 } | 1643 } |
| 1644 | 1644 |
| 1645 | 1645 |
| 1646 bool IntegerInstructionSelector::IsPotentialUint32Definition(Definition* def) { | 1646 bool IntegerInstructionSelector::IsPotentialUint32Definition(Definition* def) { |
| 1647 // TODO(johnmccutchan): Consider Smi operations, to avoid unnecessary tagging | 1647 // TODO(johnmccutchan): Consider Smi operations, to avoid unnecessary tagging |
| 1648 // & untagged of intermediate results. | 1648 // & untagged of intermediate results. |
| 1649 // TODO(johnmccutchan): Consider phis. | 1649 // TODO(johnmccutchan): Consider phis. |
| 1650 return def->IsBoxInteger() || // BoxMint. | 1650 return def->IsBoxInt64() || |
| 1651 def->IsUnboxInteger() || // UnboxMint. | 1651 def->IsUnboxInt64() || |
| 1652 def->IsBinaryMintOp() || | 1652 def->IsBinaryMintOp() || |
| 1653 def->IsShiftMintOp() || | 1653 def->IsShiftMintOp() || |
| 1654 def->IsUnaryMintOp(); | 1654 def->IsUnaryMintOp(); |
| 1655 } | 1655 } |
| 1656 | 1656 |
| 1657 | 1657 |
| 1658 void IntegerInstructionSelector::FindPotentialUint32Definitions() { | 1658 void IntegerInstructionSelector::FindPotentialUint32Definitions() { |
| 1659 if (FLAG_trace_integer_ir_selection) { | 1659 if (FLAG_trace_integer_ir_selection) { |
| 1660 OS::Print("++++ Finding potential Uint32 definitions:\n"); | 1660 OS::Print("++++ Finding potential Uint32 definitions:\n"); |
| 1661 } | 1661 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1733 !selected_uint32_defs_->Contains(defn->ssa_temp_index())) { | 1733 !selected_uint32_defs_->Contains(defn->ssa_temp_index())) { |
| 1734 return false; | 1734 return false; |
| 1735 } | 1735 } |
| 1736 } | 1736 } |
| 1737 return true; | 1737 return true; |
| 1738 } | 1738 } |
| 1739 | 1739 |
| 1740 | 1740 |
| 1741 bool IntegerInstructionSelector::CanBecomeUint32(Definition* def) { | 1741 bool IntegerInstructionSelector::CanBecomeUint32(Definition* def) { |
| 1742 ASSERT(IsPotentialUint32Definition(def)); | 1742 ASSERT(IsPotentialUint32Definition(def)); |
| 1743 if (def->IsBoxInteger()) { | 1743 if (def->IsBoxInt64()) { |
| 1744 // If a BoxInteger's input is a candidate, the box is a candidate. | 1744 // If a BoxInt64's input is a candidate, the box is a candidate. |
| 1745 BoxIntegerInstr* box = def->AsBoxInteger(); | 1745 Definition* box_input = def->AsBoxInt64()->value()->definition(); |
| 1746 Definition* box_input = box->value()->definition(); | |
| 1747 return selected_uint32_defs_->Contains(box_input->ssa_temp_index()); | 1746 return selected_uint32_defs_->Contains(box_input->ssa_temp_index()); |
| 1748 } | 1747 } |
| 1749 // A right shift with an input outside of Uint32 range cannot be converted | 1748 // A right shift with an input outside of Uint32 range cannot be converted |
| 1750 // because we need the high bits. | 1749 // because we need the high bits. |
| 1751 if (def->IsShiftMintOp()) { | 1750 if (def->IsShiftMintOp()) { |
| 1752 ShiftMintOpInstr* op = def->AsShiftMintOp(); | 1751 ShiftMintOpInstr* op = def->AsShiftMintOp(); |
| 1753 if (op->op_kind() == Token::kSHR) { | 1752 if (op->op_kind() == Token::kSHR) { |
| 1754 Definition* shift_input = op->left()->definition(); | 1753 Definition* shift_input = op->left()->definition(); |
| 1755 ASSERT(shift_input != NULL); | 1754 ASSERT(shift_input != NULL); |
| 1756 Range* range = shift_input->range(); | 1755 Range* range = shift_input->range(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1811 ASSERT(IsPotentialUint32Definition(def)); | 1810 ASSERT(IsPotentialUint32Definition(def)); |
| 1812 // Should not see constant instructions. | 1811 // Should not see constant instructions. |
| 1813 ASSERT(!def->IsConstant()); | 1812 ASSERT(!def->IsConstant()); |
| 1814 if (def->IsBinaryMintOp()) { | 1813 if (def->IsBinaryMintOp()) { |
| 1815 BinaryMintOpInstr* op = def->AsBinaryMintOp(); | 1814 BinaryMintOpInstr* op = def->AsBinaryMintOp(); |
| 1816 Token::Kind op_kind = op->op_kind(); | 1815 Token::Kind op_kind = op->op_kind(); |
| 1817 Value* left = op->left()->CopyWithType(); | 1816 Value* left = op->left()->CopyWithType(); |
| 1818 Value* right = op->right()->CopyWithType(); | 1817 Value* right = op->right()->CopyWithType(); |
| 1819 intptr_t deopt_id = op->DeoptimizationTarget(); | 1818 intptr_t deopt_id = op->DeoptimizationTarget(); |
| 1820 return new(I) BinaryUint32OpInstr(op_kind, left, right, deopt_id); | 1819 return new(I) BinaryUint32OpInstr(op_kind, left, right, deopt_id); |
| 1821 } else if (def->IsBoxInteger()) { | 1820 } else if (def->IsBoxInt64()) { |
| 1822 BoxIntegerInstr* box = def->AsBoxInteger(); | 1821 Value* value = def->AsBoxInt64()->value()->CopyWithType(); |
| 1823 Value* value = box->value()->CopyWithType(); | |
| 1824 return new(I) BoxUint32Instr(value); | 1822 return new(I) BoxUint32Instr(value); |
| 1825 } else if (def->IsUnboxInteger()) { | 1823 } else if (def->IsUnboxInt64()) { |
| 1826 UnboxIntegerInstr* unbox = def->AsUnboxInteger(); | 1824 UnboxInstr* unbox = def->AsUnboxInt64(); |
| 1827 Value* value = unbox->value()->CopyWithType(); | 1825 Value* value = unbox->value()->CopyWithType(); |
| 1828 intptr_t deopt_id = unbox->deopt_id(); | 1826 intptr_t deopt_id = unbox->DeoptimizationTarget(); |
| 1829 return new(I) UnboxUint32Instr(value, deopt_id); | 1827 return new(I) UnboxUint32Instr(value, deopt_id); |
| 1830 } else if (def->IsUnaryMintOp()) { | 1828 } else if (def->IsUnaryMintOp()) { |
| 1831 UnaryMintOpInstr* op = def->AsUnaryMintOp(); | 1829 UnaryMintOpInstr* op = def->AsUnaryMintOp(); |
| 1832 Token::Kind op_kind = op->op_kind(); | 1830 Token::Kind op_kind = op->op_kind(); |
| 1833 Value* value = op->value()->CopyWithType(); | 1831 Value* value = op->value()->CopyWithType(); |
| 1834 intptr_t deopt_id = op->DeoptimizationTarget(); | 1832 intptr_t deopt_id = op->DeoptimizationTarget(); |
| 1835 return new(I) UnaryUint32OpInstr(op_kind, value, deopt_id); | 1833 return new(I) UnaryUint32OpInstr(op_kind, value, deopt_id); |
| 1836 } else if (def->IsShiftMintOp()) { | 1834 } else if (def->IsShiftMintOp()) { |
| 1837 ShiftMintOpInstr* op = def->AsShiftMintOp(); | 1835 ShiftMintOpInstr* op = def->AsShiftMintOp(); |
| 1838 Token::Kind op_kind = op->op_kind(); | 1836 Token::Kind op_kind = op->op_kind(); |
| (...skipping 1062 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2901 } | 2899 } |
| 2902 | 2900 |
| 2903 | 2901 |
| 2904 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2902 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2905 InferRangeHelper(left()->definition()->range(), | 2903 InferRangeHelper(left()->definition()->range(), |
| 2906 right()->definition()->range(), | 2904 right()->definition()->range(), |
| 2907 range); | 2905 range); |
| 2908 } | 2906 } |
| 2909 | 2907 |
| 2910 | 2908 |
| 2911 void BoxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 2909 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2912 const Range* value_range = value()->definition()->range(); | 2910 const Range* value_range = value()->definition()->range(); |
| 2913 if (!Range::IsUnknown(value_range)) { | 2911 if (!Range::IsUnknown(value_range)) { |
| 2914 *range = *value_range; | 2912 *range = *value_range; |
| 2915 } | 2913 } |
| 2916 } | 2914 } |
| 2917 | 2915 |
| 2918 | 2916 |
| 2919 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 2917 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2920 if (value()->definition()->Type()->ToCid() == kSmiCid) { | 2918 if (value()->definition()->Type()->ToCid() == kSmiCid) { |
| 2921 const Range* value_range = analysis->GetSmiRange(value()); | 2919 const Range* value_range = analysis->GetSmiRange(value()); |
| 2922 if (!Range::IsUnknown(value_range)) { | 2920 if (!Range::IsUnknown(value_range)) { |
| 2923 *range = *value_range; | 2921 *range = *value_range; |
| 2924 } | 2922 } |
| 2925 } else if (value()->definition()->IsMintDefinition() || | 2923 } else if (value()->definition()->IsMintDefinition() || |
| 2926 value()->definition()->IsInt32Definition()) { | 2924 value()->definition()->IsInt32Definition()) { |
| 2927 const Range* value_range = value()->definition()->range(); | 2925 const Range* value_range = value()->definition()->range(); |
| 2928 if (!Range::IsUnknown(value_range)) { | 2926 if (!Range::IsUnknown(value_range)) { |
| 2929 *range = *value_range; | 2927 *range = *value_range; |
| 2930 } | 2928 } |
| 2931 } else if (value()->Type()->ToCid() == kSmiCid) { | 2929 } else if (value()->Type()->ToCid() == kSmiCid) { |
| 2932 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); | 2930 *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
| 2933 } else { | 2931 } else { |
| 2934 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); | 2932 *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
| 2935 } | 2933 } |
| 2936 } | 2934 } |
| 2937 | 2935 |
| 2938 | 2936 |
| 2937 void UnboxInt64Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2938 const Range* value_range = value()->definition()->range(); |
| 2939 if (value_range != NULL) { |
| 2940 *range = *value_range; |
| 2941 } else if (!value()->definition()->IsMintDefinition() && |
| 2942 (value()->definition()->Type()->ToCid() != kSmiCid)) { |
| 2943 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
| 2944 } |
| 2945 } |
| 2946 |
| 2947 |
| 2939 void UnboxedIntConverterInstr::InferRange(RangeAnalysis* analysis, | 2948 void UnboxedIntConverterInstr::InferRange(RangeAnalysis* analysis, |
| 2940 Range* range) { | 2949 Range* range) { |
| 2941 ASSERT((from() == kUnboxedInt32) || | 2950 ASSERT((from() == kUnboxedInt32) || |
| 2942 (from() == kUnboxedMint) || | 2951 (from() == kUnboxedMint) || |
| 2943 (from() == kUnboxedUint32)); | 2952 (from() == kUnboxedUint32)); |
| 2944 ASSERT((to() == kUnboxedInt32) || | 2953 ASSERT((to() == kUnboxedInt32) || |
| 2945 (to() == kUnboxedMint) || | 2954 (to() == kUnboxedMint) || |
| 2946 (to() == kUnboxedUint32)); | 2955 (to() == kUnboxedUint32)); |
| 2947 const Range* value_range = value()->definition()->range(); | 2956 const Range* value_range = value()->definition()->range(); |
| 2948 if (Range::IsUnknown(value_range)) { | 2957 if (Range::IsUnknown(value_range)) { |
| 2949 return; | 2958 return; |
| 2950 } | 2959 } |
| 2951 | 2960 |
| 2952 if (to() == kUnboxedUint32) { | 2961 if (to() == kUnboxedUint32) { |
| 2953 // TODO(vegorov): improve range information for unboxing to Uint32. | 2962 // TODO(vegorov): improve range information for unboxing to Uint32. |
| 2954 *range = Range( | 2963 *range = Range( |
| 2955 RangeBoundary::FromConstant(0), | 2964 RangeBoundary::FromConstant(0), |
| 2956 RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32))); | 2965 RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32))); |
| 2957 } else { | 2966 } else { |
| 2958 *range = *value_range; | 2967 *range = *value_range; |
| 2959 if (to() == kUnboxedInt32) { | 2968 if (to() == kUnboxedInt32) { |
| 2960 range->Clamp(RangeBoundary::kRangeBoundaryInt32); | 2969 range->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 2961 } | 2970 } |
| 2962 } | 2971 } |
| 2963 } | 2972 } |
| 2964 | 2973 |
| 2965 | 2974 |
| 2966 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2967 const Range* input_range = value()->definition()->range(); | |
| 2968 if (input_range != NULL) { | |
| 2969 bool is_smi = input_range->Fits(RangeBoundary::kRangeBoundarySmi); | |
| 2970 set_is_smi(is_smi); | |
| 2971 // The output range is the same as the input range. | |
| 2972 *range = *input_range; | |
| 2973 } | |
| 2974 } | |
| 2975 | |
| 2976 | |
| 2977 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2978 const Range* value_range = value()->definition()->range(); | |
| 2979 if (value_range != NULL) { | |
| 2980 *range = *value_range; | |
| 2981 } else if (!value()->definition()->IsMintDefinition() && | |
| 2982 (value()->definition()->Type()->ToCid() != kSmiCid)) { | |
| 2983 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | |
| 2984 } | |
| 2985 } | |
| 2986 | |
| 2987 | |
| 2988 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { | 2975 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { |
| 2989 Range* index_range = index()->definition()->range(); | 2976 Range* index_range = index()->definition()->range(); |
| 2990 | 2977 |
| 2991 // Range of the index is unknown can't decide if the check is redundant. | 2978 // Range of the index is unknown can't decide if the check is redundant. |
| 2992 if (index_range == NULL) { | 2979 if (index_range == NULL) { |
| 2993 if (!(index()->BindsToConstant() && index()->BoundConstant().IsSmi())) { | 2980 if (!(index()->BindsToConstant() && index()->BoundConstant().IsSmi())) { |
| 2994 return false; | 2981 return false; |
| 2995 } | 2982 } |
| 2996 | 2983 |
| 2997 Range range; | 2984 Range range; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3040 } | 3027 } |
| 3041 } while (CanonicalizeMaxBoundary(&max) || | 3028 } while (CanonicalizeMaxBoundary(&max) || |
| 3042 CanonicalizeMinBoundary(&canonical_length)); | 3029 CanonicalizeMinBoundary(&canonical_length)); |
| 3043 | 3030 |
| 3044 // Failed to prove that maximum is bounded with array length. | 3031 // Failed to prove that maximum is bounded with array length. |
| 3045 return false; | 3032 return false; |
| 3046 } | 3033 } |
| 3047 | 3034 |
| 3048 | 3035 |
| 3049 } // namespace dart | 3036 } // namespace dart |
| OLD | NEW |