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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
11 #include "vm/exceptions.h" | 11 #include "vm/exceptions.h" |
12 #include "vm/flow_graph_builder.h" | 12 #include "vm/flow_graph_builder.h" |
13 #include "vm/flow_graph_compiler.h" | 13 #include "vm/flow_graph_compiler.h" |
14 #include "vm/flow_graph_range_analysis.h" | 14 #include "vm/flow_graph_range_analysis.h" |
15 #include "vm/hash_map.h" | 15 #include "vm/hash_map.h" |
16 #include "vm/il_printer.h" | 16 #include "vm/il_printer.h" |
17 #include "vm/intermediate_language.h" | 17 #include "vm/intermediate_language.h" |
18 #include "vm/object_store.h" | 18 #include "vm/object_store.h" |
19 #include "vm/parser.h" | 19 #include "vm/parser.h" |
20 #include "vm/regexp_assembler.h" | |
20 #include "vm/resolver.h" | 21 #include "vm/resolver.h" |
21 #include "vm/scopes.h" | 22 #include "vm/scopes.h" |
22 #include "vm/stack_frame.h" | 23 #include "vm/stack_frame.h" |
23 #include "vm/symbols.h" | 24 #include "vm/symbols.h" |
24 | 25 |
25 namespace dart { | 26 namespace dart { |
26 | 27 |
27 DEFINE_FLAG(int, getter_setter_ratio, 13, | 28 DEFINE_FLAG(int, getter_setter_ratio, 13, |
28 "Ratio of getter/setter usage used for double field unboxing heuristics"); | 29 "Ratio of getter/setter usage used for double field unboxing heuristics"); |
29 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 30 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
(...skipping 1594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1624 if (!ShouldInlineSimd()) { | 1625 if (!ShouldInlineSimd()) { |
1625 return false; | 1626 return false; |
1626 } | 1627 } |
1627 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, | 1628 return InlineByteArrayViewStore(target, call, receiver, receiver_cid, |
1628 kTypedDataInt32x4ArrayCid, | 1629 kTypedDataInt32x4ArrayCid, |
1629 ic_data, entry, last); | 1630 ic_data, entry, last); |
1630 case MethodRecognizer::kStringBaseCodeUnitAt: | 1631 case MethodRecognizer::kStringBaseCodeUnitAt: |
1631 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); | 1632 return InlineStringCodeUnitAt(call, receiver_cid, entry, last); |
1632 case MethodRecognizer::kStringBaseCharAt: | 1633 case MethodRecognizer::kStringBaseCharAt: |
1633 return InlineStringBaseCharAt(call, receiver_cid, entry, last); | 1634 return InlineStringBaseCharAt(call, receiver_cid, entry, last); |
1635 case MethodRecognizer::kOneByteString_oneCodeUnitAt: | |
1636 case MethodRecognizer::kTwoByteString_oneCodeUnitAt: | |
1637 return InlineStringCodeUnitsAt(call, receiver_cid, 1, entry, last); | |
1638 case MethodRecognizer::kOneByteString_twoCodeUnitsAt: | |
1639 case MethodRecognizer::kTwoByteString_twoCodeUnitsAt: | |
1640 return InlineStringCodeUnitsAt(call, receiver_cid, 2, entry, last); | |
1641 case MethodRecognizer::kOneByteString_fourCodeUnitsAt: | |
1642 return InlineStringCodeUnitsAt(call, receiver_cid, 4, entry, last); | |
1634 case MethodRecognizer::kDoubleAdd: | 1643 case MethodRecognizer::kDoubleAdd: |
1635 return InlineDoubleOp(Token::kADD, call, entry, last); | 1644 return InlineDoubleOp(Token::kADD, call, entry, last); |
1636 case MethodRecognizer::kDoubleSub: | 1645 case MethodRecognizer::kDoubleSub: |
1637 return InlineDoubleOp(Token::kSUB, call, entry, last); | 1646 return InlineDoubleOp(Token::kSUB, call, entry, last); |
1638 case MethodRecognizer::kDoubleMul: | 1647 case MethodRecognizer::kDoubleMul: |
1639 return InlineDoubleOp(Token::kMUL, call, entry, last); | 1648 return InlineDoubleOp(Token::kMUL, call, entry, last); |
1640 case MethodRecognizer::kDoubleDiv: | 1649 case MethodRecognizer::kDoubleDiv: |
1641 return InlineDoubleOp(Token::kDIV, call, entry, last); | 1650 return InlineDoubleOp(Token::kDIV, call, entry, last); |
1642 default: | 1651 default: |
1643 return false; | 1652 return false; |
(...skipping 1189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2833 *entry = new(I) TargetEntryInstr(flow_graph()->allocate_block_id(), | 2842 *entry = new(I) TargetEntryInstr(flow_graph()->allocate_block_id(), |
2834 call->GetBlock()->try_index()); | 2843 call->GetBlock()->try_index()); |
2835 (*entry)->InheritDeoptTarget(I, call); | 2844 (*entry)->InheritDeoptTarget(I, call); |
2836 | 2845 |
2837 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); | 2846 *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry); |
2838 | 2847 |
2839 return true; | 2848 return true; |
2840 } | 2849 } |
2841 | 2850 |
2842 | 2851 |
2852 Definition* FlowGraphOptimizer::PrepareInlineStringIndexOpUnchecked( | |
2853 Instruction* call, | |
2854 intptr_t cid, | |
2855 intptr_t count, | |
2856 Definition* str, | |
2857 Definition* index, | |
2858 Instruction* cursor) { | |
2859 LoadCodeUnitsInstr* load = new(I) LoadCodeUnitsInstr( | |
Vyacheslav Egorov (Google)
2014/10/01 20:13:21
[ignore this comment]
This is *a*whole*lot* of co
jgruber1
2014/10/03 18:59:51
I agree, the reason behind this was that LoadIndex
| |
2860 new(I) Value(str), | |
2861 new(I) Value(index), | |
2862 Instance::ElementSizeFor(cid), | |
2863 count, | |
2864 cid, | |
2865 Isolate::kNoDeoptId, | |
2866 call->token_pos()); | |
2867 | |
2868 cursor = flow_graph()->AppendTo(cursor, | |
2869 load, | |
2870 NULL, | |
2871 FlowGraph::kValue); | |
2872 ASSERT(cursor == load); | |
2873 return load; | |
2874 } | |
2875 | |
2876 | |
2877 bool FlowGraphOptimizer::InlineStringCodeUnitsAt( | |
2878 Instruction* call, | |
2879 intptr_t cid, | |
2880 intptr_t count, | |
2881 TargetEntryInstr** entry, | |
2882 Definition** last) { | |
2883 // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp. | |
2884 if (RawObject::IsExternalStringClassId(cid)) { | |
2885 return false; | |
2886 } | |
2887 | |
2888 Definition* str = call->ArgumentAt(0); | |
2889 Definition* index = call->ArgumentAt(1); | |
2890 | |
2891 *entry = new(I) TargetEntryInstr(flow_graph()->allocate_block_id(), | |
2892 call->GetBlock()->try_index()); | |
2893 (*entry)->InheritDeoptTarget(I, call); | |
2894 | |
2895 *last = PrepareInlineStringIndexOpUnchecked( | |
2896 call, cid, count, str, index, *entry); | |
2897 | |
2898 return true; | |
2899 } | |
2900 | |
2901 | |
2843 bool FlowGraphOptimizer::InlineStringBaseCharAt( | 2902 bool FlowGraphOptimizer::InlineStringBaseCharAt( |
2844 Instruction* call, | 2903 Instruction* call, |
2845 intptr_t cid, | 2904 intptr_t cid, |
2846 TargetEntryInstr** entry, | 2905 TargetEntryInstr** entry, |
2847 Definition** last) { | 2906 Definition** last) { |
2848 // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp. | 2907 // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp. |
2849 if (RawObject::IsExternalStringClassId(cid) || cid != kOneByteStringCid) { | 2908 if (RawObject::IsExternalStringClassId(cid) || cid != kOneByteStringCid) { |
2850 return false; | 2909 return false; |
2851 } | 2910 } |
2852 Definition* str = call->ArgumentAt(0); | 2911 Definition* str = call->ArgumentAt(0); |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3025 Bigint::neg_offset(), | 3084 Bigint::neg_offset(), |
3026 new(I) Value(bigint), | 3085 new(I) Value(bigint), |
3027 new(I) Value(value), | 3086 new(I) Value(value), |
3028 kEmitStoreBarrier, | 3087 kEmitStoreBarrier, |
3029 call->token_pos()); | 3088 call->token_pos()); |
3030 ReplaceCall(call, store); | 3089 ReplaceCall(call, store); |
3031 return true; | 3090 return true; |
3032 } | 3091 } |
3033 | 3092 |
3034 if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) || | 3093 if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) || |
3035 (recognized_kind == MethodRecognizer::kStringBaseCharAt)) && | 3094 (recognized_kind == MethodRecognizer::kStringBaseCharAt) || |
3095 (recognized_kind == MethodRecognizer::kOneByteString_oneCodeUnitAt) || | |
3096 (recognized_kind == MethodRecognizer::kOneByteString_twoCodeUnitsAt) || | |
3097 (recognized_kind == MethodRecognizer::kOneByteString_fourCodeUnitsAt) || | |
3098 (recognized_kind == MethodRecognizer::kTwoByteString_oneCodeUnitAt) || | |
3099 (recognized_kind == MethodRecognizer::kTwoByteString_twoCodeUnitsAt)) && | |
3036 (ic_data.NumberOfChecks() == 1) && | 3100 (ic_data.NumberOfChecks() == 1) && |
3037 ((class_ids[0] == kOneByteStringCid) || | 3101 ((class_ids[0] == kOneByteStringCid) || |
3038 (class_ids[0] == kTwoByteStringCid))) { | 3102 (class_ids[0] == kTwoByteStringCid))) { |
3039 return TryReplaceInstanceCallWithInline(call); | 3103 return TryReplaceInstanceCallWithInline(call); |
3040 } | 3104 } |
3041 | 3105 |
3042 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | 3106 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { |
3043 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | 3107 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { |
3044 // This is an internal method, no need to check argument types nor | 3108 // This is an internal method, no need to check argument types nor |
3045 // range. | 3109 // range. |
(...skipping 4634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7680 } | 7744 } |
7681 | 7745 |
7682 | 7746 |
7683 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { | 7747 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { |
7684 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 7748 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
7685 it.Current()->Accept(this); | 7749 it.Current()->Accept(this); |
7686 } | 7750 } |
7687 } | 7751 } |
7688 | 7752 |
7689 | 7753 |
7754 void ConstantPropagator::VisitIndirectEntry(IndirectEntryInstr* block) { | |
7755 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
7756 it.Current()->Accept(this); | |
7757 } | |
7758 } | |
7759 | |
7760 | |
7690 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { | 7761 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { |
7691 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | 7762 const GrowableArray<Definition*>& defs = *block->initial_definitions(); |
7692 for (intptr_t i = 0; i < defs.length(); ++i) { | 7763 for (intptr_t i = 0; i < defs.length(); ++i) { |
7693 defs[i]->Accept(this); | 7764 defs[i]->Accept(this); |
7694 } | 7765 } |
7695 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 7766 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
7696 it.Current()->Accept(this); | 7767 it.Current()->Accept(this); |
7697 } | 7768 } |
7698 } | 7769 } |
7699 | 7770 |
(...skipping 27 matching lines...) Expand all Loading... | |
7727 SetReachable(instr->successor()); | 7798 SetReachable(instr->successor()); |
7728 | 7799 |
7729 // Phi value depends on the reachability of a predecessor. We have | 7800 // Phi value depends on the reachability of a predecessor. We have |
7730 // to revisit phis every time a predecessor becomes reachable. | 7801 // to revisit phis every time a predecessor becomes reachable. |
7731 for (PhiIterator it(instr->successor()); !it.Done(); it.Advance()) { | 7802 for (PhiIterator it(instr->successor()); !it.Done(); it.Advance()) { |
7732 it.Current()->Accept(this); | 7803 it.Current()->Accept(this); |
7733 } | 7804 } |
7734 } | 7805 } |
7735 | 7806 |
7736 | 7807 |
7808 void ConstantPropagator::VisitIndirectGoto(IndirectGotoInstr* instr) { | |
7809 for (intptr_t i = 0; i < instr->SuccessorCount(); i++) { | |
7810 SetReachable(instr->SuccessorAt(i)); | |
7811 } | |
7812 } | |
7813 | |
7814 | |
7737 void ConstantPropagator::VisitBranch(BranchInstr* instr) { | 7815 void ConstantPropagator::VisitBranch(BranchInstr* instr) { |
7738 instr->comparison()->Accept(this); | 7816 instr->comparison()->Accept(this); |
7739 | 7817 |
7740 // The successors may be reachable, but only if this instruction is. (We | 7818 // The successors may be reachable, but only if this instruction is. (We |
7741 // might be analyzing it because the constant value of one of its inputs | 7819 // might be analyzing it because the constant value of one of its inputs |
7742 // has changed.) | 7820 // has changed.) |
7743 if (reachable_->Contains(instr->GetBlock()->preorder_number())) { | 7821 if (reachable_->Contains(instr->GetBlock()->preorder_number())) { |
7744 if (instr->constant_target() != NULL) { | 7822 if (instr->constant_target() != NULL) { |
7745 ASSERT((instr->constant_target() == instr->true_successor()) || | 7823 ASSERT((instr->constant_target() == instr->true_successor()) || |
7746 (instr->constant_target() == instr->false_successor())); | 7824 (instr->constant_target() == instr->false_successor())); |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8138 SetValue(instr, result); | 8216 SetValue(instr, result); |
8139 return; | 8217 return; |
8140 } | 8218 } |
8141 } | 8219 } |
8142 } | 8220 } |
8143 SetValue(instr, non_constant_); | 8221 SetValue(instr, non_constant_); |
8144 } | 8222 } |
8145 } | 8223 } |
8146 | 8224 |
8147 | 8225 |
8226 void ConstantPropagator::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | |
8227 // TODO(jgruber): Implement constant propagation. | |
8228 SetValue(instr, non_constant_); | |
8229 } | |
8230 | |
8231 | |
8148 void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) { | 8232 void ConstantPropagator::VisitStoreIndexed(StoreIndexedInstr* instr) { |
8149 SetValue(instr, instr->value()->definition()->constant_value()); | 8233 SetValue(instr, instr->value()->definition()->constant_value()); |
8150 } | 8234 } |
8151 | 8235 |
8152 | 8236 |
8153 void ConstantPropagator::VisitStoreInstanceField( | 8237 void ConstantPropagator::VisitStoreInstanceField( |
8154 StoreInstanceFieldInstr* instr) { | 8238 StoreInstanceFieldInstr* instr) { |
8155 SetValue(instr, instr->value()->definition()->constant_value()); | 8239 SetValue(instr, instr->value()->definition()->constant_value()); |
8156 } | 8240 } |
8157 | 8241 |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8780 const Object& right = instr->right()->definition()->constant_value(); | 8864 const Object& right = instr->right()->definition()->constant_value(); |
8781 if (IsNonConstant(left) || IsNonConstant(right)) { | 8865 if (IsNonConstant(left) || IsNonConstant(right)) { |
8782 SetValue(instr, non_constant_); | 8866 SetValue(instr, non_constant_); |
8783 } else if (IsConstant(left) && IsConstant(right)) { | 8867 } else if (IsConstant(left) && IsConstant(right)) { |
8784 // TODO(srdjan): Handle min and max. | 8868 // TODO(srdjan): Handle min and max. |
8785 SetValue(instr, non_constant_); | 8869 SetValue(instr, non_constant_); |
8786 } | 8870 } |
8787 } | 8871 } |
8788 | 8872 |
8789 | 8873 |
8874 void ConstantPropagator::VisitCaseInsensitiveCompareUC16( | |
8875 CaseInsensitiveCompareUC16Instr *instr) { | |
Florian Schneider
2014/10/01 17:04:13
Not sure if it's actually worth supporting: do you
jgruber1
2014/10/03 18:59:51
Done.
| |
8876 const Object& str = instr->str()->definition()->constant_value(); | |
8877 const Object& lhs_index = instr->lhs_index()->definition()->constant_value(); | |
8878 const Object& rhs_index = instr->rhs_index()->definition()->constant_value(); | |
8879 const Object& length = instr->length()->definition()->constant_value(); | |
8880 | |
8881 if (IsConstant(str) && str.IsString() && | |
8882 IsConstant(lhs_index) && lhs_index.IsSmi() && | |
8883 IsConstant(rhs_index) && rhs_index.IsSmi() && | |
8884 IsConstant(length) && length.IsSmi()) { | |
8885 const Bool& result = | |
8886 Bool::Handle(isolate(), | |
8887 IRRegExpMacroAssembler::CaseInsensitiveCompareUC16( | |
8888 String::Cast(str).raw(), | |
8889 Smi::Cast(lhs_index).raw(), | |
8890 Smi::Cast(rhs_index).raw(), | |
8891 Smi::Cast(length).raw())); | |
8892 SetValue(instr, result); | |
8893 } else { | |
8894 SetValue(instr, non_constant_); | |
8895 } | |
8896 } | |
8897 | |
8898 | |
8790 void ConstantPropagator::VisitUnboxDouble(UnboxDoubleInstr* instr) { | 8899 void ConstantPropagator::VisitUnboxDouble(UnboxDoubleInstr* instr) { |
8791 const Object& value = instr->value()->definition()->constant_value(); | 8900 const Object& value = instr->value()->definition()->constant_value(); |
8792 if (IsNonConstant(value)) { | 8901 if (IsNonConstant(value)) { |
8793 SetValue(instr, non_constant_); | 8902 SetValue(instr, non_constant_); |
8794 } else if (IsConstant(value)) { | 8903 } else if (IsConstant(value)) { |
8795 // TODO(kmillikin): Handle conversion. | 8904 // TODO(kmillikin): Handle conversion. |
8796 SetValue(instr, non_constant_); | 8905 SetValue(instr, non_constant_); |
8797 } | 8906 } |
8798 } | 8907 } |
8799 | 8908 |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8929 } else { | 9038 } else { |
8930 BlockEntryInstr* block = block_worklist_.RemoveLast(); | 9039 BlockEntryInstr* block = block_worklist_.RemoveLast(); |
8931 block->Accept(this); | 9040 block->Accept(this); |
8932 } | 9041 } |
8933 } | 9042 } |
8934 } | 9043 } |
8935 | 9044 |
8936 | 9045 |
8937 static bool IsEmptyBlock(BlockEntryInstr* block) { | 9046 static bool IsEmptyBlock(BlockEntryInstr* block) { |
8938 return block->next()->IsGoto() && | 9047 return block->next()->IsGoto() && |
8939 (!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)); | 9048 (!block->IsJoinEntry() || (block->AsJoinEntry()->phis() == NULL)) && |
9049 !block->IsIndirectEntry(); | |
8940 } | 9050 } |
8941 | 9051 |
8942 | 9052 |
8943 // Traverses a chain of empty blocks and returns the first reachable non-empty | 9053 // Traverses a chain of empty blocks and returns the first reachable non-empty |
8944 // block that is not dominated by the start block. The empty blocks are added | 9054 // block that is not dominated by the start block. The empty blocks are added |
8945 // to the supplied bit vector. | 9055 // to the supplied bit vector. |
8946 static BlockEntryInstr* FindFirstNonEmptySuccessor( | 9056 static BlockEntryInstr* FindFirstNonEmptySuccessor( |
8947 TargetEntryInstr* block, | 9057 TargetEntryInstr* block, |
8948 BitVector* empty_blocks) { | 9058 BitVector* empty_blocks) { |
8949 BlockEntryInstr* current = block; | 9059 BlockEntryInstr* current = block; |
(...skipping 1170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10120 | 10230 |
10121 // Insert materializations at environment uses. | 10231 // Insert materializations at environment uses. |
10122 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 10232 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
10123 CreateMaterializationAt( | 10233 CreateMaterializationAt( |
10124 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); | 10234 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); |
10125 } | 10235 } |
10126 } | 10236 } |
10127 | 10237 |
10128 | 10238 |
10129 } // namespace dart | 10239 } // namespace dart |
OLD | NEW |