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/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 3912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3923 UNREACHABLE(); | 3923 UNREACHABLE(); |
3924 } | 3924 } |
3925 | 3925 |
3926 | 3926 |
3927 void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { | 3927 void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) { |
3928 // Instruction is eliminated when translating to SSA. | 3928 // Instruction is eliminated when translating to SSA. |
3929 UNREACHABLE(); | 3929 UNREACHABLE(); |
3930 } | 3930 } |
3931 | 3931 |
3932 | 3932 |
3933 void ConstantPropagator::VisitIfThenElse(IfThenElseInstr* instr) { | |
3934 const Object& left = instr->left()->definition()->constant_value(); | |
3935 const Object& right = instr->right()->definition()->constant_value(); | |
3936 | |
3937 if (IsNonConstant(left) || IsNonConstant(right)) { | |
3938 // TODO(vegorov): incorporate nullability information into the lattice. | |
Florian Schneider
2013/04/10 13:59:50
Maybe check Token::IsEqualityOperator(kind()) even
Vyacheslav Egorov (Google)
2013/04/10 14:51:32
Done.
| |
3939 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || | |
3940 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { | |
3941 bool result = left.IsNull() ? instr->right()->Type()->IsNull() | |
3942 : instr->left()->Type()->IsNull(); | |
3943 if (instr->kind() == Token::kNE_STRICT || | |
3944 instr->kind() == Token::kNE) { | |
3945 result = !result; | |
3946 } | |
3947 SetValue(instr, Smi::Handle( | |
3948 Smi::New(result ? instr->if_true() : instr->if_false()))); | |
3949 } else { | |
3950 SetValue(instr, non_constant_); | |
3951 } | |
3952 } else if (IsConstant(left) && IsConstant(right)) { | |
3953 bool result = (left.raw() == right.raw()); | |
3954 if (instr->kind() == Token::kNE_STRICT || | |
3955 instr->kind() == Token::kNE) { | |
3956 result = !result; | |
3957 } | |
3958 SetValue(instr, Smi::Handle( | |
3959 Smi::New(result ? instr->if_true() : instr->if_false()))); | |
3960 } | |
3961 } | |
3962 | |
3963 | |
3933 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { | 3964 void ConstantPropagator::VisitStrictCompare(StrictCompareInstr* instr) { |
3934 const Object& left = instr->left()->definition()->constant_value(); | 3965 const Object& left = instr->left()->definition()->constant_value(); |
3935 const Object& right = instr->right()->definition()->constant_value(); | 3966 const Object& right = instr->right()->definition()->constant_value(); |
3936 | 3967 |
3937 if (IsNonConstant(left) || IsNonConstant(right)) { | 3968 if (IsNonConstant(left) || IsNonConstant(right)) { |
3938 // TODO(vegorov): incorporate nullability information into the lattice. | 3969 // TODO(vegorov): incorporate nullability information into the lattice. |
3939 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || | 3970 if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) || |
3940 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { | 3971 (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) { |
3941 bool result = left.IsNull() ? instr->right()->Type()->IsNull() | 3972 bool result = left.IsNull() ? instr->right()->Type()->IsNull() |
3942 : instr->left()->Type()->IsNull(); | 3973 : instr->left()->Type()->IsNull(); |
(...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4742 | 4773 |
4743 if (changed) { | 4774 if (changed) { |
4744 // We may have changed the block order and the dominator tree. | 4775 // We may have changed the block order and the dominator tree. |
4745 flow_graph->DiscoverBlocks(); | 4776 flow_graph->DiscoverBlocks(); |
4746 GrowableArray<BitVector*> dominance_frontier; | 4777 GrowableArray<BitVector*> dominance_frontier; |
4747 flow_graph->ComputeDominators(&dominance_frontier); | 4778 flow_graph->ComputeDominators(&dominance_frontier); |
4748 } | 4779 } |
4749 } | 4780 } |
4750 | 4781 |
4751 | 4782 |
4783 static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) { | |
4784 return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) && | |
4785 ((block->next() == block->last_instruction()) || | |
4786 ((block->next() == defn) && (defn->next() == block->last_instruction()))); | |
4787 } | |
4788 | |
4789 | |
4790 static void EliminateTrivialBlock(BlockEntryInstr* block, | |
4791 Definition* instr, | |
4792 IfThenElseInstr* before) { | |
4793 block->UnuseAllInputs(); | |
4794 block->last_instruction()->UnuseAllInputs(); | |
4795 | |
4796 if ((block->next() == instr) && | |
4797 (instr->next() == block->last_instruction())) { | |
4798 before->previous()->LinkTo(instr); | |
4799 instr->LinkTo(before); | |
4800 } | |
4801 } | |
4802 | |
4803 | |
4804 void IfConverter::Simplify(FlowGraph* flow_graph) { | |
4805 if (!IfThenElseInstr::IsSupported()) { | |
4806 return; | |
4807 } | |
4808 | |
4809 bool changed = false; | |
4810 | |
4811 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder(); | |
4812 for (BlockIterator it(postorder); !it.Done(); it.Advance()) { | |
4813 BlockEntryInstr* block = it.Current(); | |
4814 JoinEntryInstr* join = block->AsJoinEntry(); | |
4815 | |
4816 // Detect diamond control flow pattern which materializes a value depending | |
4817 // on the result of the comparison: | |
4818 // | |
4819 // Ba: | |
4820 // ... | |
4821 // Branch if COMP goto (Bb, Bc) | |
4822 // Bb: -- trivial block that contains at most one definition | |
4823 // c1 = Constant(...) | |
4824 // goto Bd | |
4825 // Bc: -- trivial block that contains at most one definition | |
4826 // c2 = Constant(...) | |
4827 // goto Bd | |
4828 // Bd: | |
4829 // v = phi(c1, c2) -- single phi | |
4830 // | |
4831 // and replace it with | |
4832 // | |
4833 // Ba: | |
4834 // v = IfThenElse(COMP ? c1 : c2) | |
4835 // | |
4836 if ((join != NULL) && | |
4837 (join->phis() != NULL) && | |
4838 (join->phis()->length() == 1) && | |
4839 (block->PredecessorCount() == 2)) { | |
4840 BlockEntryInstr* pred1 = block->PredecessorAt(0); | |
Florian Schneider
2013/04/10 13:59:50
Why not use the same names as in the comments for
Vyacheslav Egorov (Google)
2013/04/10 14:51:32
Changed names in the comment to reflect naming in
| |
4841 BlockEntryInstr* pred2 = block->PredecessorAt(1); | |
4842 | |
4843 PhiInstr* phi = (*join->phis())[0]; | |
4844 Value* v1 = phi->InputAt(0); | |
4845 Value* v2 = phi->InputAt(1); | |
4846 | |
4847 if (IsTrivialBlock(pred1, v1->definition()) && | |
4848 IsTrivialBlock(pred2, v2->definition()) && | |
4849 (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) { | |
4850 BlockEntryInstr* pred = pred1->PredecessorAt(0); | |
4851 BranchInstr* branch = pred->last_instruction()->AsBranch(); | |
4852 ComparisonInstr* comparison = branch->comparison(); | |
4853 | |
4854 // Check if the platform supports efficient branchless IfThenElseInstr | |
4855 // for the given combination of comparison and values flowing from | |
4856 // false and true paths. | |
4857 if (IfThenElseInstr::Supports(comparison, v1, v2)) { | |
Florian Schneider
2013/04/10 13:59:50
I think the code becomes simpler with an early ret
Vyacheslav Egorov (Google)
2013/04/10 14:51:32
Can't use early return (there is a loop around thi
| |
4858 Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2; | |
4859 Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2; | |
4860 | |
4861 IfThenElseInstr* if_then_else = new IfThenElseInstr( | |
4862 comparison->kind(), | |
4863 comparison->InputAt(0)->Copy(), | |
4864 comparison->InputAt(1)->Copy(), | |
4865 if_true->Copy(), | |
4866 if_false->Copy()); | |
4867 flow_graph->InsertBefore(branch, | |
4868 if_then_else, | |
4869 NULL, | |
4870 Definition::kValue); | |
4871 | |
4872 phi->ReplaceUsesWith(if_then_else); | |
4873 | |
4874 // Connect IfThenElseInstr to the first instruction in the merge block | |
4875 // effectively eliminating diamond control flow. | |
4876 // Current block as well as pred1 and pred2 blocks are no longer in | |
4877 // the graph at this point. | |
4878 if_then_else->LinkTo(join->next()); | |
4879 pred->set_last_instruction(join->last_instruction()); | |
4880 | |
4881 // Resulting block must inherit block id from the eliminated current | |
4882 // block to guarantee that ordering of phi operands in its successor | |
4883 // stays consistent. | |
4884 pred->set_block_id(block->block_id()); | |
4885 | |
4886 // If v1 and v2 were defined inside eliminated blocks pred1/pred2 | |
4887 // move them out to the place before inserted IfThenElse instruction. | |
4888 EliminateTrivialBlock(pred1, v1->definition(), if_then_else); | |
4889 EliminateTrivialBlock(pred2, v2->definition(), if_then_else); | |
4890 | |
4891 // Update use lists to reflect changes in the graph. | |
4892 phi->UnuseAllInputs(); | |
4893 branch->UnuseAllInputs(); | |
4894 | |
4895 // The graph has changed. Recompute dominators and block orders after | |
4896 // this pass is finished. | |
4897 changed = true; | |
4898 } | |
4899 } | |
4900 } | |
4901 } | |
4902 | |
4903 if (changed) { | |
4904 // We may have changed the block order and the dominator tree. | |
4905 flow_graph->DiscoverBlocks(); | |
4906 GrowableArray<BitVector*> dominance_frontier; | |
4907 flow_graph->ComputeDominators(&dominance_frontier); | |
4908 } | |
4909 } | |
4910 | |
4911 | |
4752 } // namespace dart | 4912 } // namespace dart |
OLD | NEW |