Chromium Code Reviews| 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 |